feat: implement broken IPCFIFO
This commit is contained in:
		@@ -70,25 +70,6 @@ const arm9_clock = bus_clock * 2;
 | 
			
		||||
 | 
			
		||||
pub fn runFrame(nds7_group: nds7.Group, nds9_group: nds9.Group) void {
 | 
			
		||||
    // TODO: might be more efficient to run them both in the same loop?
 | 
			
		||||
    {
 | 
			
		||||
        const scheduler = nds7_group.scheduler;
 | 
			
		||||
 | 
			
		||||
        const cycles_per_dot = arm7_clock / dot_clock + 1;
 | 
			
		||||
        comptime std.debug.assert(cycles_per_dot == 6);
 | 
			
		||||
 | 
			
		||||
        const cycles_per_frame = 355 * 263 * cycles_per_dot;
 | 
			
		||||
        const frame_end = scheduler.tick + cycles_per_frame;
 | 
			
		||||
 | 
			
		||||
        const cpu = nds7_group.cpu;
 | 
			
		||||
        const bus = nds7_group.bus;
 | 
			
		||||
 | 
			
		||||
        while (scheduler.tick < frame_end) {
 | 
			
		||||
            cpu.step();
 | 
			
		||||
 | 
			
		||||
            if (scheduler.tick >= scheduler.next()) scheduler.handle(bus);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const scheduler = nds9_group.scheduler;
 | 
			
		||||
 | 
			
		||||
@@ -107,6 +88,25 @@ pub fn runFrame(nds7_group: nds7.Group, nds9_group: nds9.Group) void {
 | 
			
		||||
            if (scheduler.tick >= scheduler.next()) scheduler.handle(bus);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const scheduler = nds7_group.scheduler;
 | 
			
		||||
 | 
			
		||||
        const cycles_per_dot = arm7_clock / dot_clock + 1;
 | 
			
		||||
        comptime std.debug.assert(cycles_per_dot == 6);
 | 
			
		||||
 | 
			
		||||
        const cycles_per_frame = 355 * 263 * cycles_per_dot;
 | 
			
		||||
        const frame_end = scheduler.tick + cycles_per_frame;
 | 
			
		||||
 | 
			
		||||
        const cpu = nds7_group.cpu;
 | 
			
		||||
        const bus = nds7_group.bus;
 | 
			
		||||
 | 
			
		||||
        while (scheduler.tick < frame_end) {
 | 
			
		||||
            cpu.step();
 | 
			
		||||
 | 
			
		||||
            if (scheduler.tick >= scheduler.next()) scheduler.handle(bus);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: Perf win to allocating on the stack instead?
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										126
									
								
								src/core/io.zig
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								src/core/io.zig
									
									
									
									
									
								
							@@ -22,21 +22,8 @@ pub const Io = struct {
 | 
			
		||||
    /// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest`
 | 
			
		||||
    irq: u32 = 0x0000_0000,
 | 
			
		||||
 | 
			
		||||
    /// IPC Synchronize
 | 
			
		||||
    /// Read/Write
 | 
			
		||||
    ipc_sync: IpcSync = .{ .raw = 0x0000_0000 },
 | 
			
		||||
 | 
			
		||||
    /// IPC Fifo Control
 | 
			
		||||
    /// Read/Write
 | 
			
		||||
    ipc_fifo_cnt: IpcFifoCnt = .{ .raw = 0x0000_0000 },
 | 
			
		||||
 | 
			
		||||
    /// IPC Send FIFO
 | 
			
		||||
    /// Write-Only
 | 
			
		||||
    ipc_fifo_send: u32 = 0x0000_0000,
 | 
			
		||||
 | 
			
		||||
    /// IPC Receive FIFO
 | 
			
		||||
    /// Read-Only
 | 
			
		||||
    ipc_fifo_recv: u32 = 0x0000_0000,
 | 
			
		||||
    /// Inter Process Communication FIFO
 | 
			
		||||
    ipc_fifo: IpcFifo = .{},
 | 
			
		||||
 | 
			
		||||
    /// Post Boot Flag
 | 
			
		||||
    /// Read/Write
 | 
			
		||||
@@ -121,6 +108,54 @@ pub inline fn writeToAddressOffset(
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const IpcFifo = struct {
 | 
			
		||||
    const Sync = IpcSync;
 | 
			
		||||
    const Control = IpcFifoCnt;
 | 
			
		||||
 | 
			
		||||
    /// IPC Synchronize
 | 
			
		||||
    /// Read/Write
 | 
			
		||||
    sync: Sync = .{ .raw = 0x0000_0000 },
 | 
			
		||||
 | 
			
		||||
    /// IPC Fifo Control
 | 
			
		||||
    /// Read/Write
 | 
			
		||||
    cnt: Control = .{ .raw = 0x0000_0000 },
 | 
			
		||||
 | 
			
		||||
    fifo: [2]Fifo = .{ Fifo{}, Fifo{} },
 | 
			
		||||
 | 
			
		||||
    const Source = enum { arm7, arm9 };
 | 
			
		||||
 | 
			
		||||
    /// IPC Send FIFO
 | 
			
		||||
    /// Write-Only
 | 
			
		||||
    pub fn send(self: *@This(), comptime src: Source, value: u32) !void {
 | 
			
		||||
        const idx = switch (src) {
 | 
			
		||||
            .arm7 => 0,
 | 
			
		||||
            .arm9 => 1,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (!self.cnt.enable_fifos.read()) return;
 | 
			
		||||
 | 
			
		||||
        try self.fifo[idx].push(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// IPC Receive FIFO
 | 
			
		||||
    /// Read-Only
 | 
			
		||||
    pub fn recv(self: *@This(), comptime src: Source) u32 {
 | 
			
		||||
        const idx = switch (src) {
 | 
			
		||||
            .arm7 => 1, // switched around on purpose
 | 
			
		||||
            .arm9 => 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const enabled = self.cnt.enable_fifos.read();
 | 
			
		||||
        const val_opt = if (enabled) self.fifo[idx].pop() else self.fifo[idx].peek();
 | 
			
		||||
 | 
			
		||||
        return val_opt orelse blk: {
 | 
			
		||||
            self.cnt.send_fifo_empty.set();
 | 
			
		||||
 | 
			
		||||
            break :blk 0x0000_0000;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const IpcSync = extern union {
 | 
			
		||||
    /// Data input to IPCSYNC Bit 8->11 of remote CPU
 | 
			
		||||
    /// Read-Only
 | 
			
		||||
@@ -187,3 +222,64 @@ pub const nds9 = struct {
 | 
			
		||||
 | 
			
		||||
    pub const PostFlag = enum(u8) { in_progress = 0, completed };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Fifo = struct {
 | 
			
		||||
    const Index = u8;
 | 
			
		||||
    const Error = error{full};
 | 
			
		||||
    const len = 0x10;
 | 
			
		||||
 | 
			
		||||
    read_idx: Index = 0,
 | 
			
		||||
    write_idx: Index = 0,
 | 
			
		||||
 | 
			
		||||
    buf: [len]u32 = [_]u32{undefined} ** len,
 | 
			
		||||
 | 
			
		||||
    comptime {
 | 
			
		||||
        const max_capacity = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type
 | 
			
		||||
 | 
			
		||||
        std.debug.assert(std.math.isPowerOfTwo(len));
 | 
			
		||||
        std.debug.assert(len <= max_capacity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn reset(self: *@This()) void {
 | 
			
		||||
        self.read_idx = 0;
 | 
			
		||||
        self.write_idx = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn push(self: *@This(), value: u32) Error!void {
 | 
			
		||||
        if (self.isFull()) return Error.full;
 | 
			
		||||
        defer self.write_idx += 1;
 | 
			
		||||
 | 
			
		||||
        self.buf[self.mask(self.write_idx)] = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn pop(self: *@This()) ?u32 {
 | 
			
		||||
        if (self.isEmpty()) return null;
 | 
			
		||||
        defer self.read_idx += 1;
 | 
			
		||||
 | 
			
		||||
        return self.buf[self.mask(self.read_idx)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn peek(self: *const @This()) ?u32 {
 | 
			
		||||
        if (self.isEmpty()) return null;
 | 
			
		||||
 | 
			
		||||
        return self.buf[self.mask(self.read_idx)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn _len(self: *const @This()) Index {
 | 
			
		||||
        return self.write_idx - self.read_idx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn isFull(self: *const @This()) bool {
 | 
			
		||||
        return self._len() == self.buf.len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn isEmpty(self: *const @This()) bool {
 | 
			
		||||
        return self.read_idx == self.write_idx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline fn mask(self: *const @This(), idx: Index) Index {
 | 
			
		||||
        const _mask: Index = @intCast(self.buf.len - 1);
 | 
			
		||||
 | 
			
		||||
        return idx & _mask;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -24,11 +24,13 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
 | 
			
		||||
            0x0400_0208 => @intFromBool(bus.io.shared.ime),
 | 
			
		||||
            0x0400_0210 => bus.io.shared.ie,
 | 
			
		||||
            0x0400_0214 => bus.io.shared.irq,
 | 
			
		||||
 | 
			
		||||
            0x0410_0000 => bus.io.shared.ipc_fifo.recv(.arm7),
 | 
			
		||||
            else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
 | 
			
		||||
        },
 | 
			
		||||
        u16 => switch (address) {
 | 
			
		||||
            0x0400_0180 => @truncate(bus.io.shared.ipc_sync.raw),
 | 
			
		||||
            0x0400_0184 => @truncate(bus.io.shared.ipc_fifo_cnt.raw),
 | 
			
		||||
            0x0400_0180 => @truncate(bus.io.shared.ipc_fifo.sync.raw),
 | 
			
		||||
            0x0400_0184 => @truncate(bus.io.shared.ipc_fifo.cnt.raw),
 | 
			
		||||
            else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
 | 
			
		||||
        },
 | 
			
		||||
        u8 => switch (address) {
 | 
			
		||||
@@ -44,11 +46,18 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
 | 
			
		||||
            0x0400_0208 => bus.io.shared.ime = value & 1 == 1,
 | 
			
		||||
            0x0400_0210 => bus.io.shared.ie = value,
 | 
			
		||||
            0x0400_0214 => bus.io.shared.irq = value,
 | 
			
		||||
 | 
			
		||||
            0x0400_0188 => bus.io.shared.ipc_fifo.send(.arm7, 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 }),
 | 
			
		||||
        },
 | 
			
		||||
        u16 => switch (address) {
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_sync.raw = value,
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo_cnt.raw = value,
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_fifo.sync.raw = blk: {
 | 
			
		||||
                const ret = value & ~@as(u16, 0xF) | (bus.io.shared.ipc_fifo.sync.raw & 0xF);
 | 
			
		||||
                log.debug("IPCFIFOSYNC <- 0x{X:0>8}", .{ret});
 | 
			
		||||
 | 
			
		||||
                break :blk ret;
 | 
			
		||||
            },
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo.cnt.raw = value,
 | 
			
		||||
            else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
 | 
			
		||||
        },
 | 
			
		||||
        u8 => switch (address) {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,14 +31,16 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
 | 
			
		||||
            0x0400_0208 => @intFromBool(bus.io.shared.ime),
 | 
			
		||||
            0x0400_0210 => bus.io.shared.ie,
 | 
			
		||||
            0x0400_0214 => bus.io.shared.irq,
 | 
			
		||||
 | 
			
		||||
            0x0410_0000 => bus.io.shared.ipc_fifo.recv(.arm9),
 | 
			
		||||
            else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
 | 
			
		||||
        },
 | 
			
		||||
        u16 => switch (address) {
 | 
			
		||||
            0x0400_0004 => bus.ppu.io.dispstat.raw,
 | 
			
		||||
            0x0400_0130 => bus.io.keyinput.load(.Monotonic),
 | 
			
		||||
 | 
			
		||||
            0x0400_0180 => @truncate(bus.io.shared.ipc_sync.raw),
 | 
			
		||||
            0x0400_0184 => @truncate(bus.io.shared.ipc_fifo_cnt.raw),
 | 
			
		||||
            0x0400_0180 => @truncate(bus.io.shared.ipc_fifo.sync.raw),
 | 
			
		||||
            0x0400_0184 => @truncate(bus.io.shared.ipc_fifo.cnt.raw),
 | 
			
		||||
            else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
 | 
			
		||||
        },
 | 
			
		||||
        u8 => switch (address) {
 | 
			
		||||
@@ -52,9 +54,14 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
 | 
			
		||||
    switch (T) {
 | 
			
		||||
        u32 => switch (address) {
 | 
			
		||||
            0x0400_0000 => bus.ppu.io.dispcnt_a.raw = value,
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_sync.raw = value,
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo_cnt.raw = value,
 | 
			
		||||
            0x0400_0188 => bus.io.shared.ipc_fifo_send = value,
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_fifo.sync.raw = blk: {
 | 
			
		||||
                const ret = value & ~@as(u32, 0xF) | (bus.io.shared.ipc_fifo.sync.raw & 0xF);
 | 
			
		||||
                log.debug("IPCFIFOSYNC <- 0x{X:0>8}", .{ret});
 | 
			
		||||
 | 
			
		||||
                break :blk ret;
 | 
			
		||||
            },
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo.cnt.raw = value,
 | 
			
		||||
            0x0400_0188 => bus.io.shared.ipc_fifo.send(.arm9, value) catch |e| std.debug.panic("IPC FIFO Error: {}", .{e}),
 | 
			
		||||
 | 
			
		||||
            0x0400_0240 => {
 | 
			
		||||
                bus.ppu.io.vramcnt_a.raw = @truncate(value >> 0); // 0x0400_0240
 | 
			
		||||
@@ -72,8 +79,13 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
 | 
			
		||||
            else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
 | 
			
		||||
        },
 | 
			
		||||
        u16 => switch (address) {
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_sync.raw = value,
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo_cnt.raw = value,
 | 
			
		||||
            0x0400_0180 => bus.io.shared.ipc_fifo.sync.raw = blk: {
 | 
			
		||||
                const ret = value & ~@as(u16, 0xF) | (bus.io.shared.ipc_fifo.sync.raw & 0xF);
 | 
			
		||||
                log.debug("IPCFIFOSYNC <- 0x{X:0>8}", .{ret});
 | 
			
		||||
 | 
			
		||||
                break :blk ret;
 | 
			
		||||
            },
 | 
			
		||||
            0x0400_0184 => bus.io.shared.ipc_fifo.cnt.raw = value,
 | 
			
		||||
            0x0400_0208 => bus.io.shared.ime = value & 1 == 1,
 | 
			
		||||
 | 
			
		||||
            else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user