feat(v5te): implement basic DTCM + ITCM

This commit is contained in:
Rekai Nyangadzayi Musuka 2023-07-26 00:13:49 -05:00
parent ba22b856ec
commit ada2a08516
2 changed files with 58 additions and 13 deletions

View File

@ -28,6 +28,8 @@ const condition_lut = [_]u16{
}; };
pub fn Arm32(comptime arch: Architecture) type { pub fn Arm32(comptime arch: Architecture) type {
const is_v5te = arch == .v5te;
return struct { return struct {
const Self = @This(); const Self = @This();
@ -40,6 +42,10 @@ pub fn Arm32(comptime arch: Architecture) type {
bank: Bank = Bank.create(), bank: Bank = Bank.create(),
// The following will be `void` on.v4t but exist on v5te
itcm: if (is_v5te) Itcm else void,
dtcm: if (is_v5te) Dtcm else void,
const arm = switch (arch) { const arm = switch (arch) {
.v4t => @import("arm/v4t.zig").arm, .v4t => @import("arm/v4t.zig").arm,
.v5te => @import("arm/v5te.zig").arm, .v5te => @import("arm/v5te.zig").arm,
@ -153,16 +159,51 @@ pub fn Arm32(comptime arch: Architecture) type {
.bus = bus, .bus = bus,
.cpsr = .{ .raw = 0x0000_001F }, .cpsr = .{ .raw = 0x0000_001F },
.spsr = .{ .raw = 0x0000_0000 }, .spsr = .{ .raw = 0x0000_0000 },
.dtcm = if (is_v5te) .{} else {},
.itcm = if (is_v5te) .{} else {},
}; };
} }
// CPU needs it's own read/write fns due to ICTM and DCTM present in v5te // 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 // 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 { pub fn read(self: *Self, comptime T: type, address: u32) T {
const readInt = std.mem.readIntSliceLittle;
if (is_v5te) {
const itcm_base: u32 = self.itcm.base_address;
const itcm_size = self.itcm.buf.len;
const dtcm_base: u32 = self.dtcm.base_address;
const dtcm_size = self.dtcm.buf.len;
// FIXME: verify correctness + can this be faster?
if (itcm_base < address and address < itcm_base + itcm_size)
return readInt(T, self.itcm.buf[address & 0x0000_7FFF ..][0..@sizeOf(T)]);
if (dtcm_base < address and address < dtcm_base + dtcm_size)
return readInt(T, self.itcm.buf[address & 0x0000_3FFF ..][0..@sizeOf(T)]);
}
return self.bus.read(T, address); return self.bus.read(T, address);
} }
pub fn write(self: *Self, comptime T: type, address: u32, value: T) void { pub fn write(self: *Self, comptime T: type, address: u32, value: T) void {
const writeInt = std.mem.writeIntSliceLittle;
if (is_v5te) {
const itcm_base: u32 = self.itcm.base_address;
const itcm_size = self.itcm.buf.len;
const dtcm_base: u32 = self.dtcm.base_address;
const dtcm_size = self.dtcm.buf.len;
// FIXME: verify correctness + can this be faster?
if (itcm_base < address and address < itcm_base + itcm_size)
return writeInt(T, self.itcm.buf[address & 0x0000_7FFF ..][0..@sizeOf(T)], value);
if (dtcm_base < address and address < dtcm_base + dtcm_size)
return writeInt(T, self.itcm.buf[address & 0x0000_3FFF ..][0..@sizeOf(T)], value);
}
return self.bus.write(T, address, value); return self.bus.write(T, address, value);
} }
@ -173,6 +214,9 @@ pub fn Arm32(comptime arch: Architecture) type {
.bus = self.bus, .bus = self.bus,
.cpsr = .{ .raw = 0x0000_001F }, .cpsr = .{ .raw = 0x0000_001F },
.spsr = .{ .raw = 0x0000_0000 }, .spsr = .{ .raw = 0x0000_0000 },
.dtcm = if (is_v5te) .{} else {},
.itcm = if (is_v5te) .{} else {},
}; };
} }
@ -352,6 +396,18 @@ pub fn Arm32(comptime arch: Architecture) type {
}; };
} }
fn Tcm(comptime count: usize, comptime default_addr: u32) type {
const KiB = 0x400;
return struct {
buf: [count * KiB]u8 = [_]u8{0x00} ** (count * KiB),
base_address: u32 = default_addr,
};
}
const Itcm = Tcm(32, 0x0000_0000);
const Dtcm = Tcm(16, 0x0080_0000); // GBATEK says default is 0x027C_0000...
pub const Mode = enum(u5) { pub const Mode = enum(u5) {
User = 0b10000, User = 0b10000,
Fiq = 0b10001, Fiq = 0b10001,

View File

@ -321,13 +321,7 @@ test "create ARMv4T interface" {
const bus_interface = Bus.init(&bus_impl); const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl); const scheduler_interface = Scheduler.init(&scheduler_impl);
var arm7tdmi = Arm7tdmi{ var arm7tdmi = Arm7tdmi.init(scheduler_interface, bus_interface);
.sched = scheduler_interface,
.bus = bus_interface,
.cpsr = .{ .raw = 0x0000_001F },
.spsr = .{ .raw = 0x0000_0000 },
};
var icpu = arm7tdmi.interface(); var icpu = arm7tdmi.interface();
icpu.reset(); icpu.reset();
@ -342,12 +336,7 @@ test "create ARMv5TE interface" {
const bus_interface = Bus.init(&bus_impl); const bus_interface = Bus.init(&bus_impl);
const scheduler_interface = Scheduler.init(&scheduler_impl); const scheduler_interface = Scheduler.init(&scheduler_impl);
var arm946es = Arm946es{ var arm946es = Arm946es.init(scheduler_interface, bus_interface);
.sched = scheduler_interface,
.bus = bus_interface,
.cpsr = .{ .raw = 0x0000_001F },
.spsr = .{ .raw = 0x0000_0000 },
};
_ = arm946es.interface(); _ = arm946es.interface();
} }