7 #include "virtualxt/lib/vxt/cpu.h"
16 #define MEM_SIZE 0x100000
17 uint8_t mem[MEM_SIZE];
19 // read and write are separated for I/O
21 uint8_t io_read[IO_SIZE];
22 uint8_t io_write[IO_SIZE];
24 int load_ihx(char *name) {
25 FILE *fp = fopen(name, "r");
31 int base = 0, entry_point = 0;
34 while (fgets(line, 0x100, fp)) {
35 for (char *p = line; *p; ++p)
42 fprintf(stderr, "garbage after EOF record: %s\n", line);
47 fprintf(stderr, "require colon: %s\n", line);
53 for (len = 0; len < 0x7f; ++len) {
54 char *p = line + 1 + len * 2;
65 buf[len] = (uint8_t)strtol(p, &q, 16);
68 fprintf(stderr, "not hex byte: %s\n", p);
74 fprintf(stderr, "empty line: %s\n", line);
79 for (int i = 0; i < len; ++i)
82 checksum -= buf[len - 1];
85 "checksum %02x, should be %02x\n",
94 fprintf(stderr, "incorrect length: %s\n", line);
98 int addr = (buf[1] << 8) | buf[2], end_addr;
102 end_addr = addr + len;
103 if (end_addr < addr || end_addr > MEM_SIZE) {
104 fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
107 memcpy(mem + addr, buf + 4, len);
114 fprintf(stderr, "invalid start address record: %s\n", line);
117 entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
121 fprintf(stderr, "invalid extended linear address record: %s\n", line);
124 base = (buf[4] << 24) | (buf[5] << 16);
129 fprintf(stderr, "invalid start linear address record: %s\n", line);
132 entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
136 fprintf(stderr, "unknown record type: 0x%x\n", buf[3]);
141 fprintf(stderr, "no EOF record\n");
149 int msdos(int ax, int dx, int ds, bool *zf) {
165 // Direct console I/O
168 int data = getchar();
201 (data = mem[dx + (ds << 4)]) != '$';
202 dx = (dx + 1) & 0xffff
215 // Create PSP -- ignore
222 // Get or set Ctrl-Break -- ignore
225 // Set interrupt vector -- ignore
228 // Get interrupt vector -- ignore
231 fprintf(stderr, "unimplemented MSDOS call 0x%02x\n", ax >> 8);
237 int read_byte(void *context, int addr) {
239 int data = mem[addr];
240 fprintf(stderr, "addr=%05x rd=%02x\n", addr, data);
247 void write_byte(void *context, int addr, int data) {
249 fprintf(stderr, "addr=%05x wr=%02x\n", addr, data);
254 int in_byte(void *context, int addr) {
257 int data = io_read[addr];
258 printf("io=%02x rd=%02x\n", addr, data);
261 return io_read[addr];
265 void out_byte(void *context, int addr, int data) {
268 printf("io=%02x wr=%02x\n", addr, data);
270 io_write[addr] = data;
274 #if defined(VXT_LIBC) && !defined(VXT_NO_LOGGING)
276 static int libc_print(const char *fmt, ...) {
279 int ret = vprintf(fmt, args);
283 int (*logger)(const char*, ...) = &libc_print;
285 static int no_print(const char *fmt, ...) {
289 int (*logger)(const char*, ...) = &no_print;
292 static void no_breakpoint(void) {}
293 void (*breakpoint)(void) = &no_breakpoint;
295 vxt_byte vxt_system_read_byte(CONSTP(vxt_system) s, vxt_pointer addr) {
297 return read_byte(NULL, addr);
300 void vxt_system_write_byte(CONSTP(vxt_system) s, vxt_pointer addr, vxt_byte data) {
302 write_byte(NULL, addr, data);
305 vxt_word vxt_system_read_word(CONSTP(vxt_system) s, vxt_pointer addr) {
306 int data = vxt_system_read_byte(s, addr);
307 return WORD(vxt_system_read_byte(s, addr + 1), data);
310 void vxt_system_write_word(CONSTP(vxt_system) s, vxt_pointer addr, vxt_word data) {
311 vxt_system_write_byte(s, addr, LBYTE(data));
312 vxt_system_write_byte(s, addr + 1, HBYTE(data));
315 vxt_byte system_in(CONSTP(vxt_system) s, vxt_word port) {
316 return in_byte(NULL, port);
319 void system_out(CONSTP(vxt_system) s, vxt_word port, vxt_byte data) {
320 out_byte(NULL, port, data);
324 int main(int argc, char **argv) {
326 printf("usage: %s image.ihx\n", argv[0]);
329 int entry_point = load_ihx(argv[1]);
336 mem[0x400] = 0xcf; // iret, for msdos emulation
343 mem[0x401] = 0xcf; // iret, for msdos emulation
346 int code_segment = (entry_point >> 16) & 0xffff;
347 mem[5 + (code_segment << 4)] = 0xc3; // ret, for bdos emulation
348 mem[6 + (code_segment << 4)] = 0xfe; // memory top, lo byte
349 mem[7 + (code_segment << 4)] = 0xff; // memory top, hi byte
350 mem[0x80 + (code_segment << 4)] = 0; // command line length
351 mem[0x81 + (code_segment << 4)] = '\r'; // command line sentinel
355 memset(&cpu, 0, sizeof(struct cpu));
357 //cpu.read_byte = rb;
358 //cpu.write_byte = wb;
360 //cpu.port_out = out;
361 cpu.regs.ip = entry_point & 0xffff;
362 cpu.regs.cs = code_segment;
363 cpu.regs.sp = 0xfffe;
364 cpu.regs.ss = code_segment;
370 "ip=%04x ax=%04x cx=%04x dx=%04x bx=%04x sp=%04x bp=%04x si=%04x di=%04x cs=%04x ds=%04x es=%04x ss=%04x flags=%04x cf=%d pf=%d af=%d zf=%d sf=%d tf=%d if=%d df=%d of=%d\n",
386 (cpu.regs.flags >> 2) & 1,
387 (cpu.regs.flags >> 4) & 1,
388 (cpu.regs.flags >> 6) & 1,
389 (cpu.regs.flags >> 7) & 1,
390 (cpu.regs.flags >> 8) & 1,
391 (cpu.regs.flags >> 9) & 1,
392 (cpu.regs.flags >> 10) & 1,
393 (cpu.regs.flags >> 11) & 1
398 (cpu.regs.ip == 0 && cpu.regs.cs == code_segment) ||
399 (cpu.regs.ip == 0 && cpu.regs.cs == 0x40)
404 if (cpu.regs.ip == 5 && cpu.regs.cs == code_segment) {
405 bool zf = (cpu.regs.flags >> 6) & 1;
406 cpu.regs.ax = msdos(cpu.regs.cl << 8, cpu.regs.dx, cpu.regs.ds, &zf);
407 cpu.regs.flags = (zf << 6) | (cpu.regs.flags & ~0x40);
409 else if (cpu.regs.ip == 1 && cpu.regs.cs == 0x40) {
410 bool zf = (cpu.regs.flags >> 6) & 1;
411 cpu.regs.ax = msdos(cpu.regs.ax, cpu.regs.dx, cpu.regs.ds, &zf);
412 cpu.regs.flags = (zf << 6) | (cpu.regs.flags & ~0x40);
429 cpu_8086_reset(&cpu);
430 cpu.regs.word.pc = entry_point;
436 "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pvf=%d hf=%d zf=%d sf=%d\n",
454 if (cpu.regs.word.pc == 0) {
458 if (cpu.regs.word.pc == 5) {
459 cpu.regs.word.de = bdos(
464 cpu_8086_execute(&cpu);