From 27a6ced4a70bc954fc965f8f17fd4408ae0b3162 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sat, 2 Jul 2022 01:46:21 -0300 Subject: [PATCH] fix(pipeline): gang.gba works --- src/cpu.zig | 87 +++++++++++++++++++++++++----------------- src/cpu/arm/branch.zig | 9 +++-- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/cpu.zig b/src/cpu.zig index e56f556..d249c3e 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -60,7 +60,7 @@ pub const Arm7tdmi = struct { const Self = @This(); r: [16]u32, - pipe: [2]u32, + pipe: Pipline, sched: *Scheduler, bus: Bus, cpsr: PSR, @@ -83,7 +83,7 @@ pub const Arm7tdmi = struct { pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self { return Self{ .r = [_]u32{0x00} ** 16, - .pipe = [_]u32{0xF000_0000} ** 2, + .pipe = Pipline.init(), .sched = sched, .bus = try Bus.init(alloc, sched, paths), .cpsr = .{ .raw = 0x0000_001F }, @@ -258,19 +258,21 @@ pub const Arm7tdmi = struct { } pub fn step(self: *Self) void { - const opcode = self.pipe[0]; - if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); + if (self.cpsr.t.read()) blk: { + 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()) { - self.stepPipeline(u16); - thumb_lut[thumbIdx(@truncate(u16, opcode))](self, &self.bus, @truncate(u16, opcode)); - } else { - self.stepPipeline(u32); + thumb_lut[thumbIdx(opcode)](self, &self.bus, opcode); + } else blk: { + const opcode = self.pipe.step(self, u32) orelse break :blk; + if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); - if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) { + if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) 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 { @@ -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 { 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; @@ -468,7 +449,7 @@ pub const Arm7tdmi = struct { const r12 = self.r[12]; const r13 = self.r[13]; 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; @@ -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 }); } } 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); @@ -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 { mode: Bitfield(u32, 0, 5), t: Bit(u32, 5), diff --git a/src/cpu/arm/branch.zig b/src/cpu/arm/branch.zig index fdfbb29..36e73e0 100644 --- a/src/cpu/arm/branch.zig +++ b/src/cpu/arm/branch.zig @@ -11,8 +11,9 @@ pub fn branch(comptime L: bool) InstrFn { fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { if (L) cpu.r[14] = cpu.r[15] - 4; - cpu.r[15] = cpu.r[15] +% (sext(u32, u24, opcode) << 2); - cpu.reloadPipeline(u32); + const offset = sext(u32, u24, opcode) << 2; + cpu.r[15] = cpu.r[15] +% offset; + cpu.pipe.flush(); } }.inner; } @@ -23,10 +24,10 @@ pub fn branchAndExchange(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { if (cpu.r[rn] & 1 == 1) { cpu.r[15] = cpu.r[rn] & ~@as(u32, 1); cpu.cpsr.t.set(); - cpu.reloadPipeline(u16); } else { cpu.r[15] = cpu.r[rn] & ~@as(u32, 3); cpu.cpsr.t.unset(); - cpu.reloadPipeline(u32); } + + cpu.pipe.flush(); }