From b667561da9687da684fc26629ef37167f1933d10 Mon Sep 17 00:00:00 2001 From: Daniele Verducci Date: Fri, 7 Feb 2025 08:18:14 +0100 Subject: [PATCH] Emulator: working decoding logic, outputting terminal to stdout --- .../z80-assembly/os/tests/out_single_char.asm | 7 + pat80-emulator/main.c | 161 ++++++++++++++---- 2 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 pat80-computer/software/z80-assembly/os/tests/out_single_char.asm diff --git a/pat80-computer/software/z80-assembly/os/tests/out_single_char.asm b/pat80-computer/software/z80-assembly/os/tests/out_single_char.asm new file mode 100644 index 0000000..17086be --- /dev/null +++ b/pat80-computer/software/z80-assembly/os/tests/out_single_char.asm @@ -0,0 +1,7 @@ +; @language: Z80 ASM +; Simple possible code test: +; outputs a single character "A" on IO port 0, then halts + +ld a,'A' +out (1),a +halt diff --git a/pat80-emulator/main.c b/pat80-emulator/main.c index 0cd1971..b40abf4 100644 --- a/pat80-emulator/main.c +++ b/pat80-emulator/main.c @@ -14,7 +14,6 @@ typedef struct { void* context; zuint8 (* read)(void *context); void (* write)(void *context, zuint8 value); - zuint16 assigned_port; } Device; typedef struct { @@ -26,17 +25,6 @@ typedef struct { } 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; } @@ -49,16 +37,91 @@ static void machine_cpu_write(Machine *self, zuint16 address, zuint8 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; + // Pat80 has 8 devices, decoded based on the 3 most significant IO addr bits. + // Note the Z80 has 16 bit address bus, but only the first 8 are used as IO addr, + // so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits + // A4-A0 may be used by the single device, at its own discretion. + zuint16 bitmask = 7; // 0000000000000111 + int decoded = port & bitmask; + if (decoded <= 0x1F) { + // Port 0 (0x00 to 0x1F): terminal + //printf("TERMINAL_READ"); + //return 'H'; + return 0x00; + } + if (decoded <= 0x3F) { + // Port 1 (0x20 to 0x3F): sound card (sn76489) + printf("\nsound_cmd[IN]: Not supported!\n"); + return 0x00; + } + if (decoded <= 0x5F) { + // Port 2 (0x40 to 0x5F) + printf("IO_ERROR_IN: No device at port 2\n"); + return 0x00; + } + if (decoded <= 0x7F) { + // Port 3 (0x60 to 0x7F) + printf("IO_ERROR_IN: No device at port 3\n"); + return 0x00; + } + if (decoded <= 0x9F) { + // Port 4 (0x80 to 0x9F) + printf("IO_ERROR_IN: No device at port 4\n"); + return 0x00; + } + if (decoded <= 0x5F) { + // Port 5 (0xA0 to 0xBF) + printf("IO_ERROR_IN: No device at port 5\n"); + return 0x00; + } + if (decoded <= 0x5F) { + // Port 6 (0xC0 to 0xDF) + printf("IO_ERROR_IN: No device at port 6\n"); + return 0x00; + } + if (decoded <= 0x5F) { + // Port 7 (0xE0 to 0xFF) + printf("IO_ERROR_IN: No device at port 7\n"); + } else { + printf("IO_ERROR_IN: Invalid port address: %#04x\n", port); + } } 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); + // Pat80 has 8 devices, decoded based on the 3 most significant IO addr bits. + // Note the Z80 has 16 bit address bus, but only the first 8 are used as IO addr, + // so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits + // A4-A0 may be used by the single device, at its own discretion. + zuint16 bitmask = 0xE0; // 0000000011100000 + int decoded = port & bitmask; + if (decoded <= 0x1F) { + // Port 0 (0x00 to 0x1F): terminal + printf("%c", value); + } else if (decoded <= 0x3F) { + // Port 1 (0x20 to 0x3F): sound card (sn76489) + printf("\nsound_cmd[%#04x]\n", value); + } else if (decoded <= 0x5F) { + // Port 2 (0x40 to 0x5F) + printf("IO_ERROR_OUT: No device at port 2\n"); + } else if (decoded <= 0x7F) { + // Port 3 (0x60 to 0x7F) + printf("IO_ERROR_OUT: No device at port 3\n"); + } else if (decoded <= 0x9F) { + // Port 4 (0x80 to 0x9F) + printf("IO_ERROR_OUT: No device at port 4\n"); + } else if (decoded <= 0x5F) { + // Port 5 (0xA0 to 0xBF) + printf("IO_ERROR_OUT: No device at port 5\n"); + } else if (decoded <= 0x5F) { + // Port 6 (0xC0 to 0xDF) + printf("IO_ERROR_OUT: No device at port 6\n"); + } else if (decoded <= 0x5F) { + // Port 7 (0xE0 to 0xFF) + printf("IO_ERROR_OUT: No device at port 7\n"); + } else { + printf("IO_ERROR_OUT: Invalid port address: %#04x\n", port); + } } @@ -91,7 +154,7 @@ void machine_power(Machine *self, zbool state) { if (state) { self->cycles = 0; - memset(self->memory, 0, 65536); + memset(self->memory, 0, MEMORY_SIZE); } z80_power(&self->cpu, state); @@ -123,6 +186,30 @@ void machine_run(Machine *self) { // self->cycles -= CYCLES_PER_FRAME; // } + + + +// TEST IMPLEM DEVICE + +zuint8 device_terminal_read(void *context) { + return 'H'; + //return 0; +} + +void device_terminal_write(void *context, zuint8 value) { + printf("%c", value); +} + +zuint8 device_sound_read(void *context) { + return 0; +} + +void device_sound_write(void *context, zuint8 value) { + printf("sound[%c]\n", value); +} + +// TEST IMPLEM DEVICE + int main(int argc, char *argv[]) { // Parse arguments if (argc < 2) { @@ -133,8 +220,13 @@ int main(int argc, char *argv[]) { // Setup virtual Pat80 computer Z80 pat80Cpu = {}; - Device pat80Devices[] = {}; - zuint8 pat80Memory[65536] = {0}; + Machine pat80 = { + /*zusize*/ .cycles = 100000, + /*Z80*/ .cpu = pat80Cpu + }; + + machine_initialize(&pat80); + machine_power(&pat80, Z_TRUE); // Load ROM into memory FILE *romFile; @@ -143,19 +235,26 @@ int main(int argc, char *argv[]) { 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 + fread(&pat80.memory,ROM_SIZE,1,romFile); // load rom from file into memory, up > fclose(romFile); - Machine pat80 = { - /*zusize*/ .cycles = 0, - /*zuint8*/ .memory = *pat80Memory, - /*Z80*/ .cpu = pat80Cpu, - /*Device**/ .devices = pat80Devices, - /*zusize*/ .device_count = 255 + // Declare system devices + Device patoTerminal = { + .read = *device_terminal_read, + .write = *device_terminal_write, }; - - machine_initialize(&pat80); - machine_power(&pat80, Z_TRUE); + Device patoSound = { + .read = *device_sound_read, + .write = *device_sound_write, + }; + + Device patoDevices[2] = { + patoTerminal, // Port 0 (0x00 to 0x1F) + patoSound // Port 1 (0x20 to 0x3F) + }; + pat80.devices = patoDevices; + pat80.device_count = 2; + machine_reset(&pat80); machine_run(&pat80); }