fix(arm): group multiply instructions together

- implement clz in ARMv5TE
This commit is contained in:
Rekai Nyangadzayi Musuka 2023-09-07 00:04:07 -05:00
parent 44b59512c0
commit 6dde25bd0f
4 changed files with 55 additions and 53 deletions

View File

@ -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;
}

View File

@ -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; const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
return struct { 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 rs = opcode >> 8 & 0xF;
const rm = opcode & 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; if (L) {
const result: u32 = @truncate(temp); const rd_hi = rd;
cpu.r[rd] = result; const rd_lo = rn;
if (S) { if (U) {
cpu.cpsr.n.write(result >> 31 & 1 == 1); // Signed (WHY IS IT U THEN?)
cpu.cpsr.z.write(result == 0); var result: i64 = @as(i64, @as(i32, @bitCast(cpu.r[rm]))) * @as(i64, @as(i32, @bitCast(cpu.r[rs])));
// V is unaffected, C is *actually* undefined in ARMv4 if (A) result +%= @bitCast(@as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]));
}
}
}.inner;
}
pub fn multiplyLong(comptime InstrFn: type, comptime U: bool, comptime A: bool, comptime S: bool) InstrFn { cpu.r[rd_hi] = @bitCast(@as(i32, @truncate(result >> 32)));
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child; 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 { cpu.r[rd_hi] = @truncate(result >> 32);
fn inner(cpu: *Arm32, opcode: u32) void { cpu.r[rd_lo] = @truncate(result);
const rd_hi = opcode >> 16 & 0xF; }
const rd_lo = opcode >> 12 & 0xF;
const rs = opcode >> 8 & 0xF;
const rm = opcode & 0xF;
if (U) { if (S) {
// Signed (WHY IS IT U THEN?) cpu.cpsr.z.write(cpu.r[rd_hi] == 0 and cpu.r[rd_lo] == 0);
var result: i64 = @as(i64, @as(i32, @bitCast(cpu.r[rm]))) * @as(i64, @as(i32, @bitCast(cpu.r[rs]))); cpu.cpsr.n.write(cpu.r[rd_hi] >> 31 & 1 == 1);
if (A) result +%= @bitCast(@as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo])); // C and V are set to meaningless values
}
cpu.r[rd_hi] = @bitCast(@as(i32, @truncate(result >> 32)));
cpu.r[rd_lo] = @bitCast(@as(i32, @truncate(result)));
} else { } else {
// Unsigned const temp: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]) + if (A) cpu.r[rn] else 0;
var result: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]); const result: u32 = @truncate(temp);
if (A) result +%= @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]); cpu.r[rd] = result;
cpu.r[rd_hi] = @truncate(result >> 32); if (S) {
cpu.r[rd_lo] = @truncate(result); cpu.cpsr.n.write(result >> 31 & 1 == 1);
} cpu.cpsr.z.write(result == 0);
// V is unaffected, C is *actually* undefined in ARMv4
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
} }
} }
}.inner; }.inner;

View File

@ -14,8 +14,8 @@ pub const arm = struct {
const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt;
const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap;
/// Arithmetic Instruction Extension Space
const multiply = @import("cpu/arm/multiply.zig").multiply; const multiply = @import("cpu/arm/multiply.zig").multiply;
const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong;
/// Determine index into ARM InstrFn LUT /// Determine index into ARM InstrFn LUT
pub fn idx(opcode: u32) u12 { pub fn idx(opcode: u32) u12 {
@ -38,18 +38,15 @@ pub const arm = struct {
handler.* = switch (@as(u2, i >> 10)) { handler.* = switch (@as(u2, i >> 10)) {
0b00 => if (i == 0x121) blk: { 0b00 => if (i == 0x121) blk: {
break :blk branchExchange(InstrFn); 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: { } else if (i & 0xFBF == 0x109) blk: {
const B = i >> 6 & 1 == 1; const B = i >> 6 & 1 == 1;
break :blk swap(InstrFn, B); 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 U = i >> 6 & 1 == 1;
const A = i >> 5 & 1 == 1; const A = i >> 5 & 1 == 1;
const S = i >> 4 & 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: { } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: {
const P = i >> 8 & 1 == 1; const P = i >> 8 & 1 == 1;
const U = i >> 7 & 1 == 1; const U = i >> 7 & 1 == 1;

View File

@ -14,11 +14,10 @@ pub const arm = struct {
const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt; const swi = @import("cpu/arm/software_interrupt.zig").armSoftwareInterrupt;
const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; const swap = @import("cpu/arm/single_data_swap.zig").singleDataSwap;
// Arithmetic Instruction Extension Space
const multiply = @import("cpu/arm/multiply.zig").multiply; const multiply = @import("cpu/arm/multiply.zig").multiply;
const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong;
const cop = @import("cpu/arm/coprocessor.zig"); const cop = @import("cpu/arm/coprocessor.zig");
const clz = @import("cpu/arm/misc_instructions.zig").clz; const clz = @import("cpu/arm/misc_instructions.zig").clz;
/// Determine index into ARM InstrFn LUT /// Determine index into ARM InstrFn LUT
@ -44,18 +43,15 @@ pub const arm = struct {
break :blk branchExchange(InstrFn); break :blk branchExchange(InstrFn);
} else if (i == 0x161) blk: { } else if (i == 0x161) blk: {
break :blk clz(InstrFn); 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: { } else if (i & 0xFBF == 0x109) blk: {
const B = i >> 6 & 1 == 1; const B = i >> 6 & 1 == 1;
break :blk swap(InstrFn, B); 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 U = i >> 6 & 1 == 1;
const A = i >> 5 & 1 == 1; const A = i >> 5 & 1 == 1;
const S = i >> 4 & 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: { } else if (i & 0xE49 == 0x009 or i & 0xE49 == 0x049) blk: {
const P = i >> 8 & 1 == 1; const P = i >> 8 & 1 == 1;
const U = i >> 7 & 1 == 1; const U = i >> 7 & 1 == 1;