58 lines
1.7 KiB
Zig

const Bus = @import("../../../lib.zig").Bus;
const sext = @import("zba-util").sext;
pub fn fmt16(comptime InstrFn: type, comptime cond: u4) InstrFn {
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
return struct {
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
// B
if (cond == 0xE or cond == 0xF)
cpu.panic("[CPU/THUMB.16] Undefined conditional branch with condition {}", .{cond});
if (!cpu.cpsr.check(cond)) return;
cpu.r[15] +%= sext(u32, u8, opcode & 0xFF) << 1;
cpu.pipe.reload(cpu);
}
}.inner;
}
pub fn fmt18(comptime InstrFn: type) InstrFn {
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
return struct {
// B but conditional
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
cpu.r[15] +%= sext(u32, u11, opcode & 0x7FF) << 1;
cpu.pipe.reload(cpu);
}
}.inner;
}
pub fn fmt19(comptime InstrFn: type, comptime is_low: bool) InstrFn {
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
return struct {
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
// BL
const offset = opcode & 0x7FF;
if (is_low) {
// Instruction 2
const next_opcode = cpu.r[15] - 2;
cpu.r[15] = cpu.r[14] +% (offset << 1);
cpu.r[14] = next_opcode | 1;
cpu.pipe.reload(cpu);
} else {
// Instruction 1
const lr_offset = sext(u32, u11, offset) << 12;
cpu.r[14] = (cpu.r[15] +% lr_offset) & ~@as(u32, 1);
}
}
}.inner;
}