diff --git a/utils/emul.c b/utils/emul.c index 9e26c43..08014d5 100644 --- a/utils/emul.c +++ b/utils/emul.c @@ -6,14 +6,35 @@ uint8_t mem[64*1024]; union regset { - uint8_t r8[8]; // AL, AH, CL, CH... - uint16_t r16[8]; // AX, CX, DX, BX, SP, BP, SI, DI + uint8_t r8[8]; // AL, AH, CL, CH... + uint16_t r16[8]; // AX, CX, DX, BX, SP, BP, SI, DI } regset; -int carry, zero; +typedef struct flagbits { + unsigned int c : 1; + unsigned int u1 : 1; + unsigned int p : 1; + unsigned int u3 : 1; + + unsigned int a : 1; + unsigned int u5 : 1; + unsigned int z : 1; + unsigned int s : 1; + + unsigned int t : 1; + unsigned int i : 1; + unsigned int d : 1; + unsigned int o : 1; + + unsigned int u12 : 4; +} flagbits; + +union flags { + uint16_t reg; + struct flagbits bit; +} flags; uint16_t ip = 0x100; -uint16_t flags = 0; uint16_t scratch; uint16_t reg; int off; @@ -25,7 +46,19 @@ void* rmptr; #define R8(x) regset.r8[fixr8ref(x)] #define R16(x) regset.r16[x] +#define FLAGMASK 0xF02A +#define CF 0 +#define PF 2 +#define AF 4 +#define ZF 6 +#define SF 7 +#define TF 8 +#define IF 9 +#define DF 10 +#define OF 11 + #define AL regset.r8[0] +#define AH regset.r8[1] #define CL regset.r8[2] #define DL regset.r8[4] #define AX regset.r16[0] @@ -54,6 +87,16 @@ void dump() { for (i=0; i<8; i++) { printf("%s=%04X ", regnames[i], regset.r16[i]); } + printf("%c", flags.bit.o ? 'O' : '-'); + printf("%c", flags.bit.d ? 'D' : '-'); + printf("%c", flags.bit.i ? 'I' : '-'); + printf("%c", flags.bit.t ? 'T' : '-'); + printf("%c", flags.bit.s ? 'S' : '-'); + printf("%c", flags.bit.z ? 'Z' : '-'); + printf("%c", flags.bit.a ? 'A' : '-'); + printf("%c", flags.bit.p ? 'P' : '-'); + printf("%c", flags.bit.c ? 'C' : '-'); + printf("\n"); printf("IP=%04X : %02X %02X\n", ip, mem[ip], mem[ip+1]); } @@ -65,17 +108,16 @@ void arith8(int op, int8_t* dst, int src) { 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 ADC: t += (src + flags.bit.c); break; + case SBB: t -= (src + flags.bit.c); 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) >> 8) & 1; + flags.bit.z = !t; + flags.bit.c = !!((t ^ p) >> 8); if (op==CMP || op==TEST) return; *dst = t; } @@ -87,25 +129,20 @@ void arith16(int op, int16_t* dst, int src) { 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 ADC: t += (src + flags.bit.c); break; + case SBB: t -= (src + flags.bit.c); 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; + flags.bit.z = !t; + flags.bit.c = !!((t ^ p) >> 8); 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); } @@ -182,7 +219,7 @@ uint16_t pop() { return v; } -void handle_syscall(int number) { +void cpm_syscall(int number) { switch(number) { case 0: exit(0); @@ -191,7 +228,18 @@ void handle_syscall(int number) { printf("%c", DL); break; default: - fprintf(stderr, "Fatal: Unhandled syscall CL=%Xh\n", number); + fprintf(stderr, "Fatal: Unhandled CP/M syscall %Xh\n", number); + exit(1); + } +} + +void dos_syscall(int number) { + switch(number) { + case 0: + exit(0); + break; + default: + fprintf(stderr, "Fatal: Unhandled DOS syscall %Xh\n", number); exit(1); } } @@ -199,10 +247,13 @@ void handle_syscall(int number) { void handle_intr(int number) { switch(number) { case 0x20: - handle_syscall(0); + dos_syscall(0); + break; + case 0x21: + dos_syscall(AH); break; case 0xE0: - handle_syscall(CL); + cpm_syscall(CL); break; default: fprintf(stderr, "Fatal: Unhandled interrupt %Xh\n", number); @@ -270,7 +321,7 @@ void step() { R16(reg) = RM16; break; case 0x9C: // PUSHF - push(get_flags()); + push(flags.reg | FLAGMASK); break; case 0xA1: // MOV AX,memoffs16 AX = *(uint16_t*)&mem[imm16()]; @@ -299,7 +350,7 @@ void step() { case 0xE8: // CALL rw reg = ip + (int16_t)imm16(); if (reg == 5) { - handle_syscall(CL); + cpm_syscall(CL); } else { push(ip); ip = reg; @@ -338,20 +389,46 @@ void copy_cmdline(char* str) { int main(int argc, char** argv) { memset(&mem, sizeof(mem), 0); memset(®set, sizeof(regset), 0); + // Prepare default exit into int 20h mem[0]=0xCD; mem[1]=0x20; push(0); - if (argc>2) { - copy_cmdline(argv[2]); + argc--; + argv++; + + while(argc && argv[0][0]=='-') { + switch(argv[0][1]) { + case 't': + flags.bit.t = 1; + break; + default: + fprintf(stderr, "Unknown option %s\n", argv[0]); + exit(1); + break; + } + argc--; + argv++; + } + + if (argc) { + FILE* fd = fopen(argv[0], "r"); + fread(mem + ip, 1, sizeof(mem) - ip, fd); + argc--; + argv++; + } else { + fprintf(stderr, "No COM file specified\n"); + exit(1); + } + + if (argc) { + copy_cmdline(argv[0]); } else { copy_cmdline(""); } - FILE* fd = fopen(argv[1], "r"); - fread(mem + ip, 1, sizeof(mem) - ip, fd); while(1) { step(); - dump(); + if (flags.bit.t) dump(); } }