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;
|
self.tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn peekTimestamp(self: *const @This()) u64 {
|
||||||
|
return self.queue.items[0].tick;
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn check(self: *@This()) ?Event {
|
pub inline fn check(self: *@This()) ?Event {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
if (self.tick < self.queue.items[0].tick) return null;
|
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;
|
const frame_end = scheduler.tick + cycles_per_frame;
|
||||||
|
|
||||||
while (scheduler.tick < frame_end) {
|
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.arm7tdmi.step();
|
||||||
system.arm946es.step();
|
},
|
||||||
system.arm946es.step();
|
}
|
||||||
|
|
||||||
if (scheduler.check()) |ev| {
|
if (scheduler.check()) |ev| {
|
||||||
const late = scheduler.tick - ev.tick;
|
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?
|
// FIXME: Perf win to allocating on the stack instead?
|
||||||
pub const SharedCtx = struct {
|
pub const SharedCtx = struct {
|
||||||
const MiB = 0x100000;
|
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.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
|
if ((bus_ptr.io.ie.raw & bus_ptr.io.irq.raw) == 0) return; // ensure there is an irq to handle
|
||||||
|
|
||||||
// TODO: Handle HALT
|
switch (dev) {
|
||||||
// HALTCNG (NDS7) and CP15 (NDS9)
|
.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 ret_addr = cpu.r[15] - if (cpu.cpsr.t.read()) 0 else @as(u32, 4);
|
||||||
const spsr = cpu.cpsr;
|
const spsr = cpu.cpsr;
|
||||||
|
|
|
@ -15,28 +15,26 @@ const log = std.log.scoped(.nds7_io);
|
||||||
pub const Io = struct {
|
pub const Io = struct {
|
||||||
shr: *SharedCtx.Io,
|
shr: *SharedCtx.Io,
|
||||||
|
|
||||||
/// Interrupt Master Enable
|
/// IME - Interrupt Master Enable
|
||||||
/// Read/Write
|
/// Read/Write
|
||||||
ime: bool = false,
|
ime: bool = false,
|
||||||
|
|
||||||
/// Interrupt Enable
|
/// IE - Interrupt Enable
|
||||||
/// Read/Write
|
/// Read/Write
|
||||||
///
|
|
||||||
/// Caller must cast the `u32` to either `nds7.IntEnable` or `nds9.IntEnable`
|
|
||||||
ie: IntEnable = .{ .raw = 0x0000_0000 },
|
ie: IntEnable = .{ .raw = 0x0000_0000 },
|
||||||
|
|
||||||
/// IF - Interrupt Request
|
/// IF - Interrupt Request
|
||||||
/// Read/Write
|
/// Read/Write
|
||||||
///
|
|
||||||
/// Caller must cast the `u32` to either `nds7.IntRequest` or `nds9.IntRequest`
|
|
||||||
irq: IntRequest = .{ .raw = 0x0000_0000 },
|
irq: IntRequest = .{ .raw = 0x0000_0000 },
|
||||||
|
|
||||||
/// Post Boot Flag
|
/// POSTFLG - Post Boot Flag
|
||||||
/// Read/Write
|
/// Read/Write
|
||||||
///
|
|
||||||
/// Caller must cast the `u8` to either `nds7.PostFlg` or `nds9.PostFlg`
|
|
||||||
postflg: PostFlag = .in_progress,
|
postflg: PostFlag = .in_progress,
|
||||||
|
|
||||||
|
/// HALTCNT - Low Power Mode Control
|
||||||
|
/// Read/Write
|
||||||
|
haltcnt: Haltcnt = .execute,
|
||||||
|
|
||||||
pub fn init(io: *SharedCtx.Io) @This() {
|
pub fn init(io: *SharedCtx.Io) @This() {
|
||||||
return .{ .shr = io };
|
return .{ .shr = io };
|
||||||
}
|
}
|
||||||
|
@ -140,4 +138,11 @@ pub const Vramstat = extern union {
|
||||||
raw: u8,
|
raw: u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Haltcnt = enum(u2) {
|
||||||
|
execute = 0,
|
||||||
|
gba_mode,
|
||||||
|
halt,
|
||||||
|
sleep,
|
||||||
|
};
|
||||||
|
|
||||||
const PostFlag = enum(u8) { in_progress = 0, completed };
|
const PostFlag = enum(u8) { in_progress = 0, completed };
|
||||||
|
|
|
@ -8,6 +8,8 @@ control: u32 = 0x0005_2078,
|
||||||
dtcm_size_base: u32 = 0x0300_000A,
|
dtcm_size_base: u32 = 0x0300_000A,
|
||||||
itcm_size_base: u32 = 0x0000_0020,
|
itcm_size_base: u32 = 0x0000_0020,
|
||||||
|
|
||||||
|
wait_for_interrupt: bool = false,
|
||||||
|
|
||||||
// Protection Unit
|
// Protection Unit
|
||||||
// cache_bits_data_unified: u32 = 0x0000_0000,
|
// cache_bits_data_unified: u32 = 0x0000_0000,
|
||||||
// cache_write_bufability: u32 = 0x0000_0000, // For Data Protection Regions
|
// 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,
|
0b000_0110_0111_001,
|
||||||
=> log.err("TODO: write to PU instruction region #{}", .{cm}),
|
=> 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_0101_000 => log.err("TODO: invalidate instruction cache", .{}),
|
||||||
0b000_0111_0110_000 => log.err("TODO: invalidate data cache", .{}),
|
0b000_0111_0110_000 => log.err("TODO: invalidate data cache", .{}),
|
||||||
0b000_0111_1010_100 => log.err("TODO: drain write buffer", .{}),
|
0b000_0111_1010_100 => log.err("TODO: drain write buffer", .{}),
|
||||||
|
|
Loading…
Reference in New Issue