fix: LDR(S)H behaviour differs between ARMv4/ARMv5TE
This commit is contained in:
parent
6f0e271360
commit
39cfa49945
|
@ -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
|
||||||
const value = cpu.read(u16, address);
|
result = switch (Arm32.arch) {
|
||||||
|
.v4t => blk: {
|
||||||
|
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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
const value = cpu.read(u16, address);
|
cpu.r[rd] = switch (Arm32.arch) {
|
||||||
|
.v4t => blk: {
|
||||||
|
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue