feat: integrate cp15 and TCM code
This commit is contained in:
parent
71541c312c
commit
30cf951d2a
27
src/arm.zig
27
src/arm.zig
|
@ -221,17 +221,14 @@ pub fn Arm32(comptime isa: Architecture) type {
|
|||
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;
|
||||
const dtcm_base = self.dtcm.base_address;
|
||||
const dtcm_size = self.dtcm.virt.size;
|
||||
|
||||
// FIXME: verify correctness + can this be faster?
|
||||
if (itcm_base < address and address < itcm_base + itcm_size)
|
||||
return readInt(T, self.itcm.buf[address..][0..@sizeOf(T)]);
|
||||
if (address < 0x0000_0000 + self.itcm.virt.size)
|
||||
return readInt(T, self.itcm.buf[address & self.itcm.virt.mask ..][0..@sizeOf(T)]);
|
||||
|
||||
if (dtcm_base < address and address < dtcm_base + dtcm_size)
|
||||
return readInt(T, self.dtcm.buf[address..][0..@sizeOf(T)]);
|
||||
return readInt(T, self.dtcm.buf[address & self.dtcm.virt.mask ..][0..@sizeOf(T)]);
|
||||
}
|
||||
|
||||
return self.bus.read(T, address);
|
||||
|
@ -241,17 +238,14 @@ pub fn Arm32(comptime isa: Architecture) type {
|
|||
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;
|
||||
const dtcm_base = self.dtcm.base_address;
|
||||
const dtcm_size = self.dtcm.virt.size;
|
||||
|
||||
// FIXME: verify correctness + can this be faster?
|
||||
if (itcm_base < address and address < itcm_base + itcm_size)
|
||||
return writeInt(T, self.itcm.buf[address..][0..@sizeOf(T)], value);
|
||||
if (address < 0x0000_0000 + self.itcm.virt.size)
|
||||
return writeInt(T, self.itcm.buf[address & self.itcm.virt.mask ..][0..@sizeOf(T)], value);
|
||||
|
||||
if (dtcm_base < address and address < dtcm_base + dtcm_size)
|
||||
return writeInt(T, self.dtcm.buf[address..][0..@sizeOf(T)], value);
|
||||
return writeInt(T, self.dtcm.buf[address & self.dtcm.virt.mask ..][0..@sizeOf(T)], value);
|
||||
}
|
||||
|
||||
return self.bus.write(T, address, value);
|
||||
|
@ -439,6 +433,7 @@ fn Tcm(comptime count: usize, comptime default_addr: u32) type {
|
|||
return struct {
|
||||
buf: [count * KiB]u8 = [_]u8{0x00} ** (count * KiB),
|
||||
base_address: u32 = default_addr,
|
||||
virt: struct { size: u32, mask: u32 } = .{ .size = count * KiB, .mask = (count * KiB) - 1 },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,34 +2,133 @@ const std = @import("std");
|
|||
|
||||
const log = std.log.scoped(.coprocessor_handler);
|
||||
|
||||
pub fn dataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: bool, comptime N: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||
_ = L;
|
||||
_ = W;
|
||||
_ = N;
|
||||
_ = U;
|
||||
_ = P;
|
||||
pub fn dataTransfer(
|
||||
comptime InstrFn: type,
|
||||
comptime P: bool,
|
||||
comptime U: bool,
|
||||
comptime N: bool,
|
||||
comptime W: bool,
|
||||
comptime L: bool,
|
||||
) InstrFn {
|
||||
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: *Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
if (!P and !W and !U) return copExt(cpu, opcode); // Coprocessor Extension Space
|
||||
|
||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor data transfer instr", .{opcode});
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const crd = opcode >> 12 & 0xF;
|
||||
const cp_num = opcode >> 8 & 0xF;
|
||||
const offset = (opcode & 0xFF) << 2;
|
||||
|
||||
// TODO: Make sure this is comptime
|
||||
const addr_mode: u2 = comptime @as(u2, @intFromBool(P)) << 1 | @intFromBool(W);
|
||||
|
||||
const start_address: u32 = switch (addr_mode) {
|
||||
0b00 => blk: {
|
||||
// Unindexed Addressing
|
||||
std.debug.assert(U == true);
|
||||
|
||||
break :blk cpu.r[rn];
|
||||
},
|
||||
0b01 => blk: {
|
||||
// Immediate Post-Indexed Addressing
|
||||
const addr = cpu.r[rn];
|
||||
cpu.r[rn] = if (U) cpu.r[rn] + offset else cpu.r[rn] - offset;
|
||||
|
||||
break :blk addr;
|
||||
},
|
||||
0b10 => if (U) cpu.r[rn] + offset else cpu.r[rn] - offset, // Immediate Offset Addressing
|
||||
0b11 => blk: {
|
||||
// Immediate Pre-Indexed Addressing
|
||||
cpu.r[rn] = if (U) cpu.r[rn] + offset else cpu.r[rn] - offset;
|
||||
|
||||
break :blk cpu.r[rn];
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Increment address + 4 (and perform op) until coprocessor says stop
|
||||
|
||||
if (L) {
|
||||
log.debug("TODO: ldc{s} p{}, c{}, 0x{X:0>8}", .{ [_]u8{if (N) 'l' else ' '}, cp_num, crd, start_address });
|
||||
} else {
|
||||
log.debug("TODO: stc{s} p{}, c{}, 0x{X:0>8}", .{ [_]u8{if (N) 'l' else ' '}, cp_num, crd, start_address });
|
||||
}
|
||||
}
|
||||
|
||||
fn copExt(cpu: *Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
const cp_num = opcode >> 8 & 0xF;
|
||||
const rd = opcode >> 12 & 0xF;
|
||||
const rn = opcode >> 16 & 0xF;
|
||||
const crm = opcode & 0xF;
|
||||
|
||||
const cp_opcode = opcode >> 4 & 0xF; // FIXME: We could get this value at comptime
|
||||
|
||||
std.debug.assert(rd != 15); // UNPREDICTABLE
|
||||
std.debug.assert(rn != 15); // UNPREDICTABLE
|
||||
|
||||
if (L) {
|
||||
// MRRC
|
||||
log.debug("TODO: mrrc p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
||||
} else {
|
||||
// MCRR
|
||||
log.debug("TODO: mcrr p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
||||
}
|
||||
}
|
||||
}.inner;
|
||||
}
|
||||
|
||||
pub fn registerTransfer(comptime InstrFn: type, comptime opcode1: u3, comptime L: bool, comptime opcode2: u3) InstrFn {
|
||||
_ = opcode2;
|
||||
_ = L;
|
||||
_ = opcode1;
|
||||
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
|
||||
|
||||
return struct {
|
||||
fn inner(cpu: *Arm32, opcode: u32) void {
|
||||
_ = cpu;
|
||||
const crn: u4 = @intCast(opcode >> 16 & 0xF);
|
||||
const rd = opcode >> 12 & 0xF;
|
||||
const cp_num = opcode >> 8 & 0xF;
|
||||
const crm: u4 = @intCast(opcode & 0xF);
|
||||
|
||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor register transfer instr", .{opcode});
|
||||
std.debug.assert(cp_num == 0xF); // There's no other coprocessor on NDS9;
|
||||
|
||||
if (L) {
|
||||
// MRC
|
||||
const value = cpu.cp15.read(opcode1, crn, crm, opcode2);
|
||||
|
||||
if (rd != 0xF) {
|
||||
cpu.r[rd] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: I can probably do this with a mask and the like
|
||||
cpu.cpsr.n.write(value >> 31 & 1 == 1);
|
||||
cpu.cpsr.z.write(value >> 30 & 1 == 1);
|
||||
cpu.cpsr.c.write(value >> 29 & 1 == 1);
|
||||
cpu.cpsr.v.write(value >> 28 & 1 == 1);
|
||||
} else {
|
||||
// MCR
|
||||
std.debug.assert(rd != 0xF); // UNPREDICTABLE
|
||||
|
||||
cpu.cp15.write(opcode1, crn, crm, opcode2, cpu.r[rd]);
|
||||
|
||||
{
|
||||
// OK so the idea is that I don't want to pass the coprocessor a reference to the CPU,
|
||||
// so there's some side effects that we need to deal with. Right now I think I'll just process
|
||||
// all side affects on every MCR write and hope this isn't too awful
|
||||
// TODO: there has to be a better way.....
|
||||
|
||||
// ICTM / DTCM Stuff
|
||||
const dtcm_size_base = cpu.cp15.read(0, 9, 1, 0); // mrc 0, c9, c1, 0
|
||||
const itcm_size_base = cpu.cp15.read(0, 9, 1, 1); // mrc 0, c9, c1, 1
|
||||
|
||||
cpu.dtcm.base_address = dtcm_size_base & 0xFFFF_F000;
|
||||
cpu.dtcm.virt.size = @as(u32, 0x200) << @truncate(std.math.clamp(dtcm_size_base >> 1 & 0x1F, 3, 23));
|
||||
cpu.dtcm.virt.mask = std.math.clamp(cpu.dtcm.virt.size, 0, @as(u32, @intCast(cpu.dtcm.buf.len))) - 1;
|
||||
|
||||
cpu.itcm.virt.size = @as(u32, 0x200) << @truncate(std.math.clamp(itcm_size_base >> 1 & 0x1F, 3, 23));
|
||||
cpu.itcm.virt.mask = std.math.clamp(cpu.itcm.virt.size, 0, @as(u32, @intCast(cpu.itcm.buf.len))) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}.inner;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ pub const arm = struct {
|
|||
return comptime comptime_blk: {
|
||||
@setEvalBranchQuota(0xE000);
|
||||
var table = [_]InstrFn{und} ** 0x1000;
|
||||
// op : 27 26 25 24 23 22 21 20 07 06 05 04
|
||||
// idx: 11 10 09 08 07 06 05 04 03 02 01 00
|
||||
|
||||
for (&table, 0..) |*handler, i| {
|
||||
handler.* = switch (@as(u2, i >> 10)) {
|
||||
|
|
Loading…
Reference in New Issue