// 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 // static void check_param_type(ctx_t *ctx, instr_t *in, uint prm, uchar fmt, int which) { bool ok; if (prm == P_REG) ok = (fmt == A_REG); else if (prm == P_IMM) ok = (fmt == A_IMM64); else /* if (prm == P_MEM) */ ok = ACC_FMT_IS_MEM(fmt); if (!ok) _except(ctx, E_ILL, "FT%d not matching %s's expected parameter types: " "fmt=0x%x prm=0x%x", which, in->full, fmt, prm); } // // Verify that access to a certain register is legal // static void checkreg(ctx_t *ctx, uint reg, bool inv_is_ok) { if (reg >= NREGS) _except(ctx, E_ILL, "Inexistent register: %u", reg); if (reg == INV) { if (!inv_is_ok) _except(ctx, E_ILL, "INV dereference"); else return; } if (ctx->r[reg].flags & RES) //_except(ctx, E_ACC, "Reserved REG: %u", reg); if (ctx->r[reg].flags & SYS) if (R(CR0) & UF) _except(ctx, E_SYS, "User access to SYS REG: %u", reg); } // // Extract operand according to fmt // void extract_param(ctx_t *ctx, acc_t *p, uchar fmt) { uint mlen, mfmt; ushort temp; p->type = fmt; if (fmt == A_REG) { p->reg = ctx->get(ctx); checkreg(ctx, p->reg, 0); p->val = R(p->reg); return; } else if (fmt == A_IMM64) { p->val = ctx->get(ctx); p->val |= (ulong)ctx->get(ctx) << 16; p->val |= (ulong)ctx->get(ctx) << 32; p->val |= (ulong)ctx->get(ctx) << 48; return; } assert(ACC_FMT_IS_MEM(fmt)); // // Handle a memory access // mlen = fmt & AM_MLEN_MASK; mfmt = fmt & AM_MFMT_MASK; p->mlen = (mlen == AM_8ACC ? 1 : (mlen == AM_16ACC ? 2 : (mlen == AM_32ACC ? 4 : (mlen == AM_64ACC ? 8 : 0)))); if (p->mlen == 0) _except(ctx, E_ILL, "Invalid MLEN for access: %x", fmt); switch (mfmt) { case AM_IMM64: p->addr = ctx->get(ctx); p->addr |= (ulong)ctx->get(ctx) << 16; p->addr |= (ulong)ctx->get(ctx) << 32; p->addr |= (ulong)ctx->get(ctx) << 48; break; case AM_RR: case AM_RRI: case AM_RRII: temp = ctx->get(ctx); p->reg1 = temp >> 8; p->reg2 = temp & 0xFF; checkreg(ctx, p->reg1, 1); checkreg(ctx, p->reg2, 1); if (mfmt == AM_RRI) { p->imm1 = 1; p->imm2 = ctx->get(ctx); } else if (mfmt == AM_RRII) { p->imm1 = ctx->get(ctx); p->imm2 = ctx->get(ctx); } else { p->imm1 = 1; p->imm2 = 0; } p->addr = R(p->reg1) + R(p->reg2) * (long)(short)p->imm1 + (long)(short)p->imm2; break; default: _except(ctx, E_ILL, "Invalid MFMT for access: %x", fmt); } } void decode(ctx_t *ctx) { instr_t *in; acc_t p1 = { 0 }; acc_t p2 = { 0 }; acc_t p3 = { 0 }; bool rep = 0; bool lock, nomore; ushort w1, w2; uchar f1 = 0, f2 = 0, f3 = 0; rpc = R(RIP); // // Process the first word of the instruction // w1 = ctx->get(ctx); // Extract first word flags lock = !!(w1 & SUFF_LOCK); nomore = !!(w1 & SUFF_NOMORE); if (w1 & SUFF_COND) ctx->cond = ctx->get(ctx); else ctx->cond = 0; w1 &= ~(SUFF_LOCK|SUFF_NOMORE|SUFF_COND); // Find instruction if (w1 >= NINSTRS) { _except(ctx, E_ILL, "No such INSTR: 0x%hX", w1); } in = &ctx->i[w1]; ctx->cur_in = in; if (!nomore) { // // Process second word // w2 = ctx->get(ctx); // REP and COND rep = !!(w2 & SUFF_REP); // Fn f3 = (w2 >> F3_SHIFT) & Fx_MASK; f2 = (w2 >> F2_SHIFT) & Fx_MASK; f1 = w2 & Fx_MASK; } // // Deal with operand 1 // if (in->prm1 == NOPRM) { if (f1 || f2 || f3) { _except(ctx, E_ILL, "FTn (%u,%u,%u) filled for 0-param INSTR '%s'", f1, f2, f3, in->full); } exec_instr(ctx, in, NULL, NULL, NULL, lock, rep); return; } check_param_type(ctx, in, in->prm1, f1, 1); extract_param(ctx, &p1, f1); // // Deal with operand 2 // if (in->prm2 == NOPRM) { if (f2 || f3) { _except(ctx, E_ILL, "FT3/FT2 (%u,%u,%u) filled for 1-param INSTR '%s'", f1, f2, f3, in->full); } exec_instr(ctx, in, &p1, NULL, NULL, lock, rep); return; } check_param_type(ctx, in, in->prm2, f2, 2); extract_param(ctx, &p2, f2); // // Deal with operand 3 // if (in->prm3 == NOPRM) { if (f3) { _except(ctx, E_ILL, "FT3 (%u,%u,%u) filled for 2-param INSTR '%s'", f1, f2, f3, in->full); } exec_instr(ctx, in, &p1, &p2, NULL, lock, rep); return; } check_param_type(ctx, in, in->prm3, f3, 3); extract_param(ctx, &p3, f3); exec_instr(ctx, in, &p1, &p2, &p3, lock, rep); }