diff --git a/src/arm/cpu/arm/psr_transfer.zig b/src/arm/cpu/arm/psr_transfer.zig index 07d03d7..42ab6f8 100644 --- a/src/arm/cpu/arm/psr_transfer.zig +++ b/src/arm/cpu/arm/psr_transfer.zig @@ -1,42 +1,52 @@ const std = @import("std"); - +const rotr = @import("zba-util").rotr; const PSR = @import("../../../arm.zig").PSR; -const log = std.log.scoped(.PsrTransfer); +const log = std.log.scoped(.ctrl_ext_space); -const rotr = @import("zba-util").rotr; - -pub fn psrTransfer(comptime InstrFn: type, comptime I: bool, comptime R: bool, comptime kind: u2) InstrFn { +pub fn control(comptime InstrFn: type, comptime I: bool, comptime op: u6) InstrFn { const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; return struct { fn inner(cpu: *Arm32, opcode: u32) void { - switch (kind) { - 0b00 => { - // MRS + if (I) { + // MSR (register) + const R = op >> 5 & 1 == 1; + msr(R, I, cpu, opcode); + + return; + } + + switch (op) { + 0b00_0000, 0b10_0000 => { // MRS + const R = op >> 5 & 1 == 1; const rd = opcode >> 12 & 0xF; if (R and !cpu.hasSPSR()) log.err("Tried to read SPSR from User/System Mode", .{}); cpu.r[rd] = if (R) cpu.spsr.raw else cpu.cpsr.raw; }, - 0b10 => { - // MSR - const field_mask: u4 = @truncate(opcode >> 16 & 0xF); - const rm_idx = opcode & 0xF; - const right = if (I) rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) * 2) else cpu.r[rm_idx]; - - if (R and !cpu.hasSPSR()) log.err("Tried to write to SPSR in User/System Mode", .{}); - - if (R) { - // arm.gba seems to expect the SPSR to do somethign in SYS mode, - // so we just assume that despite writing to the SPSR in USR or SYS mode - // being UNPREDICTABLE, it just magically has a working SPSR somehow - cpu.spsr.raw = fieldMask(&cpu.spsr, field_mask, right); - } else { - if (cpu.isPrivileged()) cpu.setCpsr(fieldMask(&cpu.cpsr, field_mask, right)); - } + 0b01_0000, 0b11_0000 => { // MSR (register) + const R = op >> 5 & 1 == 1; + msr(R, false, cpu, opcode); }, - else => cpu.panic("[CPU/PSR Transfer] Bits 21:220 of {X:0>8} are undefined", .{opcode}), + else => cpu.panic("unhandled instruction: 0x{X:0>8}", .{opcode}), + } + } + + inline fn msr(comptime R: bool, comptime imm: bool, cpu: *Arm32, opcode: u32) void { + const field_mask: u4 = @truncate(opcode >> 16 & 0xF); + const rm_idx = opcode & 0xF; + const right = if (imm) rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) * 2) else cpu.r[rm_idx]; + + if (R and !cpu.hasSPSR()) log.err("Tried to write to SPSR in User/System Mode", .{}); + + if (R) { + // arm.gba seems to expect the SPSR to do somethign in SYS mode, + // so we just assume that despite writing to the SPSR in USR or SYS mode + // being UNPREDICTABLE, it just magically has a working SPSR somehow + cpu.spsr.raw = fieldMask(&cpu.spsr, field_mask, right); + } else { + if (cpu.isPrivileged()) cpu.setCpsr(fieldMask(&cpu.cpsr, field_mask, right)); } } }.inner; diff --git a/src/arm/v4t.zig b/src/arm/v4t.zig index d7e1d1b..acce81e 100644 --- a/src/arm/v4t.zig +++ b/src/arm/v4t.zig @@ -5,7 +5,6 @@ pub const arm = struct { pub const lut: [0x1000]InstrFn = populate(); const processing = @import("cpu/arm/data_processing.zig").dataProcessing; - const psrTransfer = @import("cpu/arm/psr_transfer.zig").psrTransfer; const transfer = @import("cpu/arm/single_data_transfer.zig").singleDataTransfer; const halfSignedTransfer = @import("cpu/arm/half_signed_data_transfer.zig").halfAndSignedDataTransfer; const blockTransfer = @import("cpu/arm/block_data_transfer.zig").blockDataTransfer; @@ -14,6 +13,9 @@ pub const arm = struct { const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; + // Control Instruction Extension Space + const control = @import("cpu/arm/psr_transfer.zig").control; + /// Arithmetic Instruction Extension Space const multiply = @import("cpu/arm/multiply.zig").multiply; @@ -56,9 +58,9 @@ pub const arm = struct { break :blk halfSignedTransfer(InstrFn, P, U, I, W, L); } else if (i & 0xD90 == 0x100) blk: { const I = i >> 9 & 1 == 1; - const R = i >> 6 & 1 == 1; - const kind = i >> 4 & 0x3; - break :blk psrTransfer(InstrFn, I, R, kind); + const op = ((i >> 5) & 0x3) << 4 | (i & 0xF); + + break :blk control(InstrFn, I, op); } else blk: { const I = i >> 9 & 1 == 1; const S = i >> 4 & 1 == 1; diff --git a/src/arm/v5te.zig b/src/arm/v5te.zig index 66d243f..4c2b387 100644 --- a/src/arm/v5te.zig +++ b/src/arm/v5te.zig @@ -5,7 +5,6 @@ pub const arm = struct { pub const lut: [0x1000]InstrFn = populate(); const processing = @import("cpu/arm/data_processing.zig").dataProcessing; - const psrTransfer = @import("cpu/arm/psr_transfer.zig").psrTransfer; const transfer = @import("cpu/arm/single_data_transfer.zig").singleDataTransfer; const halfSignedTransfer = @import("cpu/arm/half_signed_data_transfer.zig").halfAndSignedDataTransfer; const blockTransfer = @import("cpu/arm/block_data_transfer.zig").blockDataTransfer; @@ -14,6 +13,9 @@ pub const arm = struct { const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; + // Control Instruction Extension Space + const control = @import("cpu/arm/psr_transfer.zig").control; + // Arithmetic Instruction Extension Space const multiply = @import("cpu/arm/multiply.zig").multiply; @@ -39,31 +41,30 @@ pub const arm = struct { for (&table, 0..) |*handler, i| { handler.* = switch (@as(u2, i >> 10)) { - 0b00 => if (i == 0x121) blk: { + 0b00 => if (i == 0x121) blk: { // 12 bits break :blk branchExchange(InstrFn); - } else if (i == 0x161) blk: { + } else if (i == 0x161) blk: { // 12 bits break :blk clz(InstrFn); - } else if (i & 0xFBF == 0x109) blk: { + } else if (i & 0xFBF == 0x109) blk: { // 11 bits const B = i >> 6 & 1 == 1; break :blk swap(InstrFn, B); - } else if (i & 0xF0F == 0x009) blk: { + } else if (i & 0xF0F == 0x009) blk: { // 8 bits const L = i >> 7 & 1 == 1; const U = i >> 6 & 1 == 1; const A = i >> 5 & 1 == 1; const S = i >> 4 & 1 == 1; break :blk multiply(InstrFn, L, U, A, S); - } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { + } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { // 6 bits const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1; const I = i >> 6 & 1 == 1; const W = i >> 5 & 1 == 1; const L = i >> 4 & 1 == 1; break :blk halfSignedTransfer(InstrFn, P, U, I, W, L); - } else if (i & 0xD90 == 0x100) blk: { + } else if (i & 0xD90 == 0x100) blk: { // 6 bits const I = i >> 9 & 1 == 1; - const R = i >> 6 & 1 == 1; - const kind = i >> 4 & 0x3; - break :blk psrTransfer(InstrFn, I, R, kind); + const op = ((i >> 5) & 0x3) << 4 | (i & 0xF); + break :blk control(InstrFn, I, op); } else blk: { const I = i >> 9 & 1 == 1; const S = i >> 4 & 1 == 1;