feat: implement Coprocessor Interface

This commit is contained in:
2023-09-15 11:02:40 -05:00
parent 5d70e4bd1d
commit 514e4d6014
2 changed files with 249 additions and 82 deletions

View File

@@ -32,6 +32,38 @@ pub const Interpreter = union(enum) {
}
};
test "create ARMv4T interface" {
var bus_impl = ExampleBus{};
var scheduler_impl = ExampleScheduler{};
const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl);
var arm7tdmi = Arm7tdmi.init(scheduler_interface, bus_interface);
var icpu = arm7tdmi.interface();
icpu.reset();
icpu.step();
// TODO: call icpu.panic()
}
test "create ARMv5TE interface" {
var bus_impl = ExampleBus{};
var scheduler_impl = ExampleScheduler{};
var cop_impl = ExampleCoprocessor{};
const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl);
const coprocessor_interface = Coprocessor.init(&cop_impl);
var arm946es = Arm946es.init(scheduler_interface, bus_interface, coprocessor_interface);
var icpu = arm946es.interface();
icpu.reset();
icpu.step();
// TODO: call icpu.panic();
}
pub const Bus = struct {
ptr: *anyopaque,
vtable: *const Vtable,
@@ -196,6 +228,118 @@ pub const Bus = struct {
}
};
test "create Bus" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
_ = iface;
}
test "call Bus reads" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
_ = iface.read(u32, 0x0000_0000);
_ = iface.read(u16, 0x0000_0000);
_ = iface.read(u8, 0x0000_0000);
_ = iface.dbgRead(u32, 0x0000_0000);
_ = iface.dbgRead(u16, 0x0000_0000);
_ = iface.dbgRead(u8, 0x0000_0000);
}
test "call Bus writes" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
_ = iface.write(u32, 0x0000_0000, 0x0000_0000);
_ = iface.write(u16, 0x0000_0000, 0x0000);
_ = iface.write(u8, 0x0000_0000, 0x00);
_ = iface.dbgWrite(u32, 0x0000_0000, 0x0000_0000);
_ = iface.dbgWrite(u16, 0x0000_0000, 0x0000);
_ = iface.dbgWrite(u8, 0x0000_0000, 0x00);
}
pub const Coprocessor = struct {
ptr: *anyopaque,
// VTable
readFn: *const fn (ptr: *anyopaque, op1: u3, cn: u4, cm: u4, op2: u3) u32,
writeFn: *const fn (ptr: *anyopaque, op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void,
resetFn: *const fn (ptr: *anyopaque) void,
pub fn init(obj: anytype) @This() {
const P = @TypeOf(obj);
const info = @typeInfo(P);
std.debug.assert(info == .Pointer); // `anytype` is a Pointer
std.debug.assert(info.Pointer.size == .One); // Single-Item Pointer
std.debug.assert(@typeInfo(info.Pointer.child) == .Struct); // Pointer Child is a `struct`
const impl = struct {
fn read(ptr: *anyopaque, op1: u3, cn: u4, cm: u4, op2: u3) u32 {
const self: P = @ptrCast(@alignCast(ptr));
return self.read(op1, cn, cm, op2);
}
fn write(ptr: *anyopaque, op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void {
const self: P = @ptrCast(@alignCast(ptr));
return self.write(op1, cn, cm, op2, value);
}
fn reset(ptr: *anyopaque) void {
const self: P = @ptrCast(@alignCast(ptr));
return self.reset();
}
};
return .{
.ptr = obj,
.readFn = impl.read,
.writeFn = impl.write,
.resetFn = impl.reset,
};
}
pub fn read(self: @This(), op1: u3, cn: u4, cm: u4, op2: u3) u32 {
return self.readFn(self.ptr, op1, cn, cm, op2);
}
pub fn write(self: @This(), op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void {
return self.writeFn(self.ptr, op1, cn, cm, op2, value);
}
pub fn reset(self: @This()) void {
return self.resetFn(self.ptr);
}
};
test "create Coprocessor" {
var cop_impl = ExampleCoprocessor{};
_ = Coprocessor.init(&cop_impl);
}
test "Coprocessor.read" {
var cop_impl = ExampleCoprocessor{};
const iface = Coprocessor.init(&cop_impl);
try testing.expectEqual(@as(u32, 0xDEADBEEF), iface.read(0, 0, 0, 0));
}
test "Coprocessor.write" {
var cop_impl = ExampleCoprocessor{};
const iface = Coprocessor.init(&cop_impl);
iface.write(0, 0, 0, 0, 0xDEADBEEF);
}
test "Coprocessor.reset" {
var cop_impl = ExampleCoprocessor{};
const iface = Coprocessor.init(&cop_impl);
iface.reset();
}
pub const Scheduler = struct {
ptr: *anyopaque,
@@ -235,6 +379,27 @@ pub const Scheduler = struct {
}
};
test "create Scheduler" {
var scheduler_impl = ExampleScheduler{};
const iface = Scheduler.init(&scheduler_impl);
_ = iface;
}
test "Scheduler.now()" {
var scheduler_impl = ExampleScheduler{};
const iface = Scheduler.init(&scheduler_impl);
try testing.expectEqual(@as(u64, 0), iface.now());
}
test "Scheduler.reset()" {
var scheduler_impl = ExampleScheduler{ .tick = std.math.maxInt(u64) };
const iface = Scheduler.init(&scheduler_impl);
iface.reset();
try testing.expectEqual(@as(u64, 0), scheduler_impl.tick);
}
// ---
// TESTING
// ---
@@ -282,61 +447,27 @@ const ExampleScheduler = struct {
}
};
test "create IBus" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
_ = iface;
}
const ExampleCoprocessor = struct {
pub fn read(self: *@This(), op1: u3, cn: u4, cm: u4, op2: u3) u32 {
_ = op2;
_ = cm;
_ = cn;
_ = op1;
_ = self;
test "call IBus reads" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
return 0xDEADBEEF;
}
_ = iface.read(u32, 0x0000_0000);
_ = iface.read(u16, 0x0000_0000);
_ = iface.read(u8, 0x0000_0000);
pub fn write(self: *@This(), op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void {
_ = value;
_ = op2;
_ = cm;
_ = cn;
_ = op1;
_ = self;
}
_ = iface.dbgRead(u32, 0x0000_0000);
_ = iface.dbgRead(u16, 0x0000_0000);
_ = iface.dbgRead(u8, 0x0000_0000);
}
test "call IBus writes" {
var bus_impl = ExampleBus{};
const iface = Bus.init(&bus_impl);
_ = iface.write(u32, 0x0000_0000, 0x0000_0000);
_ = iface.write(u16, 0x0000_0000, 0x0000);
_ = iface.write(u8, 0x0000_0000, 0x00);
_ = iface.dbgWrite(u32, 0x0000_0000, 0x0000_0000);
_ = iface.dbgWrite(u16, 0x0000_0000, 0x0000);
_ = iface.dbgWrite(u8, 0x0000_0000, 0x00);
}
test "create ARMv4T interface" {
var bus_impl = ExampleBus{};
var scheduler_impl = ExampleScheduler{};
const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl);
var arm7tdmi = Arm7tdmi.init(scheduler_interface, bus_interface);
var icpu = arm7tdmi.interface();
icpu.reset();
icpu.step();
// TODO: call icpu.panic()
}
test "create ARMv5TE interface" {
var bus_impl = ExampleBus{};
var scheduler_impl = ExampleScheduler{};
const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl);
var arm946es = Arm946es.init(scheduler_interface, bus_interface);
_ = arm946es.interface();
}
pub fn reset(self: *@This()) void {
self.* = .{};
}
};