114 lines
2.8 KiB
Zig
114 lines
2.8 KiB
Zig
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();
|
|
}
|