chore: drop *Bus argument from the InstrFn LUT
This commit is contained in:
parent
f31c4bdb65
commit
ba22b856ec
19
src/arm.zig
19
src/arm.zig
|
@ -50,6 +50,7 @@ pub fn Arm32(comptime arch: Architecture) type {
|
|||
.v5te => @import("arm/v5te.zig").thumb,
|
||||
};
|
||||
|
||||
// FIXME: What about .v5te?
|
||||
const Pipeline = struct {
|
||||
stage: [2]?u32,
|
||||
flushed: bool,
|
||||
|
@ -147,7 +148,7 @@ pub fn Arm32(comptime arch: Architecture) type {
|
|||
};
|
||||
|
||||
pub fn init(scheduler: Scheduler, bus: Bus) Self {
|
||||
return Self{
|
||||
return .{
|
||||
.sched = scheduler,
|
||||
.bus = bus,
|
||||
.cpsr = .{ .raw = 0x0000_001F },
|
||||
|
@ -155,6 +156,16 @@ pub fn Arm32(comptime arch: Architecture) type {
|
|||
};
|
||||
}
|
||||
|
||||
// CPU needs it's own read/write fns due to ICTM and DCTM present in v5te
|
||||
// I considered implementing Bus.cpu_read and Bus.cpu_write but ended up considering that a bit too leaky
|
||||
pub fn read(self: *Self, comptime T: type, address: u32) T {
|
||||
return self.bus.read(T, address);
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, comptime T: type, address: u32, value: T) void {
|
||||
return self.bus.write(T, address, value);
|
||||
}
|
||||
|
||||
// FIXME: Resetting disables logging (if enabled)
|
||||
pub fn reset(self: *Self) void {
|
||||
self.* = .{
|
||||
|
@ -276,12 +287,12 @@ pub fn Arm32(comptime arch: Architecture) type {
|
|||
|
||||
if (self.cpsr.t.read()) {
|
||||
const opcode: u16 = @truncate(self.pipe.step(self, u16) orelse return);
|
||||
thumb.lut[thumb.idx(opcode)](self, self.bus, opcode);
|
||||
thumb.lut[thumb.idx(opcode)](self, opcode);
|
||||
} else {
|
||||
const opcode = self.pipe.step(self, u32) orelse return;
|
||||
|
||||
if (self.cpsr.check(@truncate(opcode >> 28))) {
|
||||
arm.lut[arm.idx(opcode)](self, self.bus, opcode);
|
||||
arm.lut[arm.idx(opcode)](self, opcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,7 +309,7 @@ pub fn Arm32(comptime arch: Architecture) type {
|
|||
// const tick_cache = self.sched.tick;
|
||||
// defer self.sched.tick = tick_cache + Bus.fetch_timings[@boolToInt(T == u32)][@truncate(u4, address >> 24)];
|
||||
|
||||
return self.bus.read(T, address);
|
||||
return self.read(T, address);
|
||||
}
|
||||
|
||||
pub fn panic(self: *const Self, comptime format: []const u8, args: anytype) noreturn {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: bool, comptime S: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rn: u4 = @truncate(opcode >> 16 & 0xF);
|
||||
const rlist = opcode & 0xFFFF;
|
||||
const r15 = rlist >> 15 & 1 == 1;
|
||||
|
@ -54,10 +52,10 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
|||
}
|
||||
|
||||
if (L) {
|
||||
cpu.r[15] = bus.read(u32, und_addr);
|
||||
cpu.r[15] = cpu.read(u32, und_addr);
|
||||
cpu.pipe.reload(cpu);
|
||||
} else {
|
||||
bus.write(u32, und_addr, cpu.r[15] + 4);
|
||||
cpu.write(u32, und_addr, cpu.r[15] + 4);
|
||||
}
|
||||
|
||||
cpu.r[rn] = if (U) cpu.r[rn] + 0x40 else cpu.r[rn] - 0x40;
|
||||
|
@ -67,7 +65,7 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
|||
i = first;
|
||||
while (i < 16) : (i += 1) {
|
||||
if (rlist >> i & 1 == 1) {
|
||||
transfer(cpu, bus, r15, i, address);
|
||||
transfer(cpu, r15, i, address);
|
||||
address += 4;
|
||||
|
||||
if (W and !L and write_to_base) {
|
||||
|
@ -80,13 +78,13 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
|||
if (W and L and rlist >> rn & 1 == 0) cpu.r[rn] = new_base;
|
||||
}
|
||||
|
||||
fn transfer(cpu: Arm32, bus: Bus, r15_present: bool, i: u5, address: u32) void {
|
||||
fn transfer(cpu: Arm32, r15_present: bool, i: u5, address: u32) void {
|
||||
if (L) {
|
||||
if (S and !r15_present) {
|
||||
// Always Transfer User mode Registers
|
||||
cpu.setUserModeRegister(i, bus.read(u32, address));
|
||||
cpu.setUserModeRegister(i, cpu.read(u32, address));
|
||||
} else {
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
|
||||
cpu.r[i] = value;
|
||||
if (i == 0xF) {
|
||||
|
@ -101,9 +99,9 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
|||
// Always Transfer User mode Registers
|
||||
// This happens regardless if r15 is in the list
|
||||
const value = cpu.getUserModeRegister(i);
|
||||
bus.write(u32, address, value + if (i == 0xF) 4 else @as(u32, 0)); // PC is already 8 ahead to make 12
|
||||
cpu.write(u32, address, value + if (i == 0xF) 4 else @as(u32, 0)); // PC is already 8 ahead to make 12
|
||||
} else {
|
||||
bus.write(u32, address, cpu.r[i] + if (i == 0xF) 4 else @as(u32, 0));
|
||||
cpu.write(u32, address, cpu.r[i] + if (i == 0xF) 4 else @as(u32, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
const sext = @import("zba-util").sext;
|
||||
|
||||
pub fn branch(comptime InstrFn: type, comptime L: bool) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
if (L) cpu.r[14] = cpu.r[15] - 4;
|
||||
|
||||
cpu.r[15] +%= sext(u32, u24, opcode) << 2;
|
||||
|
@ -18,7 +17,7 @@ pub fn branchAndExchange(comptime InstrFn: type) InstrFn {
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
pub fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
pub fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rn = opcode & 0xF;
|
||||
|
||||
const thumb = cpu.r[rn] & 1 == 1;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const std = @import("std");
|
||||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const log = std.log.scoped(.coprocessor_handler);
|
||||
|
||||
|
@ -12,7 +11,7 @@ pub fn dataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: bool,
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
|
||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor data transfer instr", .{opcode});
|
||||
|
@ -27,7 +26,7 @@ pub fn registerTransfer(comptime InstrFn: type, comptime opcode1: u3, comptime L
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
|
||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor register transfer instr", .{opcode});
|
||||
|
@ -41,7 +40,7 @@ pub fn dataProcessing(comptime InstrFn: type, comptime opcode1: u4, comptime opc
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
|
||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor data processing instr", .{opcode});
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const exec = @import("../barrel_shifter.zig").exec;
|
||||
const ror = @import("../barrel_shifter.zig").ror;
|
||||
|
||||
|
@ -7,7 +5,7 @@ pub fn dataProcessing(comptime InstrFn: type, comptime I: bool, comptime S: bool
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rd: u4 = @truncate(opcode >> 12 & 0xF);
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const old_carry = @intFromBool(cpu.cpsr.c.read());
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const sext = @import("zba-util").sext;
|
||||
const rotr = @import("zba-util").rotr;
|
||||
|
||||
|
@ -7,7 +5,7 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const rd = opcode >> 12 & 0xF;
|
||||
const rm = opcode & 0xF;
|
||||
|
@ -24,16 +22,16 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
|||
switch (@as(u2, @truncate(opcode >> 5))) {
|
||||
0b01 => {
|
||||
// LDRH
|
||||
const value = bus.read(u16, address);
|
||||
const value = cpu.read(u16, address);
|
||||
result = rotr(u32, value, 8 * (address & 1));
|
||||
},
|
||||
0b10 => {
|
||||
// LDRSB
|
||||
result = sext(u32, u8, bus.read(u8, address));
|
||||
result = sext(u32, u8, cpu.read(u8, address));
|
||||
},
|
||||
0b11 => {
|
||||
// LDRSH
|
||||
const value = bus.read(u16, address);
|
||||
const value = cpu.read(u16, address);
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
result = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||
|
@ -45,7 +43,7 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
|||
// STRH
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
} else unreachable; // SWP
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
pub fn multiply(comptime InstrFn: type, comptime A: bool, comptime S: bool) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rd = opcode >> 16 & 0xF;
|
||||
const rn = opcode >> 12 & 0xF;
|
||||
const rs = opcode >> 8 & 0xF;
|
||||
|
@ -27,7 +25,7 @@ pub fn multiplyLong(comptime InstrFn: type, comptime U: bool, comptime A: bool,
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rd_hi = opcode >> 16 & 0xF;
|
||||
const rd_lo = opcode >> 12 & 0xF;
|
||||
const rs = opcode >> 8 & 0xF;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
const std = @import("std");
|
||||
|
||||
const Bus = @import("../../../lib.zig").Bus;
|
||||
const PSR = @import("../../../arm.zig").PSR;
|
||||
|
||||
const log = std.log.scoped(.PsrTransfer);
|
||||
|
@ -11,7 +10,7 @@ pub fn psrTransfer(comptime InstrFn: type, comptime I: bool, comptime R: bool, c
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
switch (kind) {
|
||||
0b00 => {
|
||||
// MRS
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const rotr = @import("zba-util").rotr;
|
||||
|
||||
pub fn singleDataSwap(comptime InstrFn: type, comptime B: bool) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const rd = opcode >> 12 & 0xF;
|
||||
const rm = opcode & 0xF;
|
||||
|
@ -15,15 +13,15 @@ pub fn singleDataSwap(comptime InstrFn: type, comptime B: bool) InstrFn {
|
|||
|
||||
if (B) {
|
||||
// SWPB
|
||||
const value = bus.read(u8, address);
|
||||
const value = cpu.read(u8, address);
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u8, address, @as(u8, @truncate(cpu.r[rm])));
|
||||
cpu.write(u8, address, @as(u8, @truncate(cpu.r[rm])));
|
||||
cpu.r[rd] = value;
|
||||
} else {
|
||||
// SWP
|
||||
const value = rotr(u32, bus.read(u32, address), 8 * (address & 0x3));
|
||||
bus.write(u32, address, cpu.r[rm]);
|
||||
const value = rotr(u32, cpu.read(u32, address), 8 * (address & 0x3));
|
||||
cpu.write(u32, address, cpu.r[rm]);
|
||||
cpu.r[rd] = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const shifter = @import("../barrel_shifter.zig");
|
||||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const rotr = @import("zba-util").rotr;
|
||||
|
||||
|
@ -7,7 +6,7 @@ pub fn singleDataTransfer(comptime InstrFn: type, comptime I: bool, comptime P:
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
||||
fn inner(cpu: Arm32, opcode: u32) void {
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const rd = opcode >> 12 & 0xF;
|
||||
|
||||
|
@ -21,10 +20,10 @@ pub fn singleDataTransfer(comptime InstrFn: type, comptime I: bool, comptime P:
|
|||
if (L) {
|
||||
if (B) {
|
||||
// LDRB
|
||||
result = bus.read(u8, address);
|
||||
result = cpu.read(u8, address);
|
||||
} else {
|
||||
// LDR
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
result = rotr(u32, value, 8 * (address & 0x3));
|
||||
}
|
||||
} else {
|
||||
|
@ -33,11 +32,11 @@ pub fn singleDataTransfer(comptime InstrFn: type, comptime I: bool, comptime P:
|
|||
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0); // PC is 12 ahead
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u8, address, @as(u8, @truncate(value)));
|
||||
cpu.write(u8, address, @as(u8, @truncate(value)));
|
||||
} else {
|
||||
// STR
|
||||
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0);
|
||||
bus.write(u32, address, value);
|
||||
cpu.write(u32, address, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
pub fn armSoftwareInterrupt(comptime InstrFn: type) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, _: u32) void {
|
||||
fn inner(cpu: Arm32, _: u32) void {
|
||||
// Copy Values from Current Mode
|
||||
const ret_addr = cpu.r[15] - 4;
|
||||
const cpsr = cpu.cpsr.raw;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const adc = @import("../arm/data_processing.zig").adc;
|
||||
const sbc = @import("../arm/data_processing.zig").sbc;
|
||||
|
||||
|
@ -12,7 +10,7 @@ pub fn fmt4(comptime InstrFn: type, comptime op: u4) InstrFn {
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rs = opcode >> 3 & 0x7;
|
||||
const rd = opcode & 0x7;
|
||||
const carry = @intFromBool(cpu.cpsr.c.read());
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
pub fn fmt14(comptime InstrFn: type, comptime L: bool, comptime R: bool) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const count = @intFromBool(R) + countRlist(opcode);
|
||||
const start = cpu.r[13] - if (!L) count * 4 else 0;
|
||||
|
||||
|
@ -21,9 +19,9 @@ pub fn fmt14(comptime InstrFn: type, comptime L: bool, comptime R: bool) InstrFn
|
|||
while (i < 8) : (i += 1) {
|
||||
if (opcode >> i & 1 == 1) {
|
||||
if (L) {
|
||||
cpu.r[i] = bus.read(u32, address);
|
||||
cpu.r[i] = cpu.read(u32, address);
|
||||
} else {
|
||||
bus.write(u32, address, cpu.r[i]);
|
||||
cpu.write(u32, address, cpu.r[i]);
|
||||
}
|
||||
|
||||
address += 4;
|
||||
|
@ -32,11 +30,11 @@ pub fn fmt14(comptime InstrFn: type, comptime L: bool, comptime R: bool) InstrFn
|
|||
|
||||
if (R) {
|
||||
if (L) {
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
cpu.r[15] = value & ~@as(u32, 1);
|
||||
cpu.pipe.reload(cpu);
|
||||
} else {
|
||||
bus.write(u32, address, cpu.r[14]);
|
||||
cpu.write(u32, address, cpu.r[14]);
|
||||
}
|
||||
address += 4;
|
||||
}
|
||||
|
@ -50,16 +48,16 @@ pub fn fmt15(comptime InstrFn: type, comptime L: bool, comptime rb: u3) InstrFn
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
var address = cpu.r[rb];
|
||||
const end_address = cpu.r[rb] + 4 * countRlist(opcode);
|
||||
|
||||
if (opcode & 0xFF == 0) {
|
||||
if (L) {
|
||||
cpu.r[15] = bus.read(u32, address);
|
||||
cpu.r[15] = cpu.read(u32, address);
|
||||
cpu.pipe.reload(cpu);
|
||||
} else {
|
||||
bus.write(u32, address, cpu.r[15] + 2);
|
||||
cpu.write(u32, address, cpu.r[15] + 2);
|
||||
}
|
||||
|
||||
cpu.r[rb] += 0x40;
|
||||
|
@ -72,9 +70,9 @@ pub fn fmt15(comptime InstrFn: type, comptime L: bool, comptime rb: u3) InstrFn
|
|||
while (i < 8) : (i += 1) {
|
||||
if (opcode >> i & 1 == 1) {
|
||||
if (L) {
|
||||
cpu.r[i] = bus.read(u32, address);
|
||||
cpu.r[i] = cpu.read(u32, address);
|
||||
} else {
|
||||
bus.write(u32, address, cpu.r[i]);
|
||||
cpu.write(u32, address, cpu.r[i]);
|
||||
}
|
||||
|
||||
if (!L and first_write) {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
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 {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
// B
|
||||
if (cond == 0xE or cond == 0xF)
|
||||
cpu.panic("[CPU/THUMB.16] Undefined conditional branch with condition {}", .{cond});
|
||||
|
@ -24,7 +22,7 @@ pub fn fmt18(comptime InstrFn: type) InstrFn {
|
|||
|
||||
return struct {
|
||||
// B but conditional
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
cpu.r[15] +%= sext(u32, u11, opcode & 0x7FF) << 1;
|
||||
cpu.pipe.reload(cpu);
|
||||
}
|
||||
|
@ -35,7 +33,7 @@ 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 {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
// BL
|
||||
const offset = opcode & 0x7FF;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const add = @import("../arm/data_processing.zig").add;
|
||||
|
||||
const lsl = @import("../barrel_shifter.zig").lsl;
|
||||
|
@ -10,7 +8,7 @@ pub fn fmt1(comptime InstrFn: type, comptime op: u2, comptime offset: u5) InstrF
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rs = opcode >> 3 & 0x7;
|
||||
const rd = opcode & 0x7;
|
||||
|
||||
|
@ -58,7 +56,7 @@ pub fn fmt5(comptime InstrFn: type, comptime op: u2, comptime h1: u1, comptime h
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rs = @as(u4, h2) << 3 | (opcode >> 3 & 0x7);
|
||||
const rd = @as(u4, h1) << 3 | (opcode & 0x7);
|
||||
|
||||
|
@ -113,7 +111,7 @@ pub fn fmt2(comptime InstrFn: type, comptime I: bool, is_sub: bool, rn: u3) Inst
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rs = opcode >> 3 & 0x7;
|
||||
const rd: u3 = @truncate(opcode);
|
||||
const op1 = cpu.r[rs];
|
||||
|
@ -147,7 +145,7 @@ pub fn fmt3(comptime InstrFn: type, comptime op: u2, comptime rd: u3) InstrFn {
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const op1 = cpu.r[rd];
|
||||
const op2: u32 = opcode & 0xFF; // Offset
|
||||
|
||||
|
@ -187,7 +185,7 @@ pub fn fmt12(comptime InstrFn: type, comptime isSP: bool, comptime rd: u3) Instr
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
// ADD
|
||||
const left = if (isSP) cpu.r[13] else cpu.r[15] & ~@as(u32, 2);
|
||||
const right = (opcode & 0xFF) << 2;
|
||||
|
@ -200,7 +198,7 @@ pub fn fmt13(comptime InstrFn: type, comptime S: bool) InstrFn {
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
// ADD
|
||||
const offset = (opcode & 0x7F) << 2;
|
||||
cpu.r[13] = if (S) cpu.r[13] - offset else cpu.r[13] + offset;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
const rotr = @import("zba-util").rotr;
|
||||
const sext = @import("zba-util").sext;
|
||||
|
||||
|
@ -7,12 +5,12 @@ pub fn fmt6(comptime InstrFn: type, comptime rd: u3) InstrFn {
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
// LDR
|
||||
const offset = (opcode & 0xFF) << 2;
|
||||
|
||||
// Bit 1 of the PC intentionally ignored
|
||||
cpu.r[rd] = bus.read(u32, (cpu.r[15] & ~@as(u32, 2)) + offset);
|
||||
cpu.r[rd] = cpu.read(u32, (cpu.r[15] & ~@as(u32, 2)) + offset);
|
||||
}
|
||||
}.inner;
|
||||
}
|
||||
|
@ -21,7 +19,7 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const ro = opcode >> 6 & 0x7;
|
||||
const rb = opcode >> 3 & 0x7;
|
||||
const rd = opcode & 0x7;
|
||||
|
@ -35,20 +33,20 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
|||
// STRH
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
},
|
||||
0b01 => {
|
||||
// LDSB
|
||||
cpu.r[rd] = sext(u32, u8, bus.read(u8, address));
|
||||
cpu.r[rd] = sext(u32, u8, cpu.read(u8, address));
|
||||
},
|
||||
0b10 => {
|
||||
// LDRH
|
||||
const value = bus.read(u16, address);
|
||||
const value = cpu.read(u16, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
||||
},
|
||||
0b11 => {
|
||||
// LDRSH
|
||||
const value = bus.read(u16, address);
|
||||
const value = cpu.read(u16, address);
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
cpu.r[rd] = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||
|
@ -59,22 +57,22 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
|||
switch (op) {
|
||||
0b00 => {
|
||||
// STR
|
||||
bus.write(u32, address, cpu.r[rd]);
|
||||
cpu.write(u32, address, cpu.r[rd]);
|
||||
},
|
||||
0b01 => {
|
||||
// STRB
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||
cpu.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||
},
|
||||
0b10 => {
|
||||
// LDR
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 0x3));
|
||||
},
|
||||
0b11 => {
|
||||
// LDRB
|
||||
cpu.r[rd] = bus.read(u8, address);
|
||||
cpu.r[rd] = cpu.read(u8, address);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +84,7 @@ pub fn fmt9(comptime InstrFn: type, comptime B: bool, comptime L: bool, comptime
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rb = opcode >> 3 & 0x7;
|
||||
const rd = opcode & 0x7;
|
||||
|
||||
|
@ -94,11 +92,11 @@ pub fn fmt9(comptime InstrFn: type, comptime B: bool, comptime L: bool, comptime
|
|||
if (B) {
|
||||
// LDRB
|
||||
const address = cpu.r[rb] + offset;
|
||||
cpu.r[rd] = bus.read(u8, address);
|
||||
cpu.r[rd] = cpu.read(u8, address);
|
||||
} else {
|
||||
// LDR
|
||||
const address = cpu.r[rb] + (@as(u32, offset) << 2);
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 0x3));
|
||||
}
|
||||
} else {
|
||||
|
@ -107,11 +105,11 @@ pub fn fmt9(comptime InstrFn: type, comptime B: bool, comptime L: bool, comptime
|
|||
const address = cpu.r[rb] + offset;
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||
cpu.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||
} else {
|
||||
// STR
|
||||
const address = cpu.r[rb] + (@as(u32, offset) << 2);
|
||||
bus.write(u32, address, cpu.r[rd]);
|
||||
cpu.write(u32, address, cpu.r[rd]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +120,7 @@ pub fn fmt10(comptime InstrFn: type, comptime L: bool, comptime offset: u5) Inst
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const rb = opcode >> 3 & 0x7;
|
||||
const rd = opcode & 0x7;
|
||||
|
||||
|
@ -130,13 +128,13 @@ pub fn fmt10(comptime InstrFn: type, comptime L: bool, comptime offset: u5) Inst
|
|||
|
||||
if (L) {
|
||||
// LDRH
|
||||
const value = bus.read(u16, address);
|
||||
const value = cpu.read(u16, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
||||
} else {
|
||||
// STRH
|
||||
|
||||
// FIXME: I shouldn't have to use @as(u8, ...) here
|
||||
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||
}
|
||||
}
|
||||
}.inner;
|
||||
|
@ -146,17 +144,17 @@ pub fn fmt11(comptime InstrFn: type, comptime L: bool, comptime rd: u3) InstrFn
|
|||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||
fn inner(cpu: Arm32, opcode: u16) void {
|
||||
const offset = (opcode & 0xFF) << 2;
|
||||
const address = cpu.r[13] + offset;
|
||||
|
||||
if (L) {
|
||||
// LDR
|
||||
const value = bus.read(u32, address);
|
||||
const value = cpu.read(u32, address);
|
||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 0x3));
|
||||
} else {
|
||||
// STR
|
||||
bus.write(u32, address, cpu.r[rd]);
|
||||
cpu.write(u32, address, cpu.r[rd]);
|
||||
}
|
||||
}
|
||||
}.inner;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
const Bus = @import("../../../lib.zig").Bus;
|
||||
|
||||
pub fn fmt17(comptime InstrFn: type) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: Arm32, _: Bus, _: u16) void {
|
||||
fn inner(cpu: Arm32, _: u16) void {
|
||||
// Copy Values from Current Mode
|
||||
const ret_addr = cpu.r[15] - 2;
|
||||
const cpsr = cpu.cpsr.raw;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
const Bus = @import("../lib.zig").Bus;
|
||||
const Arm7tdmi = @import("../arm.zig").Arm32(.v4t);
|
||||
|
||||
pub const arm = struct {
|
||||
pub const InstrFn = *const fn (*Arm7tdmi, Bus, u32) void;
|
||||
pub const InstrFn = *const fn (*Arm7tdmi, u32) void;
|
||||
pub const lut: [0x1000]InstrFn = populate();
|
||||
|
||||
const processing = @import("cpu/arm/data_processing.zig").dataProcessing;
|
||||
|
@ -25,7 +24,7 @@ pub const arm = struct {
|
|||
}
|
||||
|
||||
// Undefined ARM Instruction handler
|
||||
fn und(cpu: *Arm7tdmi, _: Bus, opcode: u32) void {
|
||||
fn und(cpu: *Arm7tdmi, opcode: u32) void {
|
||||
const id = idx(opcode);
|
||||
cpu.panic("[CPU/Decode] ID: 0x{X:0>3} 0x{X:0>8} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ pub const arm = struct {
|
|||
};
|
||||
|
||||
pub const thumb = struct {
|
||||
pub const InstrFn = *const fn (*Arm7tdmi, Bus, u16) void;
|
||||
pub const InstrFn = *const fn (*Arm7tdmi, u16) void;
|
||||
pub const lut: [0x400]InstrFn = populate();
|
||||
|
||||
const processing = @import("cpu/thumb/data_processing.zig");
|
||||
|
@ -120,7 +119,7 @@ pub const thumb = struct {
|
|||
}
|
||||
|
||||
/// Undefined THUMB Instruction Handler
|
||||
fn und(cpu: *Arm7tdmi, _: Bus, opcode: u16) void {
|
||||
fn und(cpu: *Arm7tdmi, opcode: u16) void {
|
||||
const id = idx(opcode);
|
||||
cpu.panic("[CPU/Decode] ID: 0b{b:0>10} 0x{X:0>2} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
const Bus = @import("../lib.zig").Bus;
|
||||
const Arm946es = @import("../arm.zig").Arm32(.v5te);
|
||||
|
||||
pub const arm = struct {
|
||||
pub const InstrFn = *const fn (*Arm946es, Bus, u32) void;
|
||||
pub const InstrFn = *const fn (*Arm946es, u32) void;
|
||||
pub const lut: [0x1000]InstrFn = populate();
|
||||
|
||||
const processing = @import("cpu/arm/data_processing.zig").dataProcessing;
|
||||
|
@ -27,7 +26,7 @@ pub const arm = struct {
|
|||
}
|
||||
|
||||
// Undefined ARM Instruction handler
|
||||
fn und(cpu: *Arm946es, _: Bus, opcode: u32) void {
|
||||
fn und(cpu: *Arm946es, opcode: u32) void {
|
||||
const id = idx(opcode);
|
||||
cpu.panic("[CPU/Decode] ID: 0x{X:0>3} 0x{X:0>8} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
@ -127,7 +126,7 @@ pub const arm = struct {
|
|||
};
|
||||
|
||||
pub const thumb = struct {
|
||||
pub const InstrFn = *const fn (*Arm946es, Bus, u16) void;
|
||||
pub const InstrFn = *const fn (*Arm946es, u16) void;
|
||||
pub const lut: [0x400]InstrFn = populate();
|
||||
|
||||
const processing = @import("cpu/thumb/data_processing.zig");
|
||||
|
@ -143,7 +142,7 @@ pub const thumb = struct {
|
|||
}
|
||||
|
||||
/// Undefined THUMB Instruction Handler
|
||||
fn und(cpu: *Arm946es, _: Bus, opcode: u16) void {
|
||||
fn und(cpu: *Arm946es, opcode: u16) void {
|
||||
const id = idx(opcode);
|
||||
cpu.panic("[CPU/Decode] ID: 0b{b:0>10} 0x{X:0>2} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue