feat(cpu): implement HALT
This commit is contained in:
parent
16b3325fe3
commit
83f94f6d9d
|
@ -41,6 +41,10 @@ pub fn reset(self: *@This()) void {
|
|||
self.tick = 0;
|
||||
}
|
||||
|
||||
pub inline fn peekTimestamp(self: *const @This()) u64 {
|
||||
return self.queue.items[0].tick;
|
||||
}
|
||||
|
||||
pub inline fn check(self: *@This()) ?Event {
|
||||
@setRuntimeSafety(false);
|
||||
if (self.tick < self.queue.items[0].tick) return null;
|
||||
|
|
|
@ -107,9 +107,18 @@ pub fn runFrame(scheduler: *Scheduler, system: System) void {
|
|||
const frame_end = scheduler.tick + cycles_per_frame;
|
||||
|
||||
while (scheduler.tick < frame_end) {
|
||||
switch (isHalted(system)) {
|
||||
.both => scheduler.tick = scheduler.peekTimestamp(),
|
||||
inline else => |halt| {
|
||||
if (comptime halt != .arm9) {
|
||||
system.arm946es.step();
|
||||
system.arm946es.step();
|
||||
}
|
||||
|
||||
if (comptime halt != .arm7)
|
||||
system.arm7tdmi.step();
|
||||
system.arm946es.step();
|
||||
system.arm946es.step();
|
||||
},
|
||||
}
|
||||
|
||||
if (scheduler.check()) |ev| {
|
||||
const late = scheduler.tick - ev.tick;
|
||||
|
@ -126,6 +135,18 @@ pub fn runFrame(scheduler: *Scheduler, system: System) void {
|
|||
}
|
||||
}
|
||||
|
||||
const Halted = enum { arm7, arm9, both, none };
|
||||
|
||||
inline fn isHalted(system: System) Halted {
|
||||
const ret = [_]Halted{ .none, .arm7, .arm9, .both };
|
||||
const nds7_bus: *System.Bus7 = @ptrCast(@alignCast(system.arm7tdmi.bus.ptr));
|
||||
|
||||
const nds9_halt: u2 = @intFromBool(system.cp15.wait_for_interrupt);
|
||||
const nds7_halt: u2 = @intFromBool(nds7_bus.io.haltcnt == .halt);
|
||||
|
||||
return ret[(nds9_halt << 1) | nds7_halt];
|
||||
}
|
||||
|
||||
// FIXME: Perf win to allocating on the stack instead?
|
||||
pub const SharedCtx = struct {
|
||||
const MiB = 0x100000;
|
||||
|
@ -320,8 +341,13 @@ pub fn handleInterrupt(comptime dev: Wram.Device, cpu: if (dev == .nds9) *System
|
|||
if (!bus_ptr.io.ime or cpu.cpsr.i.read()) return; // ensure irqs are enabled
|
||||
if ((bus_ptr.io.ie.raw & bus_ptr.io.irq.raw) == 0) return; // ensure there is an irq to handle
|
||||
|
||||
// TODO: Handle HALT
|
||||
// HALTCNG (NDS7) and CP15 (NDS9)
|
||||
switch (dev) {
|
||||
.nds9 => {
|
||||
const cp15: *System.Cp15 = @ptrCast(@alignCast(cpu.cp15.ptr));
|
||||
cp15.wait_for_interrupt = false;
|
||||
},
|
||||
.nds7 => bus_ptr.io.haltcnt = .execute,
|
||||
}
|
||||
|
||||
const ret_addr = cpu.r[15] - if (cpu.cpsr.t.read()) 0 else @as(u32, 4);
|
||||
const spsr = cpu.cpsr;
|
||||
|
|
|
@ -15,28 +15,26 @@ const log = std.log.scoped(.nds7_io);
|
|||
pub const Io = struct {
|
||||
shr: *SharedCtx.Io,
|
||||
|
||||
/// Interrupt Master Enable
|
||||
/// IME - Interrupt Master Enable
|
||||
/// Read/Write
|
||||
ime: bool = false,
|
||||
|
||||
/// Interrupt Enable
|
||||
/// IE - Interrupt Enable
|
||||
/// Read/Write
|
||||
///
|
||||
/// Caller must cast the `u32` to either `nds7.IntEnable` or `nds9.IntEnable`
|
||||
ie: IntEnable = .{ .raw = 0x0000_0000 },
|
||||
|
||||
/// IF - Interrupt Request
|
||||
/// Read/Write
|
||||
///
|
||||
/// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest`
|
||||
irq: IntRequest = .{ .raw = 0x0000_0000 },
|
||||
|
||||
/// Post Boot Flag
|
||||
/// POSTFLG - Post Boot Flag
|
||||
/// Read/Write
|
||||
///
|
||||
/// Caller must cast the `u8` to either `nds7.PostFlg` or `nds9.PostFlg`
|
||||
postflg: PostFlag = .in_progress,
|
||||
|
||||
/// HALTCNT - Low Power Mode Control
|
||||
/// Read/Write
|
||||
haltcnt: Haltcnt = .execute,
|
||||
|
||||
pub fn init(io: *SharedCtx.Io) @This() {
|
||||
return .{ .shr = io };
|
||||
}
|
||||
|
@ -140,4 +138,11 @@ pub const Vramstat = extern union {
|
|||
raw: u8,
|
||||
};
|
||||
|
||||
const Haltcnt = enum(u2) {
|
||||
execute = 0,
|
||||
gba_mode,
|
||||
halt,
|
||||
sleep,
|
||||
};
|
||||
|
||||
const PostFlag = enum(u8) { in_progress = 0, completed };
|
||||
|
|
|
@ -8,6 +8,8 @@ control: u32 = 0x0005_2078,
|
|||
dtcm_size_base: u32 = 0x0300_000A,
|
||||
itcm_size_base: u32 = 0x0000_0020,
|
||||
|
||||
wait_for_interrupt: bool = false,
|
||||
|
||||
// Protection Unit
|
||||
// cache_bits_data_unified: u32 = 0x0000_0000,
|
||||
// cache_write_bufability: u32 = 0x0000_0000, // For Data Protection Regions
|
||||
|
@ -73,7 +75,7 @@ pub fn write(self: *@This(), op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void
|
|||
0b000_0110_0111_001,
|
||||
=> log.err("TODO: write to PU instruction region #{}", .{cm}),
|
||||
|
||||
0b000_0111_0000_100 => log.err("TODO: halt ARM946E-S", .{}),
|
||||
0b000_0111_0000_100 => self.wait_for_interrupt = true, // NDS9 Halt
|
||||
0b000_0111_0101_000 => log.err("TODO: invalidate instruction cache", .{}),
|
||||
0b000_0111_0110_000 => log.err("TODO: invalidate data cache", .{}),
|
||||
0b000_0111_1010_100 => log.err("TODO: drain write buffer", .{}),
|
||||
|
|
Loading…
Reference in New Issue