chore(cpu): lay groundwork for THUMB instruction decoding and execution

This commit is contained in:
Rekai Nyangadzayi Musuka 2022-01-14 05:23:16 -04:00
parent ae37b1218b
commit 0cf052838d
7 changed files with 55 additions and 17 deletions

View File

@ -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 });
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {