const std = @import("std"); const common = @import("../common.zig"); const Mirroring = common.Mirroring; pub const Nrom = @This(); mirroring_mode: Mirroring, pub fn init(initial_mirroring: Mirroring) Nrom { return .{ .mirroring_mode = initial_mirroring }; } pub fn cpuRead(_: *const Nrom, address: u16, prg_rom: []const u8, prg_ram: []const u8) ?u8 { if (address >= 0x6000 and address <= 0x7fff) { const offset = address - 0x6000; if (offset < prg_ram.len) return prg_ram[offset]; return 0; } if (address >= 0x8000 and address <= 0xffff) { const mask: usize = if (prg_rom.len <= 0x4000) 0x3fff else 0x7fff; const offset = (address - 0x8000) & mask; if (offset < prg_rom.len) return prg_rom[offset]; return 0; } return null; } pub fn cpuWrite(_: *Nrom, address: u16, value: u8, prg_ram: []u8) bool { if (address >= 0x6000 and address <= 0x7fff) { const offset = address - 0x6000; if (offset < prg_ram.len) { prg_ram[offset] = value; return true; } } return false; } pub fn ppuRead(_: *const Nrom, address: u16, chr_rom: []const u8, chr_ram: []const u8, chr_is_ram: bool) ?u8 { if (address < 0x2000) { if (chr_is_ram) { if (address < chr_ram.len) return chr_ram[address]; } else { if (chr_rom.len > 0) return chr_rom[address & (chr_rom.len - 1)]; } return 0; } return null; } pub fn ppuWrite(_: *Nrom, address: u16, value: u8, chr_ram: []u8, chr_is_ram: bool) bool { if (address < 0x2000 and chr_is_ram) { if (address < chr_ram.len) { chr_ram[address] = value; return true; } } return false; } pub fn mirroring(self: *const Nrom) Mirroring { return self.mirroring_mode; } pub fn irqLine(_: *const Nrom) bool { return false; } pub fn notifyPpuAddress(_: *Nrom, _: u16) void {} test "nrom prg mirroring" { var nrom = Nrom.init(.horizontal); var prg_16k: [0x4000]u8 = undefined; @memset(&prg_16k, 0x42); prg_16k[0] = 0x11; var ram: [0x2000]u8 = undefined; @memset(&ram, 0); // 16K PRG is mirrored at $8000 and $C000 try std.testing.expectEqual(@as(?u8, 0x11), nrom.cpuRead(0x8000, &prg_16k, &ram)); try std.testing.expectEqual(@as(?u8, 0x11), nrom.cpuRead(0xc000, &prg_16k, &ram)); }