// The OS/K Team licences this file to you under the MIT license. // See the LICENSE file in the project root for more information. #include "instrs.h" #include "arch_i.h" #define _NEED_ARCH_I #include "arch_i.h" IMPL_START_0(nop) { } IMPL_END; // // Logical instructions // IMPL_START_2(and) { v1 &= v2; } IMPL_OUT; IMPL_START_2(or) { v1 |= v2; } IMPL_OUT; IMPL_START_2(xor) { v1 ^= v2; } IMPL_OUT; IMPL_START_2(shl) { v1 <<= v2; } IMPL_OUT; IMPL_START_2(shr) { v1 >>= v2; } IMPL_OUT; IMPL_START_1(not) { v1 = ~v1; } IMPL_OUT; // // Unsigned arithmetic instructions // IMPL_START_2(add) { v1 += v2; } IMPL_OUT; IMPL_START_2(sub) { v1 -= v2; } IMPL_OUT; IMPL_START_1(mul) { // Adapted from www.codeproject.com/Tips/618570/UInt-Multiplication-Squaring ulong v2 = v1; v1 = ctx->r[RAX].val; ulong u1 = (v1 & 0xffffffff); ulong u2 = (v2 & 0xffffffff); ulong t = (u1 * u2); ulong w3 = (t & 0xffffffff); ulong k = (t >> 32); v1 >>= 32; t = (v1 * u2) + k; k = (t & 0xffffffff); ulong w1 = (t >> 32); v2 >>= 32; t = (u1 * v2) + k; k = (t >> 32); ctx->r[RDX].val = (v1 * v2) + w1 + k; ctx->r[RAX].val = (t << 32) + w3; } IMPL_END; IMPL_START_1(div) { ctx->r[RDX].val = ctx->r[RAX].val % v1; ctx->r[RAX].val = ctx->r[RAX].val / v1; } IMPL_END; IMPL_START_1(inc) { v1++; } IMPL_OUT; IMPL_START_1(dec) { v1--; } IMPL_OUT; // // Comparison instructions // IMPL_START_2(cmp) { if (v1 == v2) { ctx->r[FLG].val |= ZF; ctx->r[FLG].val &= ~CF; } else if (v1 < v2) { ctx->r[FLG].val &= ~ZF; ctx->r[FLG].val |= CF; } else { ctx->r[FLG].val &= ~ZF; ctx->r[FLG].val &= ~CF; } } IMPL_END; IMPL_START_2(test) { ulong v = v1 & v2; if (v == 0) ctx->r[FLG].val |= ZF; else ctx->r[FLG].val &= ~ZF; } IMPL_END; // // Jump instructions // // // Movement instructions // IMPL_START_2(mov) { v1 = v2; } IMPL_OUT; IMPL_START_2(xchg) { ulong t = v1; v1 = v2; v2 = t; } IMPL_OUT; IMPL_START_1(lea) { assert(p2->mem); v1 = (p2->type == A_REG ? ctx->r[p2->val].val : p2->val) + p2->off; } IMPL_OUT; // // Stack manipulation instructions // IMPL_START_1(push) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val > ctx->r[RBP].val) { _except(ctx, E_STK, "RSP above RBP"); } writemem64(ctx, v1, ctx->r[RSP].val); ctx->r[RSP].val -= 8; } IMPL_END; IMPL_START_1(pop) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val >= ctx->r[RBP].val) { _except(ctx, E_STK, "RBP above RSP"); } ctx->r[RSP].val += 8; v1 = readmem64(ctx, ctx->r[RSP].val); } IMPL_OUT; IMPL_START_1(call) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val > ctx->r[RBP].val) { _except(ctx, E_STK, "RSP above RBP"); } writemem64(ctx, ctx->r[RIP].val, ctx->r[RSP].val); ctx->r[RSP].val -= 8; ctx->r[RIP].val = v1; } IMPL_END; IMPL_START_0(ret) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val >= ctx->r[RBP].val) { _except(ctx, E_STK, "RBP above RSP"); } ctx->r[RSP].val += 8; ctx->r[RIP].val = readmem64(ctx, ctx->r[RSP].val); } IMPL_END; IMPL_START_0(pushf) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val > ctx->r[RBP].val) { _except(ctx, E_STK, "RSP above RBP"); } writemem64(ctx, ctx->r[FLG].val, ctx->r[RSP].val); ctx->r[RSP].val -= 8; } IMPL_END; IMPL_START_0(popf) { if (ctx->r[RSP].val % 8 > 0 || ctx->r[RBP].val % 8 > 0) { _except(ctx, E_STK, "Misaligned stack REGS"); } if (ctx->r[RSP].val >= ctx->r[RBP].val) { _except(ctx, E_STK, "RBP above RSP"); } CHK_SUPERV(); // XXX ctx->r[RSP].val += 8; ctx->r[FLG].val = readmem64(ctx, ctx->r[RSP].val); } IMPL_END; // // Supervisor only instructions // IMPL_START_0(cli) { CHK_SUPERV(); ctx->r[FLG].val &= ~IF; } IMPL_END; IMPL_START_0(sti) { CHK_SUPERV(); ctx->r[FLG].val |= IF; } IMPL_END; IMPL_START_0(stop) { _except(ctx, E_SHT, "STOP INSTR"); } IMPL_END;