chore: move DMA and Timers from io to bus

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-03-15 08:25:26 -03:00
parent 1fd80c1c23
commit 04d54ec97a
6 changed files with 123 additions and 105 deletions

View File

@ -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(),
};
}

View File

@ -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) {

View File

@ -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}),

View File

@ -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,
}

View File

@ -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;
}

View File

@ -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