fix: LDR(S)H behaviour differs between ARMv4/ARMv5TE
This commit is contained in:
@@ -27,8 +27,10 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
||||
switch (op) {
|
||||
0b01 => {
|
||||
// LDRH
|
||||
const value = cpu.read(u16, address);
|
||||
result = rotr(u32, value, 8 * (address & 1));
|
||||
result = switch (Arm32.arch) {
|
||||
.v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
|
||||
.v5te => cpu.read(u16, address),
|
||||
};
|
||||
},
|
||||
0b10 => {
|
||||
// LDRSB
|
||||
@@ -36,10 +38,17 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
||||
},
|
||||
0b11 => {
|
||||
// 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
|
||||
result = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||
break :blk switch (address & 1 == 1) {
|
||||
true => sext(u32, u8, @as(u8, @truncate(value >> 8))),
|
||||
false => sext(u32, u16, value),
|
||||
};
|
||||
},
|
||||
.v5te => sext(u32, u16, cpu.read(u16, address)),
|
||||
};
|
||||
},
|
||||
0b00 => unreachable,
|
||||
}
|
||||
|
@@ -41,15 +41,24 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
||||
},
|
||||
0b10 => {
|
||||
// LDRH
|
||||
const value = cpu.read(u16, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
||||
cpu.r[rd] = switch (Arm32.arch) {
|
||||
.v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
|
||||
.v5te => cpu.read(u16, address),
|
||||
};
|
||||
},
|
||||
0b11 => {
|
||||
// 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
|
||||
cpu.r[rd] = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||
break :blk switch (address & 1 == 1) {
|
||||
true => sext(u32, u8, @as(u8, @truncate(value >> 8))),
|
||||
false => sext(u32, u16, value),
|
||||
};
|
||||
},
|
||||
.v5te => sext(u32, u16, cpu.read(u16, address)),
|
||||
};
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@@ -128,8 +137,10 @@ pub fn fmt10(comptime InstrFn: type, comptime L: bool, comptime offset: u5) Inst
|
||||
|
||||
if (L) {
|
||||
// LDRH
|
||||
const value = cpu.read(u16, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
||||
cpu.r[rd] = switch (Arm32.arch) {
|
||||
.v4t => rotr(u32, cpu.read(u16, address), 8 * (address & 1)),
|
||||
.v5te => cpu.read(u16, address),
|
||||
};
|
||||
} else {
|
||||
// STRH
|
||||
|
||||
|
Reference in New Issue
Block a user