diff --git a/src/Bus.zig b/src/Bus.zig index cb55041..54ed0e2 100644 --- a/src/Bus.zig +++ b/src/Bus.zig @@ -7,6 +7,8 @@ const Io = @import("bus/io.zig").Io; const Iwram = @import("bus/Iwram.zig"); const Ppu = @import("ppu.zig").Ppu; const Apu = @import("apu.zig").Apu; +const DmaControllers = @import("bus/dma.zig").DmaControllers; +const Timers = @import("bus/timer.zig").Timers; const Scheduler = @import("scheduler.zig").Scheduler; const io = @import("bus/io.zig"); @@ -20,8 +22,11 @@ pak: GamePak, bios: Bios, ppu: Ppu, apu: Apu, +dma: DmaControllers, +tim: Timers, iwram: Iwram, ewram: Ewram, + io: Io, pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, maybe_bios: ?[]const u8) !Self { @@ -32,7 +37,9 @@ pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, maybe_bio .apu = Apu.init(), .iwram = try Iwram.init(alloc), .ewram = try Ewram.init(alloc), - .io = Io.init(sched), + .dma = DmaControllers.init(), + .tim = Timers.init(sched), + .io = Io.init(), }; } diff --git a/src/bus/dma.zig b/src/bus/dma.zig index 54a510e..47fc852 100644 --- a/src/bus/dma.zig +++ b/src/bus/dma.zig @@ -5,8 +5,26 @@ const Bus = @import("../Bus.zig"); const log = std.log.scoped(.DmaTransfer); +pub const DmaControllers = struct { + const Self = @This(); + + _0: DmaController(0), + _1: DmaController(1), + _2: DmaController(2), + _3: DmaController(3), + + pub fn init() Self { + return .{ + ._0 = DmaController(0).init(), + ._1 = DmaController(1).init(), + ._2 = DmaController(2).init(), + ._3 = DmaController(3).init(), + }; + } +}; + /// Function that creates a DMAController. Determines unique DMA Controller behaiour at compile-time -pub fn DmaController(comptime id: u2) type { +fn DmaController(comptime id: u2) type { return struct { const Self = @This(); @@ -171,10 +189,10 @@ pub fn DmaController(comptime id: u2) type { } pub fn pollBlankingDma(bus: *Bus, comptime kind: DmaKind) void { - bus.io.dma0.pollBlankingDma(kind); - bus.io.dma1.pollBlankingDma(kind); - bus.io.dma2.pollBlankingDma(kind); - bus.io.dma3.pollBlankingDma(kind); + bus.dma._0.pollBlankingDma(kind); + bus.dma._1.pollBlankingDma(kind); + bus.dma._2.pollBlankingDma(kind); + bus.dma._3.pollBlankingDma(kind); } const Adjustment = enum(u2) { diff --git a/src/bus/io.zig b/src/bus/io.zig index 380012b..b3ff351 100644 --- a/src/bus/io.zig +++ b/src/bus/io.zig @@ -4,7 +4,6 @@ const Bit = @import("bitfield").Bit; const Bitfield = @import("bitfield").Bitfield; const Bus = @import("../Bus.zig"); const DmaController = @import("dma.zig").DmaController; -const Timer = @import("timer.zig").Timer; const Scheduler = @import("../scheduler.zig").Scheduler; const panic_on_und_io: bool = false; @@ -20,24 +19,9 @@ pub const Io = struct { irq: InterruptRequest, postflg: PostFlag, haltcnt: HaltControl, - - // DMA Controllers - // TODO: Figure out how to turn this into an array - dma0: DmaController(0), - dma1: DmaController(1), - dma2: DmaController(2), - dma3: DmaController(3), - - // Timers - // TODO: Figure out how to turn this into an array - tim0: Timer(0), - tim1: Timer(1), - tim2: Timer(2), - tim3: Timer(3), - keyinput: KeyInput, - pub fn init(sched: *Scheduler) Self { + pub fn init() Self { return .{ .ime = false, .ie = .{ .raw = 0x0000 }, @@ -45,18 +29,6 @@ pub const Io = struct { .keyinput = .{ .raw = 0x03FF }, .postflg = .FirstBoot, .haltcnt = .Execute, - - // Dma Controllers - .dma0 = DmaController(0).init(), - .dma1 = DmaController(1).init(), - .dma2 = DmaController(2).init(), - .dma3 = DmaController(3).init(), - - // Timers - .tim0 = Timer(0).init(sched), - .tim1 = Timer(1).init(sched), - .tim2 = Timer(2).init(sched), - .tim3 = Timer(3).init(sched), }; } @@ -74,16 +46,16 @@ pub fn read32(bus: *const Bus, addr: u32) u32 { 0x0400_0006 => @as(u32, bus.ppu.bg[0].cnt.raw) << 16 | bus.ppu.vcount.raw, // DMA Transfers - 0x0400_00B8 => @as(u32, bus.io.dma0.cnt.raw) << 16, - 0x0400_00C4 => @as(u32, bus.io.dma1.cnt.raw) << 16, - 0x0400_00D0 => @as(u32, bus.io.dma1.cnt.raw) << 16, - 0x0400_00DC => @as(u32, bus.io.dma3.cnt.raw) << 16, + 0x0400_00B8 => @as(u32, bus.dma._0.cnt.raw) << 16, + 0x0400_00C4 => @as(u32, bus.dma._1.cnt.raw) << 16, + 0x0400_00D0 => @as(u32, bus.dma._1.cnt.raw) << 16, + 0x0400_00DC => @as(u32, bus.dma._3.cnt.raw) << 16, // Timers - 0x0400_0100 => @as(u32, bus.io.tim0.cnt.raw) << 16 | bus.io.tim0.counter(), - 0x0400_0104 => @as(u32, bus.io.tim1.cnt.raw) << 16 | bus.io.tim1.counter(), - 0x0400_0108 => @as(u32, bus.io.tim2.cnt.raw) << 16 | bus.io.tim2.counter(), - 0x0400_010C => @as(u32, bus.io.tim3.cnt.raw) << 16 | bus.io.tim3.counter(), + 0x0400_0100 => @as(u32, bus.tim._0.cnt.raw) << 16 | bus.tim._0.counter(), + 0x0400_0104 => @as(u32, bus.tim._1.cnt.raw) << 16 | bus.tim._1.counter(), + 0x0400_0108 => @as(u32, bus.tim._2.cnt.raw) << 16 | bus.tim._2.counter(), + 0x0400_010C => @as(u32, bus.tim._3.cnt.raw) << 16 | bus.tim._3.counter(), // Interrupts 0x0400_0200 => @as(u32, bus.io.irq.raw) << 16 | bus.io.ie.raw, @@ -112,24 +84,24 @@ pub fn write32(bus: *Bus, addr: u32, word: u32) void { 0x0400_00A4 => log.warn("Wrote 0x{X:0>8} to FIFO_B", .{word}), // DMA Transfers - 0x0400_00B0 => bus.io.dma0.writeSad(word), - 0x0400_00B4 => bus.io.dma0.writeDad(word), - 0x0400_00B8 => bus.io.dma0.writeCnt(word), - 0x0400_00BC => bus.io.dma1.writeSad(word), - 0x0400_00C0 => bus.io.dma1.writeDad(word), - 0x0400_00C4 => bus.io.dma1.writeCnt(word), - 0x0400_00C8 => bus.io.dma2.writeSad(word), - 0x0400_00CC => bus.io.dma2.writeDad(word), - 0x0400_00D0 => bus.io.dma2.writeCnt(word), - 0x0400_00D4 => bus.io.dma3.writeSad(word), - 0x0400_00D8 => bus.io.dma3.writeDad(word), - 0x0400_00DC => bus.io.dma3.writeCnt(word), + 0x0400_00B0 => bus.dma._0.writeSad(word), + 0x0400_00B4 => bus.dma._0.writeDad(word), + 0x0400_00B8 => bus.dma._0.writeCnt(word), + 0x0400_00BC => bus.dma._1.writeSad(word), + 0x0400_00C0 => bus.dma._1.writeDad(word), + 0x0400_00C4 => bus.dma._1.writeCnt(word), + 0x0400_00C8 => bus.dma._2.writeSad(word), + 0x0400_00CC => bus.dma._2.writeDad(word), + 0x0400_00D0 => bus.dma._2.writeCnt(word), + 0x0400_00D4 => bus.dma._3.writeSad(word), + 0x0400_00D8 => bus.dma._3.writeDad(word), + 0x0400_00DC => bus.dma._3.writeCnt(word), // Timers - 0x0400_0100 => bus.io.tim0.writeCnt(word), - 0x0400_0104 => bus.io.tim1.writeCnt(word), - 0x0400_0108 => bus.io.tim2.writeCnt(word), - 0x0400_010C => bus.io.tim3.writeCnt(word), + 0x0400_0100 => bus.tim._0.writeCnt(word), + 0x0400_0104 => bus.tim._1.writeCnt(word), + 0x0400_0108 => bus.tim._2.writeCnt(word), + 0x0400_010C => bus.tim._3.writeCnt(word), // Serial Communication 1 0x0400_0120 => log.warn("Wrote 0x{X:0>8} to SIODATA32", .{word}), @@ -153,14 +125,14 @@ pub fn read16(bus: *const Bus, addr: u32) u16 { 0x0400_0088 => bus.apu.bias.raw, // Timers - 0x0400_0100 => bus.io.tim0.counter(), - 0x0400_0102 => bus.io.tim0.cnt.raw, - 0x0400_0104 => bus.io.tim1.counter(), - 0x0400_0106 => bus.io.tim1.cnt.raw, - 0x0400_0108 => bus.io.tim2.counter(), - 0x0400_010A => bus.io.tim2.cnt.raw, - 0x0400_010C => bus.io.tim3.counter(), - 0x0400_010E => bus.io.tim3.cnt.raw, + 0x0400_0100 => bus.tim._0.counter(), + 0x0400_0102 => bus.tim._0.cnt.raw, + 0x0400_0104 => bus.tim._1.counter(), + 0x0400_0106 => bus.tim._1.cnt.raw, + 0x0400_0108 => bus.tim._2.counter(), + 0x0400_010A => bus.tim._2.cnt.raw, + 0x0400_010C => bus.tim._3.counter(), + 0x0400_010E => bus.tim._3.cnt.raw, // Serial Communication 1 0x0400_0128 => unimplementedRead("Read halfword from SIOCNT", .{}), @@ -216,24 +188,24 @@ pub fn write16(bus: *Bus, addr: u32, halfword: u16) void { 0x0400_0088 => bus.apu.bias.raw = halfword, // Dma Transfers - 0x0400_00B8 => bus.io.dma0.writeWordCount(halfword), - 0x0400_00BA => bus.io.dma0.writeCntHigh(halfword), - 0x0400_00C4 => bus.io.dma1.writeWordCount(halfword), - 0x0400_00C6 => bus.io.dma1.writeCntHigh(halfword), - 0x0400_00D0 => bus.io.dma2.writeWordCount(halfword), - 0x0400_00D2 => bus.io.dma2.writeCntHigh(halfword), - 0x0400_00DC => bus.io.dma3.writeWordCount(halfword), - 0x0400_00DE => bus.io.dma3.writeCntHigh(halfword), + 0x0400_00B8 => bus.dma._0.writeWordCount(halfword), + 0x0400_00BA => bus.dma._0.writeCntHigh(halfword), + 0x0400_00C4 => bus.dma._1.writeWordCount(halfword), + 0x0400_00C6 => bus.dma._1.writeCntHigh(halfword), + 0x0400_00D0 => bus.dma._2.writeWordCount(halfword), + 0x0400_00D2 => bus.dma._2.writeCntHigh(halfword), + 0x0400_00DC => bus.dma._3.writeWordCount(halfword), + 0x0400_00DE => bus.dma._3.writeCntHigh(halfword), // Timers - 0x0400_0100 => bus.io.tim0.writeCntLow(halfword), - 0x0400_0102 => bus.io.tim0.writeCntHigh(halfword), - 0x0400_0104 => bus.io.tim1.writeCntLow(halfword), - 0x0400_0106 => bus.io.tim1.writeCntHigh(halfword), - 0x0400_0108 => bus.io.tim2.writeCntLow(halfword), - 0x0400_010A => bus.io.tim2.writeCntHigh(halfword), - 0x0400_010C => bus.io.tim3.writeCntLow(halfword), - 0x0400_010E => bus.io.tim3.writeCntHigh(halfword), + 0x0400_0100 => bus.tim._0.writeCntLow(halfword), + 0x0400_0102 => bus.tim._0.writeCntHigh(halfword), + 0x0400_0104 => bus.tim._1.writeCntLow(halfword), + 0x0400_0106 => bus.tim._1.writeCntHigh(halfword), + 0x0400_0108 => bus.tim._2.writeCntLow(halfword), + 0x0400_010A => bus.tim._2.writeCntHigh(halfword), + 0x0400_010C => bus.tim._3.writeCntLow(halfword), + 0x0400_010E => bus.tim._3.writeCntHigh(halfword), // Serial Communication 1 0x0400_0120 => log.warn("Wrote 0x{X:0>4} to SIOMULTI0", .{halfword}), diff --git a/src/bus/timer.zig b/src/bus/timer.zig index 14fd851..d57a34e 100644 --- a/src/bus/timer.zig +++ b/src/bus/timer.zig @@ -8,7 +8,25 @@ const Arm7tdmi = @import("../cpu.zig").Arm7tdmi; const log = std.log.scoped(.Timer); -pub fn Timer(comptime id: u2) type { +pub const Timers = struct { + const Self = @This(); + + _0: Timer(0), + _1: Timer(1), + _2: Timer(2), + _3: Timer(3), + + pub fn init(sched: *Scheduler) Self { + return .{ + ._0 = Timer(0).init(sched), + ._1 = Timer(1).init(sched), + ._2 = Timer(2).init(sched), + ._3 = Timer(3).init(sched), + }; + } +}; + +fn Timer(comptime id: u2) type { return struct { const Self = @This(); @@ -69,8 +87,11 @@ pub fn Timer(comptime id: u2) type { self.cnt.raw = halfword; } - pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi, io: *Io) void { + pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi) void { // Fire IRQ if enabled + const io = &cpu.bus.io; + const tim = &cpu.bus.tim; + if (self.cnt.irq.read()) { switch (id) { 0 => io.irq.tim0_overflow.set(), @@ -84,23 +105,23 @@ pub fn Timer(comptime id: u2) type { // Perform Cascade Behaviour switch (id) { - 0 => if (io.tim1.cnt.cascade.read()) { - io.tim1._counter +%= 1; + 0 => if (tim._1.cnt.cascade.read()) { + tim._1._counter +%= 1; - if (io.tim1._counter == 0) - io.tim1.handleOverflow(cpu, io); + if (tim._1._counter == 0) + tim._1.handleOverflow(cpu); }, - 1 => if (io.tim2.cnt.cascade.read()) { - io.tim2._counter +%= 1; + 1 => if (tim._2.cnt.cascade.read()) { + tim._2._counter +%= 1; - if (io.tim2._counter == 0) - io.tim2.handleOverflow(cpu, io); + if (tim._2._counter == 0) + tim._2.handleOverflow(cpu); }, - 2 => if (io.tim3.cnt.cascade.read()) { - io.tim3._counter +%= 1; + 2 => if (tim._3.cnt.cascade.read()) { + tim._3._counter +%= 1; - if (io.tim3._counter == 0) - io.tim3.handleOverflow(cpu, io); + if (tim._3._counter == 0) + tim._3.handleOverflow(cpu); }, 3 => {}, // There is no Timer for TIM3 to "cascade" to, } diff --git a/src/cpu.zig b/src/cpu.zig index 9de9e81..bc35712 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -296,10 +296,10 @@ pub const Arm7tdmi = struct { } fn handleDMATransfers(self: *Self) bool { - if (self.bus.io.dma0.step(self.bus)) return self.bus.io.dma0.isBlocking(); - if (self.bus.io.dma1.step(self.bus)) return self.bus.io.dma1.isBlocking(); - if (self.bus.io.dma2.step(self.bus)) return self.bus.io.dma2.isBlocking(); - if (self.bus.io.dma3.step(self.bus)) return self.bus.io.dma3.isBlocking(); + if (self.bus.dma._0.step(self.bus)) return self.bus.dma._0.isBlocking(); + if (self.bus.dma._1.step(self.bus)) return self.bus.dma._1.isBlocking(); + if (self.bus.dma._2.step(self.bus)) return self.bus.dma._2.isBlocking(); + if (self.bus.dma._3.step(self.bus)) return self.bus.dma._3.isBlocking(); return false; } diff --git a/src/scheduler.zig b/src/scheduler.zig index 1239e9e..e94435f 100644 --- a/src/scheduler.zig +++ b/src/scheduler.zig @@ -43,10 +43,10 @@ pub const Scheduler = struct { }, .TimerOverflow => |id| { switch (id) { - 0 => bus.io.tim0.handleOverflow(cpu, &bus.io), - 1 => bus.io.tim1.handleOverflow(cpu, &bus.io), - 2 => bus.io.tim2.handleOverflow(cpu, &bus.io), - 3 => bus.io.tim3.handleOverflow(cpu, &bus.io), + 0 => bus.tim._0.handleOverflow(cpu), + 1 => bus.tim._1.handleOverflow(cpu), + 2 => bus.tim._2.handleOverflow(cpu), + 3 => bus.tim._3.handleOverflow(cpu), } }, .HBlank => bus.ppu.handleHBlankEnd(cpu), // The end of a HBlank