fix: LDR(S)H behaviour differs between ARMv4/ARMv5TE

This commit is contained in:
Rekai Nyangadzayi Musuka 2024-03-11 10:35:33 -05:00
parent 6f0e271360
commit add00ba9bf
3 changed files with 36 additions and 14 deletions

View File

@ -9,8 +9,8 @@
}, },
.dependencies = .{ .dependencies = .{
.@"zba-util" = .{ .@"zba-util" = .{
.url = "https://git.musuka.dev/paoda/zba-util/archive/78b944a98f18592512241f71ca2267ef951c82e1.tar.gz", .url = "https://git.musuka.dev/paoda/zba-util/archive/7ebaf2854a2d31ef30691427681286e35130b1ae.tar.gz",
.hash = "12207da7e1f5d6180666db9575f84373055b230cb4259a4b6310562293338dc10b9d", .hash = "12206ea1b29665cecb78bf2c269d1d0ed0a9b6f5f1dffe2aceaddd1cd8abc13a2f08",
}, },
}, },
} }

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const sext = @import("zba-util").sext; const sext = @import("zba-util").sext;
const rotr = @import("zba-util").rotr; const rotr = @import("zba-util").rotr;
const alignAddr = @import("zba-util").alignAddr;
const log = std.log.scoped(.half_and_signed_data_transfer); const log = std.log.scoped(.half_and_signed_data_transfer);
@ -27,8 +28,10 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
switch (op) { switch (op) {
0b01 => { 0b01 => {
// LDRH // LDRH
const value = cpu.read(u16, address); result = switch (Arm32.arch) {
result = rotr(u32, value, 8 * (address & 1)); .v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
.v5te => cpu.read(u16, alignAddr(u16, address)),
};
}, },
0b10 => { 0b10 => {
// LDRSB // LDRSB
@ -36,10 +39,17 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
}, },
0b11 => { 0b11 => {
// LDRSH // LDRSH
result = switch (Arm32.arch) {
.v4t => blk: {
const value = cpu.read(u16, address); const value = cpu.read(u16, address);
// FIXME: I shouldn't have to use @as(u8, ...) here break :blk switch (address & 1 == 1) {
result = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value); true => sext(u32, u8, @as(u8, @truncate(value >> 8))),
false => sext(u32, u16, value),
};
},
.v5te => sext(u32, u16, cpu.read(u16, alignAddr(u16, address))),
};
}, },
0b00 => unreachable, 0b00 => unreachable,
} }

View File

@ -1,5 +1,6 @@
const rotr = @import("zba-util").rotr; const rotr = @import("zba-util").rotr;
const sext = @import("zba-util").sext; const sext = @import("zba-util").sext;
const alignAddr = @import("zba-util").alignAddr;
pub fn fmt6(comptime InstrFn: type, comptime rd: u3) InstrFn { pub fn fmt6(comptime InstrFn: type, comptime rd: u3) InstrFn {
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
@ -41,15 +42,24 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
}, },
0b10 => { 0b10 => {
// LDRH // LDRH
const value = cpu.read(u16, address); cpu.r[rd] = switch (Arm32.arch) {
cpu.r[rd] = rotr(u32, value, 8 * (address & 1)); .v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
.v5te => cpu.read(u16, alignAddr(u16, address)),
};
}, },
0b11 => { 0b11 => {
// LDRSH // LDRSH
cpu.r[rd] = switch (Arm32.arch) {
.v4t => blk: {
const value = cpu.read(u16, address); const value = cpu.read(u16, address);
// FIXME: I shouldn't have to use @as(u8, ...) here break :blk switch (address & 1 == 1) {
cpu.r[rd] = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value); true => sext(u32, u8, @as(u8, @truncate(value >> 8))),
false => sext(u32, u16, value),
};
},
.v5te => sext(u32, u16, cpu.read(u16, alignAddr(u16, address))),
};
}, },
} }
} else { } else {
@ -128,8 +138,10 @@ pub fn fmt10(comptime InstrFn: type, comptime L: bool, comptime offset: u5) Inst
if (L) { if (L) {
// LDRH // LDRH
const value = cpu.read(u16, address); cpu.r[rd] = switch (Arm32.arch) {
cpu.r[rd] = rotr(u32, value, 8 * (address & 1)); .v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
.v5te => cpu.read(u16, alignAddr(u16, address)),
};
} else { } else {
// STRH // STRH