// 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 #include bool eval_cond(ctx_t *ctx, uint cond) { bool neg = cond & (1 << 4); bool ok; cond &= ~(1 << 4); switch (cond) { case CD_NONE: ok = 1; break; case CD_C: ok = flg&CF; break; case CD_O: ok = flg&OF; break; case CD_Z: ok = flg&ZF; break; case CD_S: ok = flg&SF; break; case CD_P: ok = flg&PF; break; case CD_A: ok = !(flg&CF || flg&ZF); break; case CD_AE: ok = !(flg&CF); break; case CD_B: ok = flg&CF; break; case CD_BE: ok = flg&CF || flg&ZF; break; case CD_G: ok = !(flg&ZF) && (!(flg&SF) == !(flg&OF)); break; case CD_GE: ok = !(flg&SF) == !(flg&OF); break; case CD_L: ok = !(flg&SF) != !(flg&OF); break; case CD_LE: ok = flg&ZF || (!(flg&SF) != !(flg&OF)); break; case CD_CXZ: ok = !rcx; break; default: _except(ctx, E_ILL, "Invalid COND value: 0x%x", (neg?cond|(1<<4):cond)); } return neg ? !ok : !!ok; } // // Executes an instruction // void exec_instr(ctx_t *ctx, instr_t *in, acc_t *p1, acc_t *p2, acc_t *p3, bool lock, bool rep) { bool out; ulong r1 = 0, r2 = 0, r3 = 0; // Global instruction counter ctx->ninstrs++; // Current frame instruction counter fc2++; // since last frame change fc1++; // since startup // // For REPs we evaluate the condition AFTER running the instruction, // in a do ... while(cond) fashion // if (ctx->cond && in->func != i_b) // 'B' instruction is special if (!rep && !eval_cond(ctx, ctx->cond)) return; if (ctx->dumpsw) dump_instr(ctx, in, p1, p2, p3, lock, rep); do_rep: out = in->func(ctx, p1, p2, p3, &r1, &r2, &r3); if (out) { if (p1->type == A_REG) R(p1->reg) = r1; else if (p1->type == A_IMM64) _except(ctx, E_ACC, "Trying to output to an IMM64"); else { assert(ACC_IS_MEM(p1)); writemem(ctx, r1, p1->addr, p1->mlen); } } if (out >= 2) { if (p2->type == A_REG) R(p2->reg) = r2; else if (p2->type == A_IMM64) _except(ctx, E_ACC, "Trying to output to an IMM64"); else { assert(ACC_IS_MEM(p2)); writemem(ctx, r2, p2->addr, p2->mlen); } } if (out >= 3) { if (p3->type == A_REG) R(p3->reg) = r3; else if (p3->type == A_IMM64) _except(ctx, E_ACC, "Trying to output to an IMM64"); else { assert(ACC_IS_MEM(p3)); writemem(ctx, r3, p3->addr, p3->mlen); } } if (rep) { // RCX remains untouched when condition fails if (!eval_cond(ctx, ctx->cond)) return; if (rcx > 0) rcx--; if (rcx == 0) return; ctx->ninstrs++; #if 0 // Show that we're REP'ing if (ctx->dumpsw) dump_instr(ctx, in, p1, p2, p3, lock, rep); #endif goto do_rep; } }