diff --git a/src/arm/cpu/arm/half_signed_data_transfer.zig b/src/arm/cpu/arm/half_signed_data_transfer.zig index 4694058..86743ce 100644 --- a/src/arm/cpu/arm/half_signed_data_transfer.zig +++ b/src/arm/cpu/arm/half_signed_data_transfer.zig @@ -17,9 +17,11 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt const modified_base = if (U) base +% offset else base -% offset; var address = if (P) modified_base else base; + const op: u2 = @truncate(opcode >> 5); var result: u32 = undefined; + if (L) { - switch (@as(u2, @truncate(opcode >> 5))) { + switch (op) { 0b01 => { // LDRH const value = cpu.read(u16, address); @@ -36,15 +38,46 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt // 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); }, - 0b00 => unreachable, // SWP + 0b00 => unreachable, // SWP / SWPB dealt with in single_data_swap.zig } } else { - if (opcode >> 5 & 0x01 == 0x01) { - // STRH + switch (op) { + 0b01 => { + // STRH - // FIXME: I shouldn't have to use @as(u8, ...) here - cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd]))); - } else unreachable; // SWP + // FIXME: I shouldn't have to use @as(u16, ...) here + cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd]))); + }, + 0b10 => { + // LDRD + if (Arm32.arch != .v5te) cpu.panic("LDRD: unsupported on arm{s}", .{@tagName(Arm32.arch)}); + if (rd & 0 != 0) cpu.panic("LDRD: UNDEFINED behaviour when Rd is not even", .{}); + if (rd == 0xE) cpu.panic("LDRD: UNPREDICTABLE behaviour when rd == 14", .{}); + if (address & 0x7 != 0b000) cpu.panic("LDRD: UNPREDICTABLE when address (0x{X:0>8} is not double (64-bit) aligned", .{address}); + + // Why do we not make use of result here? + // + // It's because L is not set so there's no chance of writing an undefined + // value to the register + // + // despite this reason, this is bad design imo + // TODO: Refactor this handler + + cpu.r[rd] = cpu.read(u32, address); + cpu.r[rd + 1] = cpu.read(u32, address + 4); + }, + 0b11 => { + // STRD + if (Arm32.arch != .v5te) cpu.panic("STRD: unsupported on arm{s}", .{@tagName(Arm32.arch)}); + if (rd & 0 != 0) cpu.panic("STRD: UNDEFINED behaviour when Rd is not even", .{}); + if (rd == 0xE) cpu.panic("STRD: UNPREDICTABLE behaviour when rd == 14", .{}); + if (address & 0x7 != 0b000) cpu.panic("STRD: UNPREDICTABLE when address (0x{X:0>8} is not double (64-bit) aligned", .{address}); + + cpu.write(u32, address, cpu.r[rd]); + cpu.write(u32, address + 4, cpu.r[rd + 1]); + }, + else => unreachable, + } } address = modified_base;