feat(v5te): implement basic DTCM + ITCM
This commit is contained in:
56
src/arm.zig
56
src/arm.zig
@@ -28,6 +28,8 @@ const condition_lut = [_]u16{
|
||||
};
|
||||
|
||||
pub fn Arm32(comptime arch: Architecture) type {
|
||||
const is_v5te = arch == .v5te;
|
||||
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
@@ -40,6 +42,10 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||
|
||||
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) {
|
||||
.v4t => @import("arm/v4t.zig").arm,
|
||||
.v5te => @import("arm/v5te.zig").arm,
|
||||
@@ -153,16 +159,51 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||
.bus = bus,
|
||||
.cpsr = .{ .raw = 0x0000_001F },
|
||||
.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
|
||||
// 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -173,6 +214,9 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||
.bus = self.bus,
|
||||
.cpsr = .{ .raw = 0x0000_001F },
|
||||
.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) {
|
||||
User = 0b10000,
|
||||
Fiq = 0b10001,
|
||||
|
Reference in New Issue
Block a user