const types = @import("types.zig"); const Mirroring = types.Mirroring; const Mmc3 = @import("mmc3.zig"); const Mapper119 = @This(); mmc3: Mmc3, pub fn init( prg_size: usize, chr_size: usize, ) Mapper119 { return .{ .mmc3 = Mmc3.init(prg_size, chr_size), }; } pub fn cpuMapRead( self: *const Mapper119, address: u16, ) ?usize { return self.mmc3.cpuMapRead(address); } pub fn cpuWrite( self: *Mapper119, address: u16, value: u8, ) void { self.mmc3.cpuWrite(address, value); } pub fn ppuMapRead( self: *Mapper119, address: u16, ) ?usize { if (address >= 0x2000) return null; const bank_val = self.getChrBankValue(address); const offset = (address % 0x0400); if ((bank_val & 0x40) != 0) { // Bit 6 is set -> Route to CHR RAM const ram_bank = @as(usize, bank_val & 7); return 0x80000000 | (ram_bank * 0x0400 + offset); } else { // Route to CHR ROM return self.mmc3.ppuMapRead(address); } } pub fn ppuMapWrite( self: *const Mapper119, address: u16, ) ?usize { if (address >= 0x2000) return null; const bank_val = self.getChrBankValue(address); const offset = (address % 0x0400); if ((bank_val & 0x40) != 0) { // Bit 6 is set -> Route write to CHR RAM const ram_bank = @as(usize, bank_val & 7); return 0x80000000 | (ram_bank * 0x0400 + offset); } else { return self.mmc3.ppuMapWrite(address); } } fn getChrBankValue(self: *const Mapper119, address: u16) u8 { const chr_mode = (self.mmc3.bank_select & 0x80) != 0; const addr_k = address / 0x0400; if (!chr_mode) { return switch (addr_k) { 0, 1 => (self.mmc3.bank_registers[0] & 0xfe) + @as(u8, @intCast(addr_k & 1)), 2, 3 => (self.mmc3.bank_registers[1] & 0xfe) + @as(u8, @intCast(addr_k & 1)), 4 => self.mmc3.bank_registers[2], 5 => self.mmc3.bank_registers[3], 6 => self.mmc3.bank_registers[4], 7 => self.mmc3.bank_registers[5], else => unreachable, }; } else { return switch (addr_k) { 0 => self.mmc3.bank_registers[2], 1 => self.mmc3.bank_registers[3], 2 => self.mmc3.bank_registers[4], 3 => self.mmc3.bank_registers[5], 4, 5 => (self.mmc3.bank_registers[0] & 0xfe) + @as(u8, @intCast(addr_k & 1)), 6, 7 => (self.mmc3.bank_registers[1] & 0xfe) + @as(u8, @intCast(addr_k & 1)), else => unreachable, }; } } pub fn mirroring( self: *const Mapper119, ) Mirroring { return self.mmc3.mirroring(); } pub fn irqAsserted( self: *const Mapper119, ) bool { return self.mmc3.irqAsserted(); } pub fn handleScanline( self: *Mapper119, ) void { self.mmc3.handleScanline(); }