fix: resolve timing regressions
make sure to use fetch timings when fetching instructions
This commit is contained in:
parent
130d40bc7f
commit
85d4690c56
|
@ -428,22 +428,24 @@ pub const Arm7tdmi = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(self: *Self) void {
|
pub fn step(self: *Self) void {
|
||||||
if (self.cpsr.t.read()) blk: {
|
defer {
|
||||||
const opcode = @truncate(u16, self.pipe.step(self, u16) orelse break :blk);
|
if (!self.pipe.flushed) self.r[15] += if (self.cpsr.t.read()) 2 else @as(u32, 4);
|
||||||
|
self.pipe.flushed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.cpsr.t.read()) {
|
||||||
|
const opcode = @truncate(u16, self.pipe.step(self, u16) orelse return);
|
||||||
if (self.logger) |*trace| trace.mgbaLog(self, opcode);
|
if (self.logger) |*trace| trace.mgbaLog(self, opcode);
|
||||||
|
|
||||||
thumb.lut[thumb.idx(opcode)](self, self.bus, opcode);
|
thumb.lut[thumb.idx(opcode)](self, self.bus, opcode);
|
||||||
} else blk: {
|
} else {
|
||||||
const opcode = self.pipe.step(self, u32) orelse break :blk;
|
const opcode = self.pipe.step(self, u32) orelse return;
|
||||||
if (self.logger) |*trace| trace.mgbaLog(self, opcode);
|
if (self.logger) |*trace| trace.mgbaLog(self, opcode);
|
||||||
|
|
||||||
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
||||||
arm.lut[arm.idx(opcode)](self, self.bus, opcode);
|
arm.lut[arm.idx(opcode)](self, self.bus, opcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.pipe.flushed) self.r[15] += if (self.cpsr.t.read()) 2 else @as(u32, 4);
|
|
||||||
self.pipe.flushed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stepDmaTransfer(self: *Self) bool {
|
pub fn stepDmaTransfer(self: *Self) bool {
|
||||||
|
@ -481,8 +483,8 @@ pub const Arm7tdmi = struct {
|
||||||
// Return if IME is disabled, CPSR I is set or there is nothing to handle
|
// Return if IME is disabled, CPSR I is set or there is nothing to handle
|
||||||
if (!self.bus.io.ime or self.cpsr.i.read() or should_handle == 0) return;
|
if (!self.bus.io.ime or self.cpsr.i.read() or should_handle == 0) return;
|
||||||
|
|
||||||
// If pipeline isn't full, return but reschedule the handling of the event
|
// If Pipeline isn't full, we have a bug
|
||||||
if (!self.pipe.isFull()) return;
|
std.debug.assert(self.pipe.isFull());
|
||||||
|
|
||||||
// log.debug("Handling Interrupt!", .{});
|
// log.debug("Handling Interrupt!", .{});
|
||||||
self.bus.io.haltcnt = .Execute;
|
self.bus.io.haltcnt = .Execute;
|
||||||
|
@ -501,23 +503,18 @@ pub const Arm7tdmi = struct {
|
||||||
self.pipe.reload(self);
|
self.pipe.reload(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn fetch(self: *Self, comptime T: type) T {
|
inline fn fetch(self: *Self, comptime T: type, address: u32) T {
|
||||||
comptime std.debug.assert(T == u32 or T == u16); // Opcode may be 32-bit (ARM) or 16-bit (THUMB)
|
comptime std.debug.assert(T == u32 or T == u16); // Opcode may be 32-bit (ARM) or 16-bit (THUMB)
|
||||||
defer self.r[15] += if (T == u32) 4 else 2;
|
|
||||||
|
|
||||||
// FIXME: You better hope this is optimized out
|
// Bus.read will advance the scheduler. There are different timings for CPU fetches,
|
||||||
|
// so we want to undo what Bus.read will apply. We can do this by caching the current tick
|
||||||
|
// This is very dumb.
|
||||||
|
//
|
||||||
|
// FIXME: Please rework this
|
||||||
const tick_cache = self.sched.tick;
|
const tick_cache = self.sched.tick;
|
||||||
defer self.sched.tick = tick_cache + Bus.fetch_timings[@boolToInt(T == u32)][@truncate(u4, self.r[15] >> 24)];
|
defer self.sched.tick = tick_cache + Bus.fetch_timings[@boolToInt(T == u32)][@truncate(u4, address >> 24)];
|
||||||
|
|
||||||
return self.bus.read(T, self.r[15]);
|
return self.bus.read(T, address);
|
||||||
}
|
|
||||||
|
|
||||||
fn debug_log(self: *const Self, file: *const File, opcode: u32) void {
|
|
||||||
if (self.binary_log) {
|
|
||||||
self.skyLog(file) catch unreachable;
|
|
||||||
} else {
|
|
||||||
self.mgbaLog(file, opcode) catch unreachable;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic(self: *const Self, comptime format: []const u8, args: anytype) noreturn {
|
pub fn panic(self: *const Self, comptime format: []const u8, args: anytype) noreturn {
|
||||||
|
@ -655,15 +652,6 @@ const Pipeline = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(self: *Self) void {
|
|
||||||
for (self.stage) |*opcode| opcode.* = null;
|
|
||||||
self.flushed = true;
|
|
||||||
|
|
||||||
// Note: If using this, add
|
|
||||||
// if (!self.pipe.flushed) self.r[15] += if (self.cpsr.t.read()) 2 else @as(u32, 4);
|
|
||||||
// to the end of Arm7tdmi.step
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn isFull(self: *const Self) bool {
|
pub fn isFull(self: *const Self) bool {
|
||||||
return self.stage[0] != null and self.stage[1] != null;
|
return self.stage[0] != null and self.stage[1] != null;
|
||||||
}
|
}
|
||||||
|
@ -672,22 +660,22 @@ const Pipeline = struct {
|
||||||
comptime std.debug.assert(T == u32 or T == u16);
|
comptime std.debug.assert(T == u32 or T == u16);
|
||||||
|
|
||||||
// FIXME: https://github.com/ziglang/zig/issues/12642
|
// FIXME: https://github.com/ziglang/zig/issues/12642
|
||||||
const opcode = self.stage[0..1][0];
|
var opcode = self.stage[0];
|
||||||
|
|
||||||
self.stage[0] = self.stage[1];
|
self.stage[0] = self.stage[1];
|
||||||
self.stage[1] = cpu.bus.read(T, cpu.r[15]);
|
self.stage[1] = cpu.fetch(T, cpu.r[15]);
|
||||||
|
|
||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload(self: *Self, cpu: *Arm7tdmi) void {
|
pub fn reload(self: *Self, cpu: *Arm7tdmi) void {
|
||||||
if (cpu.cpsr.t.read()) {
|
if (cpu.cpsr.t.read()) {
|
||||||
self.stage[0] = cpu.bus.read(u16, cpu.r[15]);
|
self.stage[0] = cpu.fetch(u16, cpu.r[15]);
|
||||||
self.stage[1] = cpu.bus.read(u16, cpu.r[15] + 2);
|
self.stage[1] = cpu.fetch(u16, cpu.r[15] + 2);
|
||||||
cpu.r[15] += 4;
|
cpu.r[15] += 4;
|
||||||
} else {
|
} else {
|
||||||
self.stage[0] = cpu.bus.read(u32, cpu.r[15]);
|
self.stage[0] = cpu.fetch(u32, cpu.r[15]);
|
||||||
self.stage[1] = cpu.bus.read(u32, cpu.r[15] + 4);
|
self.stage[1] = cpu.fetch(u32, cpu.r[15] + 4);
|
||||||
cpu.r[15] += 8;
|
cpu.r[15] += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,6 @@ pub fn fmt4(comptime op: u4) InstrFn {
|
||||||
cpu.cpsr.z.write(result == 0);
|
cpu.cpsr.z.write(result == 0);
|
||||||
cpu.cpsr.c.write(overflow);
|
cpu.cpsr.c.write(overflow);
|
||||||
cpu.cpsr.v.write(((op1 ^ result) & (op2 ^ result)) >> 31 & 1 == 1);
|
cpu.cpsr.v.write(((op1 ^ result) & (op2 ^ result)) >> 31 & 1 == 1);
|
||||||
|
|
||||||
// FIXME: Pretty sure CMN Is the same
|
|
||||||
},
|
},
|
||||||
0x6 => {
|
0x6 => {
|
||||||
// SBC
|
// SBC
|
||||||
|
|
Loading…
Reference in New Issue