📄 decoder.c
字号:
break; case 6: /* Set system reg 8 (Highlighted button) */ data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); /* Not system reg!! */ if(cond) { command->registers->SPRM[8] = data; } break; } if(vm_getbits(command, 51, 4)) { return eval_link_instruction(command, cond, return_values); } return 0;}/* Evaluate set operation Sets the register given to the value indicated by op and data. For the swap case the contents of reg is stored in reg2.*/static void eval_set_op(command_t* command, int32_t op, int32_t reg, int32_t reg2, int32_t data) { const int32_t shortmax = 0xffff; int32_t tmp; switch(op) { case 1: set_GPRM(command->registers, reg, data); break; case 2: /* SPECIAL CASE - SWAP! */ set_GPRM(command->registers, reg2, get_GPRM(command->registers, reg)); set_GPRM(command->registers, reg, data); break; case 3: tmp = get_GPRM(command->registers, reg) + data; if(tmp > shortmax) tmp = shortmax; set_GPRM(command->registers, reg, (uint16_t)tmp); break; case 4: tmp = get_GPRM(command->registers, reg) - data; if(tmp < 0) tmp = 0; set_GPRM(command->registers, reg, (uint16_t)tmp); break; case 5: tmp = get_GPRM(command->registers, reg) * data; if(tmp > shortmax) tmp = shortmax; set_GPRM(command->registers, reg, (uint16_t)tmp); break; case 6: if (data != 0) { set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) / data) ); } else { set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ } break; case 7: if (data != 0) { set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) % data) ); } else { set_GPRM(command->registers, reg, 0xffff); /* Avoid that divide by zero! */ } break; case 8: /* SPECIAL CASE - RND! Return numbers between 1 and data. */ set_GPRM(command->registers, reg, 1 + ((uint16_t) ((float) data * rand()/(RAND_MAX+1.0))) ); break; case 9: set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) & data) ); break; case 10: set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) | data) ); break; case 11: set_GPRM(command->registers, reg, (get_GPRM(command->registers, reg) ^ data) ); break; }}/* Evaluate set instruction, combined with either Link or Compare. */static void eval_set_version_1(command_t* command, int32_t cond) { uint8_t op = vm_getbits(command, 59, 4); uint8_t reg = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ uint8_t reg2 = vm_getbits(command, 19, 4); uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 31); if(cond) { eval_set_op(command, op, reg, reg2, data); }}/* Evaluate set instruction, combined with both Link and Compare. */static void eval_set_version_2(command_t* command, int32_t cond) { uint8_t op = vm_getbits(command, 59, 4); uint8_t reg = vm_getbits(command, 51, 4); uint8_t reg2 = vm_getbits(command, 35, 4); /* FIXME: This is different from vmcmd.c!!! */ uint16_t data = eval_reg_or_data(command, vm_getbits(command, 60, 1), 47); if(cond) { eval_set_op(command, op, reg, reg2, data); }}/* Evaluate a command returns row number of goto, 0 if no goto, -1 if link. Link command in return_values */static int32_t eval_command(uint8_t *bytes, registers_t* registers, link_t *return_values) { int32_t cond, res = 0; command_t command; command.instruction =( (uint64_t) bytes[0] << 56 ) | ( (uint64_t) bytes[1] << 48 ) | ( (uint64_t) bytes[2] << 40 ) | ( (uint64_t) bytes[3] << 32 ) | ( (uint64_t) bytes[4] << 24 ) | ( (uint64_t) bytes[5] << 16 ) | ( (uint64_t) bytes[6] << 8 ) | (uint64_t) bytes[7] ; command.examined = 0; command.registers = registers; memset(return_values, 0, sizeof(link_t)); switch(vm_getbits(&command, 63, 3)) { /* three first old_bits */ case 0: /* Special instructions */ cond = eval_if_version_1(&command); res = eval_special_instruction(&command, cond); if(res == -1) { fprintf(MSG_OUT, "libdvdnav: Unknown Instruction!\n"); abort(); } break; case 1: /* Link/jump instructions */ if(vm_getbits(&command, 60, 1)) { cond = eval_if_version_2(&command); res = eval_jump_instruction(&command, cond, return_values); } else { cond = eval_if_version_1(&command); res = eval_link_instruction(&command, cond, return_values); } if(res) res = -1; break; case 2: /* System set instructions */ cond = eval_if_version_2(&command); res = eval_system_set(&command, cond, return_values); if(res) res = -1; break; case 3: /* Set instructions, either Compare or Link may be used */ cond = eval_if_version_3(&command); eval_set_version_1(&command, cond); if(vm_getbits(&command, 51, 4)) { res = eval_link_instruction(&command, cond, return_values); } if(res) res = -1; break; case 4: /* Set, Compare -> Link Sub-Instruction */ eval_set_version_2(&command, /*True*/ 1); cond = eval_if_version_4(&command); res = eval_link_subins(&command, cond, return_values); if(res) res = -1; break; case 5: /* Compare -> (Set and Link Sub-Instruction) */ /* FIXME: These are wrong. Need to be updated from vmcmd.c */ cond = eval_if_version_4(&command); eval_set_version_2(&command, cond); res = eval_link_subins(&command, cond, return_values); if(res) res = -1; break; case 6: /* Compare -> Set, allways Link Sub-Instruction */ /* FIXME: These are wrong. Need to be updated from vmcmd.c */ cond = eval_if_version_4(&command); eval_set_version_2(&command, cond); res = eval_link_subins(&command, /*True*/ 1, return_values); if(res) res = -1; break; default: /* Unknown command */ fprintf(MSG_OUT, "libdvdnav: WARNING: Unknown Command=%x\n", vm_getbits(&command, 63, 3)); abort(); } /* Check if there are bits not yet examined */ if(command.instruction & ~ command.examined) { fprintf(MSG_OUT, "libdvdnav: decoder.c: [WARNING, unknown bits:"); fprintf(MSG_OUT, " %08llx", (command.instruction & ~ command.examined) ); fprintf(MSG_OUT, "]\n"); } return res;}/* Evaluate a set of commands in the given register set (which is modified) */int32_t vmEval_CMD(vm_cmd_t commands[], int32_t num_commands, registers_t *registers, link_t *return_values) { int32_t i = 0; int32_t total = 0; #ifdef TRACE /* DEBUG */ fprintf(MSG_OUT, "libdvdnav: Registers before transaction\n"); vm_print_registers( registers ); fprintf(MSG_OUT, "libdvdnav: Full list of commands to execute\n"); for(i = 0; i < num_commands; i++) vm_print_cmd(i, &commands[i]); fprintf(MSG_OUT, "libdvdnav: --------------------------------------------\n"); fprintf(MSG_OUT, "libdvdnav: Single stepping commands\n");#endif i = 0; while(i < num_commands && total < 100000) { int32_t line; #ifdef TRACE vm_print_cmd(i, &commands[i]);#endif line = eval_command(&commands[i].bytes[0], registers, return_values); if (line < 0) { /* Link command */#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); vm_print_registers( registers ); fprintf(MSG_OUT, "libdvdnav: eval: Doing Link/Jump/Call\n"); #endif return 1; } if (line > 0) /* Goto command */ i = line - 1; else /* Just continue on the next line */ i++; total++; } memset(return_values, 0, sizeof(link_t));#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: Registers after transaction\n"); vm_print_registers( registers );#endif return 0;}#ifdef TRACEstatic char *linkcmd2str(link_cmd_t cmd) { switch(cmd) { case LinkNoLink: return "LinkNoLink"; case LinkTopC: return "LinkTopC"; case LinkNextC: return "LinkNextC"; case LinkPrevC: return "LinkPrevC"; case LinkTopPG: return "LinkTopPG"; case LinkNextPG: return "LinkNextPG"; case LinkPrevPG: return "LinkPrevPG"; case LinkTopPGC: return "LinkTopPGC"; case LinkNextPGC: return "LinkNextPGC"; case LinkPrevPGC: return "LinkPrevPGC"; case LinkGoUpPGC: return "LinkGoUpPGC"; case LinkTailPGC: return "LinkTailPGC"; case LinkRSM: return "LinkRSM"; case LinkPGCN: return "LinkPGCN"; case LinkPTTN: return "LinkPTTN"; case LinkPGN: return "LinkPGN"; case LinkCN: return "LinkCN"; case Exit: return "Exit"; case JumpTT: return "JumpTT"; case JumpVTS_TT: return "JumpVTS_TT"; case JumpVTS_PTT: return "JumpVTS_PTT"; case JumpSS_FP: return "JumpSS_FP"; case JumpSS_VMGM_MENU: return "JumpSS_VMGM_MENU"; case JumpSS_VTSM: return "JumpSS_VTSM"; case JumpSS_VMGM_PGC: return "JumpSS_VMGM_PGC"; case CallSS_FP: return "CallSS_FP"; case CallSS_VMGM_MENU: return "CallSS_VMGM_MENU"; case CallSS_VTSM: return "CallSS_VTSM"; case CallSS_VMGM_PGC: return "CallSS_VMGM_PGC"; case PlayThis: return "PlayThis"; } return "*** (bug)";}void vm_print_link(link_t value) { char *cmd = linkcmd2str(value.command); switch(value.command) { case LinkNoLink: case LinkTopC: case LinkNextC: case LinkPrevC: case LinkTopPG: case LinkNextPG: case LinkPrevPG: case LinkTopPGC: case LinkNextPGC: case LinkPrevPGC: case LinkGoUpPGC: case LinkTailPGC: case LinkRSM: fprintf(MSG_OUT, "libdvdnav: %s (button %d)\n", cmd, value.data1); break; case LinkPGCN: case JumpTT: case JumpVTS_TT: case JumpSS_VMGM_MENU: /* == 2 -> Title Menu */ case JumpSS_VMGM_PGC: fprintf(MSG_OUT, "libdvdnav: %s %d\n", cmd, value.data1); break; case LinkPTTN: case LinkPGN: case LinkCN: fprintf(MSG_OUT, "libdvdnav: %s %d (button %d)\n", cmd, value.data1, value.data2); break; case Exit: case JumpSS_FP: case PlayThis: /* Humm.. should we have this at all.. */ fprintf(MSG_OUT, "libdvdnav: %s\n", cmd); break; case JumpVTS_PTT: fprintf(MSG_OUT, "libdvdnav: %s %d:%d\n", cmd, value.data1, value.data2); break; case JumpSS_VTSM: fprintf(MSG_OUT, "libdvdnav: %s vts %d title %d menu %d\n", cmd, value.data1, value.data2, value.data3); break; case CallSS_FP: fprintf(MSG_OUT, "libdvdnav: %s resume cell %d\n", cmd, value.data1); break; case CallSS_VMGM_MENU: /* == 2 -> Title Menu */ case CallSS_VTSM: fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); break; case CallSS_VMGM_PGC: fprintf(MSG_OUT, "libdvdnav: %s %d resume cell %d\n", cmd, value.data1, value.data2); break; } }void vm_print_registers( registers_t *registers ) { int32_t i; fprintf(MSG_OUT, "libdvdnav: # "); for(i = 0; i < 24; i++) fprintf(MSG_OUT, " %2d |", i); fprintf(MSG_OUT, "\nlibdvdnav: SRPMS: "); for(i = 0; i < 24; i++) fprintf(MSG_OUT, "%04x|", registers->SPRM[i]); fprintf(MSG_OUT, "\nlibdvdnav: GRPMS: "); for(i = 0; i < 16; i++) fprintf(MSG_OUT, "%04x|", get_GPRM(registers, i) ); fprintf(MSG_OUT, "\nlibdvdnav: Gmode: "); for(i = 0; i < 16; i++) fprintf(MSG_OUT, "%04x|", registers->GPRM_mode[i]); fprintf(MSG_OUT, "\nlibdvdnav: Gtime: "); for(i = 0; i < 16; i++) fprintf(MSG_OUT, "%04lx|", registers->GPRM_time[i].tv_sec & 0xffff); fprintf(MSG_OUT, "\n");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -