Improve flag handling for emulator
This commit is contained in:
parent
a30f4f3287
commit
305663c110
135
utils/emul.c
135
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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user