diff --git a/pat80-emulator/CMakeLists.txt b/pat80-emulator/CMakeLists.txt index f3f7177..f7e2139 100644 --- a/pat80-emulator/CMakeLists.txt +++ b/pat80-emulator/CMakeLists.txt @@ -1,6 +1,7 @@ -cmake_minimum_required(VERSION 3.5.0) +cmake_minimum_required(VERSION 3.10.0) project(pat80-emulator VERSION 0.1.0 LANGUAGES C) -find_package(Z80 REQUIRED Shared) add_executable(pat80-emulator main.c) +find_package(Z80 REQUIRED) +target_link_libraries(pat80-emulator Z80) diff --git a/pat80-emulator/README.md b/pat80-emulator/README.md index bf7e0e2..a92db2d 100644 --- a/pat80-emulator/README.md +++ b/pat80-emulator/README.md @@ -10,6 +10,10 @@ Create the makefile with cmake: `cd build && cmake ..` ## Build -Enter the `build` directory and run `make` +Enter the `build` directory and run `make`. +An executable file named `pat80-emulator` is created. ## Usage + +Enter the `build` directory +Run `./pat80-emulator` diff --git a/pat80-emulator/main.c b/pat80-emulator/main.c index f80fadb..2674b04 100644 --- a/pat80-emulator/main.c +++ b/pat80-emulator/main.c @@ -1,5 +1,145 @@ -#include +#include /* Z_NULL */ +#include +#include -int main(int, char**){ - printf("Hello, from pat80-emulator!\n"); -} +#define CYCLES_PER_FRAME 69888 +#define CYCLES_AT_INT 24 +#define CYCLES_PER_INT 32 +#define ROM_SIZE 0x8000 /* 32 KiB */ +#define MEMORY_SIZE 0x8000 /* 32 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_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() { + // Setup virtual Pat80 computer + Z80 pat80Cpu = {}; + Device pat80Devices[] = {}; + zuint8 pat80Memory[65536] = {0}; + + 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); +} \ No newline at end of file