From c34c2ee6eb4c174a7cb26c39b0e212ce279f5445 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Wed, 2 Feb 2022 08:44:33 -0400 Subject: [PATCH] feat(cpu): implement ARM SWP and SWPB --- src/cpu.zig | 89 ++++++++++++----------- src/cpu/arm/half_signed_data_transfer.zig | 11 +-- src/cpu/arm/single_data_swap.zig | 29 ++++++++ 3 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 src/cpu/arm/single_data_swap.zig diff --git a/src/cpu.zig b/src/cpu.zig index 2a23124..dafbfb4 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -19,6 +19,7 @@ const branchAndExchange = @import("cpu/arm/branch.zig").branchAndExchange; const softwareInterrupt = @import("cpu/arm/software_interrupt.zig").softwareInterrupt; const multiply = @import("cpu/arm/multiply.zig").multiply; const multiplyLong = @import("cpu/arm/multiply_long.zig").multiplyLong; +const singleDataSwap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; // THUMB Instruction Groups const format1 = @import("cpu/thumb/format1.zig").format1; @@ -491,33 +492,35 @@ fn thumbPopulate() [0x400]ThumbInstrFn { fn armPopulate() [0x1000]ArmInstrFn { return comptime { - @setEvalBranchQuota(0x5000); // TODO: Figure out exact size + @setEvalBranchQuota(0xC000); // TODO: Figure out exact size var lut = [_]ArmInstrFn{armUndefined} ** 0x1000; var i: usize = 0; while (i < lut.len) : (i += 1) { - if (i >> 10 & 0x3 == 0b00) { - const I = i >> 9 & 1 == 1; - const S = i >> 4 & 1 == 1; - const instrKind = i >> 5 & 0xF; - - lut[i] = dataProcessing(I, S, instrKind); - } - - if (i >> 10 & 0x3 == 0b00 and i >> 7 & 0x3 == 0b10 and i >> 4 & 1 == 0) { - // PSR Transfer - const I = i >> 9 & 1 == 1; - const R = i >> 6 & 1 == 1; - const kind = i >> 4 & 0x3; - - lut[i] = psrTransfer(I, R, kind); - } - + // Instructions with Opcode[27] == 0 if (i == 0x121) { + // Bits 27:20 and 7:4 lut[i] = branchAndExchange; - } + } else if (i >> 6 & 0x3F == 0b000000 and i & 0xF == 0b1001) { + // Bits 27:22 and 7:4 + const A = i >> 5 & 1 == 1; + const S = i >> 4 & 1 == 1; - if (i >> 9 & 0x7 == 0b000 and i >> 3 & 1 == 1 and i & 1 == 1) { + lut[i] = multiply(A, S); + } else if (i >> 7 & 0x1F == 0b00010 and i >> 4 & 0x3 == 0b00 and i & 0xF == 0b1001) { + // Bits 27:23, 21:20 and 7:4 + const B = i >> 6 & 1 == 1; + + lut[i] = singleDataSwap(B); + } else if (i >> 7 & 0x1F == 0b00001 and i & 0xF == 0b1001) { + // Bits 27:23 and bits 7:4 + const U = i >> 6 & 1 == 1; + const A = i >> 5 & 1 == 1; + const S = i >> 4 & 1 == 1; + + lut[i] = multiplyLong(U, A, S); + } else if (i >> 9 & 0x7 == 0b000 and i >> 3 & 1 == 1 and i & 1 == 1) { + // Bits 27:25, 7 and 4 const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1; const I = i >> 6 & 1 == 1; @@ -525,24 +528,18 @@ fn armPopulate() [0x1000]ArmInstrFn { const L = i >> 4 & 1 == 1; lut[i] = halfAndSignedDataTransfer(P, U, I, W, L); - } + } else if (i >> 9 & 0x7 == 0b011 and i & 1 == 1) { + // Bits 27:25 and 4 + lut[i] = armUndefined; + } else if (i >> 10 & 0x3 == 0b00 and i >> 7 & 0x3 == 0b10 and i >> 4 & 1 == 0) { + // Bits 27:26, 24:23 and 20 + const I = i >> 9 & 1 == 1; + const R = i >> 6 & 1 == 1; + const kind = i >> 4 & 0x3; - if (i >> 6 & 0x3F == 0b000000 and i & 0xF == 0b1001) { - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - - lut[i] = multiply(A, S); - } - - if (i >> 7 & 0x1F == 0b00001 and i & 0xF == 0b1001) { - const U = i >> 6 & 1 == 1; - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - - lut[i] = multiplyLong(U, A, S); - } - - if (i >> 10 & 0x3 == 0b01) { + lut[i] = psrTransfer(I, R, kind); + } else if (i >> 10 & 0x3 == 0b01) { + // Bits 27:26 const I = i >> 9 & 1 == 1; const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1; @@ -551,9 +548,18 @@ fn armPopulate() [0x1000]ArmInstrFn { const L = i >> 4 & 1 == 1; lut[i] = singleDataTransfer(I, P, U, B, W, L); + } else if (i >> 10 & 0x3 == 0b00) { + // Bits 27:26 + const I = i >> 9 & 1 == 1; + const S = i >> 4 & 1 == 1; + const instrKind = i >> 5 & 0xF; + + lut[i] = dataProcessing(I, S, instrKind); } + // Instructions with Opcode[27] == 1 if (i >> 9 & 0x7 == 0b100) { + // Bits 27:25 const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1; const S = i >> 6 & 1 == 1; @@ -561,14 +567,11 @@ fn armPopulate() [0x1000]ArmInstrFn { const L = i >> 4 & 1 == 1; lut[i] = blockDataTransfer(P, U, S, W, L); - } - - if (i >> 9 & 0x7 == 0b101) { + } else if (i >> 9 & 0x7 == 0b101) { + // Bits 27:25 const L = i >> 8 & 1 == 1; lut[i] = branch(L); - } - - if (i >> 8 & 0xF == 0b1111) lut[i] = softwareInterrupt(); + } else if (i >> 8 & 0xF == 0b1111) lut[i] = softwareInterrupt(); // Bits 27:24 } return lut; diff --git a/src/cpu/arm/half_signed_data_transfer.zig b/src/cpu/arm/half_signed_data_transfer.zig index 3986b62..5011c9e 100644 --- a/src/cpu/arm/half_signed_data_transfer.zig +++ b/src/cpu/arm/half_signed_data_transfer.zig @@ -33,12 +33,6 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: if (L) { switch (@truncate(u2, opcode >> 5)) { - 0b00 => { - // SWP - const value = bus.read32(cpu.r[rn]); - const tmp = std.math.rotr(u32, value, 8 * (cpu.r[rn] & 0x3)); - bus.write32(cpu.r[rm], tmp); - }, 0b01 => { // LDRH const value = bus.read16(address & 0xFFFF_FFFE); @@ -54,14 +48,13 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: cpu.r[rd] = util.u32SignExtend(16, @as(u32, bus.read16(address))); cpu.panic("[CPU|ARM|LDRSH] TODO: Affect the CPSR", .{}); }, + 0b00 => unreachable, // SWP } } else { if (opcode >> 5 & 0x01 == 0x01) { // STRH bus.write16(address, @truncate(u16, cpu.r[rd])); - } else { - std.debug.print("[CPU|ARM|SignedDataTransfer] {X:0>8} was improperly decoded", .{opcode}); - } + } else unreachable; // SWP } address = modified_base; diff --git a/src/cpu/arm/single_data_swap.zig b/src/cpu/arm/single_data_swap.zig new file mode 100644 index 0000000..c7b531a --- /dev/null +++ b/src/cpu/arm/single_data_swap.zig @@ -0,0 +1,29 @@ +const std = @import("std"); + +const Bus = @import("../../Bus.zig"); +const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; +const InstrFn = @import("../../cpu.zig").ArmInstrFn; + +pub fn singleDataSwap(comptime B: bool) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u32) void { + const rn = opcode >> 16 & 0xF; + const rd = opcode >> 12 & 0xF; + const rm = opcode & 0xF; + + const address = cpu.r[rn]; + + if (B) { + // SWPB + const value = bus.read8(address); + bus.write8(address, @truncate(u8, cpu.r[rm])); + cpu.r[rd] = value; + } else { + // SWP + const value = std.math.rotr(u32, bus.read32(address), 8 * (address & 0x3)); + bus.write32(address, cpu.r[rm]); + cpu.r[rd] = value; + } + } + }.inner; +}