add nes cartridge subsystem and 41 ines mapper variants
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
const types = @import("types.zig");
|
||||
const Mirroring = types.Mirroring;
|
||||
|
||||
const Mapper65 = @This();
|
||||
|
||||
prg_banks: [3]u8 = [_]u8{ 0, 1, 2 },
|
||||
chr_banks: [8]u8 = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
|
||||
mirroring_mode: Mirroring = .vertical,
|
||||
|
||||
irq_enabled: bool = false,
|
||||
irq_counter: u16 = 0,
|
||||
irq_reload: u16 = 0,
|
||||
irq_assert: bool = false,
|
||||
|
||||
prg_bank_count: usize,
|
||||
chr_bank_count: usize,
|
||||
|
||||
pub fn init(
|
||||
prg_size: usize,
|
||||
chr_size: usize,
|
||||
mirroring_mode: Mirroring,
|
||||
) Mapper65 {
|
||||
return .{
|
||||
.prg_bank_count = prg_size / 0x2000,
|
||||
.chr_bank_count = if (chr_size > 0) chr_size / 0x0400 else 1,
|
||||
.mirroring_mode = mirroring_mode,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn cpuMapRead(
|
||||
self: *const Mapper65,
|
||||
address: u16,
|
||||
) ?usize {
|
||||
if (address < 0x8000) return null;
|
||||
|
||||
const offset = @as(usize, address & 0x1fff);
|
||||
const last_bank = self.prg_bank_count - 1;
|
||||
|
||||
switch ((address - 0x8000) / 0x2000) {
|
||||
0 => return (@as(usize, self.prg_banks[0]) % self.prg_bank_count) * 0x2000 + offset,
|
||||
1 => return (@as(usize, self.prg_banks[1]) % self.prg_bank_count) * 0x2000 + offset,
|
||||
2 => return (@as(usize, self.prg_banks[2]) % self.prg_bank_count) * 0x2000 + offset,
|
||||
3 => return last_bank * 0x2000 + offset,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpuWrite(
|
||||
self: *Mapper65,
|
||||
address: u16,
|
||||
value: u8,
|
||||
) void {
|
||||
if (address < 0x8000) return;
|
||||
|
||||
switch (address) {
|
||||
0x8000 => self.prg_banks[0] = value,
|
||||
0xa000 => self.prg_banks[1] = value,
|
||||
0xc000 => self.prg_banks[2] = value,
|
||||
|
||||
0x9001 => self.mirroring_mode = if ((value & 0x80) != 0) .horizontal else .vertical,
|
||||
|
||||
0x9003 => {
|
||||
self.irq_enabled = (value & 0x80) != 0;
|
||||
self.irq_assert = false;
|
||||
},
|
||||
0x9004 => {
|
||||
self.irq_reload = (self.irq_reload & 0xff00) | value;
|
||||
},
|
||||
0x9005 => {
|
||||
self.irq_reload = (self.irq_reload & 0x00ff) | (@as(u16, value) << 8);
|
||||
self.irq_counter = self.irq_reload;
|
||||
self.irq_assert = false;
|
||||
},
|
||||
|
||||
0xb000 => self.chr_banks[0] = value,
|
||||
0xb001 => self.chr_banks[1] = value,
|
||||
0xb002 => self.chr_banks[2] = value,
|
||||
0xb003 => self.chr_banks[3] = value,
|
||||
0xb004 => self.chr_banks[4] = value,
|
||||
0xb005 => self.chr_banks[5] = value,
|
||||
0xb006 => self.chr_banks[6] = value,
|
||||
0xb007 => self.chr_banks[7] = value,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ppuMapRead(
|
||||
self: *const Mapper65,
|
||||
address: u16,
|
||||
) ?usize {
|
||||
if (address >= 0x2000) return null;
|
||||
|
||||
const slot = address / 0x0400;
|
||||
const offset = @as(usize, address & 0x03ff);
|
||||
const bank = @as(usize, self.chr_banks[slot]) % self.chr_bank_count;
|
||||
|
||||
return bank * 0x0400 + offset;
|
||||
}
|
||||
|
||||
pub fn ppuMapWrite(
|
||||
self: *const Mapper65,
|
||||
address: u16,
|
||||
) ?usize {
|
||||
return self.ppuMapRead(address);
|
||||
}
|
||||
|
||||
pub fn mirroring(
|
||||
self: *const Mapper65,
|
||||
) Mirroring {
|
||||
return self.mirroring_mode;
|
||||
}
|
||||
|
||||
pub fn irqAsserted(
|
||||
self: *const Mapper65,
|
||||
) bool {
|
||||
return self.irq_assert;
|
||||
}
|
||||
Reference in New Issue
Block a user