Mercurial > libdvdnav.hg
annotate vm/decoder.c @ 249:5d643668f1e3 src
I added this code myself a long time ago, but now I am quite convinced that
it is wrong: Why would we filter out SPU stream change events that switch
SPUs off? This breaks watching the trailer on the RC2 of "Girl, interrupted",
because you always get unwanted subtitles.
When I added this code, it fixed a problem with the RC2 of "Terminator", but
I cannot reproduce this problem any more. Back then, the menu highlights would
not show up, but they do now. I assume the problem really got fixed with proper
support for forced subtitles in xine, so this crappy workaround here can go
away.
After all, this way it is more symmetric to audio stream change events,
because these are not filtered.
author | mroi |
---|---|
date | Sun, 12 Sep 2004 15:12:43 +0000 |
parents | e75c52894630 |
children | 130c10495b66 |
rev | line source |
---|---|
225 | 1 /* |
2 * Copyright (C) 2000, 2001 Martin Norbäck, Håkan Hjort | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
225
diff
changeset
|
3 * 2002-2004 the dvdnav project |
225 | 4 * |
5 * This file is part of libdvdnav, a DVD navigation library. It is modified | |
6 * from a file originally part of the Ogle DVD player. | |
7 * | |
8 * libdvdnav is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * libdvdnav is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
21 * | |
22 * $Id$ | |
23 * | |
24 */ | |
25 | |
26 #ifdef HAVE_CONFIG_H | |
27 #include "config.h" | |
28 #endif | |
29 | |
30 #include <stdio.h> | |
31 #include <stdlib.h> | |
32 #include <inttypes.h> | |
33 #include <string.h> /* For memset */ | |
34 #include "ifo_types.h" /* vm_cmd_t */ | |
35 | |
36 #include "dvdnav_internal.h" | |
37 | |
38 uint32_t vm_getbits(command_t *command, int32_t start, int32_t count) { | |
39 uint64_t result = 0; | |
40 uint64_t bit_mask = 0; | |
41 uint64_t examining = 0; | |
42 int32_t bits; | |
43 | |
44 if (count == 0) return 0; | |
45 | |
46 if ( ((start - count) < -1) || | |
47 (count > 32) || | |
48 (start > 63) || | |
49 (count < 0) || | |
50 (start < 0) ) { | |
51 fprintf(MSG_OUT, "libdvdnav: Bad call to vm_getbits. Parameter out of range\n"); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
225
diff
changeset
|
52 abort(); |
225 | 53 } |
54 /* all ones, please */ | |
55 bit_mask = ~bit_mask; | |
56 bit_mask >>= 63 - start; | |
57 bits = start + 1 - count; | |
58 examining = ((bit_mask >> bits) << bits ); | |
59 command->examined |= examining; | |
60 result = (command->instruction & bit_mask) >> bits; | |
61 return (uint32_t) result; | |
62 } | |
63 | |
64 static uint16_t get_GPRM(registers_t* registers, uint8_t reg) { | |
65 if (registers->GPRM_mode[reg] & 0x01) { | |
66 struct timeval current_time, time_offset; | |
67 uint16_t result; | |
68 /* Counter mode */ | |
69 /* fprintf(MSG_OUT, "libdvdnav: Getting counter %d\n",reg);*/ | |
70 gettimeofday(¤t_time, NULL); | |
71 time_offset.tv_sec = current_time.tv_sec - registers->GPRM_time[reg].tv_sec; | |
72 time_offset.tv_usec = current_time.tv_usec - registers->GPRM_time[reg].tv_usec; | |
73 if (time_offset.tv_usec < 0) { | |
74 time_offset.tv_sec--; | |
75 time_offset.tv_usec += 1000000; | |
76 } | |
77 result = (uint16_t) (time_offset.tv_sec & 0xffff); | |
78 registers->GPRM[reg]=result; | |
79 return result; | |
80 | |
81 } else { | |
82 /* Register mode */ | |
83 return registers->GPRM[reg]; | |
84 } | |
85 | |
86 } | |
87 | |
88 static void set_GPRM(registers_t* registers, uint8_t reg, uint16_t value) { | |
89 if (registers->GPRM_mode[reg] & 0x01) { | |
90 struct timeval current_time; | |
91 /* Counter mode */ | |
92 /* fprintf(MSG_OUT, "libdvdnav: Setting counter %d\n",reg); */ | |
93 gettimeofday(¤t_time, NULL); | |
94 registers->GPRM_time[reg] = current_time; | |
95 registers->GPRM_time[reg].tv_sec -= value; | |
96 } | |
97 registers->GPRM[reg] = value; | |
98 } | |
99 | |
100 /* Eval register code, can either be system or general register. | |
101 SXXX_XXXX, where S is 1 if it is system register. */ | |
102 static uint16_t eval_reg(command_t* command, uint8_t reg) { | |
103 if(reg & 0x80) { | |
104 if ((reg & 0x1f) == 20) { | |
105 fprintf(MSG_OUT, "libdvdnav: Suspected RCE Region Protection!!!\n"); | |
106 } | |
107 return command->registers->SPRM[reg & 0x1f]; /* FIXME max 24 not 32 */ | |
108 } else { | |
109 return get_GPRM(command->registers, reg & 0x0f) ; | |
110 } | |
111 } | |
112 | |
113 /* Eval register or immediate data. | |
114 AAAA_AAAA BBBB_BBBB, if immediate use all 16 bits for data else use | |
115 lower eight bits for the system or general purpose register. */ | |
116 static uint16_t eval_reg_or_data(command_t* command, int32_t imm, int32_t start) { | |
117 if(imm) { /* immediate */ | |
118 return vm_getbits(command, start, 16); | |
119 } else { | |
120 return eval_reg(command, vm_getbits(command, (start - 8), 8)); | |
121 } | |
122 } | |
123 | |
124 /* Eval register or immediate data. | |
125 xBBB_BBBB, if immediate use all 7 bits for data else use | |
126 lower four bits for the general purpose register number. */ | |
127 /* Evaluates gprm or data depending on bit, data is in byte n */ | |
128 static uint16_t eval_reg_or_data_2(command_t* command, | |
129 int32_t imm, int32_t start) { | |
130 if(imm) /* immediate */ | |
131 return vm_getbits(command, (start - 1), 7); | |
132 else | |
133 return get_GPRM(command->registers, (vm_getbits(command, (start - 4), 4)) ); | |
134 } | |
135 | |
136 | |
137 /* Compare data using operation, return result from comparison. | |
138 Helper function for the different if functions. */ | |
139 static int32_t eval_compare(uint8_t operation, uint16_t data1, uint16_t data2) { | |
140 switch(operation) { | |
141 case 1: | |
142 return data1 & data2; | |
143 case 2: | |
144 return data1 == data2; | |
145 case 3: | |
146 return data1 != data2; | |
147 case 4: | |
148 return data1 >= data2; | |
149 case 5: | |
150 return data1 > data2; | |
151 case 6: | |
152 return data1 <= data2; | |
153 case 7: | |
154 return data1 < data2; | |
155 } | |
156 fprintf(MSG_OUT, "libdvdnav: eval_compare: Invalid comparison code\n"); | |
157 return 0; | |
158 } | |
159 | |
160 | |
161 /* Evaluate if version 1. | |
162 Has comparison data in byte 3 and 4-5 (immediate or register) */ | |
163 static int32_t eval_if_version_1(command_t* command) { | |
164 uint8_t op = vm_getbits(command, 54, 3); | |
165 if(op) { | |
166 return eval_compare(op, eval_reg(command, vm_getbits(command, 39, 8)), | |
167 eval_reg_or_data(command, vm_getbits(command, 55, 1), 31)); | |
168 } | |
169 return 1; | |
170 } | |
171 | |
172 /* Evaluate if version 2. | |
173 This version only compares register which are in byte 6 and 7 */ | |
174 static int32_t eval_if_version_2(command_t* command) { | |
175 uint8_t op = vm_getbits(command, 54, 3); | |
176 if(op) { | |
177 return eval_compare(op, eval_reg(command, vm_getbits(command, 15, 8)), | |
178 eval_reg(command, vm_getbits(command, 7, 8))); | |
179 } | |
180 return 1; | |
181 } | |
182 | |
183 /* Evaluate if version 3. | |
184 Has comparison data in byte 2 and 6-7 (immediate or register) */ | |
185 static int32_t eval_if_version_3(command_t* command) { | |
186 uint8_t op = vm_getbits(command, 54, 3); | |
187 if(op) { | |
188 return eval_compare(op, eval_reg(command, vm_getbits(command, 47, 8)), | |
189 eval_reg_or_data(command, vm_getbits(command, 55, 1), 15)); | |
190 } | |
191 return 1; | |
192 } | |
193 | |
194 /* Evaluate if version 4. | |
195 Has comparison data in byte 1 and 4-5 (immediate or register) | |
196 The register in byte 1 is only the lowe nibble (4 bits) */ | |
197 static int32_t eval_if_version_4(command_t* command) { | |
198 uint8_t op = vm_getbits(command, 54, 3); | |
199 if(op) { | |
200 return eval_compare(op, eval_reg(command, vm_getbits(command, 51, 4)), | |
201 eval_reg_or_data(command, vm_getbits(command, 55, 1), 31)); | |
202 } | |
203 return 1; | |
204 } | |
205 | |
206 /* Evaluate special instruction.... returns the new row/line number, | |
207 0 if no new row and 256 if Break. */ | |
208 static int32_t eval_special_instruction(command_t* command, int32_t cond) { | |
209 int32_t line, level; | |
210 | |
211 switch(vm_getbits(command, 51, 4)) { | |
212 case 0: /* NOP */ | |
213 line = 0; | |
214 return cond ? line : 0; | |
215 case 1: /* Goto line */ | |
216 line = vm_getbits(command, 7, 8); | |
217 return cond ? line : 0; | |
218 case 2: /* Break */ | |
219 /* max number of rows < 256, so we will end this set */ | |
220 line = 256; | |
221 return cond ? 256 : 0; | |
222 case 3: /* Set temporary parental level and goto */ | |
223 line = vm_getbits(command, 7, 8); | |
224 level = vm_getbits(command, 11, 4); | |
225 if(cond) { | |
226 /* This always succeeds now, if we want real parental protection */ | |
227 /* we need to ask the user and have passwords and stuff. */ | |
228 command->registers->SPRM[13] = level; | |
229 } | |
230 return cond ? line : 0; | |
231 } | |
232 return 0; | |
233 } | |
234 | |
235 /* Evaluate link by subinstruction. | |
236 Return 1 if link, or 0 if no link | |
237 Actual link instruction is in return_values parameter */ | |
238 static int32_t eval_link_subins(command_t* command, int32_t cond, link_t *return_values) { | |
239 uint16_t button = vm_getbits(command, 15, 6); | |
240 uint8_t linkop = vm_getbits(command, 4, 5); | |
241 | |
242 if(linkop > 0x10) | |
243 return 0; /* Unknown Link by Sub-Instruction command */ | |
244 | |
245 /* Assumes that the link_cmd_t enum has the same values as the LinkSIns codes */ | |
246 return_values->command = linkop; | |
247 return_values->data1 = button; | |
248 return cond; | |
249 } | |
250 | |
251 | |
252 /* Evaluate link instruction. | |
253 Return 1 if link, or 0 if no link | |
254 Actual link instruction is in return_values parameter */ | |
255 static int32_t eval_link_instruction(command_t* command, int32_t cond, link_t *return_values) { | |
256 uint8_t op = vm_getbits(command, 51, 4); | |
257 | |
258 switch(op) { | |
259 case 1: | |
260 return eval_link_subins(command, cond, return_values); | |
261 case 4: | |
262 return_values->command = LinkPGCN; | |
263 return_values->data1 = vm_getbits(command, 14, 15); | |
264 return cond; | |
265 case 5: | |
266 return_values->command = LinkPTTN; | |
267 return_values->data1 = vm_getbits(command, 9, 10); | |
268 return_values->data2 = vm_getbits(command, 15, 6); | |
269 return cond; | |
270 case 6: | |
271 return_values->command = LinkPGN; | |
272 return_values->data1 = vm_getbits(command, 6, 7); | |
273 return_values->data2 = vm_getbits(command, 15, 6); | |
274 return cond; | |
275 case 7: | |
276 return_values->command = LinkCN; | |
277 return_values->data1 = vm_getbits(command, 7, 8); | |
278 return_values->data2 = vm_getbits(command, 15, 6); | |
279 return cond; | |
280 } | |
281 return 0; | |
282 } | |
283 | |
284 | |
285 /* Evaluate a jump instruction. | |
286 returns 1 if jump or 0 if no jump | |
287 actual jump instruction is in return_values parameter */ | |
288 static int32_t eval_jump_instruction(command_t* command, int32_t cond, link_t *return_values) { | |
289 | |
290 switch(vm_getbits(command, 51, 4)) { | |
291 case 1: | |
292 return_values->command = Exit; | |
293 return cond; | |
294 case 2: | |
295 return_values->command = JumpTT; | |
296 return_values->data1 = vm_getbits(command, 22, 7); | |
297 return cond; | |
298 case 3: | |
299 return_values->command = JumpVTS_TT; | |
300 return_values->data1 = vm_getbits(command, 22, 7); | |
301 return cond; | |
302 case 5: | |
303 return_values->command = JumpVTS_PTT; | |
304 return_values->data1 = vm_getbits(command, 22, 7); | |
305 return_values->data2 = vm_getbits(command, 41, 10); | |
306 return cond; | |
307 case 6: | |
308 switch(vm_getbits(command, 23, 2)) { | |
309 case 0: | |
310 return_values->command = JumpSS_FP; | |
311 return cond; | |
312 case 1: | |
313 return_values->command = JumpSS_VMGM_MENU; | |
314 return_values->data1 = vm_getbits(command, 19, 4); | |
315 return cond; | |
316 case 2: | |
317 return_values->command = JumpSS_VTSM; | |
318 return_values->data1 = vm_getbits(command, 31, 8); | |
319 return_values->data2 = vm_getbits(command, 39, 8); | |
320 return_values->data3 = vm_getbits(command, 19, 4); | |
321 return cond; | |
322 case 3: | |
323 return_values->command = JumpSS_VMGM_PGC; | |
324 return_values->data1 = vm_getbits(command, 46, 15); | |
325 return cond; | |
326 } | |
327 break; | |
328 case 8: | |
329 switch(vm_getbits(command, 23, 2)) { | |
330 case 0: | |
331 return_values->command = CallSS_FP; | |
332 return_values->data1 = vm_getbits(command, 31, 8); | |
333 return cond; | |
334 case 1: | |
335 return_values->command = CallSS_VMGM_MENU; | |
336 return_values->data1 = vm_getbits(command, 19, 4); | |
337 return_values->data2 = vm_getbits(command, 31, 8); | |
338 return cond; | |
339 case 2: | |
340 return_values->command = CallSS_VTSM; | |
341 return_values->data1 = vm_getbits(command, 19, 4); | |
342 return_values->data2 = vm_getbits(command, 31, 8); | |
343 return cond; | |
344 case 3: | |
345 return_values->command = CallSS_VMGM_PGC; | |
346 return_values->data1 = vm_getbits(command, 46, 15); | |
347 return_values->data2 = vm_getbits(command, 31, 8); | |
348 return cond; | |
349 } | |
350 break; | |
351 } | |
352 return 0; | |
353 } | |
354 | |
355 /* Evaluate a set sytem register instruction | |
356 May contain a link so return the same as eval_link */ | |
357 static int32_t eval_system_set(command_t* command, int32_t cond, link_t *return_values) { | |
358 int32_t i; | |
359 uint16_t data, data2; | |
360 | |
361 switch(vm_getbits(command, 59, 4)) { | |
362 case 1: /* Set system reg 1 &| 2 &| 3 (Audio, Subp. Angle) */ | |
363 for(i = 1; i <= 3; i++) { | |
364 if(vm_getbits(command, 63 - ((2 + i)*8), 1)) { | |
365 data = eval_reg_or_data_2(command, vm_getbits(command, 60, 1), (47 - (i*8))); | |
366 if(cond) { | |
367 command->registers->SPRM[i] = data; | |
368 } | |
369 } | |
370 } | |
371 break; | |
372 case 2: /* Set system reg 9 & 10 (Navigation timer, Title PGC number) */ | |
373 data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); | |
374 data2 = vm_getbits(command, 23, 8); /* ?? size */ | |
375 if(cond) { | |
376 command->registers->SPRM[9] = data; /* time */ | |
377 command->registers->SPRM[10] = data2; /* pgcN */ | |
378 } | |
379 break; | |
380 case 3: /* Mode: Counter / Register + Set */ | |
381 data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); | |
382 data2 = vm_getbits(command, 19, 4); | |
383 if(vm_getbits(command, 23, 1)) { | |
384 command->registers->GPRM_mode[data2] |= 1; /* Set bit 0 */ | |
385 } else { | |
386 command->registers->GPRM_mode[data2] &= ~ 0x01; /* Reset bit 0 */ | |
387 } | |
388 if(cond) { | |
389 set_GPRM(command->registers, data2, data); | |
390 } | |
391 break; | |
392 case 6: /* Set system reg 8 (Highlighted button) */ | |
393 data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); /* Not system reg!! */ | |
394 if(cond) { | |
395 command->registers->SPRM[8] = data; | |
396 } | |
397 break; | |
398 } | |
399 if(vm_getbits(command, 51, 4)) { | |
400 return eval_link_instruction(command, cond, return_values); | |
401 } | |
402 return 0; | |
403 } | |
404 | |
405 | |
406 /* Evaluate set operation | |
407 Sets the register given to the value indicated by op and data. | |
408 For the swap case the contents of reg is stored in reg2. | |
409 */ | |
410 static void eval_set_op(command_t* command, int32_t op, int32_t reg, int32_t reg2, int32_t data) { | |
411 const int32_t shortmax = 0xffff; | |
412 int32_t tmp; | |
413 switch(op) { | |
414 case 1: | |
415 set_GPRM(command->registers, reg, data); | |
416 break; | |
417 case 2: /* SPECIAL CASE - SWAP! */ | |
418 set_GPRM(command->registers, reg2, get_GPRM(command->registers, reg)); | |
419 set_GPRM(command->registers, reg, data); | |
420 break; | |
421 case 3: | |
422 tmp = get_GPRM(command->registers, reg) + data; | |
423 if(tmp > shortmax) tmp = shortmax; | |
424 set_GPRM(command->registers, reg, (uint16_t)tmp); | |
425 break; | |
426 case 4: | |
427 tmp = get_GPRM(command->registers, reg) - data; | |
428 if(tmp < 0) tmp = 0; | |
429 set_GPRM(command->registers, reg, (uint16_t)tmp); | |
430 break; | |
431 case 5: | |
432 tmp = get_GPRM(command->registers, reg) * data; | |
433 if(tmp > shortmax) tmp = shortmax; | |
434 set_GPRM(command->registers, reg, (uint16_t)tmp); | |
435 break; | |
436 case 6: | |
437 if (data != 0) { | |
438 set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) / data) ); | |
439 } else { | |
440 set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ | |
441 } | |
442 break; | |
443 case 7: | |
444 if (data != 0) { | |
445 set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) % data) ); | |
446 } else { | |
447 set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ | |
448 } | |
449 break; | |
450 case 8: /* SPECIAL CASE - RND! Return numbers between 1 and data. */ | |
451 set_GPRM(command->registers, reg, 1 + ((uint16_t) ((float) data * rand()/(RAND_MAX+1.0))) ); | |
452 break; | |
453 case 9: | |
454 set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) & data) ); | |
455 break; | |
456 case 10: | |
457 set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) | data) ); | |
458 break; | |
459 case 11: | |
460 set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) ^ data) ); | |
461 break; | |
462 } | |
463 } | |
464 | |
465 /* Evaluate set instruction, combined with either Link or Compare. */ | |
466 static void eval_set_version_1(command_t* command, int32_t cond) { | |
467 uint8_t op = vm_getbits(command, 59, 4); | |
468 uint8_t reg = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ | |
469 uint8_t reg2 = vm_getbits(command, 19, 4); | |
470 uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); | |
471 | |
472 if(cond) { | |
473 eval_set_op(command, op, reg, reg2, data); | |
474 } | |
475 } | |
476 | |
477 | |
478 /* Evaluate set instruction, combined with both Link and Compare. */ | |
479 static void eval_set_version_2(command_t* command, int32_t cond) { | |
480 uint8_t op = vm_getbits(command, 59, 4); | |
481 uint8_t reg = vm_getbits(command, 51, 4); | |
482 uint8_t reg2 = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ | |
483 uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); | |
484 | |
485 if(cond) { | |
486 eval_set_op(command, op, reg, reg2, data); | |
487 } | |
488 } | |
489 | |
490 | |
491 /* Evaluate a command | |
492 returns row number of goto, 0 if no goto, -1 if link. | |
493 Link command in return_values */ | |
494 static int32_t eval_command(uint8_t *bytes, registers_t* registers, link_t *return_values) { | |
495 int32_t cond, res = 0; | |
496 command_t command; | |
497 command.instruction =( (uint64_t) bytes[0] << 56 ) | | |
498 ( (uint64_t) bytes[1] << 48 ) | | |
499 ( (uint64_t) bytes[2] << 40 ) | | |
500 ( (uint64_t) bytes[3] << 32 ) | | |
501 ( (uint64_t) bytes[4] << 24 ) | | |
502 ( (uint64_t) bytes[5] << 16 ) | | |
503 ( (uint64_t) bytes[6] << 8 ) | | |
504 (uint64_t) bytes[7] ; | |
505 command.examined = 0; | |
506 command.registers = registers; | |
507 memset(return_values, 0, sizeof(link_t)); | |
508 | |
509 switch(vm_getbits(&command, 63, 3)) { /* three first old_bits */ | |
510 case 0: /* Special instructions */ | |
511 cond = eval_if_version_1(&command); | |
512 res = eval_special_instruction(&command, cond); | |
513 if(res == -1) { | |
514 fprintf(MSG_OUT, "libdvdnav: Unknown Instruction!\n"); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
225
diff
changeset
|
515 abort(); |
225 | 516 } |
517 break; | |
518 case 1: /* Link/jump instructions */ | |
519 if(vm_getbits(&command, 60, 1)) { | |
520 cond = eval_if_version_2(&command); | |
521 res = eval_jump_instruction(&command, cond, return_values); | |
522 } else { | |
523 cond = eval_if_version_1(&command); | |
524 res = eval_link_instruction(&command, cond, return_values); | |
525 } | |
526 if(res) | |
527 res = -1; | |
528 break; | |
529 case 2: /* System set instructions */ | |
530 cond = eval_if_version_2(&command); | |
531 res = eval_system_set(&command, cond, return_values); | |
532 if(res) | |
533 res = -1; | |
534 break; | |
535 case 3: /* Set instructions, either Compare or Link may be used */ | |
536 cond = eval_if_version_3(&command); | |
537 eval_set_version_1(&command, cond); | |
538 if(vm_getbits(&command, 51, 4)) { | |
539 res = eval_link_instruction(&command, cond, return_values); | |
540 } | |
541 if(res) | |
542 res = -1; | |
543 break; | |
544 case 4: /* Set, Compare -> Link Sub-Instruction */ | |
545 eval_set_version_2(&command, /*True*/ 1); | |
546 cond = eval_if_version_4(&command); | |
547 res = eval_link_subins(&command, cond, return_values); | |
548 if(res) | |
549 res = -1; | |
550 break; | |
551 case 5: /* Compare -> (Set and Link Sub-Instruction) */ | |
552 /* FIXME: These are wrong. Need to be updated from vmcmd.c */ | |
553 cond = eval_if_version_4(&command); | |
554 eval_set_version_2(&command, cond); | |
555 res = eval_link_subins(&command, cond, return_values); | |
556 if(res) | |
557 res = -1; | |
558 break; | |
559 case 6: /* Compare -> Set, allways Link Sub-Instruction */ | |
560 /* FIXME: These are wrong. Need to be updated from vmcmd.c */ | |
561 cond = eval_if_version_4(&command); | |
562 eval_set_version_2(&command, cond); | |
563 res = eval_link_subins(&command, /*True*/ 1, return_values); | |
564 if(res) | |
565 res = -1; | |
566 break; | |
567 default: /* Unknown command */ | |
568 fprintf(MSG_OUT, "libdvdnav: WARNING: Unknown Command=%x\n", vm_getbits(&command, 63, 3)); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
225
diff
changeset
|
569 abort(); |
225 | 570 } |
571 /* Check if there are bits not yet examined */ | |
572 | |
573 if(command.instruction & ~ command.examined) { | |
574 fprintf(MSG_OUT, "libdvdnav: decoder.c: [WARNING, unknown bits:"); | |
575 fprintf(MSG_OUT, " %08llx", (command.instruction & ~ command.examined) ); | |
576 fprintf(MSG_OUT, "]\n"); | |
577 } | |
578 | |
579 return res; | |
580 } | |
581 | |
582 /* Evaluate a set of commands in the given register set (which is modified) */ | |
583 int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands, | |
584 registers_t *registers, link_t *return_values) { | |
585 int32_t i = 0; | |
586 int32_t total = 0; | |
587 | |
588 #ifdef TRACE | |
589 /* DEBUG */ | |
590 fprintf(MSG_OUT, "libdvdnav: Registers before transaction\n"); | |
591 vm_print_registers( registers ); | |
592 fprintf(MSG_OUT, "libdvdnav: Full list of commands to execute\n"); | |
593 for(i = 0; i < num_commands; i++) | |
594 vm_print_cmd(i, &commands[i]); | |
595 fprintf(MSG_OUT, "libdvdnav: --------------------------------------------\n"); | |
596 fprintf(MSG_OUT, "libdvdnav: Single stepping commands\n"); | |
597 #endif | |
598 | |
599 i = 0; | |
600 while(i < num_commands && total < 100000) { | |
601 int32_t line; | |
602 | |
603 #ifdef TRACE | |
604 vm_print_cmd(i, &commands[i]); | |
605 #endif | |
606 | |
607 line = eval_command(&commands[i].bytes[0], registers, return_values); | |
608 | |
609 if (line < 0) { /* Link command */ | |
610 #ifdef TRACE | |
611 fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); | |
612 vm_print_registers( registers ); | |
613 fprintf(MSG_OUT, "libdvdnav: eval: Doing Link/Jump/Call\n"); | |
614 #endif | |
615 return 1; | |
616 } | |
617 | |
618 if (line > 0) /* Goto command */ | |
619 i = line - 1; | |
620 else /* Just continue on the next line */ | |
621 i++; | |
622 | |
623 total++; | |
624 } | |
625 | |
626 memset(return_values, 0, sizeof(link_t)); | |
627 #ifdef TRACE | |
628 fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); | |
629 vm_print_registers( registers ); | |
630 #endif | |
631 return 0; | |
632 } | |
633 | |
634 #ifdef TRACE | |
635 | |
636 static char *linkcmd2str(link_cmd_t cmd) { | |
637 switch(cmd) { | |
638 case LinkNoLink: | |
639 return "LinkNoLink"; | |
640 case LinkTopC: | |
641 return "LinkTopC"; | |
642 case LinkNextC: | |
643 return "LinkNextC"; | |
644 case LinkPrevC: | |
645 return "LinkPrevC"; | |
646 case LinkTopPG: | |
647 return "LinkTopPG"; | |
648 case LinkNextPG: | |
649 return "LinkNextPG"; | |
650 case LinkPrevPG: | |
651 return "LinkPrevPG"; | |
652 case LinkTopPGC: | |
653 return "LinkTopPGC"; | |
654 case LinkNextPGC: | |
655 return "LinkNextPGC"; | |
656 case LinkPrevPGC: | |
657 return "LinkPrevPGC"; | |
658 case LinkGoUpPGC: | |
659 return "LinkGoUpPGC"; | |
660 case LinkTailPGC: | |
661 return "LinkTailPGC"; | |
662 case LinkRSM: | |
663 return "LinkRSM"; | |
664 case LinkPGCN: | |
665 return "LinkPGCN"; | |
666 case LinkPTTN: | |
667 return "LinkPTTN"; | |
668 case LinkPGN: | |
669 return "LinkPGN"; | |
670 case LinkCN: | |
671 return "LinkCN"; | |
672 case Exit: | |
673 return "Exit"; | |
674 case JumpTT: | |
675 return "JumpTT"; | |
676 case JumpVTS_TT: | |
677 return "JumpVTS_TT"; | |
678 case JumpVTS_PTT: | |
679 return "JumpVTS_PTT"; | |
680 case JumpSS_FP: | |
681 return "JumpSS_FP"; | |
682 case JumpSS_VMGM_MENU: | |
683 return "JumpSS_VMGM_MENU"; | |
684 case JumpSS_VTSM: | |
685 return "JumpSS_VTSM"; | |
686 case JumpSS_VMGM_PGC: | |
687 return "JumpSS_VMGM_PGC"; | |
688 case CallSS_FP: | |
689 return "CallSS_FP"; | |
690 case CallSS_VMGM_MENU: | |
691 return "CallSS_VMGM_MENU"; | |
692 case CallSS_VTSM: | |
693 return "CallSS_VTSM"; | |
694 case CallSS_VMGM_PGC: | |
695 return "CallSS_VMGM_PGC"; | |
696 case PlayThis: | |
697 return "PlayThis"; | |
698 } | |
699 return "*** (bug)"; | |
700 } | |
701 | |
702 void vm_print_link(link_t value) { | |
703 char *cmd = linkcmd2str(value.command); | |
704 | |
705 switch(value.command) { | |
706 case LinkNoLink: | |
707 case LinkTopC: | |
708 case LinkNextC: | |
709 case LinkPrevC: | |
710 case LinkTopPG: | |
711 case LinkNextPG: | |
712 case LinkPrevPG: | |
713 case LinkTopPGC: | |
714 case LinkNextPGC: | |
715 case LinkPrevPGC: | |
716 case LinkGoUpPGC: | |
717 case LinkTailPGC: | |
718 case LinkRSM: | |
719 fprintf(MSG_OUT, "libdvdnav: %s (button %d)\n", cmd, value.data1); | |
720 break; | |
721 case LinkPGCN: | |
722 case JumpTT: | |
723 case JumpVTS_TT: | |
724 case JumpSS_VMGM_MENU: /* == 2 -> Title Menu */ | |
725 case JumpSS_VMGM_PGC: | |
726 fprintf(MSG_OUT, "libdvdnav: %s %d\n", cmd, value.data1); | |
727 break; | |
728 case LinkPTTN: | |
729 case LinkPGN: | |
730 case LinkCN: | |
731 fprintf(MSG_OUT, "libdvdnav: %s %d (button %d)\n", cmd, value.data1, value.data2); | |
732 break; | |
733 case Exit: | |
734 case JumpSS_FP: | |
735 case PlayThis: /* Humm.. should we have this at all.. */ | |
736 fprintf(MSG_OUT, "libdvdnav: %s\n", cmd); | |
737 break; | |
738 case JumpVTS_PTT: | |
739 fprintf(MSG_OUT, "libdvdnav: %s %d:%d\n", cmd, value.data1, value.data2); | |
740 break; | |
741 case JumpSS_VTSM: | |
742 fprintf(MSG_OUT, "libdvdnav: %s vts %d title %d menu %d\n", | |
743 cmd, value.data1, value.data2, value.data3); | |
744 break; | |
745 case CallSS_FP: | |
746 fprintf(MSG_OUT, "libdvdnav: %s resume cell %d\n", cmd, value.data1); | |
747 break; | |
748 case CallSS_VMGM_MENU: /* == 2 -> Title Menu */ | |
749 case CallSS_VTSM: | |
750 fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); | |
751 break; | |
752 case CallSS_VMGM_PGC: | |
753 fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); | |
754 break; | |
755 } | |
756 } | |
757 | |
758 void vm_print_registers( registers_t *registers ) { | |
759 int32_t i; | |
760 fprintf(MSG_OUT, "libdvdnav: # "); | |
761 for(i = 0; i < 24; i++) | |
762 fprintf(MSG_OUT, " %2d |", i); | |
763 fprintf(MSG_OUT, "\nlibdvdnav: SRPMS: "); | |
764 for(i = 0; i < 24; i++) | |
765 fprintf(MSG_OUT, "%04x|", registers->SPRM[i]); | |
766 fprintf(MSG_OUT, "\nlibdvdnav: GRPMS: "); | |
767 for(i = 0; i < 16; i++) | |
768 fprintf(MSG_OUT, "%04x|", get_GPRM(registers, i) ); | |
769 fprintf(MSG_OUT, "\nlibdvdnav: Gmode: "); | |
770 for(i = 0; i < 16; i++) | |
771 fprintf(MSG_OUT, "%04x|", registers->GPRM_mode[i]); | |
772 fprintf(MSG_OUT, "\nlibdvdnav: Gtime: "); | |
773 for(i = 0; i < 16; i++) | |
774 fprintf(MSG_OUT, "%04lx|", registers->GPRM_time[i].tv_sec & 0xffff); | |
775 fprintf(MSG_OUT, "\n"); | |
776 } | |
777 | |
778 #endif | |
779 |