diff --git a/src/cpu_bus.c b/src/cpu_bus.c index 8437e81..31e8659 100644 --- a/src/cpu_bus.c +++ b/src/cpu_bus.c @@ -12,8 +12,7 @@ void create_cpu_bus(cpu_bus_t *bus, memset(bus->memory, 0, CPU_RAM_SIZE); } -address_t mirror_address_cpu_bus(address_t address, - unsigned long prg_ram_size) { +address_t mirror_cpu_bus(address_t address, unsigned long prg_ram_size) { if (address < CPU_MAP_PPU_REG) { // Mirrored RAM region return CPU_MAP_START + ((address - CPU_MAP_START) % 0x800); @@ -27,74 +26,14 @@ address_t mirror_address_cpu_bus(address_t address, return address; } -unsigned char *get_memory_cpu_bus(cpu_bus_t *bus, address_t address) { - address_t norm_address = - mirror_address_cpu_bus(address, bus->rom->header.prg_ram_size); - switch (norm_address) { - case PPU_REG_CTRL: - return &bus->ppu->ctrl; - case PPU_REG_MASK: - return &bus->ppu->mask; - case PPU_REG_STATUS: - return &bus->ppu->status; - case PPU_REG_OAMADDR: - return &bus->ppu->oam_addr; - case PPU_REG_OAMDATA: - return &bus->ppu->oam_data; - case PPU_REG_SCROLL: - return &bus->ppu->scroll; - case PPU_REG_ADDR: - return &bus->ppu->addr; - case PPU_REG_DATA: - return &bus->ppu->data; - case PPU_REG_OAMDMA: - return &bus->ppu->oam_dma; - case APU_REG_PULSE1_0: - return &bus->apu->channel_registers.pulse1[0]; - case APU_REG_PULSE1_1: - return &bus->apu->channel_registers.pulse1[1]; - case APU_REG_PULSE1_2: - return &bus->apu->channel_registers.pulse1[2]; - case APU_REG_PULSE1_3: - return &bus->apu->channel_registers.pulse1[3]; - case APU_REG_PULSE2_0: - return &bus->apu->channel_registers.pulse2[0]; - case APU_REG_PULSE2_1: - return &bus->apu->channel_registers.pulse2[1]; - case APU_REG_PULSE2_2: - return &bus->apu->channel_registers.pulse2[2]; - case APU_REG_PULSE2_3: - return &bus->apu->channel_registers.pulse2[3]; - case APU_REG_TRIANGLE_0: - return &bus->apu->channel_registers.triangle[0]; - case APU_REG_TRIANGLE_1: - return &bus->apu->channel_registers.triangle[1]; - case APU_REG_TRIANGLE_2: - return &bus->apu->channel_registers.triangle[2]; - case APU_REG_TRIANGLE_3: - return &bus->apu->channel_registers.triangle[3]; - case APU_REG_NOISE_0: - return &bus->apu->channel_registers.noise[0]; - case APU_REG_NOISE_1: - return &bus->apu->channel_registers.noise[1]; - case APU_REG_NOISE_2: - return &bus->apu->channel_registers.noise[2]; - case APU_REG_NOISE_3: - return &bus->apu->channel_registers.noise[3]; - case APU_REG_DMC_0: - return &bus->apu->channel_registers.dmc[0]; - case APU_REG_DMC_1: - return &bus->apu->channel_registers.dmc[1]; - case APU_REG_DMC_2: - return &bus->apu->channel_registers.dmc[2]; - case APU_REG_DMC_3: - return &bus->apu->channel_registers.dmc[3]; - case APU_REG_STATUS: - return &bus->apu->status; - case APU_REG_FRAME_COUNTER: - return &bus->apu->frame_counter; - default: - return bus->memory + norm_address; +void oamdma_cpu_bus(cpu_bus_t *bus, unsigned char value) { + address_t dma_addr = value << 8; + for (unsigned i = 0; i < 256; i++) { + // Get + unsigned char data = read_cpu_bus(bus, dma_addr + i); + + // Put + write_cpu_bus(bus, PPU_REG_OAMDATA, data); } } @@ -102,64 +41,25 @@ unsigned char read_cpu_bus(cpu_bus_t *bus, address_t address) { if (address >= CPU_MAP_ROM) { return read_cpu_mapper(bus->mapper, address); } else { - unsigned char *ptr = get_memory_cpu_bus(bus, address); - unsigned char result = *ptr; - - // Read from write only registers (return the latch) - if (ptr == &bus->ppu->ctrl || ptr == &bus->ppu->mask || - ptr == &bus->ppu->oam_addr || ptr == &bus->ppu->scroll || - ptr == &bus->ppu->addr || ptr == &bus->ppu->oam_dma) { - result = bus->ppu->io_databus; - } - - // Read from PPUSTATUS - if (ptr == &bus->ppu->status) { - bus->ppu->status &= ~PPU_STATUS_VBLANK; - bus->ppu->w = false; - - // Suppress setting VBlank and NMI if reading too close - if (bus->ppu->scanline == PPU_SCANLINE_VBLANK) { - if (bus->ppu->dot <= 1) { - bus->ppu->suppress_vbl = true; - } - if (bus->ppu->dot <= 3) { - bus->ppu->suppress_nmi = true; - } - } - - // Set low 5 bits of status register to io latch - result &= ~0x1F; - result |= bus->ppu->io_databus & 0x1F; - bus->ppu->io_databus = result; - } - - // Read from OAMDATA (overwrite result with value from primary OAM) - if (ptr == &bus->ppu->oam_data) { - result = bus->ppu->primary_oam[bus->ppu->oam_addr]; - if ((bus->ppu->oam_addr % 4) == 2) { - result &= 0xE3; - } - bus->ppu->io_databus = result; + address = mirror_cpu_bus(address, bus->rom->header.prg_ram_size); + switch (address) { + case PPU_REG_STATUS: + return read_status_ppu(bus->ppu); + case PPU_REG_OAMDATA: + return read_oamdata_ppu(bus->ppu); + case PPU_REG_DATA: + return read_data_ppu(bus->ppu); + case PPU_REG_CTRL: + case PPU_REG_MASK: + case PPU_REG_ADDR: + case PPU_REG_SCROLL: + case PPU_REG_OAMADDR: + case PPU_REG_OAMDMA: + return bus->ppu->io_databus; + // TODO: Handle APU, controller input registers + default: + return bus->memory[address]; } - - // Read from PPUDATA (overwrite result with value from VRAM) - if (ptr == &bus->ppu->data) { - address_t vram_addr = bus->ppu->v & 0x3FFF; - result = bus->buffer2007; - bus->buffer2007 = read_ppu_bus(bus->ppu->bus, vram_addr); - - // Set high 2 bits from palette to io latch and apply PPU effects - if (bus->ppu->v >= PPU_MAP_PALETTE && !is_rendering_ppu(bus->ppu)) { - address_t palette_addr = bus->ppu->v & 0x1F; - result = read_palette_ppu(bus->ppu, palette_addr); - result &= ~0xC0; - result |= bus->ppu->io_databus & 0xC0; - } - increment_vram_address_ppu(bus->ppu); - bus->ppu->io_databus = result; - } - - return result; } } @@ -167,109 +67,38 @@ void write_cpu_bus(cpu_bus_t *bus, address_t address, unsigned char value) { if (address >= CPU_MAP_ROM) { write_cpu_mapper(bus->mapper, address, value); } else { - unsigned char *ptr = get_memory_cpu_bus(bus, address); - unsigned char prev_value = *ptr; - if (ptr != &bus->ppu->status) { - *get_memory_cpu_bus(bus, address) = value; - } - - // Write to PPUMASK, PPUSTATUS, OAMADDR (set the latch) - if (ptr == &bus->ppu->mask || ptr == &bus->ppu->status || - ptr == &bus->ppu->oam_addr) { - bus->ppu->io_databus = value; - } - - // Write to PPUCTRL - if (ptr == &bus->ppu->ctrl) { - address_t gh = (value & 0x03) << 10; - bus->ppu->t = (bus->ppu->t & 0x73FF) | gh; - bus->ppu->io_databus = value; - - // Disable NMI if cleared near VBlank disable - if ((prev_value & PPU_CTRL_NMI) && - !(bus->ppu->ctrl & PPU_CTRL_NMI) && bus->ppu->dot <= 3) { - set_nmi_interrupt(bus->ppu->interrupt, false); - } - - // Trigger NMI if VBlank is set - if ((bus->ppu->status & PPU_STATUS_VBLANK) && - (bus->ppu->ctrl & PPU_CTRL_NMI) && - !(prev_value & PPU_CTRL_NMI) && bus->ppu->dot != 1) { - set_nmi_interrupt(bus->ppu->interrupt, true); - } - } - - // Write to OAMDATA - if (ptr == &bus->ppu->oam_data) { - if (is_rendering_ppu(bus->ppu)) { - bus->ppu->oam_addr += 0x04; // Bump high 6 bits - } else { - bus->ppu->primary_oam[bus->ppu->oam_addr++] = value; - } - bus->ppu->io_databus = value; - } - - // Write to PPUSCROLL - if (ptr == &bus->ppu->scroll) { - if (!bus->ppu->w) { - address_t abcde = (value & 0xF8) >> 3; - address_t fgh = value & 0x07; - - bus->ppu->t = (bus->ppu->t & 0xFFE0) | abcde; - bus->ppu->x = fgh; - } else { - address_t ab = (value & 0xC0) << 2; - address_t cde = (value & 0x38) << 2; - address_t fgh = (value & 0x07) << 12; - address_t tmask = ab | cde | fgh; - - bus->ppu->t = (bus->ppu->t & 0xC1F) | tmask; - } - bus->ppu->w = !bus->ppu->w; - bus->ppu->io_databus = value; - } - - // Write to PPUADDR - if (ptr == &bus->ppu->addr) { - if (!bus->ppu->w) { - address_t hi = value & 0x3F; - address_t lo = bus->ppu->t & 0x00FF; - bus->ppu->t = (hi << 8) | lo; - } else { - bus->ppu->t = (bus->ppu->t & 0x7F00) | value; - bus->ppu->v = bus->ppu->t; - } - bus->ppu->w = !bus->ppu->w; - bus->ppu->io_databus = value; - } - - // Write to PPUDATA - if (ptr == &bus->ppu->data) { - if (bus->ppu->v >= PPU_MAP_PALETTE && !is_rendering_ppu(bus->ppu)) { - address_t palette_addr = bus->ppu->v & 0x1F; - write_palette_ppu(bus->ppu, palette_addr, value); - } else { - address_t vram_addr = bus->ppu->v & 0x3FFF; - write_ppu_bus(bus->ppu->bus, vram_addr, value); - } - increment_vram_address_ppu(bus->ppu); - bus->ppu->io_databus = value; - - // TODO: - // https://www.nesdev.org/wiki/PPU_scrolling#$2007_reads_and_writes - } - - // Write to OAMDMA (TODO: fix cycle timing, make this a CPU routine?) - if (ptr == &bus->ppu->oam_dma) { - address_t dma_addr = value << 8; - for (unsigned i = 0; i < 256; i++) { - // Get - unsigned char data = read_cpu_bus(bus, dma_addr + i); - - // Put - write_cpu_bus(bus, PPU_REG_OAMDATA, data); - } + address = mirror_cpu_bus(address, bus->rom->header.prg_ram_size); + switch (address) { + case PPU_REG_CTRL: + write_ctrl_ppu(bus->ppu, value); + break; + case PPU_REG_MASK: + write_mask_ppu(bus->ppu, value); + break; + case PPU_REG_OAMDATA: + write_oamdata_ppu(bus->ppu, value); + break; + case PPU_REG_SCROLL: + write_scroll_ppu(bus->ppu, value); + break; + case PPU_REG_ADDR: + write_addr_ppu(bus->ppu, value); + break; + case PPU_REG_DATA: + write_data_ppu(bus->ppu, value); + break; + case PPU_REG_OAMADDR: + write_oamaddr_ppu(bus->ppu, value); + break; + case PPU_REG_OAMDMA: + oamdma_cpu_bus(bus, value); + case PPU_REG_STATUS: bus->ppu->io_databus = value; + break; + // TODO: Handle APU, controller input registers + default: + bus->memory[address] = value; + break; } } } diff --git a/src/cpu_bus.h b/src/cpu_bus.h index 0a5a6bf..cf994a9 100644 --- a/src/cpu_bus.h +++ b/src/cpu_bus.h @@ -122,16 +122,7 @@ void create_cpu_bus(cpu_bus_t *bus, * @param prg_ram_size * @return address_t */ -address_t mirror_address_cpu_bus(address_t address, unsigned long prg_ram_size); - -/** - * @brief Get the physical pointer to memory for a given address. - * - * @param bus - * @param address - * @return unsigned char* - */ -unsigned char *get_memory_cpu_bus(cpu_bus_t *bus, address_t address); +address_t mirror_cpu_bus(address_t address, unsigned long prg_ram_size); /** * @brief Read a byte from the CPU's memory map. diff --git a/src/ppu.c b/src/ppu.c index 323930e..c002744 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -4,12 +4,7 @@ void create_ppu(ppu_t *ppu, ppu_bus_t *bus, interrupt_t *interrupt) { ppu->ctrl = 0; ppu->mask = 0; ppu->status = PPU_STATUS_VBLANK | PPU_STATUS_S_OVERFLOW; - ppu->oam_addr = 0; - ppu->oam_data = 0; - ppu->scroll = 0; - ppu->addr = 0; - ppu->data = 0; - ppu->oam_dma = 0; + ppu->oamaddr = 0; ppu->v = 0; ppu->t = 0; @@ -127,19 +122,150 @@ void increment_vram_address_ppu(ppu_t *ppu) { ppu->v += ((ppu->ctrl >> 2) & 1) * 31; } +unsigned char read_status_ppu(ppu_t *ppu) { + // Set low 5 bits of status register to io latch + unsigned char result = ppu->status; + result &= ~0x1F; + result |= ppu->io_databus & 0x1F; + ppu->io_databus = result; + + // Update registers + ppu->status &= ~PPU_STATUS_VBLANK; + ppu->w = false; + + // Suppress setting VBlank and NMI if reading too close + if (ppu->scanline == PPU_SCANLINE_VBLANK) { + if (ppu->dot <= 1) { + ppu->suppress_vbl = true; + } + if (ppu->dot <= 3) { + ppu->suppress_nmi = true; + } + } + return result; +} + +unsigned char read_oamdata_ppu(ppu_t *ppu) { + unsigned char result = ppu->primary_oam[ppu->oamaddr]; + if ((ppu->oamaddr % 4) == 2) { + result &= 0xE3; + } + ppu->io_databus = result; + return result; +} + +unsigned char read_data_ppu(ppu_t *ppu) { + address_t vram_addr = ppu->v & 0x3FFF; + unsigned char result = ppu->buffer2007; + ppu->buffer2007 = read_ppu_bus(ppu->bus, vram_addr); + + // Set high 2 bits from palette to io latch and apply PPU effects + if (ppu->v >= PPU_MAP_PALETTE && !is_rendering_ppu(ppu)) { + address_t palette_addr = ppu->v & 0x1F; + result = read_palette_ppu(ppu, palette_addr); + result &= ~0xC0; + result |= ppu->io_databus & 0xC0; + } + increment_vram_address_ppu(ppu); + ppu->io_databus = result; + return result; +} + +void write_ctrl_ppu(ppu_t *ppu, unsigned char value) { + unsigned char prev_value = ppu->ctrl; + ppu->ctrl = value; + + address_t gh = (value & 0x03) << 10; + ppu->t = (ppu->t & 0x73FF) | gh; + ppu->io_databus = value; + + // Disable NMI if cleared near VBlank disable + if ((prev_value & PPU_CTRL_NMI) && !(ppu->ctrl & PPU_CTRL_NMI) && + ppu->dot <= 3) { + set_nmi_interrupt(ppu->interrupt, false); + } + + // Trigger NMI if VBlank is set + if ((ppu->status & PPU_STATUS_VBLANK) && (ppu->ctrl & PPU_CTRL_NMI) && + !(prev_value & PPU_CTRL_NMI) && ppu->dot != 1) { + set_nmi_interrupt(ppu->interrupt, true); + } +} + +void write_mask_ppu(ppu_t *ppu, unsigned char value) { + ppu->mask = value; + ppu->io_databus = value; +} + +void write_oamaddr_ppu(ppu_t *ppu, unsigned char value) { + ppu->oamaddr = value; + ppu->io_databus = value; +} + +void write_oamdata_ppu(ppu_t *ppu, unsigned char value) { + if (is_rendering_ppu(ppu)) { + ppu->oamaddr += 0x04; // Bump high 6 bits + } else { + ppu->primary_oam[ppu->oamaddr++] = value; + } + ppu->io_databus = value; +} + +void write_scroll_ppu(ppu_t *ppu, unsigned char value) { + if (!ppu->w) { + address_t abcde = (value & 0xF8) >> 3; + address_t fgh = value & 0x07; + + ppu->t = (ppu->t & 0xFFE0) | abcde; + ppu->x = fgh; + } else { + address_t ab = (value & 0xC0) << 2; + address_t cde = (value & 0x38) << 2; + address_t fgh = (value & 0x07) << 12; + address_t tmask = ab | cde | fgh; + + ppu->t = (ppu->t & 0xC1F) | tmask; + } + ppu->w = !ppu->w; + ppu->io_databus = value; +} + +void write_addr_ppu(ppu_t *ppu, unsigned char value) { + if (!ppu->w) { + address_t hi = value & 0x3F; + address_t lo = ppu->t & 0x00FF; + ppu->t = (hi << 8) | lo; + } else { + ppu->t = (ppu->t & 0x7F00) | value; + ppu->v = ppu->t; + } + ppu->w = !ppu->w; + ppu->io_databus = value; +} + +void write_data_ppu(ppu_t *ppu, unsigned char value) { + if (ppu->v >= PPU_MAP_PALETTE && !is_rendering_ppu(ppu)) { + address_t palette_addr = ppu->v & 0x1F; + write_palette_ppu(ppu, palette_addr, value); + } else { + address_t vram_addr = ppu->v & 0x3FFF; + write_ppu_bus(ppu->bus, vram_addr, value); + } + increment_vram_address_ppu(ppu); + ppu->io_databus = value; + + // TODO: + // https://www.nesdev.org/wiki/PPU_scrolling#$2007_reads_and_writes +} + void read_state_ppu(ppu_t *ppu, char *buffer, unsigned buffer_size) { snprintf(buffer, buffer_size, - "CTRL:%02X STATUS:%02X MASK:%02X SCROLL:%02X ADDR:%02X DATA:%02X " - "OAMADDR:%02X OAMDATA:%02X CYC:%3d,%3d", + "CTRL:%02X STATUS:%02X MASK:%02X OAMADDR:%02X CYC:%3d,%3d", ppu->ctrl, ppu->status, ppu->mask, - ppu->scroll, - ppu->addr, - ppu->data, - ppu->oam_addr, - ppu->oam_data, + ppu->oamaddr, ppu->scanline, ppu->dot); } @@ -341,7 +467,7 @@ void execute_events_ppu(ppu_t *ppu, ppu_event_t *events) { break; case PPU_EVENT_CLEAR_OAMADDR: if (enabled) { - ppu->oam_addr = 0; + ppu->oamaddr = 0; } break; case PPU_EVENT_CLEAR_FLAGS: diff --git a/src/ppu.h b/src/ppu.h index a6dcca7..1771593 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -89,37 +89,7 @@ typedef struct { * @brief OAMADDR register. * */ - unsigned char oam_addr; - - /** - * @brief OAMDATA register. - * - */ - unsigned char oam_data; - - /** - * @brief PPUSCROLL register. - * - */ - unsigned char scroll; - - /** - * @brief PPUADDR register. - * - */ - unsigned char addr; - - /** - * @brief PPUDATA register. - * - */ - unsigned char data; - - /** - * @brief OAMDMA register. - * - */ - unsigned char oam_dma; + unsigned char oamaddr; /** * @brief Current VRAM address. @@ -199,6 +169,12 @@ typedef struct { */ unsigned char palette[PPU_PALETTE_SIZE]; + /** + * @brief Read buffer for PPUDATA. + * + */ + unsigned char buffer2007; + /** * @brief Data bus for communicating with the CPU. * @@ -333,6 +309,85 @@ void write_palette_ppu(ppu_t *ppu, */ void increment_vram_address_ppu(ppu_t *ppu); +/** + * @brief Read from PPUSTATUS. + * + * @param ppu + */ +unsigned char read_status_ppu(ppu_t *ppu); + +/** + * @brief Read from OAMDATA. + * + * @param ppu + * @return unsigned char + */ +unsigned char read_oamdata_ppu(ppu_t *ppu); + +/** + * @brief Read from PPUDATA. + * + * @param ppu + * @return unsigned char + */ +unsigned char read_data_ppu(ppu_t *ppu); + +/** + * @brief Write to PPUCTRL. + * + * @param ppu + * @param value + */ +void write_ctrl_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to PPUMASK. + * + * @param ppu + * @param value + */ +void write_mask_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to OAMADDR. + * + * @param ppu + * @param value + */ +void write_oamaddr_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to OAMDATA. + * + * @param ppu + * @param value + */ +void write_oamdata_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to PPUSCROLL. + * + * @param ppu + * @param value + */ +void write_scroll_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to PPUADDR. + * + * @param ppu + * @param value + */ +void write_addr_ppu(ppu_t *ppu, unsigned char value); + +/** + * @brief Write to PPUDATA. + * + * @param ppu + * @param value + */ +void write_data_ppu(ppu_t *ppu, unsigned char value); + /** * @brief Read the current state of the CPU for debugging. * diff --git a/tests/src/cpu-memory-test.c b/tests/src/cpu-memory-test.c index 5e0292b..9906967 100644 --- a/tests/src/cpu-memory-test.c +++ b/tests/src/cpu-memory-test.c @@ -8,165 +8,49 @@ int tests_run = 0; static char *test_mirror_ram() { // RAM - mu_assert("RAM (L)", mirror_address_cpu_bus(0x0000, 0x2000) == 0); - mu_assert("RAM (M)", mirror_address_cpu_bus(0x0050, 0x2000) == 0x050); - mu_assert("RAM (H)", mirror_address_cpu_bus(0x07ff, 0x2000) == 0x07ff); + mu_assert("RAM (L)", mirror_cpu_bus(0x0000, 0x2000) == 0); + mu_assert("RAM (M)", mirror_cpu_bus(0x0050, 0x2000) == 0x050); + mu_assert("RAM (H)", mirror_cpu_bus(0x07ff, 0x2000) == 0x07ff); // Mirror 0 - mu_assert("RAM Mirror 0 (L)", mirror_address_cpu_bus(0x0800, 0x2000) == 0); - mu_assert("RAM Mirror 0 (M)", - mirror_address_cpu_bus(0x0900, 0x2000) == 0x0100); - mu_assert("RAM Mirror 0 (H)", - mirror_address_cpu_bus(0x0fff, 0x2000) == 0x07ff); + mu_assert("RAM Mirror 0 (L)", mirror_cpu_bus(0x0800, 0x2000) == 0); + mu_assert("RAM Mirror 0 (M)", mirror_cpu_bus(0x0900, 0x2000) == 0x0100); + mu_assert("RAM Mirror 0 (H)", mirror_cpu_bus(0x0fff, 0x2000) == 0x07ff); // Mirror 1 - mu_assert("RAM Mirror 1 (L)", mirror_address_cpu_bus(0x1000, 0x2000) == 0); - mu_assert("RAM Mirror 1 (M)", - mirror_address_cpu_bus(0x1100, 0x2000) == 0x0100); - mu_assert("RAM Mirror 1 (H)", - mirror_address_cpu_bus(0x17ff, 0x2000) == 0x07ff); + mu_assert("RAM Mirror 1 (L)", mirror_cpu_bus(0x1000, 0x2000) == 0); + mu_assert("RAM Mirror 1 (M)", mirror_cpu_bus(0x1100, 0x2000) == 0x0100); + mu_assert("RAM Mirror 1 (H)", mirror_cpu_bus(0x17ff, 0x2000) == 0x07ff); // Mirror 2 - mu_assert("RAM Mirror 2 (L)", mirror_address_cpu_bus(0x1800, 0x2000) == 0); - mu_assert("RAM Mirror 2 (M)", - mirror_address_cpu_bus(0x1900, 0x2000) == 0x0100); - mu_assert("RAM Mirror 2 (H)", - mirror_address_cpu_bus(0x1fff, 0x2000) == 0x07ff); + mu_assert("RAM Mirror 2 (L)", mirror_cpu_bus(0x1800, 0x2000) == 0); + mu_assert("RAM Mirror 2 (M)", mirror_cpu_bus(0x1900, 0x2000) == 0x0100); + mu_assert("RAM Mirror 2 (H)", mirror_cpu_bus(0x1fff, 0x2000) == 0x07ff); return 0; } static char *test_mirror_ppu() { // PPU - mu_assert("PPU (L)", mirror_address_cpu_bus(0x2000, 0x2000) == 0x2000); - mu_assert("PPU (M)", mirror_address_cpu_bus(0x2004, 0x2000) == 0x2004); - mu_assert("PPU (H)", mirror_address_cpu_bus(0x2007, 0x2000) == 0x2007); + mu_assert("PPU (L)", mirror_cpu_bus(0x2000, 0x2000) == 0x2000); + mu_assert("PPU (M)", mirror_cpu_bus(0x2004, 0x2000) == 0x2004); + mu_assert("PPU (H)", mirror_cpu_bus(0x2007, 0x2000) == 0x2007); // First Mirror - mu_assert("PPU Mirror 0 (L)", - mirror_address_cpu_bus(0x2008, 0x2000) == 0x2000); - mu_assert("PPU Mirror 0 (M)", - mirror_address_cpu_bus(0x200c, 0x2000) == 0x2004); - mu_assert("PPU Mirror 0 (H)", - mirror_address_cpu_bus(0x200f, 0x2000) == 0x2007); + mu_assert("PPU Mirror 0 (L)", mirror_cpu_bus(0x2008, 0x2000) == 0x2000); + mu_assert("PPU Mirror 0 (M)", mirror_cpu_bus(0x200c, 0x2000) == 0x2004); + mu_assert("PPU Mirror 0 (H)", mirror_cpu_bus(0x200f, 0x2000) == 0x2007); // Last Mirror - mu_assert("PPU Mirror last (L)", - mirror_address_cpu_bus(0x3ff8, 0x2000) == 0x2000); - mu_assert("PPU Mirror last (M)", - mirror_address_cpu_bus(0x3ffc, 0x2000) == 0x2004); - mu_assert("PPU Mirror last (H)", - mirror_address_cpu_bus(0x3fff, 0x2000) == 0x2007); + mu_assert("PPU Mirror last (L)", mirror_cpu_bus(0x3ff8, 0x2000) == 0x2000); + mu_assert("PPU Mirror last (M)", mirror_cpu_bus(0x3ffc, 0x2000) == 0x2004); + mu_assert("PPU Mirror last (H)", mirror_cpu_bus(0x3fff, 0x2000) == 0x2007); return 0; } static char *test_mirror_apu() { - mu_assert("APU I/O (L)", mirror_address_cpu_bus(0x4000, 0x2000) == 0x4000); - mu_assert("APU I/O (M)", mirror_address_cpu_bus(0x4017, 0x2000) == 0x4017); - mu_assert("APU I/O (H)", mirror_address_cpu_bus(0x4019, 0x2000) == 0x4019); - return 0; -} - -static char *test_map_ppu_registers() { - emulator_t emu; - create_emulator(&emu, "../roms/nestest/nestest.nes"); - mu_assert("PPU CTRL", - &emu.ppu.ctrl == get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_CTRL)); - mu_assert("PPU MASK", - &emu.ppu.mask == get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_MASK)); - mu_assert("PPU STATUS", - &emu.ppu.status == - get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_STATUS)); - mu_assert("PPU OAM ADDR", - &emu.ppu.oam_addr == - get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_OAMADDR)); - mu_assert("PPU OAM DATA", - &emu.ppu.oam_data == - get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_OAMDATA)); - mu_assert("PPU SCROLL", - &emu.ppu.scroll == - get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_SCROLL)); - mu_assert("PPU ADDR", - &emu.ppu.addr == get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_ADDR)); - mu_assert("PPU DATA", - &emu.ppu.data == get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_DATA)); - mu_assert("PPU OAM DMA", - &emu.ppu.oam_dma == - get_memory_cpu_bus(&emu.cpu_bus, PPU_REG_OAMDMA)); - destroy_emulator(&emu); - return 0; -} - -static char *test_map_apu_registers() { - emulator_t emu; - create_emulator(&emu, "../roms/nestest/nestest.nes"); - mu_assert("APU PULSE1 0", - &emu.apu.channel_registers.pulse1[0] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE1_0)); - mu_assert("APU PULSE1 1", - &emu.apu.channel_registers.pulse1[1] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE1_1)); - mu_assert("APU PULSE1 2", - &emu.apu.channel_registers.pulse1[2] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE1_2)); - mu_assert("APU PULSE1 3", - &emu.apu.channel_registers.pulse1[3] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE1_3)); - mu_assert("APU PULSE2 0", - &emu.apu.channel_registers.pulse2[0] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE2_0)); - mu_assert("APU PULSE2 1", - &emu.apu.channel_registers.pulse2[1] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE2_1)); - mu_assert("APU PULSE2 2", - &emu.apu.channel_registers.pulse2[2] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE2_2)); - mu_assert("APU PULSE2 3", - &emu.apu.channel_registers.pulse2[3] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_PULSE2_3)); - mu_assert("APU TRIANGLE 0", - &emu.apu.channel_registers.triangle[0] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_TRIANGLE_0)); - mu_assert("APU TRIANGLE 1", - &emu.apu.channel_registers.triangle[1] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_TRIANGLE_1)); - mu_assert("APU TRIANGLE 2", - &emu.apu.channel_registers.triangle[2] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_TRIANGLE_2)); - mu_assert("APU TRIANGLE 3", - &emu.apu.channel_registers.triangle[3] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_TRIANGLE_3)); - mu_assert("APU NOISE 0", - &emu.apu.channel_registers.noise[0] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_NOISE_0)); - mu_assert("APU NOISE 1", - &emu.apu.channel_registers.noise[1] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_NOISE_1)); - mu_assert("APU NOISE 2", - &emu.apu.channel_registers.noise[2] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_NOISE_2)); - mu_assert("APU NOISE 3", - &emu.apu.channel_registers.noise[3] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_NOISE_3)); - mu_assert("APU DMC 0", - &emu.apu.channel_registers.dmc[0] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_DMC_0)); - mu_assert("APU DMC 1", - &emu.apu.channel_registers.dmc[1] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_DMC_1)); - mu_assert("APU DMC 2", - &emu.apu.channel_registers.dmc[2] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_DMC_2)); - mu_assert("APU DMC 3", - &emu.apu.channel_registers.dmc[3] == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_DMC_3)); - mu_assert("APU STATUS", - &emu.apu.status == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_STATUS)); - mu_assert("APU FRAME COUNTER", - &emu.apu.frame_counter == - get_memory_cpu_bus(&emu.cpu_bus, APU_REG_FRAME_COUNTER)); - - destroy_emulator(&emu); + mu_assert("APU I/O (L)", mirror_cpu_bus(0x4000, 0x2000) == 0x4000); + mu_assert("APU I/O (M)", mirror_cpu_bus(0x4017, 0x2000) == 0x4017); + mu_assert("APU I/O (H)", mirror_cpu_bus(0x4019, 0x2000) == 0x4019); return 0; } @@ -202,8 +86,6 @@ static char *all_tests() { mu_run_test(test_mirror_ram); mu_run_test(test_mirror_ppu); mu_run_test(test_mirror_apu); - mu_run_test(test_map_ppu_registers); - mu_run_test(test_map_apu_registers); mu_run_test(test_mapper0); mu_run_test(test_stack); return 0;