diff --git a/utils/emul.c b/utils/emul.c index b5e59f2..1f8bc09 100644 --- a/utils/emul.c +++ b/utils/emul.c @@ -10,8 +10,9 @@ union regset { uint16_t r16[8]; // AX, CX, DX, BX, SP, BP, SI, DI } regset; +int carry, zero; + uint16_t ip = 0x100; -uint16_t flags; uint16_t scratch; uint16_t reg; int off; @@ -23,7 +24,6 @@ void* rmptr; #define R8(x) regset.r8[fixr8ref(x)] #define R16(x) regset.r16[x] -#define syscall_number regset.r8[4] #define AL regset.r8[0] #define CL regset.r8[2] #define DL regset.r8[4] @@ -34,6 +34,16 @@ void* rmptr; #define SI regset.r16[6] #define DI regset.r16[7] +#define ADD 0 +#define OR 1 +#define ADC 2 +#define SBB 3 +#define AND 4 +#define SUB 5 +#define XOR 6 +#define CMP 7 +#define TEST 8 + const char* const regnames[] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", 0 }; // Dump registers @@ -47,6 +57,32 @@ void dump() { printf("IP=%04X : %X\n", ip, mem[ip]); } +void arith16(int op, int16_t* dst, int src) { + // I'll just assume this sign-extends + int t = *dst; + int p = *dst; + switch (op) { + case ADD: t += src; break; + case OR: t |= src; break; + case ADC: t += (src + carry); break; + case SBB: t -= (src + carry); break; + case AND: t &= src; break; + case SUB: t -= src; break; + case XOR: t ^= src; break; + case CMP: t -= src; break; + case TEST: t &= src; break; + } + zero=!t; + // I dont think the following is correct + carry=((t ^ p) >> 16) & 1; + if (op==CMP || op==TEST) return; + *dst = t; +} + +uint16_t get_flags() { + return (carry & 1) | ((zero & 1)<< 6); +} + int fixr8ref(int r) { return ((r << 1) & 0b110) | ((r >> 2) & 0b1); } @@ -71,7 +107,7 @@ void modrm(int size) { uint8_t rm = (mem[ip]) & 0b111; ip++; if (mod == 3) { - if (size == BIT8) { + if (size == BIT16) { rmptr = &R16(rm); } else { rmptr = &R8(rm); @@ -156,15 +192,25 @@ void step() { uint8_t opcode = mem[ip]; ip++; switch(opcode) { + case 0x50 ... 0x57: // PUSH reg16 + push(R16(opcode-0x50)); + break; + case 0x58 ... 0x5F: // POP reg16 + R16(opcode-0x58)=pop(); + break; case 0x70 ... 0x7F: // Jcc reg = ip + (int8_t)imm8(); if (cond(opcode-0x70)) { ip = reg; } break; + case 0x83: // ARITH r/m16,imm8 + modrm(BIT16); + arith16(reg, &RM16, imm8()); + break; case 0x84: // TEST r/m8,reg8 modrm(BIT8); - scratch = AL & RM8; + scratch = R8(reg) & RM8; break; case 0x88: // MOV r/m8,reg8 modrm(BIT8); @@ -174,6 +220,9 @@ void step() { modrm(BIT16); R16(reg) = RM16; break; + case 0x9C: // PUSHF + push(get_flags()); + break; case 0xA1: // MOV AX,memoffs16 AX = *(uint16_t*)&mem[imm16()]; break;