diff --git a/src/core/io.zig b/src/core/io.zig index 788f3d7..7297fac 100644 --- a/src/core/io.zig +++ b/src/core/io.zig @@ -12,6 +12,9 @@ pub const Io = struct { ipc: Ipc = .{}, wramcnt: WramCnt = .{ .raw = 0x00 }, + + // Read Only + keyinput: AtomicKeyInput = .{}, }; fn warn(comptime format: []const u8, args: anytype) u0 { @@ -390,3 +393,41 @@ const Fifo = struct { return idx & _mask; } }; + +/// Read Only +/// 0 = Pressed, 1 = Released +pub const KeyInput = extern union { + a: Bit(u16, 0), + b: Bit(u16, 1), + select: Bit(u16, 2), + start: Bit(u16, 3), + right: Bit(u16, 4), + left: Bit(u16, 5), + up: Bit(u16, 6), + down: Bit(u16, 7), + shoulder_r: Bit(u16, 8), + shoulder_l: Bit(u16, 9), + raw: u16, +}; + +const AtomicKeyInput = struct { + const Self = @This(); + const Ordering = std.atomic.Ordering; + + inner: KeyInput = .{ .raw = 0x03FF }, + + pub inline fn load(self: *const Self, comptime ordering: Ordering) u16 { + return switch (ordering) { + .AcqRel, .Release => @compileError("not supported for atomic loads"), + else => @atomicLoad(u16, &self.inner.raw, ordering), + }; + } + + pub inline fn fetchOr(self: *Self, value: u16, comptime ordering: Ordering) void { + _ = @atomicRmw(u16, &self.inner.raw, .Or, value, ordering); + } + + pub inline fn fetchAnd(self: *Self, value: u16, comptime ordering: Ordering) void { + _ = @atomicRmw(u16, &self.inner.raw, .And, value, ordering); + } +}; diff --git a/src/core/nds7/io.zig b/src/core/nds7/io.zig index 8778a2c..b850301 100644 --- a/src/core/nds7/io.zig +++ b/src/core/nds7/io.zig @@ -3,6 +3,8 @@ const std = @import("std"); const Bitfield = @import("bitfield").Bitfield; const Bit = @import("bitfield").Bit; +const Ppu = @import("../ppu.zig").Ppu; + const Bus = @import("Bus.zig"); const SharedCtx = @import("../emu.zig").SharedCtx; const masks = @import("../io.zig").masks; @@ -35,9 +37,15 @@ pub const Io = struct { /// Read/Write haltcnt: Haltcnt = .execute, + ppu: ?*Ppu.Io = null, + pub fn init(io: *SharedCtx.Io) @This() { return .{ .shr = io }; } + + pub fn configure(self: *@This(), ppu: *Ppu) void { + self.ppu = &ppu.io; + } }; pub fn read(bus: *const Bus, comptime T: type, address: u32) T { @@ -58,12 +66,14 @@ 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 }), }, u16 => switch (address) { + 0x0400_0004 => bus.io.ppu.?.nds7.dispstat.raw, // DMA Transfers 0x0400_00B0...0x0400_00DE => warn("TODO: impl DMA", .{}), // Timers 0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}), + 0x0400_0130 => bus.io.shr.keyinput.load(.Monotonic), 0x0400_0180 => @truncate(bus.io.shr.ipc._nds7.sync.raw), 0x0400_0184 => @truncate(bus.io.shr.ipc._nds7.cnt.raw), else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), @@ -111,6 +121,8 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds7, value), 0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds7, value), + + 0x0400_0208 => bus.io.ime = value & 1 == 1, else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>4})", .{ T, address, value }), }, u8 => switch (address) { diff --git a/src/core/nds9/io.zig b/src/core/nds9/io.zig index 6fe726b..4ff3be1 100644 --- a/src/core/nds9/io.zig +++ b/src/core/nds9/io.zig @@ -34,9 +34,6 @@ pub const Io = struct { /// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest` irq: IntRequest = .{ .raw = 0x0000_0000 }, - // Read Only - keyinput: AtomicKeyInput = .{}, - /// DS Maths div: Divisor = .{}, sqrt: SquareRootUnit = .{}, @@ -65,9 +62,9 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { 0x0400_02A8, 0x0400_02AC => @truncate(bus.io.div.remainder >> shift(u64, address)), 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), + + 0x0400_4000, 0x0400_4008 => 0x0000_0000, // Lets software know this is NOT a DSi else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), }, u16 => switch (address) { @@ -79,7 +76,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { 0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}), 0x0400_0004 => bus.ppu.io.nds9.dispstat.raw, - 0x0400_0130 => bus.io.keyinput.load(.Monotonic), + 0x0400_0130 => bus.io.shr.keyinput.load(.Monotonic), 0x0400_0180 => @truncate(bus.io.shr.ipc._nds9.sync.raw), 0x0400_0184 => @truncate(bus.io.shr.ipc._nds9.cnt.raw), @@ -97,6 +94,8 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { // Timers 0x0400_0100...0x0400_010F => warn("TODO: impl timer", .{}), + 0x0400_0208 => @intFromBool(bus.io.ime), + 0x0400_4000 => 0x00, // Lets software know this is NOT a DSi else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }), }, @@ -147,11 +146,16 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { bus.io.sqrt.schedule(bus.scheduler); }, + // Engine B 0x0400_0304 => bus.ppu.io.powcnt.raw = value, + 0x0400_1000 => bus.ppu.engines[1].dispcnt.raw = value, + else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), }, u16 => switch (address) { + 0x0400_0004 => bus.ppu.io.nds9.dispstat.raw = value, + // DMA Transfers 0x0400_00B0...0x0400_00DE => log.warn("TODO: impl DMA", .{}), 0x0400_00E0...0x0400_00EE => log.warn("TODO: impl DMA fill", .{}), @@ -185,6 +189,8 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { // Timers 0x0400_0100...0x0400_010F => log.warn("TODO: impl timer", .{}), + 0x0400_0208 => bus.io.ime = value & 1 == 1, + 0x0400_0240 => { bus.ppu.vram.io.cnt_a.raw = value; bus.ppu.vram.update(); @@ -470,41 +476,3 @@ pub const Dispstat = extern union { lyc: Bitfield(u16, 7, 9), raw: u16, }; - -/// Read Only -/// 0 = Pressed, 1 = Released -pub const KeyInput = extern union { - a: Bit(u16, 0), - b: Bit(u16, 1), - select: Bit(u16, 2), - start: Bit(u16, 3), - right: Bit(u16, 4), - left: Bit(u16, 5), - up: Bit(u16, 6), - down: Bit(u16, 7), - shoulder_r: Bit(u16, 8), - shoulder_l: Bit(u16, 9), - raw: u16, -}; - -const AtomicKeyInput = struct { - const Self = @This(); - const Ordering = std.atomic.Ordering; - - inner: KeyInput = .{ .raw = 0x03FF }, - - pub inline fn load(self: *const Self, comptime ordering: Ordering) u16 { - return switch (ordering) { - .AcqRel, .Release => @compileError("not supported for atomic loads"), - else => @atomicLoad(u16, &self.inner.raw, ordering), - }; - } - - pub inline fn fetchOr(self: *Self, value: u16, comptime ordering: Ordering) void { - _ = @atomicRmw(u16, &self.inner.raw, .Or, value, ordering); - } - - pub inline fn fetchAnd(self: *Self, value: u16, comptime ordering: Ordering) void { - _ = @atomicRmw(u16, &self.inner.raw, .And, value, ordering); - } -}; diff --git a/src/core/ppu.zig b/src/core/ppu.zig index 0479585..183b68d 100644 --- a/src/core/ppu.zig +++ b/src/core/ppu.zig @@ -29,13 +29,13 @@ pub const Ppu = struct { const ty = @import("nds9/io.zig"); nds9: struct { - dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 }, - vcount: ty.Vcount = .{ .raw = 0x0000_0000 }, + dispstat: ty.Dispstat = .{ .raw = 0x00000 }, + vcount: ty.Vcount = .{ .raw = 0x0000 }, } = .{}, nds7: struct { - dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 }, - vcount: ty.Vcount = .{ .raw = 0x0000_0000 }, + dispstat: ty.Dispstat = .{ .raw = 0x0000 }, + vcount: ty.Vcount = .{ .raw = 0x00000 }, } = .{}, powcnt: ty.PowCnt = .{ .raw = 0x0000_0000 }, diff --git a/src/main.zig b/src/main.zig index e4060bf..8a8f696 100644 --- a/src/main.zig +++ b/src/main.zig @@ -51,6 +51,9 @@ pub fn main() !void { var bus7 = try System.Bus7.init(allocator, &scheduler, ctx); var bus9 = try System.Bus9.init(allocator, &scheduler, ctx); + // TODO: Think of a better way to do this + bus7.io.configure(&bus9.ppu); + var arm7tdmi = System.Arm7tdmi.init(IScheduler.init(&scheduler), IBus.init(&bus7)); var arm946es = System.Arm946es.init(IScheduler.init(&scheduler), IBus.init(&bus9), ICoprocessor.init(&cp15)); diff --git a/src/platform.zig b/src/platform.zig index 9faa95c..a5fcf17 100644 --- a/src/platform.zig +++ b/src/platform.zig @@ -8,7 +8,7 @@ const imgui = @import("ui/imgui.zig"); const emu = @import("core/emu.zig"); const System = @import("core/emu.zig").System; -const KeyInput = @import("core/nds9/io.zig").KeyInput; +const KeyInput = @import("core/io.zig").KeyInput; const Scheduler = @import("core/Scheduler.zig"); const Allocator = std.mem.Allocator; @@ -141,7 +141,7 @@ pub const Ui = struct { else => {}, } - system.bus9.io.keyinput.fetchAnd(~keyinput.raw, .Monotonic); + system.bus9.io.shr.keyinput.fetchAnd(~keyinput.raw, .Monotonic); }, SDL.SDL_KEYUP => { // TODO: Make use of compare_and_xor? @@ -162,7 +162,7 @@ pub const Ui = struct { else => {}, } - system.bus9.io.keyinput.fetchOr(keyinput.raw, .Monotonic); + system.bus9.io.shr.keyinput.fetchOr(keyinput.raw, .Monotonic); }, else => {}, }