diff --git a/.gitignore b/.gitignore index 4b1d77a..c1f9720 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /bin /zig-cache /zig-out +/docs +**/*.log \ No newline at end of file diff --git a/src/cpu.zig b/src/cpu.zig index d3bb169..02b7718 100644 --- a/src/cpu.zig +++ b/src/cpu.zig @@ -2,8 +2,10 @@ const std = @import("std"); const util = @import("util.zig"); const bitfield = @import("bitfield"); +const BarrelShifter = @import("cpu/barrel_shifter.zig"); const Bus = @import("bus.zig").Bus; const Scheduler = @import("scheduler.zig").Scheduler; + const Bitfield = bitfield.Bitfield; const Bit = bitfield.Bit; @@ -160,7 +162,7 @@ fn populate() [0x1000]InstrFn { }; } -const CPSR = extern union { +pub const CPSR = extern union { mode: Bitfield(u32, 0, 5), t: Bit(u32, 5), f: Bit(u32, 6), diff --git a/src/cpu/barrel_shifter.zig b/src/cpu/barrel_shifter.zig new file mode 100644 index 0000000..1e8c9fb --- /dev/null +++ b/src/cpu/barrel_shifter.zig @@ -0,0 +1,83 @@ +const std = @import("std"); + +const arm = @import("../cpu.zig"); +const Arm7tdmi = arm.Arm7tdmi; +const CPSR = arm.CPSR; + +pub inline fn exec(cpu: *Arm7tdmi, opcode: u32) u32 { + var shift_amt: u8 = undefined; + if (opcode >> 4 & 1 == 1) { + shift_amt = @truncate(u8, cpu.r[opcode >> 8 & 0xF]); + } else { + shift_amt = @truncate(u8, opcode >> 7 & 0x1F); + } + + const rm = cpu.r[opcode & 0xF]; + + return switch (@truncate(u2, opcode >> 5)) { + 0b00 => logical_left(&cpu.cpsr, rm, shift_amt), + 0b01 => logical_right(&cpu.cpsr, rm, shift_amt), + 0b10 => arithmetic_right(&cpu.cpsr, rm, shift_amt), + 0b11 => rotate_right(&cpu.cpsr, rm, shift_amt), + }; +} + +pub inline fn logical_left(cpsr: *CPSR, rm: u32, shift_byte: u8) u32 { + const shift_amt = @truncate(u5, shift_byte); + const bit_count: u8 = @typeInfo(u32).Int.bits; + + var result: u32 = 0x0000_0000; + + if (shift_byte < bit_count) { + // We can perform a well-defined shift here + + // FIXME: We assume cpu.r[rs] == 0 and imm_shift == 0 are equivalent + if (shift_amt != 0) { + const carry_bit = @truncate(u5, bit_count - shift_amt); + cpsr.c.write(rm >> carry_bit & 1 == 1); + } + + result = rm << shift_amt; + } else if (shift_byte == bit_count) { + // Shifted all bits out, carry bit is bit 0 of rm + cpsr.c.write(rm & 1 == 1); + } else { + // Shifted all bits out, carry bit has also been shifted out + cpsr.c.write(false); + } + + return result; +} + +pub inline fn logical_right(cpsr: *CPSR, rm: u32, shift_byte: u8) u32 { + const shift_amt = @truncate(u5, shift_byte); + const bit_count: u8 = @typeInfo(u32).Int.bits; + + var result: u32 = 0x0000_0000; + + if (shift_byte == 0 or shift_byte == bit_count) { + // Actualy LSR #32 + cpsr.c.write(rm >> 31 & 1 == 1); + } else if (shift_byte < bit_count) { + // We can perform a well-defined shift + const carry_bit = shift_amt - 1; + cpsr.c.write(rm >> carry_bit & 1 == 1); + + result = rm >> shift_amt; + } else { + // All bits have been shifted out, including carry bit + cpsr.c.write(false); + } + + return result; +} + +pub fn arithmetic_right(_: *CPSR, _: u32, _: u8) u32 { + // @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)) + std.debug.panic("[BarrelShifter] implement arithmetic shift right", .{}); +} + +pub fn rotate_right(_: *CPSR, _: u32, _: u8) u32 { + // std.math.rotr(u32, r_val, amount) + std.debug.panic("[BarrelShifter] implement rotate right", .{}); +} diff --git a/src/cpu/data_processing.zig b/src/cpu/data_processing.zig index 4bfcb9d..1f73716 100644 --- a/src/cpu/data_processing.zig +++ b/src/cpu/data_processing.zig @@ -1,9 +1,10 @@ const std = @import("std"); -const processor = @import("../cpu.zig"); +const arm = @import("../cpu.zig"); +const BarrelShifter = @import("barrel_shifter.zig"); const Bus = @import("../bus.zig").Bus; -const Arm7tdmi = processor.Arm7tdmi; -const InstrFn = processor.InstrFn; +const Arm7tdmi = arm.Arm7tdmi; +const InstrFn = arm.InstrFn; pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instrKind: u4) InstrFn { return struct { @@ -15,7 +16,7 @@ pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instr if (I) { op2 = std.math.rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) << 1); } else { - op2 = registerOp2(cpu, opcode); + op2 = BarrelShifter.exec(cpu, opcode); } switch (instrKind) { @@ -45,7 +46,7 @@ pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instr cpu.cpsr.n.write(result >> 31 & 1 == 1); cpu.cpsr.z.write(result == 0); cpu.cpsr.c.write(op2 <= op1_val); - cpu.cpsr.v.write(v_ctx and (result >> 31 & 1== 1)); + cpu.cpsr.v.write(v_ctx and (result >> 31 & 1 == 1)); }, else => std.debug.panic("[CPU] TODO: implement data processing type {}", .{instrKind}), } @@ -53,22 +54,22 @@ pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instr }.dataProcessing; } -fn registerOp2(cpu: *const Arm7tdmi, opcode: u32) u32 { - var amount: u32 = undefined; - if (opcode >> 4 & 0x01 == 0x01) { - amount = cpu.r[opcode >> 8 & 0xF] & 0xFF; - } else { - amount = opcode >> 7 & 0x1F; - } +// fn registerOp2(cpu: *const Arm7tdmi, opcode: u32) u32 { +// var amount: u32 = undefined; +// if (opcode >> 4 & 0x01 == 0x01) { +// amount = cpu.r[opcode >> 8 & 0xF] & 0xFF; +// } else { +// amount = opcode >> 7 & 0x1F; +// } - const rm = opcode & 0xF; - const r_val = cpu.r[rm]; +// const rm = opcode & 0xF; +// const r_val = cpu.r[rm]; - return switch (opcode >> 5 & 0x03) { - 0b00 => r_val << @truncate(u5, amount), - 0b01 => r_val >> @truncate(u5, amount), - 0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)), - 0b11 => std.math.rotr(u32, r_val, amount), - else => unreachable, - }; -} +// return switch (opcode >> 5 & 0x03) { +// 0b00 => r_val << @truncate(u5, amount), +// 0b01 => r_val >> @truncate(u5, amount), +// 0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)), +// 0b11 => std.math.rotr(u32, r_val, amount), +// else => unreachable, +// }; +// } diff --git a/src/cpu/half_signed_data_transfer.zig b/src/cpu/half_signed_data_transfer.zig index 7adfb2a..23814fc 100644 --- a/src/cpu/half_signed_data_transfer.zig +++ b/src/cpu/half_signed_data_transfer.zig @@ -1,10 +1,10 @@ const std = @import("std"); -const processor = @import("../cpu.zig"); +const arm = @import("../cpu.zig"); const util = @import("../util.zig"); const Bus = @import("../bus.zig").Bus; -const Arm7tdmi = processor.Arm7tdmi; -const InstrFn = processor.InstrFn; +const Arm7tdmi = arm.Arm7tdmi; +const InstrFn = arm.InstrFn; pub fn comptimeHalfSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn { return struct { diff --git a/src/cpu/single_data_transfer.zig b/src/cpu/single_data_transfer.zig index acef639..c30bb00 100644 --- a/src/cpu/single_data_transfer.zig +++ b/src/cpu/single_data_transfer.zig @@ -1,10 +1,11 @@ const std = @import("std"); const util = @import("../util.zig"); -const processor = @import("../cpu.zig"); +const arm = @import("../cpu.zig"); +const BarrelShifter = @import("barrel_shifter.zig"); const Bus = @import("../bus.zig").Bus; -const Arm7tdmi = processor.Arm7tdmi; -const InstrFn = processor.InstrFn; +const Arm7tdmi = arm.Arm7tdmi; +const InstrFn = arm.InstrFn; pub fn comptimeSingleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn { return struct { @@ -48,15 +49,14 @@ pub fn comptimeSingleDataTransfer(comptime I: bool, comptime P: bool, comptime U } fn registerOffset(cpu: *Arm7tdmi, opcode: u32) u32 { - const amount = opcode >> 7 & 0x1F; - const rm = opcode & 0xF; - const r_val = cpu.r[rm]; + const shift_byte = @truncate(u8, opcode >> 7 & 0x1F); - return switch (opcode >> 5 & 0x03) { - 0b00 => r_val << @truncate(u5, amount), - 0b01 => r_val >> @truncate(u5, amount), - 0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)), - 0b11 => std.math.rotr(u32, r_val, amount), - else => unreachable, + const rm = cpu.r[opcode & 0xF]; + + return switch (@truncate(u2, opcode >> 5)) { + 0b00 => BarrelShifter.logical_left(&cpu.cpsr, rm, shift_byte), + 0b01 => BarrelShifter.logical_right(&cpu.cpsr, rm, shift_byte), + 0b10 => BarrelShifter.arithmetic_right(&cpu.cpsr, rm, shift_byte), + 0b11 => BarrelShifter.rotate_right(&cpu.cpsr, rm, shift_byte), }; }