diff --git a/src/cpu/arm/half_signed_data_transfer.zig b/src/cpu/arm/half_signed_data_transfer.zig index 5011c9e..3edb9b4 100644 --- a/src/cpu/arm/half_signed_data_transfer.zig +++ b/src/cpu/arm/half_signed_data_transfer.zig @@ -28,25 +28,24 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: offset = cpu.r[rm]; } - const modified_base = if (U) base + offset else base - offset; + const modified_base = if (U) base +% offset else base -% offset; var address = if (P) modified_base else base; + var result: u32 = undefined; if (L) { switch (@truncate(u2, opcode >> 5)) { 0b01 => { // LDRH const value = bus.read16(address & 0xFFFF_FFFE); - cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); + result = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); }, 0b10 => { // LDRSB - cpu.r[rd] = util.u32SignExtend(8, @as(u32, bus.read8(address))); - cpu.panic("[CPU|ARM|LDRSB] TODO: Affect the CPSR", .{}); + result = util.u32SignExtend(8, @as(u32, bus.read8(address))); }, 0b11 => { // LDRSH - cpu.r[rd] = util.u32SignExtend(16, @as(u32, bus.read16(address))); - cpu.panic("[CPU|ARM|LDRSH] TODO: Affect the CPSR", .{}); + result = util.u32SignExtend(16, @as(u32, bus.read16(address & 0xFFFF_FFFE))); }, 0b00 => unreachable, // SWP } @@ -59,6 +58,7 @@ pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: address = modified_base; if (W and P or !P) cpu.r[rn] = address; + if (L) cpu.r[rd] = result; // // This emulates the LDR rd == rn behaviour } }.inner; } diff --git a/src/cpu/arm/single_data_transfer.zig b/src/cpu/arm/single_data_transfer.zig index c2c98be..39f166b 100644 --- a/src/cpu/arm/single_data_transfer.zig +++ b/src/cpu/arm/single_data_transfer.zig @@ -20,19 +20,20 @@ pub fn singleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, base = cpu.r[rn]; } - const offset = if (I) registerOffset(cpu, opcode) else opcode & 0xFFF; + const offset = if (I) shifter.immShift(false, cpu, opcode) else opcode & 0xFFF; - const modified_base = if (U) base + offset else base - offset; + const modified_base = if (U) base +% offset else base -% offset; var address = if (P) modified_base else base; + var result: u32 = undefined; if (L) { if (B) { // LDRB - cpu.r[rd] = bus.read8(address); + result = bus.read8(address); } else { // LDR const value = bus.read32(address & 0xFFFF_FFFC); - cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); + result = std.math.rotr(u32, value, 8 * (address & 0x3)); } } else { if (B) { @@ -47,20 +48,7 @@ pub fn singleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, address = modified_base; if (W and P or !P) cpu.r[rn] = address; - - // TODO: W-bit forces non-privledged mode for the transfer + if (L) cpu.r[rd] = result; // This emulates the LDR rd == rn behaviour } }.inner; } - -fn registerOffset(cpu: *Arm7tdmi, opcode: u32) u32 { - const amount = @truncate(u8, opcode >> 7 & 0x1F); - const rm = cpu.r[opcode & 0xF]; - - return switch (@truncate(u2, opcode >> 5)) { - 0b00 => shifter.logicalLeft(false, &cpu.cpsr, rm, amount), - 0b01 => shifter.logicalRight(false, &cpu.cpsr, rm, amount), - 0b10 => shifter.arithmeticRight(false, &cpu.cpsr, rm, amount), - 0b11 => shifter.rotateRight(false, &cpu.cpsr, rm, amount), - }; -} diff --git a/src/cpu/barrel_shifter.zig b/src/cpu/barrel_shifter.zig index 0cc7838..89d77bc 100644 --- a/src/cpu/barrel_shifter.zig +++ b/src/cpu/barrel_shifter.zig @@ -29,7 +29,7 @@ fn registerShift(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 { }; } -fn immShift(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 { +pub fn immShift(comptime S: bool, cpu: *Arm7tdmi, opcode: u32) u32 { const amount = @truncate(u8, opcode >> 7 & 0x1F); const rm_idx = opcode & 0xF; @@ -132,11 +132,9 @@ pub fn arithmeticRight(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) result = @bitCast(u32, @bitCast(i32, rm) >> amount); if (S and total_amount != 0) cpsr.c.write(rm >> (amount - 1) & 1 == 1); } else { - if (S) { - // ASR #32 and ASR #>32 have the same result - result = @bitCast(u32, @bitCast(i32, rm) >> 31); - cpsr.c.write(result >> 31 & 1 == 1); - } + // ASR #32 and ASR #>32 have the same result + result = @bitCast(u32, @bitCast(i32, rm) >> 31); + if (S) cpsr.c.write(result >> 31 & 1 == 1); } return result;