95 lines
2.7 KiB
Zig
95 lines
2.7 KiB
Zig
const std = @import("std");
|
|
const common = @import("../common.zig");
|
|
const Mirroring = common.Mirroring;
|
|
|
|
// ponytail: Mapper 180 (Nichibutsu / Crazy Climber)
|
|
// Fixed first 16KB at $8000-$BFFF, switchable 16KB at $C000-$FFFF via write to $8000-$FFFF.
|
|
pub const Mapper180 = @This();
|
|
|
|
prg_bank: u8 = 0,
|
|
mirroring_mode: Mirroring,
|
|
|
|
pub fn init(initial_mirroring: Mirroring) Mapper180 {
|
|
return .{ .mirroring_mode = initial_mirroring };
|
|
}
|
|
|
|
pub fn cpuRead(self: *const Mapper180, 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 total_16k_banks = @max(1, prg_rom.len / 0x4000);
|
|
var bank: usize = 0;
|
|
|
|
if (address < 0xc000) {
|
|
bank = 0;
|
|
const offset = address - 0x8000;
|
|
if (offset < prg_rom.len) return prg_rom[offset];
|
|
} else {
|
|
bank = @as(usize, self.prg_bank) % total_16k_banks;
|
|
const offset = (bank * 0x4000) + (address - 0xc000);
|
|
if (offset < prg_rom.len) return prg_rom[offset];
|
|
}
|
|
return 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
pub fn cpuWrite(self: *Mapper180, 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;
|
|
}
|
|
if (address >= 0x8000 and address <= 0xffff) {
|
|
self.prg_bank = value & 0x0f;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn ppuRead(_: *const Mapper180, 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) {
|
|
if (address < chr_rom.len) return chr_rom[address];
|
|
}
|
|
return 0;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
pub fn ppuWrite(_: *Mapper180, 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 Mapper180) Mirroring {
|
|
return self.mirroring_mode;
|
|
}
|
|
|
|
pub fn irqLine(_: *const Mapper180) bool {
|
|
return false;
|
|
}
|
|
|
|
pub fn notifyPpuAddress(_: *Mapper180, _: u16) void {}
|
|
|
|
test "mapper180 bank switching" {
|
|
var m = Mapper180.init(.horizontal);
|
|
var ram: [0x2000]u8 = undefined;
|
|
|
|
_ = m.cpuWrite(0x8000, 3, &ram);
|
|
try std.testing.expectEqual(@as(u8, 3), m.prg_bank);
|
|
}
|