diff --git a/src/gamegear.c b/src/gamegear.c index e08cc72..41c071e 100644 --- a/src/gamegear.c +++ b/src/gamegear.c @@ -207,9 +207,6 @@ const char* gamegear_get_exception(GameGear *gg) case Z80_EXC_UNIMPLEMENTED_OPCODE: SET_EXC("unimplemented opcode: 0x%02X", gg->cpu.exc_data) break; - case Z80_EXC_IO_ERROR: - SET_EXC("I/O error on port 0x%02X", gg->cpu.exc_data) - break; default: SET_EXC("unknown exception") break; diff --git a/src/io.c b/src/io.c index c66172a..70434b6 100644 --- a/src/io.c +++ b/src/io.c @@ -2,6 +2,7 @@ Released under the terms of the MIT License. See LICENSE for details. */ #include "io.h" +#include "logging.h" /* Initialize an IO object. @@ -17,7 +18,12 @@ void io_init(IO *io, VDP *vdp, PSG *psg) */ void io_power(IO *io) { - io->except = false; + io->ports[0x00] = 0xC0; // Overseas mode, NTSC + io->ports[0x01] = 0x7F; + io->ports[0x02] = 0xFF; + io->ports[0x03] = 0x00; + io->ports[0x04] = 0xFF; + io->ports[0x05] = 0x00; } /* @@ -29,37 +35,67 @@ bool io_check_irq(IO *io) } /* + Read from one of the system ports, which are numbered from 0x00 to 0x06. +*/ +static uint8_t read_system_port(IO *io, uint8_t port) +{ + switch (port) { + case 0x00: + // TODO: MSB is state of START button + return (io->ports[port] & 0x7F) | (0 << 7); + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + return io->ports[port]; + } + return 0xFF; +} + +/* + Write to one of the system ports, which are numbered from 0x00 to 0x06. +*/ +static void write_system_port(IO *io, uint8_t port, uint8_t value) +{ + switch (port) { + case 0x01: + case 0x02: + case 0x03: + io->ports[port] = value; + break; + case 0x05: + io->ports[port] = value & 0xF8; + break; + case 0x06: + psg_stereo(io->psg, value); + break; + } +} + +/* Read and return a byte from the given port. */ uint8_t io_port_read(IO *io, uint8_t port) { - if (port <= 0x06) { - if (port == 0x00) - return 0xC0; - // TODO: GG specific registers; initial state: C0 7F FF 00 FF 00 FF - } else if (port <= 0x3F) { + if (port <= 0x06) + return read_system_port(io, port); + else if (port <= 0x3F) return 0xFF; - } else if (port <= 0x7F && !(port % 2)) { + else if (port <= 0x7F && !(port % 2)) return io->vdp->v_counter; - } else if (port <= 0x7F) { + else if (port <= 0x7F) return io->vdp->h_counter; - } else if (port <= 0xBF && !(port % 2)) { + else if (port <= 0xBF && !(port % 2)) return vdp_read_data(io->vdp); - } else if (port <= 0xBF) { + else if (port <= 0xBF) return vdp_read_control(io->vdp); - } else if (port == 0xCD || port == 0xDC) { - // TODO: Return the I/O port A/B register - return 0xFF; - } else if (port == 0xC1 || port == 0xDD) { - // TODO: Return the I/O port B/misc. register + else if (port == 0xCD || port == 0xDC) + return 0xFF; // TODO: Return the I/O port A/B register + else if (port == 0xC1 || port == 0xDD) + return 0xFF; // TODO: Return the I/O port B/misc. register + else return 0xFF; - } else { - return 0xFF; - } - - io->except = true; - io->exc_port = port; - return 0; } /* @@ -67,28 +103,16 @@ uint8_t io_port_read(IO *io, uint8_t port) */ void io_port_write(IO *io, uint8_t port, uint8_t value) { - if (port <= 0x06) { - // TODO: GG specific registers; initial state: C0 7F FF 00 FF 00 FF - goto except; - } else if (port <= 0x3F && !(port % 2)) { - // TODO: Write to memory control register - goto except; - } else if (port <= 0x3F) { - // TODO: Write to I/O control register - goto except; - } else if (port <= 0x7F) { + if (port <= 0x06) + write_system_port(io, port, value); + else if (port <= 0x3F && !(port % 2)) + return; // TODO: Write to memory control register + else if (port <= 0x3F) + return; // TODO: Write to I/O control register + else if (port <= 0x7F) psg_write(io->psg, value); - } else if (port <= 0xBF && !(port % 2)) { + else if (port <= 0xBF && !(port % 2)) vdp_write_data(io->vdp, value); - } else if (port <= 0xBF) { + else if (port <= 0xBF) vdp_write_control(io->vdp, value); - } else { - return; - } - - return; - - except: - io->except = true; - io->exc_port = port; } diff --git a/src/io.h b/src/io.h index ec4df5f..578f799 100644 --- a/src/io.h +++ b/src/io.h @@ -14,8 +14,7 @@ typedef struct { VDP *vdp; PSG *psg; - bool except; - uint8_t exc_port; + uint8_t ports[6]; } IO; /* Functions */ diff --git a/src/psg.c b/src/psg.c index 786502e..c0f792a 100644 --- a/src/psg.c +++ b/src/psg.c @@ -41,3 +41,13 @@ void psg_write(PSG *psg, uint8_t byte) (void) psg; TRACE("PSG ignoring write: 0x%02X", byte) } + +/* + Send a byte to the PSG's stereo control. +*/ +void psg_stereo(PSG *psg, uint8_t byte) +{ + // TODO + (void) psg; + TRACE("PSG ignoring stereo: 0x%02X", byte) +} diff --git a/src/psg.h b/src/psg.h index 1fe7246..deb3502 100644 --- a/src/psg.h +++ b/src/psg.h @@ -19,3 +19,4 @@ void psg_init(PSG*); void psg_free(PSG*); void psg_power(PSG*); void psg_write(PSG*, uint8_t); +void psg_stereo(PSG*, uint8_t); diff --git a/src/vdp.c b/src/vdp.c index 37d41a9..75fe332 100644 --- a/src/vdp.c +++ b/src/vdp.c @@ -433,43 +433,4 @@ void vdp_dump_registers(const VDP *vdp) DEBUG("- $08: 0x%02X (HS)", regs[0x08]) DEBUG("- $09: 0x%02X (VS)", regs[0x09]) DEBUG("- $0A: 0x%02X (LC)", regs[0x0A]) - - // TODO: remove me! - DEBUG("Dumping CRAM:") - for (uint8_t i = 0; i < 32; i += 8) { - uint16_t w[8]; - for (uint8_t j = 0; j < 8; j++) - w[j] = get_color(vdp, (i + j) % 16, i & 16); - - DEBUG("- %04X %04X %04X %04X %04X %04X %04X %04X", - w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]) - } - - return; - - DEBUG("Dumping PNT:") - for (uint16_t i = 0; i < 18; i++) { - uint16_t w[20]; - for (uint8_t j = 0; j < 20; j++) - w[j] = get_background_tile(vdp, i + 3, j + 6); - - DEBUG("- %03X %03X %03X %03X %03X %03X %03X %03X %03X %03X" - " %03X %03X %03X %03X %03X %03X %03X %03X %03X %03X", - w[0x00], w[0x01], w[0x02], w[0x03], w[0x04], w[0x05], w[0x06], - w[0x07], w[0x08], w[0x09], w[0x0A], w[0x0B], w[0x0C], w[0x0D], - w[0x0E], w[0x0F], w[0x10], w[0x11], w[0x12], w[0x13]) - } - - DEBUG("Dumping PGT:") - for (uint16_t i = 0; i < /* 512 */ 32; i++) { - uint32_t w[8]; - for (uint8_t j = 0; j < 8; j++) - w[j] = vdp->vram[32 * i + 4 * j] + - (vdp->vram[32 * i + 4 * j + 1] << 8) + - (vdp->vram[32 * i + 4 * j + 2] << 16) + - (vdp->vram[32 * i + 4 * j + 3] << 24); - - DEBUG("- 0x%04X: %08X %08X %08X %08X %08X %08X %08X %08X", i, - w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]) - } } diff --git a/src/z80.c b/src/z80.c index 0cbbe24..7c4943d 100644 --- a/src/z80.c +++ b/src/z80.c @@ -130,37 +130,6 @@ static inline uint16_t stack_pop(Z80 *z80) } /* - Check for errors after an I/O operation. -*/ -static void handle_io_errors(Z80 *z80) -{ - if (z80->io->except) { - z80->except = true; - z80->exc_code = Z80_EXC_IO_ERROR; - z80->exc_data = z80->io->exc_port; - } -} - -/* - Read and return a byte from the given port, and check for errors. -*/ -static inline uint8_t read_port(Z80 *z80, uint8_t port) -{ - uint8_t value = io_port_read(z80->io, port); - handle_io_errors(z80); - return value; -} - -/* - Write a byte to the given port, and check for errors. -*/ -static inline void write_port(Z80 *z80, uint8_t port, uint8_t value) -{ - io_port_write(z80->io, port, value); - handle_io_errors(z80); -} - -/* Extract an 8-bit register from the given opcode and return a pointer to it. */ static inline uint8_t* extract_reg(Z80 *z80, uint8_t opcode) diff --git a/src/z80.h b/src/z80.h index 4b7ee56..631ca78 100644 --- a/src/z80.h +++ b/src/z80.h @@ -11,7 +11,6 @@ #define Z80_EXC_NOT_POWERED 0 #define Z80_EXC_UNIMPLEMENTED_OPCODE 1 -#define Z80_EXC_IO_ERROR 2 /* Structs */ diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 23c838c..e363247 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -1969,7 +1969,7 @@ static uint8_t z80_inst_in_a_n(Z80 *z80, uint8_t opcode) { (void) opcode; uint8_t port = mmu_read_byte(z80->mmu, ++z80->regs.pc); - z80->regs.a = read_port(z80, port); + z80->regs.a = io_port_read(z80->io, port); z80->regs.pc++; return 11; } @@ -1980,7 +1980,7 @@ static uint8_t z80_inst_in_a_n(Z80 *z80, uint8_t opcode) */ static uint8_t z80_inst_in_r_c(Z80 *z80, uint8_t opcode) { - uint8_t data = read_port(z80, z80->regs.c); + uint8_t data = io_port_read(z80->io, z80->regs.c); if (opcode != 0x70) *extract_reg(z80, opcode) = data; @@ -1996,7 +1996,8 @@ static uint8_t z80_inst_in_r_c(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_ini(Z80 *z80, uint8_t opcode) { (void) opcode; - mmu_write_byte(z80->mmu, z80->regs.hl, read_port(z80, z80->regs.c)); + uint8_t data = io_port_read(z80->io, z80->regs.c); + mmu_write_byte(z80->mmu, z80->regs.hl, data); set_flags_blockio(z80); z80->regs.hl++; @@ -2025,7 +2026,8 @@ static uint8_t z80_inst_inir(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_ind(Z80 *z80, uint8_t opcode) { (void) opcode; - mmu_write_byte(z80->mmu, z80->regs.hl, read_port(z80, z80->regs.c)); + uint8_t data = io_port_read(z80->io, z80->regs.c); + mmu_write_byte(z80->mmu, z80->regs.hl, data); set_flags_blockio(z80); z80->regs.hl--; @@ -2055,7 +2057,7 @@ static uint8_t z80_inst_out_n_a(Z80 *z80, uint8_t opcode) { (void) opcode; uint8_t port = mmu_read_byte(z80->mmu, ++z80->regs.pc); - write_port(z80, port, z80->regs.a); + io_port_write(z80->io, port, z80->regs.a); z80->regs.pc++; return 11; } @@ -2068,7 +2070,7 @@ static uint8_t z80_inst_out_n_a(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_out_c_r(Z80 *z80, uint8_t opcode) { uint8_t value = opcode != 0x71 ? *extract_reg(z80, opcode) : 0; - write_port(z80, z80->regs.c, value); + io_port_write(z80->io, z80->regs.c, value); z80->regs.pc++; return 12; } @@ -2080,7 +2082,8 @@ static uint8_t z80_inst_out_c_r(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_outi(Z80 *z80, uint8_t opcode) { (void) opcode; - write_port(z80, z80->regs.c, mmu_read_byte(z80->mmu, z80->regs.hl)); + uint8_t data = mmu_read_byte(z80->mmu, z80->regs.hl); + io_port_write(z80->io, z80->regs.c, data); set_flags_blockio(z80); z80->regs.hl++; @@ -2109,7 +2112,8 @@ static uint8_t z80_inst_otir(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_outd(Z80 *z80, uint8_t opcode) { (void) opcode; - write_port(z80, z80->regs.c, mmu_read_byte(z80->mmu, z80->regs.hl)); + uint8_t data = mmu_read_byte(z80->mmu, z80->regs.hl); + io_port_write(z80->io, z80->regs.c, data); set_flags_blockio(z80); z80->regs.hl--;