Emulator: working decoding logic, outputting terminal to stdout
This commit is contained in:
parent
882f258ad8
commit
b667561da9
@ -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
|
@ -14,7 +14,6 @@ typedef struct {
|
|||||||
void* context;
|
void* context;
|
||||||
zuint8 (* read)(void *context);
|
zuint8 (* read)(void *context);
|
||||||
void (* write)(void *context, zuint8 value);
|
void (* write)(void *context, zuint8 value);
|
||||||
zuint16 assigned_port;
|
|
||||||
} Device;
|
} Device;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -26,17 +25,6 @@ typedef struct {
|
|||||||
} Machine;
|
} 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) {
|
static zuint8 machine_cpu_read(Machine *self, zuint16 address) {
|
||||||
return address < MEMORY_SIZE ? self->memory[address] : 0xFF;
|
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) {
|
static zuint8 machine_cpu_in(Machine *self, zuint16 port) {
|
||||||
Device *device = machine_find_device(self, port);
|
// 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,
|
||||||
return device != Z_NULL ? device->read(device->context) : 0xFF;
|
// 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) {
|
static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value) {
|
||||||
Device *device = machine_find_device(self, port);
|
// 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,
|
||||||
if (device != Z_NULL) device->write(device->context, value);
|
// 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)
|
if (state)
|
||||||
{
|
{
|
||||||
self->cycles = 0;
|
self->cycles = 0;
|
||||||
memset(self->memory, 0, 65536);
|
memset(self->memory, 0, MEMORY_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
z80_power(&self->cpu, state);
|
z80_power(&self->cpu, state);
|
||||||
@ -123,6 +186,30 @@ void machine_run(Machine *self) {
|
|||||||
// self->cycles -= CYCLES_PER_FRAME;
|
// 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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -133,8 +220,13 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Setup virtual Pat80 computer
|
// Setup virtual Pat80 computer
|
||||||
Z80 pat80Cpu = {};
|
Z80 pat80Cpu = {};
|
||||||
Device pat80Devices[] = {};
|
Machine pat80 = {
|
||||||
zuint8 pat80Memory[65536] = {0};
|
/*zusize*/ .cycles = 100000,
|
||||||
|
/*Z80*/ .cpu = pat80Cpu
|
||||||
|
};
|
||||||
|
|
||||||
|
machine_initialize(&pat80);
|
||||||
|
machine_power(&pat80, Z_TRUE);
|
||||||
|
|
||||||
// Load ROM into memory
|
// Load ROM into memory
|
||||||
FILE *romFile;
|
FILE *romFile;
|
||||||
@ -143,19 +235,26 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Unable to open rom file at %s", romFilePath);
|
printf("Unable to open rom file at %s", romFilePath);
|
||||||
exit(1);
|
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);
|
fclose(romFile);
|
||||||
|
|
||||||
Machine pat80 = {
|
// Declare system devices
|
||||||
/*zusize*/ .cycles = 0,
|
Device patoTerminal = {
|
||||||
/*zuint8*/ .memory = *pat80Memory,
|
.read = *device_terminal_read,
|
||||||
/*Z80*/ .cpu = pat80Cpu,
|
.write = *device_terminal_write,
|
||||||
/*Device**/ .devices = pat80Devices,
|
|
||||||
/*zusize*/ .device_count = 255
|
|
||||||
};
|
};
|
||||||
|
Device patoSound = {
|
||||||
machine_initialize(&pat80);
|
.read = *device_sound_read,
|
||||||
machine_power(&pat80, Z_TRUE);
|
.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_reset(&pat80);
|
||||||
machine_run(&pat80);
|
machine_run(&pat80);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user