#include /* Z_NULL */ #include #include #include #include #define CYCLES_PER_FRAME 69888 #define CYCLES_AT_INT 24 #define CYCLES_PER_INT 32 #define ROM_SIZE 0x8000 /* 32 KiB */ #define MEMORY_SIZE 0xFFFF /* 64 KiB */ typedef struct { void* context; zuint8 (* read)(void *context); void (* write)(void *context, zuint8 value); zuint16 assigned_port; } Device; typedef struct { zusize cycles; zuint8 memory[65536]; Z80 cpu; Device* devices; zusize device_count; } Machine; Device *machine_find_device(Machine *self, zuint16 port) { zusize index = 0; for (; index < self->device_count; index++) if (self->devices[index].assigned_port == port) return &self->devices[index]; return Z_NULL; } static zuint8 machine_cpu_read(Machine *self, zuint16 address) { return address < MEMORY_SIZE ? self->memory[address] : 0xFF; } static void machine_cpu_write(Machine *self, zuint16 address, zuint8 value) { if (address >= ROM_SIZE && address < MEMORY_SIZE) self->memory[address] = value; } static zuint8 machine_cpu_in(Machine *self, zuint16 port) { Device *device = machine_find_device(self, port); return device != Z_NULL ? device->read(device->context) : 0xFF; } static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value) { Device *device = machine_find_device(self, port); if (device != Z_NULL) device->write(device->context, value); } void machine_initialize(Machine *self) { self->cpu.context = self; self->cpu.fetch_opcode = self->cpu.fetch = self->cpu.nop = self->cpu.read = (Z80Read )machine_cpu_read; self->cpu.write = (Z80Write)machine_cpu_write; self->cpu.in = (Z80Read )machine_cpu_in; self->cpu.out = (Z80Write)machine_cpu_out; self->cpu.halt = Z_NULL; self->cpu.nmia = Z_NULL; self->cpu.inta = Z_NULL; self->cpu.int_fetch = Z_NULL; self->cpu.ld_i_a = Z_NULL; self->cpu.ld_r_a = Z_NULL; self->cpu.reti = Z_NULL; self->cpu.retn = Z_NULL; self->cpu.hook = Z_NULL; self->cpu.illegal = Z_NULL; self->cpu.options = Z80_MODEL_ZILOG_NMOS; /* Create and initialize devices... */ } void machine_power(Machine *self, zbool state) { if (state) { self->cycles = 0; memset(self->memory, 0, 65536); } z80_power(&self->cpu, state); } void machine_reset(Machine *self) { z80_instant_reset(&self->cpu); } void machine_run(Machine *self) { z80_run(&self->cpu, Z80_MAXIMUM_CYCLES); } // void machine_run_frame(Machine *self) // { // /* CPU cycles before the INT signal */ // self->cycles += z80_execute(&self->cpu, CYCLES_AT_INT - self->cycles); // /* CPU cycles during the INT signal */ // z80_int(&self->cpu, Z_TRUE); // self->cycles += z80_run(&self->cpu, (CYCLES_AT_INT + CYCLES_PER_INT) - self->cycles); // z80_int(&self->cpu, Z_FALSE); // /* CPU cycles after the INT signal */ // self->cycles += z80_execute(&self->cpu, CYCLES_PER_FRAME - self->cycles); // self->cycles -= CYCLES_PER_FRAME; // } int main(int argc, char *argv[]) { // Parse arguments if (argc < 2) { printf("Usage: %s [romFile]\n", argv[0]); exit(0); } char* romFilePath = argv[1]; // Setup virtual Pat80 computer Z80 pat80Cpu = {}; Device pat80Devices[] = {}; zuint8 pat80Memory[65536] = {0}; // Load ROM into memory FILE *romFile; romFile = fopen(romFilePath,"rb"); if (romFile == NULL) { printf("Unable to open rom file at %s", romFilePath); exit(1); } fread(pat80Memory,ROM_SIZE,1,romFile); // load rom from file into memory, up to ROM_SIZE fclose(romFile); Machine pat80 = { /*zusize*/ .cycles = 0, /*zuint8*/ .memory = *pat80Memory, /*Z80*/ .cpu = pat80Cpu, /*Device**/ .devices = pat80Devices, /*zusize*/ .device_count = 255 }; machine_initialize(&pat80); machine_power(&pat80, Z_TRUE); machine_reset(&pat80); machine_run(&pat80); }