// The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #include // // Read the "DECD" file before reading this code // // // Instruction fetch // static uchar fetchb(void) { uchar v = *(ctx->mp + R(RIP) + R(CR1) - MEMOFF); R(RIP) += 1; return v; } static ushort fetchw(void) { ushort v = *(ushort *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF); R(RIP) += 2; return v; } static uint fetchd(void) { uint v = *(uint *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF); R(RIP) += 4; return v; } static ulong fetchq(void) { ulong v = *(ulong *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF); R(RIP) += 8; return v; } // // Verify that access to a certain register is legal // static void checkreg(uint reg) { if (reg >= NREGS) _except(E_ILL, "Inexistent register: %u", reg); if (ctx->r[reg].flags & RES) _except(E_ACC, "Reserved REG: %u", reg); if (ctx->r[reg].flags & SYS) if (R(CR0) & UF) _except(E_SYS, "User access to SYS REG: %u", reg); } // // Verify that given access length is that of a byte/word/dword/qword // static void checklength(instr_t *in, uint len) { static const int lentab[9] = { 0, 1, 1, 0, 1, 0, 0, 0, 1 }; if (len > 8 || lentab[len] == 0) _except(E_ILL, "%s: Invalid memory access length: %u", in->name, len); } // // Extracts one operand // static void extract_param(instr_t *in, acc_t *p) { // Get next operand ModRM-like byte uchar fmt = fetchb(); uchar hi = (fmt & 0b11100000) >> 5; uchar lo = fmt & 0b00011111; // // Registers // if (hi == 0) { p->reg = lo; p->type = A_REG; checkreg(p->reg); p->val = R(p->reg); return; } // // Immediates // if (hi == 7) { switch (lo) { case 1: p->type = A_IMM8; p->val = fetchb(); break; case 2: p->type = A_IMM16; p->val = fetchw(); break; case 4: p->type = A_IMM32; p->val = fetchd(); break; case 8: p->type = A_IMM64; p->val = fetchq(); break; default: _except(E_ILL, "%s: Invalid immediate length: %hhu", in->name, lo); } return; } // // Memory operands // checklength(in, lo); p->mlen = lo; switch (hi) { case 1: p->type = AM_RR; p->reg1 = fetchb(); p->reg2 = p->imm1 = p->imm2 = 0; break; case 2: p->type = AM_RR; p->reg1 = fetchb(); p->reg2 = fetchb(); p->imm1 = 1; p->imm2 = 0; break; case 3: p->type = AM_RRI; p->reg1 = fetchb(); p->imm2 = (short)fetchw(); p->reg2 = RZX; p->imm1 = 1; break; case 4: p->type = AM_RRI; p->reg1 = fetchb(); p->reg2 = fetchb(); p->imm2 = (int)fetchd(); p->imm1 = 1; break; case 5: p->type = AM_RRII; p->reg1 = fetchb(); p->reg2 = fetchb(); p->imm1 = fetchb(); p->imm2 = (short)fetchd(); break; case 6: p->type = AM_RRI; p->reg1 = fetchb(); p->imm2 = fetchq(); p->reg2 = RZX; p->imm1 = 1; break; } p->addr = R(p->reg1) + R(p->reg2) * (long)p->imm1 + p->imm2; } // // Instruction fetch & decode // void decode(void) { ushort b; instr_t *in; acc_t p1 = { 0 }, p2 = { 0 }, p3 = { 0 }; //logerr("decodin'\n"); ctx->cur_pc = R(RIP); // Address range check // (assumes max. instruction length is 32 bytes) if (R(RIP) + R(CR1) - MEMOFF >= ctx->mz - 32) _except(E_ACC, "Executing out of memory"); // Instruction bytes b = fetchb(); // Renge check if (b >= NINSTRS) _except(E_ILL, "No such INSTR: 0x%hhX", b); // Find instruction in = &ctx->i[b]; ctx->cur_in = in; // Operand 1? if (in->nprms == 0) { exec_instr(in, NULL, NULL, NULL); return; } extract_param(in, &p1); // Operand 2? if (in->nprms == 1) { exec_instr(in, &p1, NULL, NULL); return; } extract_param(in, &p2); // Operand 1? if (in->nprms == 2) { exec_instr(in, &p1, &p2, NULL); return; } extract_param(in, &p3); exec_instr(in, &p1, &p2, &p3); }