feat: implement basic cp15 coprocessor
This commit is contained in:
parent
8eaadff0c3
commit
6518fcc68b
|
@ -1 +1 @@
|
||||||
Subproject commit c94912887e0c403dc2116162e3f43e32f9412e59
|
Subproject commit 30cf951d2a4ccba3ff7ce70ceeae44780af5f1a1
|
|
@ -1,6 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const Bus = @import("nds9/Bus.zig");
|
pub const Bus = @import("nds9/Bus.zig");
|
||||||
|
pub const Cp15 = @import("nds9/Cp15.zig");
|
||||||
pub const io = @import("nds9/io.zig");
|
pub const io = @import("nds9/io.zig");
|
||||||
pub const Scheduler = @import("nds9/Scheduler.zig");
|
pub const Scheduler = @import("nds9/Scheduler.zig");
|
||||||
pub const Arm946es = @import("arm32").Arm946es;
|
pub const Arm946es = @import("arm32").Arm946es;
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.cp15);
|
||||||
|
|
||||||
|
control: u32 = 0x0005_2078,
|
||||||
|
dtcm_size_base: u32 = 0x0300_000A,
|
||||||
|
itcm_size_base: u32 = 0x0000_0020,
|
||||||
|
|
||||||
|
// Protection Unit
|
||||||
|
// cache_bits_data_unified: u32 = 0x0000_0000,
|
||||||
|
// cache_write_bufability: u32 = 0x0000_0000, // For Data Protection Regions
|
||||||
|
// cache_bits_instr: u32 = 0x0000_0000,
|
||||||
|
|
||||||
|
/// Used in ARMv5TE MRC
|
||||||
|
pub fn read(self: *const @This(), op1: u3, cn: u4, cm: u4, op2: u3) u32 {
|
||||||
|
return switch (addr(op1, cn, cm, op2)) {
|
||||||
|
// c0, c0, ?
|
||||||
|
0b000_0000_0000_000 => 0x4105_9461, // Main ID Register
|
||||||
|
0b000_0000_0000_001 => 0x0F0D_2112, // Cache Type Register
|
||||||
|
0b000_0000_0000_010 => 0x00140180, // TCM Size Register (ICTM is 0x8000 bytes, DTCM is 0x4000 bytes)
|
||||||
|
0b000_0000_0000_011...0b000_0000_0000_111 => 0x4105_9461, // Unused, return Main ID Register
|
||||||
|
|
||||||
|
0b000_0001_0000_000 => self.control, // Control Register
|
||||||
|
|
||||||
|
// 0b000_0010_0000_000 => return self.cache_bits_data_unified & ~@as(u32, 0xFFFF_FF00),
|
||||||
|
// 0b000_0010_0000_001 => return self.cache_bits_instr & ~@as(u32, 0xFFFF_FF00),
|
||||||
|
// 0b000_0011_0000_000 => return self.cache_write_bufability & ~@as(u32, 0xFFFF_FF00),
|
||||||
|
0b000_1001_0001_000 => return self.dtcm_size_base, // Data TCM Size / Base
|
||||||
|
0b000_1001_0001_001 => return self.itcm_size_base, // Instruction TCM Size / Base
|
||||||
|
else => panic("TODO: implement read from register {}, c{}, c{}, {}", .{ op1, cn, cm, op2 }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used in ARMv5TE MCR
|
||||||
|
pub fn write(self: *@This(), op1: u3, cn: u4, cm: u4, op2: u3, value: u32) void {
|
||||||
|
switch (addr(op1, cn, cm, op2)) {
|
||||||
|
0b000_0001_0000_000 => { // Control Register
|
||||||
|
|
||||||
|
const zeroes: u32 = 0b11111111_11110000_00001111_00000010; // every bit except one_mask + 0, 2, 7, 12..19 are zero
|
||||||
|
const ones: u32 = 0b00000000_00000000_00000000_01111000; // bits 3..6 are always set
|
||||||
|
|
||||||
|
self.control = (value & ~zeroes) | ones;
|
||||||
|
},
|
||||||
|
0b000_1001_0001_000 => { // Data TCM Size / Base
|
||||||
|
const zeroes: u32 = 0b00000000_00000000_00001111_11000001;
|
||||||
|
|
||||||
|
self.dtcm_size_base = value & ~zeroes;
|
||||||
|
|
||||||
|
const size_shamt: u5 = blk: {
|
||||||
|
const size = self.dtcm_size_base >> 1 & 0x1F;
|
||||||
|
|
||||||
|
if (size < 3) break :blk 3;
|
||||||
|
if (size > 23) break :blk 23;
|
||||||
|
|
||||||
|
break :blk @intCast(size);
|
||||||
|
};
|
||||||
|
|
||||||
|
log.debug("DTCM Virtual Size: {}B", .{@as(u32, 0x200) << size_shamt});
|
||||||
|
log.debug("DTCM Region Base: 0x{X:0>8}", .{self.dtcm_size_base & 0xFFFF_F000});
|
||||||
|
},
|
||||||
|
0b000_1001_0001_001 => { // Instruction TCM Size / Base
|
||||||
|
const zeroes: u32 = 0b00000000_00000000_00001111_11000001;
|
||||||
|
const itcm_specific: u32 = 0b11111111_11111111_11110000_00000000;
|
||||||
|
|
||||||
|
self.itcm_size_base = value & ~(zeroes | itcm_specific);
|
||||||
|
|
||||||
|
const size_shamt: u5 = blk: {
|
||||||
|
const size = self.dtcm_size_base >> 1 & 0x1F;
|
||||||
|
|
||||||
|
if (size < 3) break :blk 3;
|
||||||
|
if (size > 23) break :blk 23;
|
||||||
|
|
||||||
|
break :blk @intCast(size);
|
||||||
|
};
|
||||||
|
|
||||||
|
log.debug("ICTM Virtual Size: {}B", .{@as(u32, 0x200) << size_shamt});
|
||||||
|
log.debug("ICTM Region Base: 0x{X:0>8}", .{0x0000_0000});
|
||||||
|
},
|
||||||
|
else => _ = panic("TODO: implement write to register {}, c{}, c{}, {}", .{ op1, cn, cm, op2 }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addr(op1: u3, cn: u4, cm: u4, op2: u3) u14 {
|
||||||
|
// 111nnnnmmmm222
|
||||||
|
// zig fmt: off
|
||||||
|
return @as(u14, op1) << 1
|
||||||
|
| @as(u14, cn) << 7
|
||||||
|
| @as(u14, cm) << 3
|
||||||
|
| @as(u14, op2) << 0;
|
||||||
|
// zig fmt: on
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(self: *@This()) void {
|
||||||
|
_ = self;
|
||||||
|
@panic("TODO: implement ability to reinit coprocessor");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn panic(comptime format: []const u8, args: anytype) u32 {
|
||||||
|
log.err(format, args);
|
||||||
|
// @panic("Coprocessor invariant broken");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ const emu = @import("core/emu.zig");
|
||||||
|
|
||||||
const IBus = @import("arm32").Bus;
|
const IBus = @import("arm32").Bus;
|
||||||
const IScheduler = @import("arm32").Scheduler;
|
const IScheduler = @import("arm32").Scheduler;
|
||||||
|
const ICoprocessor = @import("arm32").Coprocessor;
|
||||||
|
|
||||||
const Ui = @import("platform.zig").Ui;
|
const Ui = @import("platform.zig").Ui;
|
||||||
const SharedContext = @import("core/emu.zig").SharedContext;
|
const SharedContext = @import("core/emu.zig").SharedContext;
|
||||||
|
|
||||||
|
@ -42,7 +44,9 @@ pub fn main() !void {
|
||||||
const nds9_group: nds9.Group = blk: {
|
const nds9_group: nds9.Group = blk: {
|
||||||
var scheduler = try nds9.Scheduler.init(allocator);
|
var scheduler = try nds9.Scheduler.init(allocator);
|
||||||
var bus = try nds9.Bus.init(allocator, &scheduler, shared_ctx);
|
var bus = try nds9.Bus.init(allocator, &scheduler, shared_ctx);
|
||||||
var arm946es = nds9.Arm946es.init(IScheduler.init(&scheduler), IBus.init(&bus));
|
var cp15 = nds9.Cp15{};
|
||||||
|
|
||||||
|
var arm946es = nds9.Arm946es.init(IScheduler.init(&scheduler), IBus.init(&bus), ICoprocessor.init(&cp15));
|
||||||
|
|
||||||
break :blk .{ .cpu = &arm946es, .bus = &bus, .scheduler = &scheduler };
|
break :blk .{ .cpu = &arm946es, .bus = &bus, .scheduler = &scheduler };
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue