diff --git a/src/arm/cpu/arm/misc_instructions.zig b/src/arm/cpu/arm/misc_instructions.zig new file mode 100644 index 0000000..ebda272 --- /dev/null +++ b/src/arm/cpu/arm/misc_instructions.zig @@ -0,0 +1,17 @@ +const sext = @import("zba-util").sext; + +pub fn clz(comptime InstrFn: type) InstrFn { + const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; + + return struct { + pub fn inner(cpu: *Arm32, opcode: u32) void { + const rd = opcode >> 12 & 0xF; + const rm = opcode & 0xF; + + if (rd == 0xF) cpu.panic("CLZ: UNPREDICTABLE behaviour when rd == 15", .{}); + if (rm == 0xF) cpu.panic("CLZ: UNPREDICTABLE behaviour when rm == 15", .{}); + + cpu.r[rd] = @clz(cpu.r[rm]); + } + }.inner; +} diff --git a/src/arm/cpu/arm/multiply.zig b/src/arm/cpu/arm/multiply.zig index 7eb788e..80118b7 100644 --- a/src/arm/cpu/arm/multiply.zig +++ b/src/arm/cpu/arm/multiply.zig @@ -1,4 +1,4 @@ -pub fn multiply(comptime InstrFn: type, comptime A: bool, comptime S: bool) InstrFn { +pub fn multiply(comptime InstrFn: type, comptime L: bool, comptime U: bool, comptime A: bool, comptime S: bool) InstrFn { const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; return struct { @@ -8,49 +8,41 @@ pub fn multiply(comptime InstrFn: type, comptime A: bool, comptime S: bool) Inst const rs = opcode >> 8 & 0xF; const rm = opcode & 0xF; - const temp: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]) + if (A) cpu.r[rn] else 0; - const result: u32 = @truncate(temp); - cpu.r[rd] = result; + if (L) { + const rd_hi = rd; + const rd_lo = rn; - if (S) { - cpu.cpsr.n.write(result >> 31 & 1 == 1); - cpu.cpsr.z.write(result == 0); - // V is unaffected, C is *actually* undefined in ARMv4 - } - } - }.inner; -} + if (U) { + // Signed (WHY IS IT U THEN?) + var result: i64 = @as(i64, @as(i32, @bitCast(cpu.r[rm]))) * @as(i64, @as(i32, @bitCast(cpu.r[rs]))); + if (A) result +%= @bitCast(@as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo])); -pub fn multiplyLong(comptime InstrFn: type, comptime U: bool, comptime A: bool, comptime S: bool) InstrFn { - const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; + cpu.r[rd_hi] = @bitCast(@as(i32, @truncate(result >> 32))); + cpu.r[rd_lo] = @bitCast(@as(i32, @truncate(result))); + } else { + // Unsigned + var result: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]); + if (A) result +%= @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]); - return struct { - fn inner(cpu: *Arm32, opcode: u32) void { - const rd_hi = opcode >> 16 & 0xF; - const rd_lo = opcode >> 12 & 0xF; - const rs = opcode >> 8 & 0xF; - const rm = opcode & 0xF; + cpu.r[rd_hi] = @truncate(result >> 32); + cpu.r[rd_lo] = @truncate(result); + } - if (U) { - // Signed (WHY IS IT U THEN?) - var result: i64 = @as(i64, @as(i32, @bitCast(cpu.r[rm]))) * @as(i64, @as(i32, @bitCast(cpu.r[rs]))); - if (A) result +%= @bitCast(@as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo])); - - cpu.r[rd_hi] = @bitCast(@as(i32, @truncate(result >> 32))); - cpu.r[rd_lo] = @bitCast(@as(i32, @truncate(result))); + if (S) { + cpu.cpsr.z.write(cpu.r[rd_hi] == 0 and cpu.r[rd_lo] == 0); + cpu.cpsr.n.write(cpu.r[rd_hi] >> 31 & 1 == 1); + // C and V are set to meaningless values + } } else { - // Unsigned - var result: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]); - if (A) result +%= @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]); + const temp: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]) + if (A) cpu.r[rn] else 0; + const result: u32 = @truncate(temp); + cpu.r[rd] = result; - cpu.r[rd_hi] = @truncate(result >> 32); - cpu.r[rd_lo] = @truncate(result); - } - - if (S) { - cpu.cpsr.z.write(cpu.r[rd_hi] == 0 and cpu.r[rd_lo] == 0); - cpu.cpsr.n.write(cpu.r[rd_hi] >> 31 & 1 == 1); - // C and V are set to meaningless values + if (S) { + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + // V is unaffected, C is *actually* undefined in ARMv4 + } } } }.inner; diff --git a/src/arm/v4t.zig b/src/arm/v4t.zig index 6fb6b21..d7e1d1b 100644 --- a/src/arm/v4t.zig +++ b/src/arm/v4t.zig @@ -14,8 +14,8 @@ pub const arm = struct { const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; + /// Arithmetic Instruction Extension Space const multiply = @import("cpu/arm/multiply.zig").multiply; - const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong; /// Determine index into ARM InstrFn LUT pub fn idx(opcode: u32) u12 { @@ -38,18 +38,15 @@ pub const arm = struct { handler.* = switch (@as(u2, i >> 10)) { 0b00 => if (i == 0x121) blk: { break :blk branchExchange(InstrFn); - } else if (i & 0xFCF == 0x009) blk: { - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - break :blk multiply(InstrFn, A, S); } else if (i & 0xFBF == 0x109) blk: { const B = i >> 6 & 1 == 1; break :blk swap(InstrFn, B); - } else if (i & 0xF8F == 0x089) blk: { + } else if (i & 0xF0F == 0x009) blk: { + 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 multiplyLong(InstrFn, U, A, S); + break :blk multiply(InstrFn, L, U, A, S); } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1; diff --git a/src/arm/v5te.zig b/src/arm/v5te.zig index 6350c80..66d243f 100644 --- a/src/arm/v5te.zig +++ b/src/arm/v5te.zig @@ -14,11 +14,10 @@ pub const arm = struct { const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; + // Arithmetic Instruction Extension Space const multiply = @import("cpu/arm/multiply.zig").multiply; - const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong; const cop = @import("cpu/arm/coprocessor.zig"); - const clz = @import("cpu/arm/misc_instructions.zig").clz; /// Determine index into ARM InstrFn LUT @@ -44,18 +43,15 @@ pub const arm = struct { break :blk branchExchange(InstrFn); } else if (i == 0x161) blk: { break :blk clz(InstrFn); - } else if (i & 0xFCF == 0x009) blk: { - const A = i >> 5 & 1 == 1; - const S = i >> 4 & 1 == 1; - break :blk multiply(InstrFn, A, S); } else if (i & 0xFBF == 0x109) blk: { const B = i >> 6 & 1 == 1; break :blk swap(InstrFn, B); - } else if (i & 0xF8F == 0x089) blk: { + } else if (i & 0xF0F == 0x009) blk: { + 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 multiplyLong(InstrFn, U, A, S); + break :blk multiply(InstrFn, L, U, A, S); } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: { const P = i >> 8 & 1 == 1; const U = i >> 7 & 1 == 1;