diff --git a/lib/arm32 b/lib/arm32 index aad3bdc..580e7ba 160000 --- a/lib/arm32 +++ b/lib/arm32 @@ -1 +1 @@ -Subproject commit aad3bdc9ea44792906a6cff9e28c15cd4e143389 +Subproject commit 580e7baca962dd73815bb4717db05b83d55fd58e diff --git a/src/core/emu.zig b/src/core/emu.zig index e520bc9..1ae155f 100644 --- a/src/core/emu.zig +++ b/src/core/emu.zig @@ -368,3 +368,38 @@ pub fn handleInterrupt(comptime proc: System.Process, cpu: *System.Cpu(proc)) vo cpu.r[15] = if (proc == .nds9) 0xFFFF_0018 else 0x0000_0018; cpu.pipe.reload(cpu); } + +pub fn fastBoot(system: System) void { + { + const Bank = System.Arm946es.Bank; + + const cpu = system.arm946es; + + // from advanDS + cpu.spsr = .{ .raw = 0x0000_000DF }; + + @memset(cpu.r[0..12], 0x0000_0000); // r0 -> r11 are zeroed + // TODO: r12, r14, and r15 are set to the entrypoint? + cpu.r[13] = 0x0300_2F7C; // FIXME: Why is there (!) in GBATEK? + cpu.bank.r[Bank.regIdx(.Irq, .R13)] = 0x0300_3F80; + cpu.bank.r[Bank.regIdx(.Supervisor, .R13)] = 0x0300_3FC0; + cpu.bank.spsr[Bank.spsrIdx(.Irq)] = .{ .raw = 0x0000_0000 }; + cpu.bank.spsr[Bank.spsrIdx(.Supervisor)] = .{ .raw = 0x0000_0000 }; + } + { + const Bank = System.Arm7tdmi.Bank; + + const cpu = system.arm7tdmi; + + // from advanDS + cpu.spsr = .{ .raw = 0x0000_000D3 }; + + @memset(cpu.r[0..12], 0x0000_0000); // r0 -> r11 are zeroed + // TODO: r12, r14, and r15 are set to the entrypoint? + cpu.r[13] = 0x0380_FD80; + cpu.bank.r[Bank.regIdx(.Irq, .R13)] = 0x0380_FF80; + cpu.bank.r[Bank.regIdx(.Supervisor, .R13)] = 0x0380_FFC0; + cpu.bank.spsr[Bank.spsrIdx(.Irq)] = .{ .raw = 0x0000_0000 }; + cpu.bank.spsr[Bank.spsrIdx(.Supervisor)] = .{ .raw = 0x0000_0000 }; + } +} diff --git a/src/core/nds7/io.zig b/src/core/nds7/io.zig index cf1fbe3..d1d0a2e 100644 --- a/src/core/nds7/io.zig +++ b/src/core/nds7/io.zig @@ -65,7 +65,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { 0x0400_0214 => bus.io.irq.raw, 0x0410_0000 => bus.io.shr.ipc.recv(.nds7), - else => 0, // 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) { 0x0400_0004 => bus.io.ppu.?.nds7.dispstat.raw, @@ -78,7 +78,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { 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 => 0, // 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) { // DMA Transfers @@ -87,11 +87,14 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { // Timers 0x0400_0100...0x0400_010F => warn("TODO: impl timer", .{}), + // RTC + 0x0400_0138 => warn("TODO: RTC read", .{}), + 0x0400_0240 => bus.vram.stat().raw, 0x0400_0241 => bus.io.shr.wramcnt.raw, 0x0400_0300 => @intFromEnum(bus.io.postflg), - else => 0, // 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"), }; @@ -112,9 +115,11 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_0214 => bus.io.irq.raw &= ~value, 0x0400_0188 => bus.io.shr.ipc.send(.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 }), }, u16 => switch (address) { + 0x0400_0004 => bus.io.ppu.?.nds7.dispstat.raw = value, + // DMA Transfers 0x0400_00B0...0x0400_00DE => dma.write(T, &bus.dma, address, value), @@ -125,7 +130,7 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 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) { // DMA Transfers @@ -134,6 +139,9 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { // Timers 0x0400_0100...0x0400_010F => log.warn("TODO: impl timer", .{}), + // RTC + 0x0400_0138 => log.warn("TODO: RTC write", .{}), + 0x0400_0208 => bus.io.ime = value & 1 == 1, 0x0400_0301 => switch ((value >> 6) & 0b11) { @@ -144,7 +152,7 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { log.err("TODO: Implement {}", .{tag}); }, }, - else => {}, // log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>2})", .{ T, address, value }), + else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>2})", .{ T, address, value }), }, else => @compileError(T ++ " is an unsupported bus write type"), } diff --git a/src/core/nds9/Cp15.zig b/src/core/nds9/Cp15.zig index 9c63f26..2ce5b83 100644 --- a/src/core/nds9/Cp15.zig +++ b/src/core/nds9/Cp15.zig @@ -4,7 +4,7 @@ const log = std.log.scoped(.cp15); const panic_on_unimplemented: bool = false; -control: u32 = 0x0005_2078, +control: u32 = 0x0001_2078, dtcm_size_base: u32 = 0x0300_000A, itcm_size_base: u32 = 0x0000_0020, diff --git a/src/core/nds9/dma.zig b/src/core/nds9/dma.zig index 6a281f2..fb1ab39 100644 --- a/src/core/nds9/dma.zig +++ b/src/core/nds9/dma.zig @@ -219,7 +219,7 @@ fn Controller(comptime id: u2) type { const start_timing: Kind = @enumFromInt(new.start_timing.read()); switch (start_timing) { - .immediate, .vblank => {}, + .immediate, .vblank, .hblank => {}, else => log.err("TODO: Implement DMA({}) {s} mode", .{ id, @tagName(start_timing) }), } diff --git a/src/core/nds9/io.zig b/src/core/nds9/io.zig index c776aca..d692d72 100644 --- a/src/core/nds9/io.zig +++ b/src/core/nds9/io.zig @@ -65,6 +65,14 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T { 0x0400_0210 => bus.io.ie.raw, 0x0400_0214 => bus.io.irq.raw, + // zig fmt: off + 0x0400_0240 => @as(u32, bus.ppu.vram.io.cnt_d.raw) << 24 + | @as(u32, bus.ppu.vram.io.cnt_c.raw) << 16 + | @as(u32, bus.ppu.vram.io.cnt_b.raw) << 8 + | bus.ppu.vram.io.cnt_a.raw << 0, + // zig fmt: on + + 0x0400_0280 => bus.io.div.cnt.raw, 0x0400_02A0, 0x0400_02A4 => @truncate(bus.io.div.result >> shift(u64, address)), 0x0400_02A8, 0x0400_02AC => @truncate(bus.io.div.remainder >> shift(u64, address)), 0x0400_02B4 => @truncate(bus.io.sqrt.result), @@ -133,6 +141,8 @@ const subset = @import("../../util.zig").subset; pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { switch (T) { u32 => switch (address) { + 0x0400_0000 => bus.ppu.engines[0].dispcnt.raw = value, + 0x0400_0004 => bus.ppu.io.nds9.dispstat.raw = @truncate(value), 0x0400_0008 => { bus.ppu.engines[0].bg[0].cnt.raw = @truncate(value >> 0); // 0x0400_0008 bus.ppu.engines[0].bg[1].cnt.raw = @truncate(value >> 16); // 0x0400_000A @@ -141,6 +151,22 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { bus.ppu.engines[0].bg[2].cnt.raw = @truncate(value >> 0); // 0x0400_000A bus.ppu.engines[0].bg[3].cnt.raw = @truncate(value >> 16); // 0x0400_000C }, + 0x00400_0010 => { + bus.ppu.engines[0].bg[0].hofs.raw = @truncate(value >> 0); // 0x0400_0010 + bus.ppu.engines[0].bg[0].vofs.raw = @truncate(value >> 16); // 0x0400_0012 + }, + 0x00400_0014 => { + bus.ppu.engines[0].bg[1].hofs.raw = @truncate(value >> 0); // 0x0400_0014 + bus.ppu.engines[0].bg[1].vofs.raw = @truncate(value >> 16); // 0x0400_0016 + }, + 0x00400_0018 => { + bus.ppu.engines[0].bg[2].hofs.raw = @truncate(value >> 0); // 0x0400_0018 + bus.ppu.engines[0].bg[2].vofs.raw = @truncate(value >> 16); // 0x0400_001A + }, + 0x00400_001C => { + bus.ppu.engines[0].bg[3].hofs.raw = @truncate(value >> 0); // 0x0400_001C + bus.ppu.engines[0].bg[3].vofs.raw = @truncate(value >> 16); // 0x0400_001E + }, // DMA Transfers 0x0400_00B0...0x0400_00DC => dma.write(T, &bus.dma, address, value), @@ -149,22 +175,22 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { // Timers 0x0400_0100...0x0400_010C => log.warn("TODO: impl timer", .{}), - 0x0400_0000 => bus.ppu.engines[0].dispcnt.raw = value, 0x0400_0180 => bus.io.shr.ipc.setIpcSync(.nds9, value), 0x0400_0184 => bus.io.shr.ipc.setIpcFifoCnt(.nds9, value), 0x0400_0188 => bus.io.shr.ipc.send(.nds9, value), + 0x0400_0208 => bus.io.ime = value & 1 == 1, + 0x0400_0210 => bus.io.ie.raw = value, + 0x0400_0214 => bus.io.irq.raw &= ~value, + 0x0400_0240 => { bus.ppu.vram.io.cnt_a.raw = @truncate(value >> 0); // 0x0400_0240 bus.ppu.vram.io.cnt_b.raw = @truncate(value >> 8); // 0x0400_0241 bus.ppu.vram.io.cnt_c.raw = @truncate(value >> 16); // 0x0400_0242 bus.ppu.vram.io.cnt_d.raw = @truncate(value >> 24); // 0x0400_0243 + + bus.ppu.vram.update(); }, - - 0x0400_0208 => bus.io.ime = value & 1 == 1, - 0x0400_0210 => bus.io.ie.raw = value, - 0x0400_0214 => bus.io.irq.raw &= ~value, - 0x0400_0244 => { bus.ppu.vram.io.cnt_e.raw = @truncate(value >> 0); // 0x0400_0244 bus.ppu.vram.io.cnt_f.raw = @truncate(value >> 8); // 0x0400_0245 @@ -175,6 +201,11 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { bus.wram.update(bus.io.shr.wramcnt); }, + 0x0400_0280 => { + bus.io.div.cnt.raw = value; + bus.io.div.schedule(bus.scheduler); + }, + 0x0400_0290, 0x0400_0294 => { bus.io.div.numerator = subset(u64, u32, address, bus.io.div.numerator, value); bus.io.div.schedule(bus.scheduler); @@ -185,6 +216,11 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { bus.io.div.schedule(bus.scheduler); }, + 0x0400_02B0 => { + bus.io.sqrt.cnt.raw = value; + bus.io.sqrt.schedule(bus.scheduler); + }, + 0x0400_02B8, 0x0400_02BC => { bus.io.sqrt.param = subset(u64, u32, address, bus.io.sqrt.param, value); bus.io.sqrt.schedule(bus.scheduler); @@ -194,6 +230,30 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void { 0x0400_0304 => bus.ppu.io.powcnt.raw = value, 0x0400_1000 => bus.ppu.engines[1].dispcnt.raw = value, + 0x0400_1008 => { + bus.ppu.engines[1].bg[0].cnt.raw = @truncate(value >> 0); // 0x0400_1008 + bus.ppu.engines[1].bg[1].cnt.raw = @truncate(value >> 16); // 0x0400_100A + }, + 0x0400_100C => { + bus.ppu.engines[1].bg[2].cnt.raw = @truncate(value >> 0); // 0x0400_100A + bus.ppu.engines[1].bg[3].cnt.raw = @truncate(value >> 16); // 0x0400_100C + }, + 0x00400_1010 => { + bus.ppu.engines[1].bg[0].hofs.raw = @truncate(value >> 0); // 0x0400_1010 + bus.ppu.engines[1].bg[0].vofs.raw = @truncate(value >> 16); // 0x0400_1012 + }, + 0x00400_1014 => { + bus.ppu.engines[1].bg[1].hofs.raw = @truncate(value >> 0); // 0x0400_1014 + bus.ppu.engines[1].bg[1].vofs.raw = @truncate(value >> 16); // 0x0400_1016 + }, + 0x00400_1018 => { + bus.ppu.engines[1].bg[2].hofs.raw = @truncate(value >> 0); // 0x0400_1018 + bus.ppu.engines[1].bg[2].vofs.raw = @truncate(value >> 16); // 0x0400_101A + }, + 0x00400_101C => { + bus.ppu.engines[1].bg[3].hofs.raw = @truncate(value >> 0); // 0x0400_101C + bus.ppu.engines[1].bg[3].vofs.raw = @truncate(value >> 16); // 0x0400_101E + }, else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }), }, diff --git a/src/main.zig b/src/main.zig index 8a8f696..10017ff 100644 --- a/src/main.zig +++ b/src/main.zig @@ -65,6 +65,8 @@ pub fn main() !void { const rom_title = try emu.load(allocator, system, rom_path); if (firm_path) |path| try emu.loadFirm(allocator, system, path); + emu.fastBoot(system); + var ui = try Ui.init(allocator); defer ui.deinit(allocator);