fix(pipeline): gang.gba works
This commit is contained in:
parent
c47ef37ba5
commit
53988b1c83
87
src/cpu.zig
87
src/cpu.zig
|
@ -60,7 +60,7 @@ pub const Arm7tdmi = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
r: [16]u32,
|
r: [16]u32,
|
||||||
pipe: [2]u32,
|
pipe: Pipline,
|
||||||
sched: *Scheduler,
|
sched: *Scheduler,
|
||||||
bus: Bus,
|
bus: Bus,
|
||||||
cpsr: PSR,
|
cpsr: PSR,
|
||||||
|
@ -83,7 +83,7 @@ pub const Arm7tdmi = struct {
|
||||||
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self {
|
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self {
|
||||||
return Self{
|
return Self{
|
||||||
.r = [_]u32{0x00} ** 16,
|
.r = [_]u32{0x00} ** 16,
|
||||||
.pipe = [_]u32{0xF000_0000} ** 2,
|
.pipe = Pipline.init(),
|
||||||
.sched = sched,
|
.sched = sched,
|
||||||
.bus = try Bus.init(alloc, sched, paths),
|
.bus = try Bus.init(alloc, sched, paths),
|
||||||
.cpsr = .{ .raw = 0x0000_001F },
|
.cpsr = .{ .raw = 0x0000_001F },
|
||||||
|
@ -258,19 +258,21 @@ pub const Arm7tdmi = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(self: *Self) void {
|
pub fn step(self: *Self) void {
|
||||||
const opcode = self.pipe[0];
|
if (self.cpsr.t.read()) blk: {
|
||||||
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
const opcode = @truncate(u16, self.pipe.step(self, u16) orelse break :blk);
|
||||||
|
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
||||||
|
|
||||||
if (self.cpsr.t.read()) {
|
thumb_lut[thumbIdx(opcode)](self, &self.bus, opcode);
|
||||||
self.stepPipeline(u16);
|
} else blk: {
|
||||||
thumb_lut[thumbIdx(@truncate(u16, opcode))](self, &self.bus, @truncate(u16, opcode));
|
const opcode = self.pipe.step(self, u32) orelse break :blk;
|
||||||
} else {
|
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
||||||
self.stepPipeline(u32);
|
|
||||||
|
|
||||||
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28)))
|
||||||
arm_lut[armIdx(opcode)](self, &self.bus, opcode);
|
arm_lut[armIdx(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 {
|
||||||
|
@ -328,27 +330,6 @@ pub const Arm7tdmi = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn stepPipeline(self: *Self, comptime T: type) void {
|
|
||||||
self.pipe[0] = self.pipe[1]; // Decoded Instr will be executed next
|
|
||||||
self.pipe[1] = self.fetch(T); // Fetch new opcode to be decoded next
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reloadPipeline(self: *Self, comptime T: type) void {
|
|
||||||
switch (T) {
|
|
||||||
u32 => {
|
|
||||||
self.pipe[0] = self.bus.read(u32, self.r[15]);
|
|
||||||
self.pipe[1] = self.bus.read(u32, self.r[15] + 4);
|
|
||||||
self.r[15] += 8;
|
|
||||||
},
|
|
||||||
u16 => {
|
|
||||||
self.pipe[0] = self.bus.read(u32, self.r[15]);
|
|
||||||
self.pipe[1] = self.bus.read(u32, self.r[15] + 2);
|
|
||||||
self.r[15] += 4;
|
|
||||||
},
|
|
||||||
else => @compileError("Pipeline Reload: unsupported read width"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn fetch(self: *Self, comptime T: type) T {
|
inline fn fetch(self: *Self, comptime T: type) 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;
|
defer self.r[15] += if (T == u32) 4 else 2;
|
||||||
|
@ -468,7 +449,7 @@ pub const Arm7tdmi = struct {
|
||||||
const r12 = self.r[12];
|
const r12 = self.r[12];
|
||||||
const r13 = self.r[13];
|
const r13 = self.r[13];
|
||||||
const r14 = self.r[14];
|
const r14 = self.r[14];
|
||||||
const r15 = self.r[15];
|
const r15 = self.r[15] -| if (self.cpsr.t.read()) 4 else @as(u32, 8);
|
||||||
|
|
||||||
const c_psr = self.cpsr.raw;
|
const c_psr = self.cpsr.raw;
|
||||||
|
|
||||||
|
@ -484,7 +465,7 @@ pub const Arm7tdmi = struct {
|
||||||
log_str = try std.fmt.bufPrint(&buf, thumb_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
log_str = try std.fmt.bufPrint(&buf, thumb_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_str = try std.fmt.bufPrint(&buf, arm_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15 - 4, c_psr, opcode });
|
log_str = try std.fmt.bufPrint(&buf, arm_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try file.writeAll(log_str);
|
_ = try file.writeAll(log_str);
|
||||||
|
@ -692,6 +673,44 @@ fn armPopulate() [0x1000]ArmInstrFn {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Pipline = struct {
|
||||||
|
const Self = @This();
|
||||||
|
stage: [2]?u32,
|
||||||
|
flushed: bool,
|
||||||
|
|
||||||
|
fn init() Self {
|
||||||
|
return .{
|
||||||
|
.stage = [_]?u32{null} ** 2,
|
||||||
|
.flushed = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(self: *Self) void {
|
||||||
|
for (self.stage) |*opcode| opcode.* = null;
|
||||||
|
self.flushed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(self: *Self, cpu: *Arm7tdmi, comptime T: type) ?u32 {
|
||||||
|
comptime std.debug.assert(T == u32 or T == u16);
|
||||||
|
|
||||||
|
const opcode = self.stage[0];
|
||||||
|
|
||||||
|
self.stage[0] = self.stage[1];
|
||||||
|
self.stage[1] = cpu.bus.read(T, cpu.r[15]);
|
||||||
|
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reload(self: *Self, cpu: *Arm7tdmi, comptime T: type) void {
|
||||||
|
comptime std.debug.assert(T == u32 or T == u16);
|
||||||
|
const inc = if (T == u32) 4 else 2;
|
||||||
|
|
||||||
|
self.stage[0] = cpu.bus.read(T, cpu.r[15]);
|
||||||
|
self.stage[1] = cpu.bus.read(T, cpu.r[15] + inc);
|
||||||
|
cpu.r[15] += inc * 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const PSR = extern union {
|
pub const PSR = extern union {
|
||||||
mode: Bitfield(u32, 0, 5),
|
mode: Bitfield(u32, 0, 5),
|
||||||
t: Bit(u32, 5),
|
t: Bit(u32, 5),
|
||||||
|
|
|
@ -11,8 +11,9 @@ pub fn branch(comptime L: bool) InstrFn {
|
||||||
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||||
if (L) cpu.r[14] = cpu.r[15] - 4;
|
if (L) cpu.r[14] = cpu.r[15] - 4;
|
||||||
|
|
||||||
cpu.r[15] = cpu.r[15] +% (sext(u32, u24, opcode) << 2);
|
const offset = sext(u32, u24, opcode) << 2;
|
||||||
cpu.reloadPipeline(u32);
|
cpu.r[15] = cpu.r[15] +% offset;
|
||||||
|
cpu.pipe.flush();
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
}
|
}
|
||||||
|
@ -23,10 +24,10 @@ pub fn branchAndExchange(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||||
if (cpu.r[rn] & 1 == 1) {
|
if (cpu.r[rn] & 1 == 1) {
|
||||||
cpu.r[15] = cpu.r[rn] & ~@as(u32, 1);
|
cpu.r[15] = cpu.r[rn] & ~@as(u32, 1);
|
||||||
cpu.cpsr.t.set();
|
cpu.cpsr.t.set();
|
||||||
cpu.reloadPipeline(u16);
|
|
||||||
} else {
|
} else {
|
||||||
cpu.r[15] = cpu.r[rn] & ~@as(u32, 3);
|
cpu.r[15] = cpu.r[rn] & ~@as(u32, 3);
|
||||||
cpu.cpsr.t.unset();
|
cpu.cpsr.t.unset();
|
||||||
cpu.reloadPipeline(u32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu.pipe.flush();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue