feat: handle DMA IRQs (maybe?)

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-05-05 22:04:59 -03:00
parent d5443d9c2f
commit 9d590b099a
4 changed files with 22 additions and 42 deletions

View File

@ -64,16 +64,7 @@ pub fn attach(self: *Self, cpu: *Arm7tdmi) void {
self.cpu = cpu;
}
pub fn handleDMATransfers(self: *Self) void {
while (self.isDmaRunning()) {
if (self.dma[1].step(self)) continue;
if (self.dma[0].step(self)) continue;
if (self.dma[2].step(self)) continue;
if (self.dma[3].step(self)) continue;
}
}
inline fn isDmaRunning(self: *const Self) bool {
pub inline fn isDmaRunning(self: *const Self) bool {
return self.dma[0].active or
self.dma[1].active or
self.dma[2].active or

View File

@ -2,6 +2,7 @@ const std = @import("std");
const DmaControl = @import("io.zig").DmaControl;
const Bus = @import("../Bus.zig");
const Arm7tdmi = @import("../cpu.zig").Arm7tdmi;
pub const DmaTuple = std.meta.Tuple(&[_]type{ DmaController(0), DmaController(1), DmaController(2), DmaController(3) });
const log = std.log.scoped(.DmaTransfer);
@ -98,44 +99,20 @@ fn DmaController(comptime id: u2) type {
self.writeCntHigh(@truncate(u16, word >> 16));
}
pub fn step(self: *Self, bus: *Bus) bool {
pub fn step(self: *Self, cpu: *Arm7tdmi) bool {
if (!self.active) return false;
const sad_adj = std.meta.intToEnum(Adjustment, self.cnt.sad_adj.read()) catch unreachable;
const dad_adj = std.meta.intToEnum(Adjustment, self.cnt.dad_adj.read()) catch unreachable;
const is_fifo = (self.id == 1 or self.id == 2) and self.cnt.start_timing.read() == 0b11;
// // if (is_fifo) {
// // const offset = @sizeOf(u32);
// // bus.write(u32, self._dad, bus.read(u32, self._sad));
// // // TODO: Deduplicate
// // switch (sad_adj) {
// // .Increment => self._sad +%= offset,
// // .Decrement => self._sad -%= offset,
// // .Fixed => {},
// // // TODO: Figure out correct behaviour on Illegal Source Addr Control Type
// // .IncrementReload => std.debug.panic("panic(DmaTransfer): {} is an illegal src addr adjustment type", .{sad_adj}),
// // }
// // self._fifo_word_count -= 1;
// // if (self._fifo_word_count == 0) {
// // self._fifo_word_count = 4;
// // self.active = false;
// // }
// // return true;
// // }
const transfer_type = self.cnt.transfer_type.read() or is_fifo;
const offset: u32 = if (transfer_type) @sizeOf(u32) else @sizeOf(u16);
if (transfer_type) {
bus.write(u32, self._dad, bus.read(u32, self._sad));
cpu.bus.write(u32, self._dad, cpu.bus.read(u32, self._sad));
} else {
bus.write(u16, self._dad, bus.read(u16, self._sad));
cpu.bus.write(u16, self._dad, cpu.bus.read(u16, self._sad));
}
switch (sad_adj) {
@ -162,12 +139,15 @@ fn DmaController(comptime id: u2) type {
// If we're not repeating, Fire the IRQs and disable the DMA
if (self.cnt.irq.read()) {
switch (id) {
0 => bus.io.irq.dma0.set(),
1 => bus.io.irq.dma0.set(),
2 => bus.io.irq.dma0.set(),
3 => bus.io.irq.dma0.set(),
0 => cpu.bus.io.irq.dma0.set(),
1 => cpu.bus.io.irq.dma0.set(),
2 => cpu.bus.io.irq.dma0.set(),
3 => cpu.bus.io.irq.dma0.set(),
}
cpu.handleInterrupt();
}
self.cnt.enabled.unset();
}

View File

@ -267,6 +267,15 @@ pub const Arm7tdmi = struct {
}
}
pub fn handleDMATransfers(self: *Self) void {
while (self.bus.isDmaRunning()) {
if (self.bus.dma[1].step(self)) continue;
if (self.bus.dma[0].step(self)) continue;
if (self.bus.dma[2].step(self)) continue;
if (self.bus.dma[3].step(self)) continue;
}
}
pub fn handleInterrupt(self: *Self) void {
const should_handle = self.bus.io.ie.raw & self.bus.io.irq.raw;

View File

@ -48,7 +48,7 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void {
while (sched.tick < frame_end) {
if (cpu.bus.io.haltcnt == .Halt) sched.tick += 1;
if (cpu.bus.io.haltcnt == .Execute) cpu.step();
cpu.bus.handleDMATransfers();
cpu.handleDMATransfers();
while (sched.tick >= sched.nextTimestamp()) {
sched.handleEvent(cpu);