Compare commits
2 Commits
d5443d9c2f
...
660c8a2d62
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | 660c8a2d62 | |
Rekai Nyangadzayi Musuka | 9d590b099a |
11
src/Bus.zig
11
src/Bus.zig
|
@ -64,16 +64,7 @@ pub fn attach(self: *Self, cpu: *Arm7tdmi) void {
|
||||||
self.cpu = cpu;
|
self.cpu = cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handleDMATransfers(self: *Self) void {
|
pub inline fn isDmaRunning(self: *const Self) bool {
|
||||||
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 {
|
|
||||||
return self.dma[0].active or
|
return self.dma[0].active or
|
||||||
self.dma[1].active or
|
self.dma[1].active or
|
||||||
self.dma[2].active or
|
self.dma[2].active or
|
||||||
|
|
|
@ -263,12 +263,12 @@ pub const Apu = struct {
|
||||||
|
|
||||||
if (@boolToInt(self.dma_cnt.chA_timer.read()) == tim_id) {
|
if (@boolToInt(self.dma_cnt.chA_timer.read()) == tim_id) {
|
||||||
self.chA.updateSample();
|
self.chA.updateSample();
|
||||||
if (self.chA.len() <= 15) cpu.bus.dma[1].enableSoundDma(0x0400_00A0);
|
if (self.chA.len() <= 15) cpu.bus.dma[1].requestSoundDma(0x0400_00A0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@boolToInt(self.dma_cnt.chB_timer.read()) == tim_id) {
|
if (@boolToInt(self.dma_cnt.chB_timer.read()) == tim_id) {
|
||||||
self.chB.updateSample();
|
self.chB.updateSample();
|
||||||
if (self.chB.len() <= 15) cpu.bus.dma[2].enableSoundDma(0x0400_00A4);
|
if (self.chB.len() <= 15) cpu.bus.dma[2].requestSoundDma(0x0400_00A4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||||
|
|
||||||
const DmaControl = @import("io.zig").DmaControl;
|
const DmaControl = @import("io.zig").DmaControl;
|
||||||
const Bus = @import("../Bus.zig");
|
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) });
|
pub const DmaTuple = std.meta.Tuple(&[_]type{ DmaController(0), DmaController(1), DmaController(2), DmaController(3) });
|
||||||
const log = std.log.scoped(.DmaTransfer);
|
const log = std.log.scoped(.DmaTransfer);
|
||||||
|
@ -98,62 +99,35 @@ fn DmaController(comptime id: u2) type {
|
||||||
self.writeCntHigh(@truncate(u16, word >> 16));
|
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;
|
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;
|
const is_fifo = (self.id == 1 or self.id == 2) and self.cnt.start_timing.read() == 0b11;
|
||||||
|
const sad_adj = Self.adjustment(self.cnt.sad_adj.read());
|
||||||
|
const dad_adj = if (is_fifo) .Fixed else Self.adjustment(self.cnt.dad_adj.read());
|
||||||
|
|
||||||
// // if (is_fifo) {
|
const transfer_type = is_fifo or self.cnt.transfer_type.read();
|
||||||
// // 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);
|
const offset: u32 = if (transfer_type) @sizeOf(u32) else @sizeOf(u16);
|
||||||
|
|
||||||
if (transfer_type) {
|
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 {
|
} 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) {
|
switch (sad_adj) {
|
||||||
.Increment => self._sad +%= offset,
|
.Increment => self._sad +%= offset,
|
||||||
.Decrement => self._sad -%= offset,
|
.Decrement => self._sad -%= offset,
|
||||||
|
// TODO: Is just ignoring this ok?
|
||||||
|
.IncrementReload => log.err("{} is a prohibited adjustment on SAD", .{sad_adj}),
|
||||||
.Fixed => {},
|
.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}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_fifo) {
|
|
||||||
switch (dad_adj) {
|
switch (dad_adj) {
|
||||||
.Increment, .IncrementReload => self._dad +%= offset,
|
.Increment, .IncrementReload => self._dad +%= offset,
|
||||||
.Decrement => self._dad -%= offset,
|
.Decrement => self._dad -%= offset,
|
||||||
.Fixed => {},
|
.Fixed => {},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self._word_count -= 1;
|
self._word_count -= 1;
|
||||||
|
|
||||||
|
@ -162,12 +136,15 @@ fn DmaController(comptime id: u2) type {
|
||||||
// If we're not repeating, Fire the IRQs and disable the DMA
|
// If we're not repeating, Fire the IRQs and disable the DMA
|
||||||
if (self.cnt.irq.read()) {
|
if (self.cnt.irq.read()) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
0 => bus.io.irq.dma0.set(),
|
0 => cpu.bus.io.irq.dma0.set(),
|
||||||
1 => bus.io.irq.dma0.set(),
|
1 => cpu.bus.io.irq.dma0.set(),
|
||||||
2 => bus.io.irq.dma0.set(),
|
2 => cpu.bus.io.irq.dma0.set(),
|
||||||
3 => bus.io.irq.dma0.set(),
|
3 => cpu.bus.io.irq.dma0.set(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu.handleInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cnt.enabled.unset();
|
self.cnt.enabled.unset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,21 +173,28 @@ fn DmaController(comptime id: u2) type {
|
||||||
|
|
||||||
if (self.cnt.repeat.read() and self.active) {
|
if (self.cnt.repeat.read() and self.active) {
|
||||||
self._word_count = if (self.word_count == 0) std.math.maxInt(@TypeOf(self._word_count)) else self.word_count;
|
self._word_count = if (self.word_count == 0) std.math.maxInt(@TypeOf(self._word_count)) else self.word_count;
|
||||||
|
if (Self.adjustment(self.cnt.dad_adj.read()) == .IncrementReload) self._dad = self.dad;
|
||||||
const dad_adj = std.meta.intToEnum(Adjustment, self.cnt.dad_adj.read()) catch unreachable;
|
|
||||||
if (dad_adj == .IncrementReload) self._dad = self.dad;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enableSoundDma(self: *Self, fifo_addr: u32) void {
|
pub fn requestSoundDma(self: *Self, fifo_addr: u32) void {
|
||||||
comptime std.debug.assert(id == 1 or id == 2);
|
comptime std.debug.assert(id == 1 or id == 2);
|
||||||
|
|
||||||
if (self.cnt.enabled.read() and self.cnt.start_timing.read() == 0b11 and self.dad == fifo_addr) {
|
const is_enabled = self.cnt.enabled.read();
|
||||||
self.active = true;
|
const is_special = self.cnt.start_timing.read() == 0b11;
|
||||||
|
const is_repeating = self.cnt.repeat.read();
|
||||||
|
const is_fifo = self.dad == fifo_addr;
|
||||||
|
|
||||||
|
if (is_enabled and is_special and is_repeating and is_fifo) {
|
||||||
self._word_count = 4;
|
self._word_count = 4;
|
||||||
self.cnt.repeat.set();
|
self.cnt.transfer_type.set();
|
||||||
|
self.active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adjustment(idx: u2) Adjustment {
|
||||||
|
return std.meta.intToEnum(Adjustment, idx) catch unreachable;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
pub fn handleInterrupt(self: *Self) void {
|
||||||
const should_handle = self.bus.io.ie.raw & self.bus.io.irq.raw;
|
const should_handle = self.bus.io.ie.raw & self.bus.io.irq.raw;
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void {
|
||||||
while (sched.tick < frame_end) {
|
while (sched.tick < frame_end) {
|
||||||
if (cpu.bus.io.haltcnt == .Halt) sched.tick += 1;
|
if (cpu.bus.io.haltcnt == .Halt) sched.tick += 1;
|
||||||
if (cpu.bus.io.haltcnt == .Execute) cpu.step();
|
if (cpu.bus.io.haltcnt == .Execute) cpu.step();
|
||||||
cpu.bus.handleDMATransfers();
|
cpu.handleDMATransfers();
|
||||||
|
|
||||||
while (sched.tick >= sched.nextTimestamp()) {
|
while (sched.tick >= sched.nextTimestamp()) {
|
||||||
sched.handleEvent(cpu);
|
sched.handleEvent(cpu);
|
||||||
|
|
Loading…
Reference in New Issue