comparison decoder.c @ 0:3ddf0eaece51 src

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