chore: dedup code in THUMB instructions

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-01-29 20:05:27 -04:00
parent bce067557f
commit ae4023e51c
8 changed files with 33 additions and 62 deletions

View File

@ -263,7 +263,7 @@ fn setArmLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, rd: u4, result: u32) voi
}
}
fn setLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, result: u32) void {
pub fn setLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, result: u32) void {
if (S) {
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);

View File

@ -5,6 +5,8 @@ const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
const shifter = @import("../barrel_shifter.zig");
const setLogicOpFlags = @import("../arm/data_processing.zig").setLogicOpFlags;
pub fn format1(comptime op: u2, comptime offset: u5) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
@ -12,17 +14,15 @@ pub fn format1(comptime op: u2, comptime offset: u5) InstrFn {
const rd = opcode & 0x7;
const result = switch (op) {
0b00 => shifter.logicalLeft(true, &cpu.cpsr, cpu.r[rs], offset),
0b01 => shifter.logicalRight(true, &cpu.cpsr, cpu.r[rs], offset),
0b10 => shifter.arithmeticRight(true, &cpu.cpsr, cpu.r[rs], offset),
0b00 => shifter.logicalLeft(true, &cpu.cpsr, cpu.r[rs], offset), // LSL
0b01 => shifter.logicalRight(true, &cpu.cpsr, cpu.r[rs], offset), // LSR
0b10 => shifter.arithmeticRight(true, &cpu.cpsr, cpu.r[rs], offset), // ASR
else => std.debug.panic("[CPU|THUMB|Fmt1] {} is an invalid op", .{op}),
};
// Equivalent to an ARM MOVS
cpu.r[rd] = result;
// Instructions of this type are equivalent to a MOVS
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);
setLogicOpFlags(true, cpu, result);
}
}.inner;
}

View File

@ -7,8 +7,9 @@ const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
pub fn format12(comptime isSP: bool, comptime rd: u3) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
const left = if (isSP) cpu.r[13] else cpu.r[15] + 2 & 0xFFFF_FFFD; // fetch (+2)
const right = @truncate(u10, opcode & 0xFF) << 2;
// ADD
const left = if (isSP) cpu.r[13] else cpu.fakePC() & 0xFFFF_FFFC;
const right = (opcode & 0xFF) << 2;
const result = left + right; // TODO: What about overflows?
cpu.r[rd] = result;
}

View File

@ -3,20 +3,24 @@ const std = @import("std");
const Bus = @import("../../Bus.zig");
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
const checkCond = @import("../../cpu.zig").checkCond;
const u32SignExtend = @import("../../util.zig").u32SignExtend;
pub fn format16(comptime cond: u4) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
const offset = (opcode & 0xFF) << 1;
// B
const offset = u32SignExtend(8, opcode & 0xFF) << 1;
const do_execute = switch (cond) {
const should_execute = switch (cond) {
0xE, 0xF => std.debug.panic("[CPU/THUMB] Undefined conditional branch with condition {}", .{cond}),
else => checkCond(cpu.cpsr, cond),
};
if (do_execute) cpu.r[15] = (cpu.fakePC() & 0xFFFF_FFFC) +% u32SignExtend(8, offset);
if (should_execute) {
cpu.r[15] = (cpu.fakePC() & 0xFFFF_FFFC) +% offset;
}
}
}.inner;
}

View File

@ -8,6 +8,7 @@ const u32SignExtend = @import("../../util.zig").u32SignExtend;
pub fn format19(comptime is_low: bool) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
// BL
const offset = opcode & 0x3FF;
if (is_low) {

View File

@ -4,6 +4,11 @@ const Bus = @import("../../Bus.zig");
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
const add = @import("../arm/data_processing.zig").add;
const sub = @import("../arm/data_processing.zig").sub;
const cmp = @import("../arm/data_processing.zig").cmp;
const setLogicOpFlags = @import("../arm/data_processing.zig").setLogicOpFlags;
pub fn format3(comptime op: u2, comptime rd: u3) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
@ -13,44 +18,11 @@ pub fn format3(comptime op: u2, comptime rd: u3) InstrFn {
0b00 => {
// MOV
cpu.r[rd] = offset;
cpu.cpsr.n.unset();
cpu.cpsr.z.write(offset == 0);
},
0b01 => {
// CMP
const left = cpu.r[rd];
const result = left -% offset;
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);
cpu.cpsr.c.write(offset <= left);
cpu.cpsr.v.write(((left ^ result) & (~offset ^ result)) >> 31 & 1 == 1);
},
0b10 => {
// ADD
const left = cpu.r[rd];
var result: u32 = undefined;
const didOverflow = @addWithOverflow(u32, left, offset, &result);
cpu.r[rd] = result;
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);
cpu.cpsr.c.write(didOverflow);
cpu.cpsr.v.write(((left ^ result) & (offset ^ result)) >> 31 & 1 == 1);
},
0b11 => {
// SUB
const left = cpu.r[rd];
const result = left -% offset;
cpu.r[rd] = result;
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);
cpu.cpsr.c.write(offset <= left);
cpu.cpsr.v.write(((left ^ result) & (~offset ^ result)) >> 31 & 1 == 1);
setLogicOpFlags(true, cpu, offset);
},
0b01 => cmp(cpu, cpu.r[rd], offset), // CMP
0b10 => cpu.r[rd] = add(true, cpu, cpu.r[rd], offset), // ADD
0b11 => cpu.r[rd] = sub(true, cpu, cpu.r[rd], offset), // SUB
}
}
}.inner;

View File

@ -4,6 +4,8 @@ const Bus = @import("../../Bus.zig");
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
const cmp = @import("../arm/data_processing.zig").cmp;
pub fn format5(comptime op: u2, comptime h1: u1, comptime h2: u1) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
@ -11,24 +13,14 @@ pub fn format5(comptime op: u2, comptime h1: u1, comptime h2: u1) InstrFn {
const dst = @as(u4, h1) << 3 | (opcode & 0x7);
switch (op) {
0b01 => {
// CMP
const left = cpu.r[dst];
const right = cpu.r[src];
const result = left -% right;
cpu.cpsr.n.write(result >> 31 & 1 == 1);
cpu.cpsr.z.write(result == 0);
cpu.cpsr.c.write(right <= left);
cpu.cpsr.v.write(((left ^ result) & (~right ^ result)) >> 31 & 1 == 1);
},
0b01 => cmp(cpu, cpu.r[dst], cpu.r[src]), // CMP
0b10 => cpu.r[dst] = cpu.r[src], // MOV
0b11 => {
// BX
cpu.cpsr.t.write(cpu.r[src] & 1 == 1);
cpu.r[15] = cpu.r[src] & 0xFFFF_FFFE;
},
else => std.debug.panic("[CPU] Op #{} is invalid for THUMB Format 5", .{op}),
else => std.debug.panic("[CPU|THUMB|Fmt5] {} is an invalid op", .{op}),
}
}
}.inner;

View File

@ -7,6 +7,7 @@ const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
pub fn format6(comptime rd: u3) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void {
// LDR
const offset = (opcode & 0xFF) << 2;
// FIXME: Should this overflow?