feat(cpu): implement ARM SWP and SWPB

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-10-21 05:12:10 -03:00
parent e7f6464564
commit 151de2eab4
3 changed files with 77 additions and 52 deletions

View File

@ -19,6 +19,7 @@ const branchAndExchange = @import("cpu/arm/branch.zig").branchAndExchange;
const softwareInterrupt = @import("cpu/arm/software_interrupt.zig").softwareInterrupt; const softwareInterrupt = @import("cpu/arm/software_interrupt.zig").softwareInterrupt;
const multiply = @import("cpu/arm/multiply.zig").multiply; const multiply = @import("cpu/arm/multiply.zig").multiply;
const multiplyLong = @import("cpu/arm/multiply_long.zig").multiplyLong; const multiplyLong = @import("cpu/arm/multiply_long.zig").multiplyLong;
const singleDataSwap = @import("cpu/arm/single_data_swap.zig").singleDataSwap;
// THUMB Instruction Groups // THUMB Instruction Groups
const format1 = @import("cpu/thumb/format1.zig").format1; const format1 = @import("cpu/thumb/format1.zig").format1;
@ -491,33 +492,35 @@ fn thumbPopulate() [0x400]ThumbInstrFn {
fn armPopulate() [0x1000]ArmInstrFn { fn armPopulate() [0x1000]ArmInstrFn {
return comptime { return comptime {
@setEvalBranchQuota(0x5000); // TODO: Figure out exact size @setEvalBranchQuota(0xC000); // TODO: Figure out exact size
var lut = [_]ArmInstrFn{armUndefined} ** 0x1000; var lut = [_]ArmInstrFn{armUndefined} ** 0x1000;
var i: usize = 0; var i: usize = 0;
while (i < lut.len) : (i += 1) { while (i < lut.len) : (i += 1) {
if (i >> 10 & 0x3 == 0b00) { // Instructions with Opcode[27] == 0
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);
}
if (i == 0x121) { if (i == 0x121) {
// Bits 27:20 and 7:4
lut[i] = branchAndExchange; 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 P = i >> 8 & 1 == 1;
const U = i >> 7 & 1 == 1; const U = i >> 7 & 1 == 1;
const I = i >> 6 & 1 == 1; const I = i >> 6 & 1 == 1;
@ -525,24 +528,18 @@ fn armPopulate() [0x1000]ArmInstrFn {
const L = i >> 4 & 1 == 1; const L = i >> 4 & 1 == 1;
lut[i] = halfAndSignedDataTransfer(P, U, I, W, L); 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) { lut[i] = psrTransfer(I, R, kind);
const A = i >> 5 & 1 == 1; } else if (i >> 10 & 0x3 == 0b01) {
const S = i >> 4 & 1 == 1; // Bits 27:26
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) {
const I = i >> 9 & 1 == 1; const I = i >> 9 & 1 == 1;
const P = i >> 8 & 1 == 1; const P = i >> 8 & 1 == 1;
const U = i >> 7 & 1 == 1; const U = i >> 7 & 1 == 1;
@ -551,9 +548,18 @@ fn armPopulate() [0x1000]ArmInstrFn {
const L = i >> 4 & 1 == 1; const L = i >> 4 & 1 == 1;
lut[i] = singleDataTransfer(I, P, U, B, W, L); 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) { if (i >> 9 & 0x7 == 0b100) {
// Bits 27:25
const P = i >> 8 & 1 == 1; const P = i >> 8 & 1 == 1;
const U = i >> 7 & 1 == 1; const U = i >> 7 & 1 == 1;
const S = i >> 6 & 1 == 1; const S = i >> 6 & 1 == 1;
@ -561,14 +567,11 @@ fn armPopulate() [0x1000]ArmInstrFn {
const L = i >> 4 & 1 == 1; const L = i >> 4 & 1 == 1;
lut[i] = blockDataTransfer(P, U, S, W, L); lut[i] = blockDataTransfer(P, U, S, W, L);
} } else if (i >> 9 & 0x7 == 0b101) {
// Bits 27:25
if (i >> 9 & 0x7 == 0b101) {
const L = i >> 8 & 1 == 1; const L = i >> 8 & 1 == 1;
lut[i] = branch(L); lut[i] = branch(L);
} } else if (i >> 8 & 0xF == 0b1111) lut[i] = softwareInterrupt(); // Bits 27:24
if (i >> 8 & 0xF == 0b1111) lut[i] = softwareInterrupt();
} }
return lut; return lut;

View File

@ -33,12 +33,6 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I:
if (L) { if (L) {
switch (@truncate(u2, opcode >> 5)) { 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 => { 0b01 => {
// LDRH // LDRH
const value = bus.read16(address & 0xFFFF_FFFE); 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.r[rd] = util.u32SignExtend(16, @as(u32, bus.read16(address)));
cpu.panic("[CPU|ARM|LDRSH] TODO: Affect the CPSR", .{}); cpu.panic("[CPU|ARM|LDRSH] TODO: Affect the CPSR", .{});
}, },
0b00 => unreachable, // SWP
} }
} else { } else {
if (opcode >> 5 & 0x01 == 0x01) { if (opcode >> 5 & 0x01 == 0x01) {
// STRH // STRH
bus.write16(address, @truncate(u16, cpu.r[rd])); bus.write16(address, @truncate(u16, cpu.r[rd]));
} else { } else unreachable; // SWP
std.debug.print("[CPU|ARM|SignedDataTransfer] {X:0>8} was improperly decoded", .{opcode});
}
} }
address = modified_base; address = modified_base;

View File

@ -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;
}