Improve flag handling for emulator

This commit is contained in:
Nero 2019-10-02 19:14:18 +00:00
parent a30f4f3287
commit 305663c110

View File

@ -6,14 +6,35 @@
uint8_t mem[64*1024]; uint8_t mem[64*1024];
union regset { union regset {
uint8_t r8[8]; // AL, AH, CL, CH... uint8_t r8[8]; // AL, AH, CL, CH...
uint16_t r16[8]; // AX, CX, DX, BX, SP, BP, SI, DI uint16_t r16[8]; // AX, CX, DX, BX, SP, BP, SI, DI
} regset; } 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 ip = 0x100;
uint16_t flags = 0;
uint16_t scratch; uint16_t scratch;
uint16_t reg; uint16_t reg;
int off; int off;
@ -25,7 +46,19 @@ void* rmptr;
#define R8(x) regset.r8[fixr8ref(x)] #define R8(x) regset.r8[fixr8ref(x)]
#define R16(x) regset.r16[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 AL regset.r8[0]
#define AH regset.r8[1]
#define CL regset.r8[2] #define CL regset.r8[2]
#define DL regset.r8[4] #define DL regset.r8[4]
#define AX regset.r16[0] #define AX regset.r16[0]
@ -54,6 +87,16 @@ void dump() {
for (i=0; i<8; i++) { for (i=0; i<8; i++) {
printf("%s=%04X ", regnames[i], regset.r16[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("\n");
printf("IP=%04X : %02X %02X\n", ip, mem[ip], mem[ip+1]); 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) { switch (op) {
case ADD: t += src; break; case ADD: t += src; break;
case OR: t |= src; break; case OR: t |= src; break;
case ADC: t += (src + carry); break; case ADC: t += (src + flags.bit.c); break;
case SBB: t -= (src + carry); break; case SBB: t -= (src + flags.bit.c); break;
case AND: t &= src; break; case AND: t &= src; break;
case SUB: t -= src; break; case SUB: t -= src; break;
case XOR: t ^= src; break; case XOR: t ^= src; break;
case CMP: t -= src; break; case CMP: t -= src; break;
case TEST: t &= src; break; case TEST: t &= src; break;
} }
zero=!t; flags.bit.z = !t;
// I dont think the following is correct flags.bit.c = !!((t ^ p) >> 8);
carry=((t ^ p) >> 8) & 1;
if (op==CMP || op==TEST) return; if (op==CMP || op==TEST) return;
*dst = t; *dst = t;
} }
@ -87,25 +129,20 @@ void arith16(int op, int16_t* dst, int src) {
switch (op) { switch (op) {
case ADD: t += src; break; case ADD: t += src; break;
case OR: t |= src; break; case OR: t |= src; break;
case ADC: t += (src + carry); break; case ADC: t += (src + flags.bit.c); break;
case SBB: t -= (src + carry); break; case SBB: t -= (src + flags.bit.c); break;
case AND: t &= src; break; case AND: t &= src; break;
case SUB: t -= src; break; case SUB: t -= src; break;
case XOR: t ^= src; break; case XOR: t ^= src; break;
case CMP: t -= src; break; case CMP: t -= src; break;
case TEST: t &= src; break; case TEST: t &= src; break;
} }
zero=!t; flags.bit.z = !t;
// I dont think the following is correct flags.bit.c = !!((t ^ p) >> 8);
carry=((t ^ p) >> 16) & 1;
if (op==CMP || op==TEST) return; if (op==CMP || op==TEST) return;
*dst = t; *dst = t;
} }
uint16_t get_flags() {
return (carry & 1) | ((zero & 1)<< 6);
}
int fixr8ref(int r) { int fixr8ref(int r) {
return ((r << 1) & 0b110) | ((r >> 2) & 0b1); return ((r << 1) & 0b110) | ((r >> 2) & 0b1);
} }
@ -182,7 +219,7 @@ uint16_t pop() {
return v; return v;
} }
void handle_syscall(int number) { void cpm_syscall(int number) {
switch(number) { switch(number) {
case 0: case 0:
exit(0); exit(0);
@ -191,7 +228,18 @@ void handle_syscall(int number) {
printf("%c", DL); printf("%c", DL);
break; break;
default: 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); exit(1);
} }
} }
@ -199,10 +247,13 @@ void handle_syscall(int number) {
void handle_intr(int number) { void handle_intr(int number) {
switch(number) { switch(number) {
case 0x20: case 0x20:
handle_syscall(0); dos_syscall(0);
break;
case 0x21:
dos_syscall(AH);
break; break;
case 0xE0: case 0xE0:
handle_syscall(CL); cpm_syscall(CL);
break; break;
default: default:
fprintf(stderr, "Fatal: Unhandled interrupt %Xh\n", number); fprintf(stderr, "Fatal: Unhandled interrupt %Xh\n", number);
@ -270,7 +321,7 @@ void step() {
R16(reg) = RM16; R16(reg) = RM16;
break; break;
case 0x9C: // PUSHF case 0x9C: // PUSHF
push(get_flags()); push(flags.reg | FLAGMASK);
break; break;
case 0xA1: // MOV AX,memoffs16 case 0xA1: // MOV AX,memoffs16
AX = *(uint16_t*)&mem[imm16()]; AX = *(uint16_t*)&mem[imm16()];
@ -299,7 +350,7 @@ void step() {
case 0xE8: // CALL rw case 0xE8: // CALL rw
reg = ip + (int16_t)imm16(); reg = ip + (int16_t)imm16();
if (reg == 5) { if (reg == 5) {
handle_syscall(CL); cpm_syscall(CL);
} else { } else {
push(ip); push(ip);
ip = reg; ip = reg;
@ -338,20 +389,46 @@ void copy_cmdline(char* str) {
int main(int argc, char** argv) { int main(int argc, char** argv) {
memset(&mem, sizeof(mem), 0); memset(&mem, sizeof(mem), 0);
memset(&regset, sizeof(regset), 0); memset(&regset, sizeof(regset), 0);
// Prepare default exit into int 20h
mem[0]=0xCD; mem[0]=0xCD;
mem[1]=0x20; mem[1]=0x20;
push(0); push(0);
if (argc>2) { argc--;
copy_cmdline(argv[2]); 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 { } else {
copy_cmdline(""); copy_cmdline("");
} }
FILE* fd = fopen(argv[1], "r");
fread(mem + ip, 1, sizeof(mem) - ip, fd);
while(1) { while(1) {
step(); step();
dump(); if (flags.bit.t) dump();
} }
} }