From 1b8db0c42764486ebc218ef3105b0df4946c8d18 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 4 Feb 2022 04:00:48 -0400 Subject: [PATCH] chore: group THUMB and select ARM instructions together (same file) --- src/cpu.zig | 45 +++--- src/cpu/arm/multiply.zig | 33 ++++ src/cpu/arm/multiply_long.zig | 38 ----- src/cpu/thumb/{format4.zig => alu.zig} | 0 .../{format14.zig => block_data_transfer.zig} | 26 +++- src/cpu/thumb/branch.zig | 54 +++++++ src/cpu/thumb/data_processing.zig | 118 +++++++++++++++ src/cpu/thumb/data_transfer.zig | 143 ++++++++++++++++++ src/cpu/thumb/format1.zig | 51 ------- src/cpu/thumb/format10.zig | 25 --- src/cpu/thumb/format11.zig | 21 --- src/cpu/thumb/format12.zig | 17 --- src/cpu/thumb/format13.zig | 14 -- src/cpu/thumb/format15.zig | 29 ---- src/cpu/thumb/format16.zig | 26 ---- src/cpu/thumb/format18.zig | 15 -- src/cpu/thumb/format19.zig | 26 ---- src/cpu/thumb/format2.zig | 33 ---- src/cpu/thumb/format3.zig | 29 ---- src/cpu/thumb/format6.zig | 17 --- src/cpu/thumb/format78.zig | 60 -------- src/cpu/thumb/format9.zig | 37 ----- .../{format5.zig => processing_branch.zig} | 0 .../{format17.zig => software_interrupt.zig} | 2 - 24 files changed, 397 insertions(+), 462 deletions(-) delete mode 100644 src/cpu/arm/multiply_long.zig rename src/cpu/thumb/{format4.zig => alu.zig} (100%) rename src/cpu/thumb/{format14.zig => block_data_transfer.zig} (68%) create mode 100644 src/cpu/thumb/branch.zig create mode 100644 src/cpu/thumb/data_processing.zig create mode 100644 src/cpu/thumb/data_transfer.zig delete mode 100644 src/cpu/thumb/format1.zig delete mode 100644 src/cpu/thumb/format10.zig delete mode 100644 src/cpu/thumb/format11.zig delete mode 100644 src/cpu/thumb/format12.zig delete mode 100644 src/cpu/thumb/format13.zig delete mode 100644 src/cpu/thumb/format15.zig delete mode 100644 src/cpu/thumb/format16.zig delete mode 100644 src/cpu/thumb/format18.zig delete mode 100644 src/cpu/thumb/format19.zig delete mode 100644 src/cpu/thumb/format2.zig delete mode 100644 src/cpu/thumb/format3.zig delete mode 100644 src/cpu/thumb/format6.zig delete mode 100644 src/cpu/thumb/format78.zig delete mode 100644 src/cpu/thumb/format9.zig rename src/cpu/thumb/{format5.zig => processing_branch.zig} (100%) rename src/cpu/thumb/{format17.zig => software_interrupt.zig} (96%) diff --git a/src/cpu.zig b/src/cpu.zig index 297cc33..54c5dfd 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -17,29 +17,34 @@ const blockDataTransfer = @import("cpu/arm/block_data_transfer.zig").blockDataTr const branch = @import("cpu/arm/branch.zig").branch; const branchAndExchange = @import("cpu/arm/branch.zig").branchAndExchange; const softwareInterrupt = @import("cpu/arm/software_interrupt.zig").softwareInterrupt; -const multiply = @import("cpu/arm/multiply.zig").multiply; -const multiplyLong = @import("cpu/arm/multiply_long.zig").multiplyLong; const singleDataSwap = @import("cpu/arm/single_data_swap.zig").singleDataSwap; +const multiply = @import("cpu/arm/multiply.zig").multiply; +const multiplyLong = @import("cpu/arm/multiply.zig").multiplyLong; + // THUMB Instruction Groups -const format1 = @import("cpu/thumb/format1.zig").format1; -const format2 = @import("cpu/thumb/format2.zig").format2; -const format3 = @import("cpu/thumb/format3.zig").format3; -const format4 = @import("cpu/thumb/format4.zig").format4; -const format5 = @import("cpu/thumb/format5.zig").format5; -const format6 = @import("cpu/thumb/format6.zig").format6; -const format78 = @import("cpu/thumb/format78.zig").format78; -const format9 = @import("cpu/thumb/format9.zig").format9; -const format10 = @import("cpu/thumb/format10.zig").format10; -const format11 = @import("cpu/thumb/format11.zig").format11; -const format12 = @import("cpu/thumb/format12.zig").format12; -const format13 = @import("cpu/thumb/format13.zig").format13; -const format14 = @import("cpu/thumb/format14.zig").format14; -const format15 = @import("cpu/thumb/format15.zig").format15; -const format16 = @import("cpu/thumb/format16.zig").format16; -const format17 = @import("cpu/thumb/format17.zig").format17; -const format18 = @import("cpu/thumb/format18.zig").format18; -const format19 = @import("cpu/thumb/format19.zig").format19; +const format1 = @import("cpu/thumb/data_processing.zig").format1; +const format2 = @import("cpu/thumb/data_processing.zig").format2; +const format3 = @import("cpu/thumb/data_processing.zig").format3; +const format12 = @import("cpu/thumb/data_processing.zig").format12; +const format13 = @import("cpu/thumb/data_processing.zig").format13; + +const format4 = @import("cpu/thumb/alu.zig").format4; +const format5 = @import("cpu/thumb/processing_branch.zig").format5; + +const format6 = @import("cpu/thumb/data_transfer.zig").format6; +const format78 = @import("cpu/thumb/data_transfer.zig").format78; +const format9 = @import("cpu/thumb/data_transfer.zig").format9; +const format10 = @import("cpu/thumb/data_transfer.zig").format10; +const format11 = @import("cpu/thumb/data_transfer.zig").format11; +const format14 = @import("cpu/thumb/block_data_transfer.zig").format14; +const format15 = @import("cpu/thumb/block_data_transfer.zig").format15; + +const format16 = @import("cpu/thumb/branch.zig").format16; +const format18 = @import("cpu/thumb/branch.zig").format18; +const format19 = @import("cpu/thumb/branch.zig").format19; + +const format17 = @import("cpu/thumb/software_interrupt.zig").format17; pub const ArmInstrFn = fn (*Arm7tdmi, *Bus, u32) void; pub const ThumbInstrFn = fn (*Arm7tdmi, *Bus, u16) void; diff --git a/src/cpu/arm/multiply.zig b/src/cpu/arm/multiply.zig index a34f9f1..64fc72e 100644 --- a/src/cpu/arm/multiply.zig +++ b/src/cpu/arm/multiply.zig @@ -24,3 +24,36 @@ pub fn multiply(comptime A: bool, comptime S: bool) InstrFn { } }.inner; } + +pub fn multiplyLong(comptime U: bool, comptime A: bool, comptime S: bool) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { + const rd_hi = opcode >> 16 & 0xF; + const rd_lo = opcode >> 12 & 0xF; + const rs = opcode >> 8 & 0xF; + const rm = opcode & 0xF; + + if (U) { + // Signed (WHY IS IT U THEN?) + var result: i64 = @as(i64, @bitCast(i32, cpu.r[rm])) * @as(i64, @bitCast(i32, cpu.r[rs])); + if (A) result +%= @bitCast(i64, @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo])); + + cpu.r[rd_hi] = @bitCast(u32, @truncate(i32, result >> 32)); + cpu.r[rd_lo] = @bitCast(u32, @truncate(i32, 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]); + + cpu.r[rd_hi] = @truncate(u32, result >> 32); + cpu.r[rd_lo] = @truncate(u32, 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 + } + } + }.inner; +} diff --git a/src/cpu/arm/multiply_long.zig b/src/cpu/arm/multiply_long.zig deleted file mode 100644 index c6de693..0000000 --- a/src/cpu/arm/multiply_long.zig +++ /dev/null @@ -1,38 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ArmInstrFn; - -pub fn multiplyLong(comptime U: bool, comptime A: bool, comptime S: bool) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { - const rd_hi = opcode >> 16 & 0xF; - const rd_lo = opcode >> 12 & 0xF; - const rs = opcode >> 8 & 0xF; - const rm = opcode & 0xF; - - if (U) { - // Signed (WHY IS IT U THEN?) - var result: i64 = @as(i64, @bitCast(i32, cpu.r[rm])) * @as(i64, @bitCast(i32, cpu.r[rs])); - if (A) result +%= @bitCast(i64, @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo])); - - cpu.r[rd_hi] = @bitCast(u32, @truncate(i32, result >> 32)); - cpu.r[rd_lo] = @bitCast(u32, @truncate(i32, 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]); - - cpu.r[rd_hi] = @truncate(u32, result >> 32); - cpu.r[rd_lo] = @truncate(u32, 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 - } - } - }.inner; -} diff --git a/src/cpu/thumb/format4.zig b/src/cpu/thumb/alu.zig similarity index 100% rename from src/cpu/thumb/format4.zig rename to src/cpu/thumb/alu.zig diff --git a/src/cpu/thumb/format14.zig b/src/cpu/thumb/block_data_transfer.zig similarity index 68% rename from src/cpu/thumb/format14.zig rename to src/cpu/thumb/block_data_transfer.zig index 651f882..b239332 100644 --- a/src/cpu/thumb/format14.zig +++ b/src/cpu/thumb/block_data_transfer.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").ThumbInstrFn; @@ -48,3 +46,27 @@ pub fn format14(comptime L: bool, comptime R: bool) InstrFn { } }.inner; } + +pub fn format15(comptime L: bool, comptime rb: u3) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { + const base = cpu.r[rb]; + + var address: u32 = base; + + var i: usize = 0; + while (i < 8) : (i += 1) { + if ((opcode >> @truncate(u3, i)) & 1 == 1) { + if (L) { + cpu.r[i] = bus.read32(address); + } else { + bus.write32(address, cpu.r[i]); + } + address += 4; + } + } + + cpu.r[rb] = address; + } + }.inner; +} diff --git a/src/cpu/thumb/branch.zig b/src/cpu/thumb/branch.zig new file mode 100644 index 0000000..ddcbd05 --- /dev/null +++ b/src/cpu/thumb/branch.zig @@ -0,0 +1,54 @@ +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 { + // B + const offset = u32SignExtend(8, opcode & 0xFF) << 1; + + const should_execute = switch (cond) { + 0xE, 0xF => cpu.panic("[CPU/THUMB] Undefined conditional branch with condition {}", .{cond}), + else => checkCond(cpu.cpsr, cond), + }; + + if (should_execute) { + cpu.r[15] = (cpu.r[15] + 2) +% offset; + } + } + }.inner; +} + +pub fn format18() InstrFn { + return struct { + // B but conditional + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + const offset = u32SignExtend(11, opcode & 0x7FF) << 1; + cpu.r[15] = (cpu.r[15] + 2) +% offset; + } + }.inner; +} + +pub fn format19(comptime is_low: bool) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + // BL + const offset = opcode & 0x7FF; + + if (is_low) { + // Instruction 2 + const old_pc = cpu.r[15]; + + cpu.r[15] = cpu.r[14] + (offset << 1); + cpu.r[14] = old_pc | 1; + } else { + // Instruction 1 + cpu.r[14] = (cpu.r[15] + 2) +% (u32SignExtend(11, @as(u32, offset)) << 12); + } + } + }.inner; +} diff --git a/src/cpu/thumb/data_processing.zig b/src/cpu/thumb/data_processing.zig new file mode 100644 index 0000000..caf59bd --- /dev/null +++ b/src/cpu/thumb/data_processing.zig @@ -0,0 +1,118 @@ +const Bus = @import("../../Bus.zig"); +const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; +const InstrFn = @import("../../cpu.zig").ThumbInstrFn; +const shifter = @import("../barrel_shifter.zig"); + +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 format1(comptime op: u2, comptime offset: u5) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + const rs = opcode >> 3 & 0x7; + const rd = opcode & 0x7; + + const result = switch (op) { + 0b00 => blk: { + // LSL + if (offset == 0) { + break :blk cpu.r[rs]; + } else { + break :blk shifter.logicalLeft(true, &cpu.cpsr, cpu.r[rs], offset); + } + }, + 0b01 => blk: { + // LSR + if (offset == 0) { + cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1); + break :blk @as(u32, 0); + } else { + break :blk shifter.logicalRight(true, &cpu.cpsr, cpu.r[rs], offset); + } + }, + 0b10 => blk: { + // ASR + if (offset == 0) { + cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1); + break :blk @bitCast(u32, @bitCast(i32, cpu.r[rs]) >> 31); + } else { + break :blk shifter.arithmeticRight(true, &cpu.cpsr, cpu.r[rs], offset); + } + }, + else => cpu.panic("[CPU|THUMB|Fmt1] {} is an invalid op", .{op}), + }; + + // Equivalent to an ARM MOVS + cpu.r[rd] = result; + setLogicOpFlags(true, cpu, result); + } + }.inner; +} + +pub fn format2(comptime I: bool, is_sub: bool, rn: u3) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + const rs = opcode >> 3 & 0x7; + const rd = @truncate(u3, opcode); + + if (is_sub) { + // SUB + cpu.r[rd] = if (I) blk: { + break :blk sub(true, cpu, cpu.r[rs], @as(u32, rn)); + } else blk: { + break :blk sub(true, cpu, cpu.r[rs], cpu.r[rn]); + }; + } else { + // ADD + cpu.r[rd] = if (I) blk: { + break :blk add(true, cpu, cpu.r[rs], @as(u32, rn)); + } else blk: { + break :blk add(true, cpu, cpu.r[rs], cpu.r[rn]); + }; + } + } + }.inner; +} + +pub fn format3(comptime op: u2, comptime rd: u3) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + const offset = @truncate(u8, opcode); + + switch (op) { + 0b00 => { + // MOV + cpu.r[rd] = offset; + 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; +} + +pub fn format12(comptime isSP: bool, comptime rd: u3) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + // ADD + const left = if (isSP) cpu.r[13] else (cpu.r[15] + 2) & 0xFFFF_FFFD; + const right = (opcode & 0xFF) << 2; + const result = left + right; // TODO: What about overflows? + cpu.r[rd] = result; + } + }.inner; +} + +pub fn format13(comptime S: bool) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { + // ADD + const offset = (opcode & 0x7F) << 2; + cpu.r[13] = if (S) cpu.r[13] - offset else cpu.r[13] + offset; + } + }.inner; +} diff --git a/src/cpu/thumb/data_transfer.zig b/src/cpu/thumb/data_transfer.zig new file mode 100644 index 0000000..6d09719 --- /dev/null +++ b/src/cpu/thumb/data_transfer.zig @@ -0,0 +1,143 @@ +const std = @import("std"); + +const Bus = @import("../../Bus.zig"); +const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; +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? + cpu.r[rd] = bus.read32((cpu.r[15] + 2 & 0xFFFF_FFFD) + offset); + } + }.inner; +} + +const u32SignExtend = @import("../../util.zig").u32SignExtend; + +pub fn format78(comptime op: u2, comptime T: bool) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { + const ro = opcode >> 6 & 0x7; + const rb = opcode >> 3 & 0x7; + const rd = opcode & 0x7; + + const address = cpu.r[rb] + cpu.r[ro]; + + if (T) { + switch (op) { + 0b00 => { + // STRH + bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd])); + }, + 0b01 => { + // LDRH + const value = bus.read16(address & 0xFFFF_FFFE); + cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); + }, + 0b10 => { + // LDSB + cpu.r[rd] = u32SignExtend(8, @as(u32, bus.read8(address))); + }, + 0b11 => { + // LDSH + cpu.r[rd] = u32SignExtend(16, @as(u32, bus.read16(address & 0xFFFF_FFFE))); + }, + } + } else { + switch (op) { + 0b00 => { + // STR + bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); + }, + 0b01 => { + // STRB + bus.write8(address, @truncate(u8, cpu.r[rd])); + }, + 0b10 => { + // LDR + const value = bus.read32(address & 0xFFFF_FFFC); + cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); + }, + 0b11 => { + // LDRB + cpu.r[rd] = bus.read8(address); + }, + } + } + } + }.inner; +} + +pub fn format9(comptime B: bool, comptime L: bool, comptime offset: u5) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { + const rb = opcode >> 3 & 0x7; + const rd = opcode & 0x7; + + if (L) { + if (B) { + // LDRB + const address = cpu.r[rb] + offset; + cpu.r[rd] = bus.read8(address); + } else { + // LDR + const address = cpu.r[rb] + (@as(u32, offset) << 2); + const value = bus.read32(address & 0xFFFF_FFFC); + cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); + } + } else { + if (B) { + // STRB + const address = cpu.r[rb] + offset; + bus.write8(address, @truncate(u8, cpu.r[rd])); + } else { + // STR + const address = cpu.r[rb] + (@as(u32, offset) << 2); + bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); + } + } + } + }.inner; +} + +pub fn format10(comptime L: bool, comptime offset: u5) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { + const rb = opcode >> 3 & 0x7; + const rd = opcode & 0x7; + + const address = cpu.r[rb] + (offset << 1); + + if (L) { + // LDRH + const value = bus.read16(address & 0xFFFF_FFFE); + cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); + } else { + // STRH + bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd])); + } + } + }.inner; +} + +pub fn format11(comptime L: bool, comptime rd: u3) InstrFn { + return struct { + fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { + const offset = (opcode & 0xFF) << 2; + const address = cpu.r[13] + offset; + + if (L) { + // LDR + const value = bus.read32(address & 0xFFFF_FFFC); + cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); + } else { + // STR + bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); + } + } + }.inner; +} diff --git a/src/cpu/thumb/format1.zig b/src/cpu/thumb/format1.zig deleted file mode 100644 index db24dcd..0000000 --- a/src/cpu/thumb/format1.zig +++ /dev/null @@ -1,51 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -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 { - const rs = opcode >> 3 & 0x7; - const rd = opcode & 0x7; - - const result = switch (op) { - 0b00 => blk: { - // LSL - if (offset == 0) { - break :blk cpu.r[rs]; - } else { - break :blk shifter.logicalLeft(true, &cpu.cpsr, cpu.r[rs], offset); - } - }, - 0b01 => blk: { - // LSR - if (offset == 0) { - cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1); - break :blk @as(u32, 0); - } else { - break :blk shifter.logicalRight(true, &cpu.cpsr, cpu.r[rs], offset); - } - }, - 0b10 => blk: { - // ASR - if (offset == 0) { - cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1); - break :blk @bitCast(u32, @bitCast(i32, cpu.r[rs]) >> 31); - } else { - break :blk shifter.arithmeticRight(true, &cpu.cpsr, cpu.r[rs], offset); - } - }, - else => cpu.panic("[CPU|THUMB|Fmt1] {} is an invalid op", .{op}), - }; - - // Equivalent to an ARM MOVS - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - } - }.inner; -} diff --git a/src/cpu/thumb/format10.zig b/src/cpu/thumb/format10.zig deleted file mode 100644 index d1093ab..0000000 --- a/src/cpu/thumb/format10.zig +++ /dev/null @@ -1,25 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; - -pub fn format10(comptime L: bool, comptime offset: u5) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { - const rb = opcode >> 3 & 0x7; - const rd = opcode & 0x7; - - const address = cpu.r[rb] + (offset << 1); - - if (L) { - // LDRH - const value = bus.read16(address & 0xFFFF_FFFE); - cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); - } else { - // STRH - bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd])); - } - } - }.inner; -} diff --git a/src/cpu/thumb/format11.zig b/src/cpu/thumb/format11.zig deleted file mode 100644 index b17783d..0000000 --- a/src/cpu/thumb/format11.zig +++ /dev/null @@ -1,21 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; - -pub fn format11(comptime L: bool, comptime rd: u3) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { - const offset = (opcode & 0xFF) << 2; - const address = cpu.r[13] + offset; - - if (L) { - const value = bus.read32(address & 0xFFFF_FFFC); - cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); - } else { - bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); - } - } - }.inner; -} diff --git a/src/cpu/thumb/format12.zig b/src/cpu/thumb/format12.zig deleted file mode 100644 index 86df0cc..0000000 --- a/src/cpu/thumb/format12.zig +++ /dev/null @@ -1,17 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -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 { - // ADD - const left = if (isSP) cpu.r[13] else (cpu.r[15] + 2) & 0xFFFF_FFFD; - const right = (opcode & 0xFF) << 2; - const result = left + right; // TODO: What about overflows? - cpu.r[rd] = result; - } - }.inner; -} diff --git a/src/cpu/thumb/format13.zig b/src/cpu/thumb/format13.zig deleted file mode 100644 index ae6c58d..0000000 --- a/src/cpu/thumb/format13.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; - -pub fn format13(comptime S: bool) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { - const offset = (opcode & 0x7F) << 2; - cpu.r[13] = if (S) cpu.r[13] - offset else cpu.r[13] + offset; - } - }.inner; -} diff --git a/src/cpu/thumb/format15.zig b/src/cpu/thumb/format15.zig deleted file mode 100644 index ec7559f..0000000 --- a/src/cpu/thumb/format15.zig +++ /dev/null @@ -1,29 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; - -pub fn format15(comptime L: bool, comptime rb: u3) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { - const base = cpu.r[rb]; - - var address: u32 = base; - - var i: usize = 0; - while (i < 8) : (i += 1) { - if ((opcode >> @truncate(u3, i)) & 1 == 1) { - if (L) { - cpu.r[i] = bus.read32(address); - } else { - bus.write32(address, cpu.r[i]); - } - address += 4; - } - } - - cpu.r[rb] = address; - } - }.inner; -} diff --git a/src/cpu/thumb/format16.zig b/src/cpu/thumb/format16.zig deleted file mode 100644 index 8893ae6..0000000 --- a/src/cpu/thumb/format16.zig +++ /dev/null @@ -1,26 +0,0 @@ -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 { - // B - const offset = u32SignExtend(8, opcode & 0xFF) << 1; - - const should_execute = switch (cond) { - 0xE, 0xF => cpu.panic("[CPU/THUMB] Undefined conditional branch with condition {}", .{cond}), - else => checkCond(cpu.cpsr, cond), - }; - - if (should_execute) { - cpu.r[15] = (cpu.r[15] + 2) +% offset; - } - } - }.inner; -} diff --git a/src/cpu/thumb/format18.zig b/src/cpu/thumb/format18.zig deleted file mode 100644 index e8a3139..0000000 --- a/src/cpu/thumb/format18.zig +++ /dev/null @@ -1,15 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; -const u32SignExtend = @import("../../util.zig").u32SignExtend; - -pub fn format18() InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { - const offset = u32SignExtend(11, opcode & 0x7FF) << 1; - cpu.r[15] = (cpu.r[15] + 2) +% offset; - } - }.inner; -} diff --git a/src/cpu/thumb/format19.zig b/src/cpu/thumb/format19.zig deleted file mode 100644 index 4fc5513..0000000 --- a/src/cpu/thumb/format19.zig +++ /dev/null @@ -1,26 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; -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 & 0x7FF; - - if (is_low) { - // Instruction 2 - const old_pc = cpu.r[15]; - - cpu.r[15] = cpu.r[14] + (offset << 1); - cpu.r[14] = old_pc | 1; - } else { - // Instruction 1 - cpu.r[14] = (cpu.r[15] + 2) +% (u32SignExtend(11, @as(u32, offset)) << 12); - } - } - }.inner; -} diff --git a/src/cpu/thumb/format2.zig b/src/cpu/thumb/format2.zig deleted file mode 100644 index 9d87f87..0000000 --- a/src/cpu/thumb/format2.zig +++ /dev/null @@ -1,33 +0,0 @@ -const std = @import("std"); - -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; - -pub fn format2(comptime I: bool, is_sub: bool, rn: u3) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void { - const rs = opcode >> 3 & 0x7; - const rd = @truncate(u3, opcode); - - if (is_sub) { - // SUB - cpu.r[rd] = if (I) blk: { - break :blk sub(true, cpu, cpu.r[rs], @as(u32, rn)); - } else blk: { - break :blk sub(true, cpu, cpu.r[rs], cpu.r[rn]); - }; - } else { - // ADD - cpu.r[rd] = if (I) blk: { - break :blk add(true, cpu, cpu.r[rs], @as(u32, rn)); - } else blk: { - break :blk add(true, cpu, cpu.r[rs], cpu.r[rn]); - }; - } - } - }.inner; -} diff --git a/src/cpu/thumb/format3.zig b/src/cpu/thumb/format3.zig deleted file mode 100644 index 0602afc..0000000 --- a/src/cpu/thumb/format3.zig +++ /dev/null @@ -1,29 +0,0 @@ -const std = @import("std"); - -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 { - const offset = @truncate(u8, opcode); - - switch (op) { - 0b00 => { - // MOV - cpu.r[rd] = offset; - 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/format6.zig b/src/cpu/thumb/format6.zig deleted file mode 100644 index 27e24f2..0000000 --- a/src/cpu/thumb/format6.zig +++ /dev/null @@ -1,17 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -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? - cpu.r[rd] = bus.read32((cpu.r[15] + 2 & 0xFFFF_FFFD) + offset); - } - }.inner; -} diff --git a/src/cpu/thumb/format78.zig b/src/cpu/thumb/format78.zig deleted file mode 100644 index 7eae426..0000000 --- a/src/cpu/thumb/format78.zig +++ /dev/null @@ -1,60 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; -const u32SignExtend = @import("../../util.zig").u32SignExtend; - -pub fn format78(comptime op: u2, comptime T: bool) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { - const ro = opcode >> 6 & 0x7; - const rb = opcode >> 3 & 0x7; - const rd = opcode & 0x7; - - const address = cpu.r[rb] + cpu.r[ro]; - - if (T) { - switch (op) { - 0b00 => { - // STRH - bus.write16(address & 0xFFFF_FFFE, @truncate(u16, cpu.r[rd])); - }, - 0b01 => { - // LDRH - const value = bus.read16(address & 0xFFFF_FFFE); - cpu.r[rd] = std.math.rotr(u32, @as(u32, value), 8 * (address & 1)); - }, - 0b10 => { - // LDSB - cpu.r[rd] = u32SignExtend(8, @as(u32, bus.read8(address))); - }, - 0b11 => { - // LDSH - cpu.r[rd] = u32SignExtend(16, @as(u32, bus.read16(address & 0xFFFF_FFFE))); - }, - } - } else { - switch (op) { - 0b00 => { - // STR - bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); - }, - 0b01 => { - // STRB - bus.write8(address, @truncate(u8, cpu.r[rd])); - }, - 0b10 => { - // LDR - const value = bus.read32(address & 0xFFFF_FFFC); - cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); - }, - 0b11 => { - // LDRB - cpu.r[rd] = bus.read8(address); - }, - } - } - } - }.inner; -} diff --git a/src/cpu/thumb/format9.zig b/src/cpu/thumb/format9.zig deleted file mode 100644 index fb772ad..0000000 --- a/src/cpu/thumb/format9.zig +++ /dev/null @@ -1,37 +0,0 @@ -const std = @import("std"); - -const Bus = @import("../../Bus.zig"); -const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; -const InstrFn = @import("../../cpu.zig").ThumbInstrFn; - -pub fn format9(comptime B: bool, comptime L: bool, comptime offset: u5) InstrFn { - return struct { - fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void { - const rb = opcode >> 3 & 0x7; - const rd = opcode & 0x7; - - if (L) { - if (B) { - // LDRB - const address = cpu.r[rb] + offset; - cpu.r[rd] = bus.read8(address); - } else { - // LDR - const address = cpu.r[rb] + (@as(u32, offset) << 2); - const value = bus.read32(address & 0xFFFF_FFFC); - cpu.r[rd] = std.math.rotr(u32, value, 8 * (address & 0x3)); - } - } else { - if (B) { - // STRB - const address = cpu.r[rb] + offset; - bus.write8(address, @truncate(u8, cpu.r[rd])); - } else { - // STR - const address = cpu.r[rb] + (@as(u32, offset) << 2); - bus.write32(address & 0xFFFF_FFFC, cpu.r[rd]); - } - } - } - }.inner; -} diff --git a/src/cpu/thumb/format5.zig b/src/cpu/thumb/processing_branch.zig similarity index 100% rename from src/cpu/thumb/format5.zig rename to src/cpu/thumb/processing_branch.zig diff --git a/src/cpu/thumb/format17.zig b/src/cpu/thumb/software_interrupt.zig similarity index 96% rename from src/cpu/thumb/format17.zig rename to src/cpu/thumb/software_interrupt.zig index 6400ca2..ada29c0 100644 --- a/src/cpu/thumb/format17.zig +++ b/src/cpu/thumb/software_interrupt.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").ThumbInstrFn;