diff --git a/src/cpu/arm/data_processing.zig b/src/cpu/arm/data_processing.zig index 4c23253..cc3ea64 100644 --- a/src/cpu/arm/data_processing.zig +++ b/src/cpu/arm/data_processing.zig @@ -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); diff --git a/src/cpu/thumb/format1.zig b/src/cpu/thumb/format1.zig index 8f66e62..b246163 100644 --- a/src/cpu/thumb/format1.zig +++ b/src/cpu/thumb/format1.zig @@ -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; } diff --git a/src/cpu/thumb/format12.zig b/src/cpu/thumb/format12.zig index 2e18810..fa026aa 100644 --- a/src/cpu/thumb/format12.zig +++ b/src/cpu/thumb/format12.zig @@ -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; } diff --git a/src/cpu/thumb/format16.zig b/src/cpu/thumb/format16.zig index 9846f52..8ec032c 100644 --- a/src/cpu/thumb/format16.zig +++ b/src/cpu/thumb/format16.zig @@ -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; } diff --git a/src/cpu/thumb/format19.zig b/src/cpu/thumb/format19.zig index c2eab4d..0c5927a 100644 --- a/src/cpu/thumb/format19.zig +++ b/src/cpu/thumb/format19.zig @@ -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) { diff --git a/src/cpu/thumb/format3.zig b/src/cpu/thumb/format3.zig index a40e627..0602afc 100644 --- a/src/cpu/thumb/format3.zig +++ b/src/cpu/thumb/format3.zig @@ -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; diff --git a/src/cpu/thumb/format5.zig b/src/cpu/thumb/format5.zig index 51c4e7f..34190d4 100644 --- a/src/cpu/thumb/format5.zig +++ b/src/cpu/thumb/format5.zig @@ -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; diff --git a/src/cpu/thumb/format6.zig b/src/cpu/thumb/format6.zig index e90be49..392578c 100644 --- a/src/cpu/thumb/format6.zig +++ b/src/cpu/thumb/format6.zig @@ -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?