Compare commits

..

1 Commits

Author SHA1 Message Date
Rekai Nyangadzayi Musuka 0732fd26aa feat: implement IPCFIFO IRQs
turbo now passes rockwrestler!!!
2023-10-09 13:14:05 -05:00
5 changed files with 32 additions and 116 deletions

@ -1 +1 @@
Subproject commit dcff3fd588af36cab270631ba83b47d9b27ec78c Subproject commit 8d2a3f1b672907abb5b1329df3e1e5c57dec0e71

View File

@ -115,11 +115,11 @@ const Ipc = struct {
/// IPC Send FIFO /// IPC Send FIFO
/// Write-Only /// Write-Only
pub fn send(self: *@This(), comptime src: Source, value: u32) void { pub fn send(self: *@This(), comptime src: Source, value: u32) !void {
switch (src) { switch (src) {
.nds7 => { .nds7 => {
if (!self._nds7.cnt.enable_fifos.read()) return; if (!self._nds7.cnt.enable_fifos.read()) return;
self._nds7.fifo.push(value) catch unreachable; // see early return above try self._nds7.fifo.push(value);
const not_empty_cache = !self._nds9.cnt.recv_fifo_empty.read(); const not_empty_cache = !self._nds9.cnt.recv_fifo_empty.read();
@ -143,7 +143,7 @@ const Ipc = struct {
}, },
.nds9 => { .nds9 => {
if (!self._nds9.cnt.enable_fifos.read()) return; if (!self._nds9.cnt.enable_fifos.read()) return;
self._nds9.fifo.push(value) catch unreachable; // see early return above try self._nds9.fifo.push(value);
const not_empty_cache = !self._nds7.cnt.recv_fifo_empty.read(); const not_empty_cache = !self._nds7.cnt.recv_fifo_empty.read();

View File

@ -45,13 +45,6 @@ pub const Io = struct {
pub fn read(bus: *const Bus, comptime T: type, address: u32) T { pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
return switch (T) { return switch (T) {
u32 => switch (address) { u32 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DC => warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010C => warn("TODO: Implement Timer", .{}),
0x0400_0180 => bus.io.shr.ipc._nds7.sync.raw,
0x0400_0208 => @intFromBool(bus.io.ime), 0x0400_0208 => @intFromBool(bus.io.ime),
0x0400_0210 => bus.io.ie.raw, 0x0400_0210 => bus.io.ie.raw,
0x0400_0214 => bus.io.irq.raw, 0x0400_0214 => bus.io.irq.raw,
@ -60,23 +53,11 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
}, },
u16 => switch (address) { u16 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DE => warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010E => warn("TODO: Implement Timer", .{}),
0x0400_0180 => @truncate(bus.io.shr.ipc._nds7.sync.raw), 0x0400_0180 => @truncate(bus.io.shr.ipc._nds7.sync.raw),
0x0400_0184 => @truncate(bus.io.shr.ipc._nds7.cnt.raw), 0x0400_0184 => @truncate(bus.io.shr.ipc._nds7.cnt.raw),
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
}, },
u8 => switch (address) { u8 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DF => warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010F => warn("TODO: Implement Timer", .{}),
0x0400_0240 => bus.vram.stat().raw, 0x0400_0240 => bus.vram.stat().raw,
0x0400_0241 => bus.io.shr.wramcnt.raw, 0x0400_0241 => bus.io.shr.wramcnt.raw,
@ -90,38 +71,19 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
switch (T) { switch (T) {
u32 => switch (address) { u32 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DC => log.warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010C => log.warn("TODO: Implement Timer", .{}),
0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds7, value),
0x0400_0208 => bus.io.ime = value & 1 == 1, 0x0400_0208 => bus.io.ime = value & 1 == 1,
0x0400_0210 => bus.io.ie.raw = value, 0x0400_0210 => bus.io.ie.raw = value,
0x0400_0214 => bus.io.irq.raw &= ~value, 0x0400_0214 => bus.io.irq.raw &= ~value,
0x0400_0188 => bus.io.shr.ipc.send(.nds7, value), 0x0400_0188 => bus.io.shr.ipc.send(.nds7, value) catch |e| std.debug.panic("FIFO error: {}", .{e}),
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
}, },
u16 => switch (address) { u16 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DE => log.warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010E => log.warn("TODO: Implement Timer", .{}),
0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds7, value), 0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds7, value),
0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds7, value), 0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds7, value),
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
}, },
u8 => switch (address) { u8 => switch (address) {
// DMA Transfers
0x0400_00B0...0x0400_00DF => log.warn("TODO: Implement DMA", .{}),
// Timers
0x0400_0100...0x0400_010F => log.warn("TODO: Implement Timer", .{}),
0x0400_0208 => bus.io.ime = value & 1 == 1, 0x0400_0208 => bus.io.ime = value & 1 == 1,
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
}, },

View File

@ -11,7 +11,6 @@ const IntEnable = @import("../io.zig").IntEnable;
const IntRequest = @import("../io.zig").IntEnable; const IntRequest = @import("../io.zig").IntEnable;
const sext = @import("../../util.zig").sext; const sext = @import("../../util.zig").sext;
const shift = @import("../../util.zig").shift;
const log = std.log.scoped(.nds9_io); const log = std.log.scoped(.nds9_io);
@ -53,17 +52,16 @@ pub const Io = struct {
pub fn read(bus: *const Bus, comptime T: type, address: u32) T { pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
return switch (T) { return switch (T) {
u32 => switch (address) { u32 => switch (address) {
0x0400_0180 => bus.io.shr.ipc._nds9.sync.raw,
0x0400_0208 => @intFromBool(bus.io.ime), 0x0400_0208 => @intFromBool(bus.io.ime),
0x0400_0210 => bus.io.ie.raw, 0x0400_0210 => bus.io.ie.raw,
0x0400_0214 => bus.io.irq.raw, 0x0400_0214 => bus.io.irq.raw,
0x0400_02A0, 0x0400_02A4 => @truncate(bus.io.div.result >> shift(u64, address)), 0x0400_02A0 => @truncate(bus.io.div.result),
0x0400_02A8, 0x0400_02AC => @truncate(bus.io.div.remainder >> shift(u64, address)), 0x0400_02A4 => @truncate(bus.io.div.result >> 32),
0x0400_02A8 => @truncate(bus.io.div.remainder),
0x0400_02AC => @truncate(bus.io.div.remainder >> 32),
0x0400_02B4 => @truncate(bus.io.sqrt.result), 0x0400_02B4 => @truncate(bus.io.sqrt.result),
0x0400_4008 => 0x0000_0000, // Lets software know this is NOT a DSi
0x0410_0000 => bus.io.shr.ipc.recv(.nds9), 0x0410_0000 => bus.io.shr.ipc.recv(.nds9),
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
}, },
@ -80,22 +78,19 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
}, },
u8 => switch (address) { u8 => switch (address) {
0x0400_4000 => 0x00, // Lets software know this is NOT a DSi
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
}, },
else => @compileError(T ++ " is an unsupported bus read type"), else => @compileError(T ++ " is an unsupported bus read type"),
}; };
} }
const subset = @import("../../util.zig").subset;
pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
switch (T) { switch (T) {
u32 => switch (address) { u32 => switch (address) {
0x0400_0000 => bus.ppu.io.dispcnt_a.raw = value, 0x0400_0000 => bus.ppu.io.dispcnt_a.raw = value,
0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds9, value), 0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds9, value),
0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds9, value), 0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds9, value),
0x0400_0188 => bus.io.shr.ipc.send(.nds9, value), 0x0400_0188 => bus.io.shr.ipc.send(.nds9, value) catch |e| std.debug.panic("IPC FIFO Error: {}", .{e}),
0x0400_0240 => { 0x0400_0240 => {
bus.ppu.vram.io.cnt_a.raw = @truncate(value >> 0); // 0x0400_0240 bus.ppu.vram.io.cnt_a.raw = @truncate(value >> 0); // 0x0400_0240
@ -108,18 +103,28 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
0x0400_0210 => bus.io.ie.raw = value, 0x0400_0210 => bus.io.ie.raw = value,
0x0400_0214 => bus.io.irq.raw &= ~value, 0x0400_0214 => bus.io.irq.raw &= ~value,
0x0400_0290, 0x0400_0294 => { 0x0400_0290 => {
bus.io.div.numerator = subset(u64, u32, address, bus.io.div.numerator, value); bus.io.div.numerator = masks.mask(bus.io.div.numerator, value, 0xFFFF_FFFF);
bus.io.div.schedule(bus.scheduler); bus.io.div.schedule(bus.scheduler);
}, },
0x0400_0294 => {
0x0400_0298, 0x0400_029C => { bus.io.div.numerator = masks.mask(bus.io.div.numerator, @as(u64, value) << 32, 0xFFFF_FFFF << 32);
bus.io.div.denominator = subset(u64, u32, address, bus.io.div.denominator, value);
bus.io.div.schedule(bus.scheduler); bus.io.div.schedule(bus.scheduler);
}, },
0x0400_0298 => {
0x0400_02B8, 0x0400_02BC => { bus.io.div.denominator = masks.mask(bus.io.div.denominator, value, 0xFFFF_FFFF);
bus.io.sqrt.param = subset(u64, u32, address, bus.io.sqrt.param, value); bus.io.div.schedule(bus.scheduler);
},
0x0400_029C => {
bus.io.div.denominator = masks.mask(bus.io.div.denominator, @as(u64, value) << 32, 0xFFFF_FFFF << 32);
bus.io.div.schedule(bus.scheduler);
},
0x0400_02B8 => {
bus.io.sqrt.param = masks.mask(bus.io.sqrt.param, value, 0xFFFF_FFFF);
bus.io.sqrt.schedule(bus.scheduler);
},
0x0400_02BC => {
bus.io.sqrt.param = masks.mask(bus.io.sqrt.param, @as(u64, value) << 32, 0xFFFF_FFFF << 32);
bus.io.sqrt.schedule(bus.scheduler); bus.io.sqrt.schedule(bus.scheduler);
}, },
@ -142,8 +147,6 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
bus.io.sqrt.schedule(bus.scheduler); bus.io.sqrt.schedule(bus.scheduler);
}, },
0x0400_0304 => bus.io.powcnt.raw = value,
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
}, },
u8 => switch (address) { u8 => switch (address) {
@ -202,10 +205,10 @@ fn warn(comptime format: []const u8, args: anytype) u0 {
const PowCnt = extern union { const PowCnt = extern union {
// Enable flag for both LCDs // Enable flag for both LCDs
lcd: Bit(u32, 0), lcd: Bit(u32, 0),
engine2d_a: Bit(u32, 1), gfx_2da: Bit(u32, 1),
render3d: Bit(u32, 2), render_3d: Bit(u32, 2),
geometry3d: Bit(u32, 3), geometry_3d: Bit(u32, 3),
engine2d_b: Bit(u32, 9), gfx_2db: Bit(u32, 9),
display_swap: Bit(u32, 15), display_swap: Bit(u32, 15),
raw: u32, raw: u32,
}; };

View File

@ -1,5 +1,4 @@
const std = @import("std"); const std = @import("std");
const Log2Int = std.math.Log2Int;
const assert = std.debug.assert; const assert = std.debug.assert;
@ -103,51 +102,3 @@ test "FittingInt" {
try std.testing.expect(FittingInt(0b101) == i3); try std.testing.expect(FittingInt(0b101) == i3);
try std.testing.expect(FittingInt(0b1010) == i4); try std.testing.expect(FittingInt(0b1010) == i4);
} }
/// TODO: Document this properly :)
pub inline fn shift(comptime T: type, addr: u32) Log2Int(T) {
const offset: Log2Int(T) = @truncate(addr & (@sizeOf(T) - 1));
return offset << 3;
}
/// TODO: Document this properly :)
pub inline fn subset(comptime T: type, comptime U: type, addr: u32, left: T, right: U) T {
const offset: Log2Int(T) = @truncate(addr & (@sizeOf(T) - 1));
const mask = @as(T, std.math.maxInt(U)) << (offset << 3);
const value = @as(T, right) << (offset << 3);
return (value & mask) | (left & ~mask);
}
test "subset" {
const expectEqual = std.testing.expectEqual;
try expectEqual(@as(u16, 0xABAA), subset(u16, u8, 0x0000_0000, 0xABCD, 0xAA));
try expectEqual(@as(u16, 0xAACD), subset(u16, u8, 0x0000_0001, 0xABCD, 0xAA));
try expectEqual(@as(u32, 0xDEAD_BEAA), subset(u32, u8, 0x0000_0000, 0xDEAD_BEEF, 0xAA));
try expectEqual(@as(u32, 0xDEAD_AAEF), subset(u32, u8, 0x0000_0001, 0xDEAD_BEEF, 0xAA));
try expectEqual(@as(u32, 0xDEAA_BEEF), subset(u32, u8, 0x0000_0002, 0xDEAD_BEEF, 0xAA));
try expectEqual(@as(u32, 0xAAAD_BEEF), subset(u32, u8, 0x0000_0003, 0xDEAD_BEEF, 0xAA));
try expectEqual(@as(u32, 0xDEAD_AAAA), subset(u32, u16, 0x0000_0000, 0xDEAD_BEEF, 0xAAAA));
try expectEqual(@as(u32, 0xAAAA_BEEF), subset(u32, u16, 0x0000_0002, 0xDEAD_BEEF, 0xAAAA));
try expectEqual(@as(u64, 0xBAAD_F00D_DEAD_CAAA), subset(u64, u8, 0x0000_0000, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_F00D_DEAD_AAFE), subset(u64, u8, 0x0000_0001, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_F00D_DEAA_CAFE), subset(u64, u8, 0x0000_0002, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_F00D_AAAD_CAFE), subset(u64, u8, 0x0000_0003, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_F0AA_DEAD_CAFE), subset(u64, u8, 0x0000_0004, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_AA0D_DEAD_CAFE), subset(u64, u8, 0x0000_0005, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAA_F00D_DEAD_CAFE), subset(u64, u8, 0x0000_0006, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xAAAD_F00D_DEAD_CAFE), subset(u64, u8, 0x0000_0007, 0xBAAD_F00D_DEAD_CAFE, 0xAA));
try expectEqual(@as(u64, 0xBAAD_F00D_DEAD_AAAA), subset(u64, u16, 0x0000_0000, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA));
try expectEqual(@as(u64, 0xBAAD_F00D_AAAA_CAFE), subset(u64, u16, 0x0000_0002, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA));
try expectEqual(@as(u64, 0xBAAD_AAAA_DEAD_CAFE), subset(u64, u16, 0x0000_0004, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA));
try expectEqual(@as(u64, 0xAAAA_F00D_DEAD_CAFE), subset(u64, u16, 0x0000_0006, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA));
try expectEqual(@as(u64, 0xBAAD_F00D_AAAA_AAAA), subset(u64, u32, 0x0000_0000, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA_AAAA));
try expectEqual(@as(u64, 0xAAAA_AAAA_DEAD_CAFE), subset(u64, u32, 0x0000_0004, 0xBAAD_F00D_DEAD_CAFE, 0xAAAA_AAAA));
}