feat: pass nds arm7wrestler
- impl behaviour of running v5te instrs on v4t cpu - impl undefined instruction exception handler - panic on what I think are still unimplemented v5te opcodes
This commit is contained in:
parent
dcff3fd588
commit
aad3bdc9ea
23
src/arm.zig
23
src/arm.zig
|
@ -409,6 +409,29 @@ pub fn Arm32(comptime isa: Architecture) type {
|
||||||
std.debug.panic(format, args);
|
std.debug.panic(format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Rename
|
||||||
|
pub fn undefinedInstructionTrap(self: *Self) void {
|
||||||
|
// Copy Values from Current Mode
|
||||||
|
const ret_addr = self.r[15] - @as(u32, if (self.cpsr.t.read()) 2 else 4);
|
||||||
|
const cpsr = self.cpsr.raw;
|
||||||
|
|
||||||
|
// Switch Mode
|
||||||
|
self.changeMode(.Undefined);
|
||||||
|
self.cpsr.t.write(false); // Force ARM Mode
|
||||||
|
self.cpsr.i.write(true); // Disable normal interrupts
|
||||||
|
|
||||||
|
self.r[14] = ret_addr; // Resume Execution
|
||||||
|
self.spsr.raw = cpsr; // Previous mode CPSR
|
||||||
|
self.r[15] = switch (Self.arch) {
|
||||||
|
.v4t => 0x0000_0004,
|
||||||
|
.v5te => blk: {
|
||||||
|
const ctrl = self.cp15.read(0, 1, 0, 0);
|
||||||
|
break :blk if (ctrl >> 13 & 1 == 1) 0xFFFF_0004 else 0x0000_0004;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.pipe.reload(self);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn interface(self: *Self) Interpreter {
|
pub fn interface(self: *Self) Interpreter {
|
||||||
return switch (isa) {
|
return switch (isa) {
|
||||||
.v4t => .{ .v4t = self },
|
.v4t => .{ .v4t = self },
|
||||||
|
|
|
@ -51,14 +51,13 @@ pub fn dataTransfer(
|
||||||
// TODO: Increment address + 4 (and perform op) until coprocessor says stop
|
// TODO: Increment address + 4 (and perform op) until coprocessor says stop
|
||||||
|
|
||||||
if (L) {
|
if (L) {
|
||||||
log.debug("TODO: ldc{s} p{}, c{}, 0x{X:0>8}", .{ [_]u8{if (N) 'l' else ' '}, cp_num, crd, start_address });
|
cpu.panic("TODO: ldc{s} p{}, c{}, 0x{X:0>8}", .{ [_]u8{if (N) 'l' else ' '}, cp_num, crd, start_address });
|
||||||
} else {
|
} else {
|
||||||
log.debug("TODO: stc{s} p{}, c{}, 0x{X:0>8}", .{ [_]u8{if (N) 'l' else ' '}, cp_num, crd, start_address });
|
cpu.panic("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 {
|
fn copExt(cpu: *Arm32, opcode: u32) void {
|
||||||
_ = cpu;
|
|
||||||
const cp_num = opcode >> 8 & 0xF;
|
const cp_num = opcode >> 8 & 0xF;
|
||||||
const rd = opcode >> 12 & 0xF;
|
const rd = opcode >> 12 & 0xF;
|
||||||
const rn = opcode >> 16 & 0xF;
|
const rn = opcode >> 16 & 0xF;
|
||||||
|
@ -71,10 +70,10 @@ pub fn dataTransfer(
|
||||||
|
|
||||||
if (L) {
|
if (L) {
|
||||||
// MRRC
|
// MRRC
|
||||||
log.debug("TODO: mrrc p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
cpu.panic("TODO: mrrc p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
||||||
} else {
|
} else {
|
||||||
// MCRR
|
// MCRR
|
||||||
log.debug("TODO: mcrr p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
cpu.panic("TODO: mcrr p{}, {}, r{}, r{}, c{}", .{ cp_num, cp_opcode, rd, rn, crm });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
|
@ -90,7 +89,11 @@ pub fn registerTransfer(comptime InstrFn: type, comptime opcode1: u3, comptime L
|
||||||
const cp_num = opcode >> 8 & 0xF;
|
const cp_num = opcode >> 8 & 0xF;
|
||||||
const crm: u4 = @intCast(opcode & 0xF);
|
const crm: u4 = @intCast(opcode & 0xF);
|
||||||
|
|
||||||
std.debug.assert(cp_num == 0xF); // There's no other coprocessor on NDS9;
|
switch (cp_num) {
|
||||||
|
14 => return,
|
||||||
|
15 => if (Arm32.arch == .v4t) return cpu.undefinedInstructionTrap(),
|
||||||
|
else => cpu.panic("MRC: unexpected coprocessor #: {}", .{cp_num}),
|
||||||
|
}
|
||||||
|
|
||||||
if (L) {
|
if (L) {
|
||||||
// MRC
|
// MRC
|
||||||
|
@ -148,9 +151,7 @@ pub fn dataProcessing(comptime InstrFn: type, comptime opcode1: u4, comptime opc
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: *Arm32, opcode: u32) void {
|
fn inner(cpu: *Arm32, opcode: u32) void {
|
||||||
_ = cpu;
|
cpu.panic("TODO: handle 0x{X:0>8} which is a coprocessor data processing instr", .{opcode});
|
||||||
|
|
||||||
log.err("TODO: handle 0x{X:0>8} which is a coprocessor data processing instr", .{opcode});
|
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
const std = @import("std");
|
||||||
const sext = @import("zba-util").sext;
|
const sext = @import("zba-util").sext;
|
||||||
const rotr = @import("zba-util").rotr;
|
const rotr = @import("zba-util").rotr;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.half_and_signed_data_transfer);
|
||||||
|
|
||||||
pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
|
pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
|
||||||
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
|
const Arm32 = @typeInfo(@typeInfo(@typeInfo(InstrFn).Pointer.child).Fn.params[0].type.?).Pointer.child;
|
||||||
|
|
||||||
|
@ -66,9 +69,9 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
||||||
// FIXME: I shouldn't have to use @as(u16, ...) here
|
// FIXME: I shouldn't have to use @as(u16, ...) here
|
||||||
cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
cpu.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||||
},
|
},
|
||||||
0b10 => {
|
0b10 => blk: {
|
||||||
// LDRD
|
// LDRD
|
||||||
if (Arm32.arch != .v5te) cpu.panic("LDRD: unsupported on arm{s}", .{@tagName(Arm32.arch)});
|
if (Arm32.arch == .v4t) break :blk;
|
||||||
if (rd & 0 != 0) cpu.panic("LDRD: UNDEFINED behaviour when Rd is not even", .{});
|
if (rd & 0 != 0) cpu.panic("LDRD: UNDEFINED behaviour when Rd is not even", .{});
|
||||||
if (rd == 0xE) cpu.panic("LDRD: UNPREDICTABLE behaviour when rd == 14", .{});
|
if (rd == 0xE) cpu.panic("LDRD: UNPREDICTABLE behaviour when rd == 14", .{});
|
||||||
if (address & 0x7 != 0b000) cpu.panic("LDRD: UNPREDICTABLE when address (0x{X:0>8} is not double (64-bit) aligned", .{address});
|
if (address & 0x7 != 0b000) cpu.panic("LDRD: UNPREDICTABLE when address (0x{X:0>8} is not double (64-bit) aligned", .{address});
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub fn control(comptime InstrFn: type, comptime I: bool, comptime op: u6) InstrF
|
||||||
},
|
},
|
||||||
0b01_0001 => cpu.panic("TODO: implement v5TE BX", .{}),
|
0b01_0001 => cpu.panic("TODO: implement v5TE BX", .{}),
|
||||||
0b11_0001 => { // CLZ
|
0b11_0001 => { // CLZ
|
||||||
|
if (Arm32.arch == .v4t) return cpu.undefinedInstructionTrap();
|
||||||
const rd = opcode >> 12 & 0xF;
|
const rd = opcode >> 12 & 0xF;
|
||||||
const rm = opcode & 0xF;
|
const rm = opcode & 0xF;
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ pub fn control(comptime InstrFn: type, comptime I: bool, comptime op: u6) InstrF
|
||||||
cpu.pipe.reload(cpu);
|
cpu.pipe.reload(cpu);
|
||||||
},
|
},
|
||||||
0b00_0101, 0b01_0101, 0b10_0101, 0b11_0101 => { // QADD / QDADD / QSUB / QDSUB
|
0b00_0101, 0b01_0101, 0b10_0101, 0b11_0101 => { // QADD / QDADD / QSUB / QDSUB
|
||||||
|
if (Arm32.arch == .v4t) return cpu.undefinedInstructionTrap();
|
||||||
const U = op >> 4 & 1 == 1;
|
const U = op >> 4 & 1 == 1;
|
||||||
const D = op >> 5 & 1 == 1;
|
const D = op >> 5 & 1 == 1;
|
||||||
|
|
||||||
|
@ -84,6 +86,7 @@ pub fn control(comptime InstrFn: type, comptime I: bool, comptime op: u6) InstrF
|
||||||
},
|
},
|
||||||
0b01_0111 => cpu.panic("TODO: handle BKPT", .{}),
|
0b01_0111 => cpu.panic("TODO: handle BKPT", .{}),
|
||||||
0b00_1000, 0b00_1010, 0b00_1100, 0b00_1110 => { // SMLA<x><y>
|
0b00_1000, 0b00_1010, 0b00_1100, 0b00_1110 => { // SMLA<x><y>
|
||||||
|
if (Arm32.arch == .v4t) return; // no-op
|
||||||
const X = op >> 1 & 1;
|
const X = op >> 1 & 1;
|
||||||
const Y = op >> 2 & 1;
|
const Y = op >> 2 & 1;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ pub const arm = struct {
|
||||||
/// Arithmetic Instruction Extension Space
|
/// Arithmetic Instruction Extension Space
|
||||||
const multiplyExt = @import("cpu/arm/multiply.zig").multiply;
|
const multiplyExt = @import("cpu/arm/multiply.zig").multiply;
|
||||||
|
|
||||||
|
const cop = @import("cpu/arm/coprocessor.zig");
|
||||||
|
|
||||||
/// Determine index into ARM InstrFn LUT
|
/// Determine index into ARM InstrFn LUT
|
||||||
pub fn idx(opcode: u32) u12 {
|
pub fn idx(opcode: u32) u12 {
|
||||||
// FIXME: omit these?
|
// FIXME: omit these?
|
||||||
|
@ -87,8 +89,29 @@ pub const arm = struct {
|
||||||
const L = i >> 8 & 1 == 1;
|
const L = i >> 8 & 1 == 1;
|
||||||
break :blk branch(InstrFn, L);
|
break :blk branch(InstrFn, L);
|
||||||
},
|
},
|
||||||
0b10 => und, // COP Data Transfer
|
0b10 => blk: {
|
||||||
0b11 => if (i >> 8 & 1 == 1) swi(InstrFn) else und, // COP Data Operation + Register Transfer
|
const P = i >> 8 & 1 == 1;
|
||||||
|
const U = i >> 7 & 1 == 1;
|
||||||
|
const N = i >> 6 & 1 == 1;
|
||||||
|
const W = i >> 5 & 1 == 1;
|
||||||
|
const L = i >> 4 & 1 == 1;
|
||||||
|
|
||||||
|
break :blk cop.dataTransfer(InstrFn, P, U, N, W, L);
|
||||||
|
},
|
||||||
|
0b11 => blk: {
|
||||||
|
if (i >> 8 & 1 == 1) break :blk swi(InstrFn);
|
||||||
|
|
||||||
|
const data_opcode1 = i >> 4 & 0xF; // bits 20 -> 23
|
||||||
|
const reg_opcode1 = i >> 5 & 0x7; // bits 21 -> 23
|
||||||
|
const opcode2 = i >> 1 & 0x7; // bits 5 -> 7
|
||||||
|
const L = i >> 4 & 1 == 1; // bit 20
|
||||||
|
|
||||||
|
// Bit 4 (index pos of 0) distinguishes between these classes of instructions
|
||||||
|
break :blk switch (i & 1 == 1) {
|
||||||
|
true => cop.registerTransfer(InstrFn, reg_opcode1, L, opcode2),
|
||||||
|
false => cop.dataProcessing(InstrFn, data_opcode1, opcode2),
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue