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