chore(cpu): lay groundwork for THUMB instruction decoding and execution
This commit is contained in:
parent
ae37b1218b
commit
0cf052838d
60
src/cpu.zig
60
src/cpu.zig
|
@ -15,8 +15,10 @@ 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;
|
||||
|
||||
pub const InstrFn = fn (*Arm7tdmi, *Bus, u32) void;
|
||||
const arm_lut: [0x1000]InstrFn = populate();
|
||||
pub const ArmInstrFn = fn (*Arm7tdmi, *Bus, u32) void;
|
||||
pub const ThumbInstrFn = fn (*Arm7tdmi, *Bus, u16) void;
|
||||
const arm_lut: [0x1000]ArmInstrFn = armPopulate();
|
||||
const thumb_lut: [0x400]ThumbInstrFn = thumbPopulate();
|
||||
|
||||
pub const Arm7tdmi = struct {
|
||||
const Self = @This();
|
||||
|
@ -49,16 +51,29 @@ pub const Arm7tdmi = struct {
|
|||
}
|
||||
|
||||
pub fn step(self: *Self) u64 {
|
||||
const opcode = self.fetch();
|
||||
// self.mgbaLog(opcode);
|
||||
if (self.cpsr.t.read()) {
|
||||
const opcode = self.thumbFetch();
|
||||
thumb_lut[thumbIdx(opcode)](self, self.bus, opcode);
|
||||
} else {
|
||||
const opcode = self.fetch();
|
||||
|
||||
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
||||
arm_lut[armIdx(opcode)](self, self.bus, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkCond(&self.cpsr, opcode)) arm_lut[armIdx(opcode)](self, self.bus, opcode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fn thumbFetch(self: *Self) u16 {
|
||||
const halfword = self.bus.read16(self.r[15]);
|
||||
self.r[15] += 2;
|
||||
return halfword;
|
||||
}
|
||||
|
||||
fn fetch(self: *Self) u32 {
|
||||
const word = self.bus.read32(self.r[15]);
|
||||
self.r[15] += if (self.cpsr.t.read()) @as(u32, 2) else @as(u32, 4);
|
||||
self.r[15] += 4;
|
||||
return word;
|
||||
}
|
||||
|
||||
|
@ -98,9 +113,13 @@ fn armIdx(opcode: u32) u12 {
|
|||
return @truncate(u12, opcode >> 20 & 0xFF) << 4 | @truncate(u12, opcode >> 4 & 0xF);
|
||||
}
|
||||
|
||||
fn checkCond(cpsr: *const PSR, opcode: u32) bool {
|
||||
fn thumbIdx(opcode: u16) u10 {
|
||||
return @truncate(u10, opcode >> 6);
|
||||
}
|
||||
|
||||
fn checkCond(cpsr: PSR, cond: u4) bool {
|
||||
// TODO: Should I implement an enum?
|
||||
return switch (@truncate(u4, opcode >> 28)) {
|
||||
return switch (cond) {
|
||||
0x0 => cpsr.z.read(), // EQ - Equal
|
||||
0x1 => !cpsr.z.read(), // NE - Not equal
|
||||
0x2 => cpsr.c.read(), // CS - Unsigned higher or same
|
||||
|
@ -120,10 +139,24 @@ fn checkCond(cpsr: *const PSR, opcode: u32) bool {
|
|||
};
|
||||
}
|
||||
|
||||
fn populate() [0x1000]InstrFn {
|
||||
fn thumbPopulate() [0x400]ThumbInstrFn {
|
||||
return comptime {
|
||||
@setEvalBranchQuota(0x800);
|
||||
var lut = [_]ThumbInstrFn{thumbUndefined} ** 0x400;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < lut.len) : (i += 1) {
|
||||
lut[i] = thumbUndefined;
|
||||
}
|
||||
|
||||
return lut;
|
||||
};
|
||||
}
|
||||
|
||||
fn armPopulate() [0x1000]ArmInstrFn {
|
||||
return comptime {
|
||||
@setEvalBranchQuota(0x5000); // TODO: Figure out exact size
|
||||
var lut = [_]InstrFn{undefinedInstruction} ** 0x1000;
|
||||
var lut = [_]ArmInstrFn{armUndefined} ** 0x1000;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < lut.len) : (i += 1) {
|
||||
|
@ -210,7 +243,12 @@ const Mode = enum(u5) {
|
|||
System = 0b11111,
|
||||
};
|
||||
|
||||
fn undefinedInstruction(_: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||
fn armUndefined(_: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||
const id = armIdx(opcode);
|
||||
std.debug.panic("[CPU] {{0x{X:}}} 0x{X:} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
||||
fn thumbUndefined(_: *Arm7tdmi, _: *Bus, opcode: u16) void {
|
||||
const id = thumbIdx(opcode);
|
||||
std.debug.panic("[CPU] {{0x{X:}}} 0x{X:} is an illegal opcode", .{ id, opcode });
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
|
||||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn blockDataTransfer(comptime P: bool, comptime U: bool, comptime S: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
|
|
@ -3,7 +3,7 @@ const util = @import("../../util.zig");
|
|||
|
||||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn branch(comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||
const BarrelShifter = @import("barrel_shifter.zig");
|
||||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime instrKind: u4) InstrFn {
|
||||
return struct {
|
||||
|
|
|
@ -3,7 +3,7 @@ const util = @import("../../util.zig");
|
|||
|
||||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn halfAndSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
|
||||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn psrTransfer(comptime I: bool, comptime isSpsr: bool) InstrFn {
|
||||
return struct {
|
||||
|
|
|
@ -5,7 +5,7 @@ const BarrelShifter = @import("barrel_shifter.zig");
|
|||
const Bus = @import("../../Bus.zig");
|
||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
|
||||
const CPSR = @import("../../cpu.zig").PSR;
|
||||
const InstrFn = @import("../../cpu.zig").InstrFn;
|
||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
|
||||
|
||||
pub fn singleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
return struct {
|
||||
|
|
Loading…
Reference in New Issue