fix(nds): impl enough i/o to get ARM7WRESTLER booting
This commit is contained in:
parent
37aff56c22
commit
64b1bdbe19
|
@ -12,6 +12,9 @@ pub const Io = struct {
|
||||||
ipc: Ipc = .{},
|
ipc: Ipc = .{},
|
||||||
|
|
||||||
wramcnt: WramCnt = .{ .raw = 0x00 },
|
wramcnt: WramCnt = .{ .raw = 0x00 },
|
||||||
|
|
||||||
|
// Read Only
|
||||||
|
keyinput: AtomicKeyInput = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn warn(comptime format: []const u8, args: anytype) u0 {
|
fn warn(comptime format: []const u8, args: anytype) u0 {
|
||||||
|
@ -390,3 +393,41 @@ const Fifo = struct {
|
||||||
return idx & _mask;
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -3,6 +3,8 @@ const std = @import("std");
|
||||||
const Bitfield = @import("bitfield").Bitfield;
|
const Bitfield = @import("bitfield").Bitfield;
|
||||||
const Bit = @import("bitfield").Bit;
|
const Bit = @import("bitfield").Bit;
|
||||||
|
|
||||||
|
const Ppu = @import("../ppu.zig").Ppu;
|
||||||
|
|
||||||
const Bus = @import("Bus.zig");
|
const Bus = @import("Bus.zig");
|
||||||
const SharedCtx = @import("../emu.zig").SharedCtx;
|
const SharedCtx = @import("../emu.zig").SharedCtx;
|
||||||
const masks = @import("../io.zig").masks;
|
const masks = @import("../io.zig").masks;
|
||||||
|
@ -35,9 +37,15 @@ pub const Io = struct {
|
||||||
/// Read/Write
|
/// Read/Write
|
||||||
haltcnt: Haltcnt = .execute,
|
haltcnt: Haltcnt = .execute,
|
||||||
|
|
||||||
|
ppu: ?*Ppu.Io = null,
|
||||||
|
|
||||||
pub fn init(io: *SharedCtx.Io) @This() {
|
pub fn init(io: *SharedCtx.Io) @This() {
|
||||||
return .{ .shr = io };
|
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 {
|
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 }),
|
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
||||||
},
|
},
|
||||||
u16 => switch (address) {
|
u16 => switch (address) {
|
||||||
|
0x0400_0004 => bus.io.ppu.?.nds7.dispstat.raw,
|
||||||
// DMA Transfers
|
// DMA Transfers
|
||||||
0x0400_00B0...0x0400_00DE => warn("TODO: impl DMA", .{}),
|
0x0400_00B0...0x0400_00DE => warn("TODO: impl DMA", .{}),
|
||||||
|
|
||||||
// Timers
|
// Timers
|
||||||
0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
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_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 }),
|
||||||
|
@ -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_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),
|
||||||
|
|
||||||
|
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 }),
|
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>4})", .{ T, address, value }),
|
||||||
},
|
},
|
||||||
u8 => switch (address) {
|
u8 => switch (address) {
|
||||||
|
|
|
@ -34,9 +34,6 @@ pub const Io = struct {
|
||||||
/// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest`
|
/// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest`
|
||||||
irq: IntRequest = .{ .raw = 0x0000_0000 },
|
irq: IntRequest = .{ .raw = 0x0000_0000 },
|
||||||
|
|
||||||
// Read Only
|
|
||||||
keyinput: AtomicKeyInput = .{},
|
|
||||||
|
|
||||||
/// DS Maths
|
/// DS Maths
|
||||||
div: Divisor = .{},
|
div: Divisor = .{},
|
||||||
sqrt: SquareRootUnit = .{},
|
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_02A8, 0x0400_02AC => @truncate(bus.io.div.remainder >> shift(u64, address)),
|
||||||
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),
|
||||||
|
|
||||||
|
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 }),
|
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
||||||
},
|
},
|
||||||
u16 => switch (address) {
|
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_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
||||||
|
|
||||||
0x0400_0004 => bus.ppu.io.nds9.dispstat.raw,
|
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_0180 => @truncate(bus.io.shr.ipc._nds9.sync.raw),
|
||||||
0x0400_0184 => @truncate(bus.io.shr.ipc._nds9.cnt.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
|
// Timers
|
||||||
0x0400_0100...0x0400_010F => warn("TODO: impl timer", .{}),
|
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
|
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 }),
|
||||||
},
|
},
|
||||||
|
@ -147,11 +146,16 @@ 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);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Engine B
|
||||||
0x0400_0304 => bus.ppu.io.powcnt.raw = value,
|
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 }),
|
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) {
|
||||||
|
0x0400_0004 => bus.ppu.io.nds9.dispstat.raw = value,
|
||||||
|
|
||||||
// DMA Transfers
|
// DMA Transfers
|
||||||
0x0400_00B0...0x0400_00DE => log.warn("TODO: impl DMA", .{}),
|
0x0400_00B0...0x0400_00DE => log.warn("TODO: impl DMA", .{}),
|
||||||
0x0400_00E0...0x0400_00EE => log.warn("TODO: impl DMA fill", .{}),
|
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
|
// Timers
|
||||||
0x0400_0100...0x0400_010F => log.warn("TODO: impl timer", .{}),
|
0x0400_0100...0x0400_010F => log.warn("TODO: impl timer", .{}),
|
||||||
|
|
||||||
|
0x0400_0208 => bus.io.ime = value & 1 == 1,
|
||||||
|
|
||||||
0x0400_0240 => {
|
0x0400_0240 => {
|
||||||
bus.ppu.vram.io.cnt_a.raw = value;
|
bus.ppu.vram.io.cnt_a.raw = value;
|
||||||
bus.ppu.vram.update();
|
bus.ppu.vram.update();
|
||||||
|
@ -470,41 +476,3 @@ pub const Dispstat = extern union {
|
||||||
lyc: Bitfield(u16, 7, 9),
|
lyc: Bitfield(u16, 7, 9),
|
||||||
raw: u16,
|
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -29,13 +29,13 @@ pub const Ppu = struct {
|
||||||
const ty = @import("nds9/io.zig");
|
const ty = @import("nds9/io.zig");
|
||||||
|
|
||||||
nds9: struct {
|
nds9: struct {
|
||||||
dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 },
|
dispstat: ty.Dispstat = .{ .raw = 0x00000 },
|
||||||
vcount: ty.Vcount = .{ .raw = 0x0000_0000 },
|
vcount: ty.Vcount = .{ .raw = 0x0000 },
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
nds7: struct {
|
nds7: struct {
|
||||||
dispstat: ty.Dispstat = .{ .raw = 0x0000_0000 },
|
dispstat: ty.Dispstat = .{ .raw = 0x0000 },
|
||||||
vcount: ty.Vcount = .{ .raw = 0x0000_0000 },
|
vcount: ty.Vcount = .{ .raw = 0x00000 },
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
powcnt: ty.PowCnt = .{ .raw = 0x0000_0000 },
|
powcnt: ty.PowCnt = .{ .raw = 0x0000_0000 },
|
||||||
|
|
|
@ -51,6 +51,9 @@ pub fn main() !void {
|
||||||
var bus7 = try System.Bus7.init(allocator, &scheduler, ctx);
|
var bus7 = try System.Bus7.init(allocator, &scheduler, ctx);
|
||||||
var bus9 = try System.Bus9.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 arm7tdmi = System.Arm7tdmi.init(IScheduler.init(&scheduler), IBus.init(&bus7));
|
||||||
var arm946es = System.Arm946es.init(IScheduler.init(&scheduler), IBus.init(&bus9), ICoprocessor.init(&cp15));
|
var arm946es = System.Arm946es.init(IScheduler.init(&scheduler), IBus.init(&bus9), ICoprocessor.init(&cp15));
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ const imgui = @import("ui/imgui.zig");
|
||||||
const emu = @import("core/emu.zig");
|
const emu = @import("core/emu.zig");
|
||||||
|
|
||||||
const System = @import("core/emu.zig").System;
|
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 Scheduler = @import("core/Scheduler.zig");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
@ -141,7 +141,7 @@ pub const Ui = struct {
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
system.bus9.io.keyinput.fetchAnd(~keyinput.raw, .Monotonic);
|
system.bus9.io.shr.keyinput.fetchAnd(~keyinput.raw, .Monotonic);
|
||||||
},
|
},
|
||||||
SDL.SDL_KEYUP => {
|
SDL.SDL_KEYUP => {
|
||||||
// TODO: Make use of compare_and_xor?
|
// TODO: Make use of compare_and_xor?
|
||||||
|
@ -162,7 +162,7 @@ pub const Ui = struct {
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
system.bus9.io.keyinput.fetchOr(keyinput.raw, .Monotonic);
|
system.bus9.io.shr.keyinput.fetchOr(keyinput.raw, .Monotonic);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue