Improve flag handling for emulator
This commit is contained in:
parent
a30f4f3287
commit
305663c110
131
utils/emul.c
131
utils/emul.c
@ -10,10 +10,31 @@ union regset {
|
|||||||
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(®set, sizeof(regset), 0);
|
memset(®set, 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user