From ada2a08516d55a61bddd96f1c29e1547d0466049 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Wed, 26 Jul 2023 00:13:49 -0500 Subject: [PATCH] feat(v5te): implement basic DTCM + ITCM --- src/arm.zig | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.zig | 15 ++------------ 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/arm.zig b/src/arm.zig index 72c8a38..62a6de6 100644 --- a/src/arm.zig +++ b/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, diff --git a/src/lib.zig b/src/lib.zig index 695d357..b5febbc 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -321,13 +321,7 @@ test "create ARMv4T interface" { const bus_interface = Bus.init(&bus_impl); const scheduler_interface = Scheduler.init(&scheduler_impl); - var arm7tdmi = Arm7tdmi{ - .sched = scheduler_interface, - .bus = bus_interface, - .cpsr = .{ .raw = 0x0000_001F }, - .spsr = .{ .raw = 0x0000_0000 }, - }; - + var arm7tdmi = Arm7tdmi.init(scheduler_interface, bus_interface); var icpu = arm7tdmi.interface(); icpu.reset(); @@ -342,12 +336,7 @@ test "create ARMv5TE interface" { const bus_interface = Bus.init(&bus_impl); const scheduler_interface = Scheduler.init(&scheduler_impl); - var arm946es = Arm946es{ - .sched = scheduler_interface, - .bus = bus_interface, - .cpsr = .{ .raw = 0x0000_001F }, - .spsr = .{ .raw = 0x0000_0000 }, - }; + var arm946es = Arm946es.init(scheduler_interface, bus_interface); _ = arm946es.interface(); }