Files
6soz/src/system/nes/bus.zig
T

158 lines
2.8 KiB
Zig
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const Cartridge = @import("cartridge.zig");
const Controller = @import("controller.zig");
const Ppu = @import("ppu.zig");
const Apu = @import("apu.zig");
const Bus = @This();
ram: [0x800]u8 =
[_]u8{0} ** 0x800,
cartridge: Cartridge,
ppu: Ppu = .{},
apu: Apu = .{},
controllers: [2]Controller = .{
.{},
.{},
},
open_bus: u8 = 0,
oam_dma_page: ?u8 = null,
pub fn init(
rom: []const u8,
) Cartridge.Error!Bus {
return .{
.cartridge = try Cartridge.init(rom),
};
}
pub fn reset(
self: *Bus,
) void {
self.ppu.reset();
self.apu.reset();
for (&self.controllers) |*controller|
controller.reset();
self.oam_dma_page = null;
}
pub inline fn read(
self: *Bus,
address: u16,
) u8 {
const value: u8 = switch (address) {
// 2 KiB internal RAM + mirrors.
0x0000...0x1fff => self.ram[address & 0x07ff],
// PPU registers + mirrors.
0x2000...0x3fff => self.ppu.cpuRead(
&self.cartridge,
address & 7,
),
// APU status.
0x4015 => self.apu.readStatus(),
// Controller 1.
0x4016 => self.controllers[0].read(),
// Controller 2.
0x4017 => self.controllers[1].read(),
// Cartridge space.
0x4020...0xffff => self.cartridge.cpuRead(address),
else => self.open_bus,
};
self.open_bus = value;
return value;
}
pub inline fn write(
self: *Bus,
address: u16,
value: u8,
) void {
self.open_bus = value;
switch (address) {
0x0000...0x1fff => self.ram[address & 0x07ff] =
value,
0x2000...0x3fff => self.ppu.cpuWrite(
&self.cartridge,
address & 7,
value,
),
0x4000...0x4013 => self.apu.write(
address,
value,
),
// OAMDMA
0x4014 => self.oam_dma_page = value,
0x4015 => self.apu.writeStatus(value),
0x4016 => {
self.controllers[0].write(value);
self.controllers[1].write(value);
},
0x4017 => self.apu.writeFrameCounter(value),
else => self.cartridge.cpuWrite(
address,
value,
),
}
}
/// Called exactly once for every CPU cycle.
pub inline fn tick(
self: *Bus,
) void {
self.apu.tick();
// NTSC NES: PPU runs at 3× CPU clock.
self.ppu.tick(&self.cartridge);
self.ppu.tick(&self.cartridge);
self.ppu.tick(&self.cartridge);
}
pub fn nmiLine(
self: *Bus,
) bool {
return self.ppu.nmiAsserted();
}
pub fn irqLine(
self: *Bus,
) bool {
return self.apu.irqAsserted() or
self.cartridge.irqAsserted();
}
pub fn takeOamDmaPage(
self: *Bus,
) ?u8 {
const page =
self.oam_dma_page;
self.oam_dma_page = null;
return page;
}