From aa19ef5f711dbc2705304ff065b772882cab49fe Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 21 Oct 2022 05:12:54 -0300 Subject: [PATCH] feat: move arm instr decoding to module --- src/core/cpu.zig | 192 +++++++++--------- src/core/cpu/arm/block_data_transfer.zig | 2 +- src/core/cpu/arm/branch.zig | 2 +- src/core/cpu/arm/data_processing.zig | 2 +- .../cpu/arm/half_signed_data_transfer.zig | 2 +- src/core/cpu/arm/multiply.zig | 2 +- src/core/cpu/arm/psr_transfer.zig | 2 +- src/core/cpu/arm/single_data_swap.zig | 2 +- src/core/cpu/arm/single_data_transfer.zig | 2 +- src/core/cpu/arm/software_interrupt.zig | 2 +- 10 files changed, 106 insertions(+), 104 deletions(-) diff --git a/src/core/cpu.zig b/src/core/cpu.zig index c8d1f66..c39c397 100644 --- a/src/core/cpu.zig +++ b/src/core/cpu.zig @@ -10,22 +10,105 @@ const FilePaths = @import("util.zig").FilePaths; const Allocator = std.mem.Allocator; const File = std.fs.File; -// ARM Instruction Groups -const dataProcessing = @import("cpu/arm/data_processing.zig").dataProcessing; -const psrTransfer = @import("cpu/arm/psr_transfer.zig").psrTransfer; -const singleDataTransfer = @import("cpu/arm/single_data_transfer.zig").singleDataTransfer; -const halfAndSignedDataTransfer = @import("cpu/arm/half_signed_data_transfer.zig").halfAndSignedDataTransfer; -const blockDataTransfer = @import("cpu/arm/block_data_transfer.zig").blockDataTransfer; -const armBranch = @import("cpu/arm/branch.zig").branch; -const branchAndExchange = @import("cpu/arm/branch.zig").branchAndExchange; -const armSoftwareInterrupt = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; -const singleDataSwap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; +// ARM Instructions +pub const arm = struct { + pub const InstrFn = fn (*Arm7tdmi, *Bus, u32) void; + const lut: [0x1000]InstrFn = populate(); -const multiply = @import("cpu/arm/multiply.zig").multiply; -const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong; + const processing = @import("cpu/arm/data_processing.zig").dataProcessing; + const psrTransfer = @import("cpu/arm/psr_transfer.zig").psrTransfer; + const transfer = @import("cpu/arm/single_data_transfer.zig").singleDataTransfer; + const halfSignedTransfer = @import("cpu/arm/half_signed_data_transfer.zig").halfAndSignedDataTransfer; + const blockTransfer = @import("cpu/arm/block_data_transfer.zig").blockDataTransfer; + const branch = @import("cpu/arm/branch.zig").branch; + const branchExchange = @import("cpu/arm/branch.zig").branchAndExchange; + const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; + const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; -// THUMB Instruction Groups + const multiply = @import("cpu/arm/multiply.zig").multiply; + const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong; + // Undefined ARM Instruction handler + fn und(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { + const id = armIdx(opcode); + cpu.panic("[CPU/Decode] ID: 0x{X:0>3} 0x{X:0>8} is an illegal opcode", .{ id, opcode }); + } + + fn populate() [0x1000]InstrFn { + return comptime { + @setEvalBranchQuota(0xE000); + var ret = [_]InstrFn{und} ** 0x1000; + + var i: usize = 0; + while (i < ret.len) : (i += 1) { + ret[i] = switch (@as(u2, i >> 10)) { + 0b00 => if (i == 0x121) blk: { + break :blk branchExchange; + } else if (i & 0xFCF == 0x009) blk: { + const A = i >> 5 & 1 == 1; + const S = i >> 4 & 1 == 1; + break :blk multiply(A, S); + } else if (i & 0xFBF == 0x109) blk: { + const B = i >> 6 & 1 == 1; + break :blk swap(B); + } else if (i & 0xF8F == 0x089) blk: { + const U = i >> 6 & 1 == 1; + const A = i >> 5 & 1 == 1; + const S = i >> 4 & 1 == 1; + break :blk multiplyLong(U, A, S); + } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { + const P = i >> 8 & 1 == 1; + const U = i >> 7 & 1 == 1; + const I = i >> 6 & 1 == 1; + const W = i >> 5 & 1 == 1; + const L = i >> 4 & 1 == 1; + break :blk halfSignedTransfer(P, U, I, W, L); + } else if (i & 0xD90 == 0x100) blk: { + const I = i >> 9 & 1 == 1; + const R = i >> 6 & 1 == 1; + const kind = i >> 4 & 0x3; + break :blk psrTransfer(I, R, kind); + } else blk: { + const I = i >> 9 & 1 == 1; + const S = i >> 4 & 1 == 1; + const instrKind = i >> 5 & 0xF; + break :blk processing(I, S, instrKind); + }, + 0b01 => if (i >> 9 & 1 == 1 and i & 1 == 1) und else blk: { + const I = i >> 9 & 1 == 1; + const P = i >> 8 & 1 == 1; + const U = i >> 7 & 1 == 1; + const B = i >> 6 & 1 == 1; + const W = i >> 5 & 1 == 1; + const L = i >> 4 & 1 == 1; + break :blk transfer(I, P, U, B, W, L); + }, + else => switch (@as(u2, i >> 9 & 0x3)) { + // MSB is guaranteed to be 1 + 0b00 => blk: { + const P = i >> 8 & 1 == 1; + const U = i >> 7 & 1 == 1; + const S = i >> 6 & 1 == 1; + const W = i >> 5 & 1 == 1; + const L = i >> 4 & 1 == 1; + break :blk blockTransfer(P, U, S, W, L); + }, + 0b01 => blk: { + const L = i >> 8 & 1 == 1; + break :blk branch(L); + }, + 0b10 => und, // COP Data Transfer + 0b11 => if (i >> 8 & 1 == 1) swi() else und, // COP Data Operation + Register Transfer + }, + }; + } + + return ret; + }; + } +}; + +// THUMB Instructions pub const thumb = struct { pub const InstrFn = fn (*Arm7tdmi, *Bus, u16) void; const lut: [0x400]InstrFn = populate(); @@ -143,9 +226,6 @@ pub const thumb = struct { } }; -pub const ArmInstrFn = fn (*Arm7tdmi, *Bus, u32) void; -const arm_lut: [0x1000]ArmInstrFn = armPopulate(); - const enable_logging = false; const log = std.log.scoped(.Arm7Tdmi); @@ -359,7 +439,7 @@ pub const Arm7tdmi = struct { if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode); if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) { - arm_lut[armIdx(opcode)](self, &self.bus, opcode); + arm.lut[armIdx(opcode)](self, &self.bus, opcode); } } } @@ -590,79 +670,6 @@ pub fn checkCond(cpsr: PSR, cond: u4) bool { }; } -fn armPopulate() [0x1000]ArmInstrFn { - return comptime { - @setEvalBranchQuota(0xE000); - var lut = [_]ArmInstrFn{armUndefined} ** 0x1000; - - var i: usize = 0; - while (i < lut.len) : (i += 1) { - lut[i] = switch (@as(u2, i >> 10)) { - 0b00 => if (i == 0x121) blk: { - break :blk branchAndExchange; - } else if (i & 0xFCF == 0x009) blk: { - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - break :blk multiply(A, S); - } else if (i & 0xFBF == 0x109) blk: { - const B = i >> 6 & 1 == 1; - break :blk singleDataSwap(B); - } else if (i & 0xF8F == 0x089) blk: { - const U = i >> 6 & 1 == 1; - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - break :blk multiplyLong(U, A, S); - } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { - const P = i >> 8 & 1 == 1; - const U = i >> 7 & 1 == 1; - const I = i >> 6 & 1 == 1; - const W = i >> 5 & 1 == 1; - const L = i >> 4 & 1 == 1; - break :blk halfAndSignedDataTransfer(P, U, I, W, L); - } else if (i & 0xD90 == 0x100) blk: { - const I = i >> 9 & 1 == 1; - const R = i >> 6 & 1 == 1; - const kind = i >> 4 & 0x3; - break :blk psrTransfer(I, R, kind); - } else blk: { - const I = i >> 9 & 1 == 1; - const S = i >> 4 & 1 == 1; - const instrKind = i >> 5 & 0xF; - break :blk dataProcessing(I, S, instrKind); - }, - 0b01 => if (i >> 9 & 1 == 1 and i & 1 == 1) armUndefined else blk: { - const I = i >> 9 & 1 == 1; - const P = i >> 8 & 1 == 1; - const U = i >> 7 & 1 == 1; - const B = i >> 6 & 1 == 1; - const W = i >> 5 & 1 == 1; - const L = i >> 4 & 1 == 1; - break :blk singleDataTransfer(I, P, U, B, W, L); - }, - else => switch (@as(u2, i >> 9 & 0x3)) { - // MSB is guaranteed to be 1 - 0b00 => blk: { - const P = i >> 8 & 1 == 1; - const U = i >> 7 & 1 == 1; - const S = i >> 6 & 1 == 1; - const W = i >> 5 & 1 == 1; - const L = i >> 4 & 1 == 1; - break :blk blockDataTransfer(P, U, S, W, L); - }, - 0b01 => blk: { - const L = i >> 8 & 1 == 1; - break :blk armBranch(L); - }, - 0b10 => armUndefined, // COP Data Transfer - 0b11 => if (i >> 8 & 1 == 1) armSoftwareInterrupt() else armUndefined, // COP Data Operation + Register Transfer - }, - }; - } - - return lut; - }; -} - pub const PSR = extern union { mode: Bitfield(u32, 0, 5), t: Bit(u32, 5), @@ -697,8 +704,3 @@ fn getMode(bits: u5) ?Mode { fn getModeChecked(cpu: *const Arm7tdmi, bits: u5) Mode { return getMode(bits) orelse cpu.panic("[CPU/CPSR] 0b{b:0>5} is an invalid CPU mode", .{bits}); } - -fn armUndefined(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { - const id = armIdx(opcode); - cpu.panic("[CPU/Decode] ID: 0x{X:0>3} 0x{X:0>8} is an illegal opcode", .{ id, opcode }); -} diff --git a/src/core/cpu/arm/block_data_transfer.zig b/src/core/cpu/arm/block_data_transfer.zig index 7946a75..637cc0a 100644 --- a/src/core/cpu/arm/block_data_transfer.zig +++ b/src/core/cpu/arm/block_data_transfer.zig @@ -1,6 +1,6 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; pub fn blockDataTransfer(comptime P: bool, comptime U: bool, comptime S: bool, comptime W: bool, comptime L: bool) InstrFn { return struct { diff --git a/src/core/cpu/arm/branch.zig b/src/core/cpu/arm/branch.zig index 5f9dfe5..31a48f0 100644 --- a/src/core/cpu/arm/branch.zig +++ b/src/core/cpu/arm/branch.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const sext = @import("../../util.zig").sext; diff --git a/src/core/cpu/arm/data_processing.zig b/src/core/cpu/arm/data_processing.zig index a2486d9..2a3b77d 100644 --- a/src/core/cpu/arm/data_processing.zig +++ b/src/core/cpu/arm/data_processing.zig @@ -1,6 +1,6 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const rotateRight = @import("../barrel_shifter.zig").rotateRight; const execute = @import("../barrel_shifter.zig").execute; diff --git a/src/core/cpu/arm/half_signed_data_transfer.zig b/src/core/cpu/arm/half_signed_data_transfer.zig index 5ffae2c..d0a4b1d 100644 --- a/src/core/cpu/arm/half_signed_data_transfer.zig +++ b/src/core/cpu/arm/half_signed_data_transfer.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const sext = @import("../../util.zig").sext; const rotr = @import("../../util.zig").rotr; diff --git a/src/core/cpu/arm/multiply.zig b/src/core/cpu/arm/multiply.zig index df03a75..f4b4104 100644 --- a/src/core/cpu/arm/multiply.zig +++ b/src/core/cpu/arm/multiply.zig @@ -1,6 +1,6 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; pub fn multiply(comptime A: bool, comptime S: bool) InstrFn { return struct { diff --git a/src/core/cpu/arm/psr_transfer.zig b/src/core/cpu/arm/psr_transfer.zig index 1049a21..b469083 100644 --- a/src/core/cpu/arm/psr_transfer.zig +++ b/src/core/cpu/arm/psr_transfer.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const PSR = @import("../../cpu.zig").PSR; const log = std.log.scoped(.PsrTransfer); diff --git a/src/core/cpu/arm/single_data_swap.zig b/src/core/cpu/arm/single_data_swap.zig index 0b68f46..f0ccfef 100644 --- a/src/core/cpu/arm/single_data_swap.zig +++ b/src/core/cpu/arm/single_data_swap.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const rotr = @import("../../util.zig").rotr; diff --git a/src/core/cpu/arm/single_data_transfer.zig b/src/core/cpu/arm/single_data_transfer.zig index b37706b..794e610 100644 --- a/src/core/cpu/arm/single_data_transfer.zig +++ b/src/core/cpu/arm/single_data_transfer.zig @@ -4,7 +4,7 @@ const util = @import("../../util.zig"); const shifter = @import("../barrel_shifter.zig"); const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; const rotr = @import("../../util.zig").rotr; diff --git a/src/core/cpu/arm/software_interrupt.zig b/src/core/cpu/arm/software_interrupt.zig index fb41864..849a6eb 100644 --- a/src/core/cpu/arm/software_interrupt.zig +++ b/src/core/cpu/arm/software_interrupt.zig @@ -1,6 +1,6 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; +const InstrFn = @import("../../cpu.zig").arm.InstrFn; pub fn armSoftwareInterrupt() InstrFn { return struct {