mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-25 18:33:11 +00:00
arm: started on fpu insns
This commit is contained in:
parent
9142328468
commit
47a7aa5a83
@ -105,6 +105,7 @@ export interface ARMCoreState {
|
||||
bankedSPSRs: number[],
|
||||
sfprs: number[],
|
||||
dfprs: number[],
|
||||
ifprs: number[],
|
||||
cycles: number,
|
||||
instructionWidth: 2 | 4
|
||||
}
|
||||
@ -113,6 +114,7 @@ interface ARMCoreType {
|
||||
gprs: Int32Array;
|
||||
sfprs: Float32Array;
|
||||
dfprs: Float64Array;
|
||||
ifprs: Int32Array;
|
||||
PC: number;
|
||||
SP: number;
|
||||
LR: number;
|
||||
@ -1769,6 +1771,201 @@ ARMCoreArm.prototype.constructUMULLS = function(rd, rn, rs, rm, condOp) {
|
||||
};
|
||||
};
|
||||
|
||||
ARMCoreArm.prototype.constructVFP3Register = function(condOp, opcode, nOperandReg, destReg, number, opcode2, mOperandReg) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var gprs = cpu.gprs;
|
||||
var sregs = cpu.sfprs;
|
||||
var dregs = cpu.dfprs;
|
||||
var iregs = cpu.ifprs;
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
switch (opcode) {
|
||||
case 1: // VMOV
|
||||
switch (opcode2) {
|
||||
case 0:
|
||||
gprs[destReg] = iregs[nOperandReg];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2: // VMUL
|
||||
switch (opcode2) {
|
||||
case 0:
|
||||
sregs[destReg] = sregs[nOperandReg] * sregs[mOperandReg];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 3: // VADD/VSUB
|
||||
switch (opcode2) {
|
||||
case 0:
|
||||
sregs[destReg] = sregs[nOperandReg] + sregs[mOperandReg];
|
||||
return;
|
||||
case 2:
|
||||
sregs[destReg] = sregs[nOperandReg] - sregs[mOperandReg];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8: // VDIV
|
||||
switch (opcode2) {
|
||||
case 0:
|
||||
sregs[destReg] = sregs[nOperandReg] / sregs[mOperandReg];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
console.log("Unsupported instruction: " + hex(opcode) + " " + hex(opcode2));
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
if opc2 != '000' && !(opc2 IN "10x") then SEE "Related encodings";
|
||||
to_integer = (opc2<2> == '1'); dp_operation = (sz == 1);
|
||||
if to_integer then
|
||||
unsigned = (opc2<0> == '0'); round_zero = (op == '1');
|
||||
d = UInt(Vd:D); m = if dp_operation then UInt(M:Vm) else UInt(Vm:M);
|
||||
else
|
||||
unsigned = (op == '0'); round_nearest = FALSE; // FALSE selects FPSCR rounding
|
||||
m = UInt(Vm:M); d = if dp_operation then UInt(D:Vd) else UInt(Vd:D);
|
||||
|
||||
if ConditionPassed() then
|
||||
EncodingSpecificOperations(); CheckVFPEnabled(TRUE);
|
||||
if to_integer then
|
||||
if dp_operation then
|
||||
S[d] = FPToFixed(D[m], 32, 0, unsigned, round_zero, TRUE);
|
||||
else
|
||||
S[d] = FPToFixed(S[m], 32, 0, unsigned, round_zero, TRUE);
|
||||
else
|
||||
if dp_operation then
|
||||
D[d] = FixedToFP(S[m], 64, 0, unsigned, round_nearest, TRUE);
|
||||
else
|
||||
S[d] = FixedToFP(S[m], 32, 0, unsigned, round_nearest, TRUE);
|
||||
*/
|
||||
ARMCoreArm.prototype.constructVCVT = function(condOp, D, opc2, Vd, sz, op, M, Vm) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var sregs = cpu.sfprs;
|
||||
var dregs = cpu.dfprs;
|
||||
var iregs = cpu.ifprs;
|
||||
var to_integer = (opc2 & 0x4) != 0;
|
||||
var dp_operation = (sz & 1) != 0;
|
||||
var unsigned = (opc2 & 0x1) == 0;
|
||||
var round_zero = false;
|
||||
var round_nearest = false;
|
||||
if (to_integer) {
|
||||
unsigned = (opc2 & 0x1) == 0;
|
||||
round_zero = (op & 0x1) != 0;
|
||||
} else {
|
||||
unsigned = (op & 0x1) == 0;
|
||||
round_nearest = false;
|
||||
}
|
||||
//console.log("VCVT: " + hex(D) + " " + hex(opc2) + " " + hex(Vd) + " " + hex(sz) + " " + hex(op) + " " + hex(M) + " " + hex(Vm) + " " + to_integer + " " + unsigned);
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
var src : number;
|
||||
var dest : number;
|
||||
// get source
|
||||
if (to_integer && dp_operation) {
|
||||
src = dregs[M];
|
||||
} else if (to_integer) {
|
||||
src = sregs[M];
|
||||
} else {
|
||||
src = iregs[M];
|
||||
}
|
||||
// convert
|
||||
if (to_integer) {
|
||||
dest = round_zero ? Math.floor(src) : Math.round(src);
|
||||
} else {
|
||||
dest = src;
|
||||
}
|
||||
// store result
|
||||
if (to_integer) {
|
||||
iregs[D] = dest;
|
||||
} else if (dp_operation) {
|
||||
dregs[D] = dest;
|
||||
} else {
|
||||
sregs[D] = dest;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ARMCoreArm.prototype.constructVLDR = function(condOp, destReg, address, single_reg) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var iregs = cpu.ifprs;
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
let addr = address();
|
||||
if (single_reg) {
|
||||
iregs[destReg] = cpu.mmu.load32(addr);
|
||||
} else {
|
||||
iregs[destReg*2] = cpu.mmu.load32(addr);
|
||||
iregs[destReg*2+1] = cpu.mmu.load32(addr+4);
|
||||
}
|
||||
cpu.mmu.wait32(addr);
|
||||
cpu.mmu.wait32(cpu.gprs[ARMRegs.PC]);
|
||||
};
|
||||
};
|
||||
|
||||
ARMCoreArm.prototype.constructVSTR = function(condOp, srcReg, address, single_reg) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var iregs = cpu.ifprs;
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
let addr = address();
|
||||
if (single_reg) {
|
||||
cpu.mmu.store32(addr, iregs[srcReg]);
|
||||
} else {
|
||||
cpu.mmu.store32(addr, iregs[srcReg*2]);
|
||||
cpu.mmu.store32(addr+4, iregs[srcReg*2+1]);
|
||||
}
|
||||
cpu.mmu.wait32(addr);
|
||||
cpu.mmu.wait32(cpu.gprs[ARMRegs.PC]);
|
||||
};
|
||||
}
|
||||
|
||||
ARMCoreArm.prototype.constructVPUSH = function(condOp, d, regs, single_regs) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var iregs = cpu.ifprs;
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
let addr = cpu.gprs[ARMRegs.SP] - regs * 4;
|
||||
cpu.gprs[ARMRegs.SP] = addr;
|
||||
for (let i = 0; i < regs; ++i) {
|
||||
cpu.mmu.store32(addr, iregs[d+i]);
|
||||
addr += 4;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ARMCoreArm.prototype.constructVPOP = function(condOp, d, regs, single_regs) {
|
||||
var cpu : ARMCoreType = this.cpu;
|
||||
var iregs = cpu.ifprs;
|
||||
return function() {
|
||||
cpu.mmu.waitPrefetch32(cpu.gprs[ARMRegs.PC]);
|
||||
if (condOp && !condOp()) {
|
||||
return;
|
||||
}
|
||||
let addr = cpu.gprs[ARMRegs.SP];
|
||||
cpu.gprs[ARMRegs.SP] += regs * 4;
|
||||
for (let i = 0; i < regs; ++i) {
|
||||
iregs[d+i] = cpu.mmu.load32(addr);
|
||||
addr += 4;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function ARMCoreThumb(cpu) {
|
||||
@ -2669,6 +2866,7 @@ function ARMCore() {
|
||||
this.gprs = new Int32Array(16);
|
||||
this.dfprs = new Float64Array(16);
|
||||
this.sfprs = new Float32Array(this.dfprs.buffer); // regs shared with dfprs
|
||||
this.ifprs = new Int32Array(this.dfprs.buffer); // regs shared with dfprs
|
||||
};
|
||||
|
||||
ARMCore.prototype.resetCPU = function(startOffset) {
|
||||
@ -2783,6 +2981,7 @@ ARMCore.prototype.freeze = function() : ARMCoreState {
|
||||
],
|
||||
'sfprs': this.sfprs.slice(),
|
||||
'dfprs': this.dfprs.slice(),
|
||||
'ifprs': this.ifprs.slice(),
|
||||
'mode': this.mode,
|
||||
'cpsrI': this.cpsrI,
|
||||
'cpsrF': this.cpsrF,
|
||||
@ -2864,8 +3063,7 @@ ARMCore.prototype.defrost = function(frost: ARMCoreState) {
|
||||
this.gprs[14] = frost.gprs[14];
|
||||
this.gprs[15] = frost.gprs[15];
|
||||
|
||||
//this.sfprs.set(frost.sfprs);
|
||||
this.dfprs.set(frost.dfprs); // regs shared with sfprs
|
||||
this.ifprs.set(frost.ifprs); // regs shared with sfprs
|
||||
|
||||
this.mode = frost.mode;
|
||||
this.cpsrI = frost.cpsrI;
|
||||
@ -3689,24 +3887,66 @@ ARMCore.prototype.compileArm = function(instruction) {
|
||||
break;
|
||||
case 0x0C000000:
|
||||
// Coprocessor data transfer
|
||||
// VSTM, VSTMDB, VSTMIA
|
||||
if ((instruction & 0x0c100f00) == 0x0c000a00) {
|
||||
// TODO
|
||||
op = this.armCompiler.constructNOP();
|
||||
/* TODO
|
||||
const rn = (instruction & 0x000F0000) >> 16;
|
||||
const vd = (instruction & 0x0000F000) >> 12;
|
||||
const imm = instruction & 0x000000FF;
|
||||
const writeback = instruction & 0x00200000;
|
||||
const increment = instruction & 0x00800000;
|
||||
const load = instruction & 0x00100000;
|
||||
const user = instruction & 0x00400000;
|
||||
op.writesPC = false;
|
||||
*/
|
||||
var load = instruction & 0x00100000;
|
||||
var w = instruction & 0x00200000;
|
||||
var user = instruction & 0x00400000;
|
||||
var u = instruction & 0x00800000;
|
||||
var p = instruction & 0x01000000;
|
||||
var rn = (instruction & 0x000F0000) >> 16;
|
||||
var crd = (instruction & 0x0000F000) >> 12;
|
||||
var cpnum = (instruction & 0x00000F00) >> 8;
|
||||
var immediate = instruction & 0x000000FF;
|
||||
var cond = (instruction >> 28) & 0xf;
|
||||
var condOp = this.conds[cond];
|
||||
|
||||
// VPUSH, VPOP
|
||||
if ((instruction & 0x0fbf0f00) == 0x0d2d0a00) {
|
||||
op = this.armCompiler.constructVPUSH(condOp, (crd<<1)|(user?1:0), immediate, true);
|
||||
}
|
||||
else if ((instruction & 0x0c100f00) == 0x0c100a00) {
|
||||
// TODO: VSTR, VLDR
|
||||
op = this.armCompiler.constructNOP();
|
||||
else if ((instruction & 0x0fbf0f00) == 0x0d2d0b00) {
|
||||
op = this.armCompiler.constructVPUSH(condOp, ((user?16:0)|crd)*2, immediate, false);
|
||||
}
|
||||
else if ((instruction & 0x0fbf0f00) == 0x0cbd0a00) {
|
||||
op = this.armCompiler.constructVPOP(condOp, (crd<<1)|(user?1:0), immediate, true);
|
||||
}
|
||||
else if ((instruction & 0x0fbf0f00) == 0x0cbd0b00) {
|
||||
op = this.armCompiler.constructVPOP(condOp, ((user?16:0)|crd)*2, immediate, false);
|
||||
}
|
||||
// VLDR, VSTR
|
||||
else if ((instruction & 0x0f200f00) == 0x0d000a00) {
|
||||
immediate *= 4;
|
||||
if (!u) immediate = -immediate;
|
||||
var overlap = false;
|
||||
var d = (crd<<1)|(user?1:0);
|
||||
|
||||
var address : AddressFunction;
|
||||
if (w) {
|
||||
address = this.armCompiler.constructAddressingMode4Writeback(immediate, offset, rn, overlap);
|
||||
} else {
|
||||
address = this.armCompiler.constructAddressingMode4(immediate, rn);
|
||||
}
|
||||
if (load) {
|
||||
op = this.armCompiler.constructVLDR(condOp, crd, address, true);
|
||||
} else {
|
||||
op = this.armCompiler.constructVSTR(condOp, crd, address, true);
|
||||
}
|
||||
} else if ((instruction & 0x0f200f00) == 0x0d000b00) {
|
||||
immediate *= 4;
|
||||
if (!u) immediate = -immediate;
|
||||
var overlap = false;
|
||||
var d = ((user?16:0)|crd)*2;
|
||||
|
||||
var address : AddressFunction;
|
||||
if (w) {
|
||||
address = this.armCompiler.constructAddressingMode4Writeback(immediate, offset, rn, overlap);
|
||||
} else {
|
||||
address = this.armCompiler.constructAddressingMode4(immediate, rn);
|
||||
}
|
||||
if (load) {
|
||||
op = this.armCompiler.constructVLDR(condOp, crd, address, false);
|
||||
} else {
|
||||
op = this.armCompiler.constructVSTR(condOp, crd, address, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0E000000:
|
||||
@ -3717,6 +3957,33 @@ ARMCore.prototype.compileArm = function(instruction) {
|
||||
op = this.armCompiler.constructSWI(immediate, condOp);
|
||||
op.writesPC = false;
|
||||
}
|
||||
// VCVT, VCVTR, VCVT
|
||||
// https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/VCVT--VCVTR--between-floating-point-and-integer--Floating-point-
|
||||
else if ((instruction & 0x0FB80E50) == 0x0EB80A40) {
|
||||
const cond = (instruction >> 28) & 0xf;
|
||||
const D = (instruction >> 22) & 0x1;
|
||||
const opc2 = (instruction >> 16) & 0x7;
|
||||
const Vd = (instruction >> 12) & 0xf;
|
||||
const sz = (instruction >> 8) & 0x1;
|
||||
const to_fixed = (instruction >> 7) & 0x1;
|
||||
const M = (instruction >> 5) & 0x1;
|
||||
const Vm = instruction & 0xf;
|
||||
op = this.armCompiler.constructVCVT(condOp, D, opc2, Vd, sz, to_fixed, M, Vm);
|
||||
op.writesPC = false;
|
||||
}
|
||||
// floating point vector instructions
|
||||
else {
|
||||
const cond = (instruction >> 28) & 0xf;
|
||||
const opcode = (instruction & 0x0F00000) >> 20;
|
||||
const CRn = (instruction & 0x000F0000) >> 16;
|
||||
const CRd = (instruction & 0x0000F000) >> 12;
|
||||
const CPn = (instruction & 0x00000F00) >> 8;
|
||||
const opcode2 = (instruction & 0b11100000) >> 5;
|
||||
const CRm = instruction & 0x0000000F;
|
||||
var condOp = this.conds[cond];
|
||||
op = this.armCompiler.constructVFP3Register(condOp, opcode, CRn, CRd, CPn, opcode2, CRm);
|
||||
op.writesPC = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new EmuHalt('Bad opcode: 0x' + instruction.toString(16));
|
||||
@ -4151,6 +4418,9 @@ export class ARM32CPU implements CPU, InstructionBased, ARMMMUInterface, ARMIRQI
|
||||
core : ARMCoreType;
|
||||
bus : ARMBus;
|
||||
memory : ARMMemoryRegion[];
|
||||
f64arr = new Float64Array(1);
|
||||
f32arr = new Float32Array(this.f64arr.buffer);
|
||||
i32arr = new Int32Array(this.f64arr.buffer);
|
||||
|
||||
BASE_OFFSET = 24;
|
||||
OFFSET_MASK = 0x00FFFFFF;
|
||||
|
@ -200,7 +200,7 @@ export class ARM32Machine extends BasicScanlineMachine
|
||||
}
|
||||
|
||||
getDebugCategories() {
|
||||
return ['CPU', 'Stack'];
|
||||
return ['CPU', 'Stack', 'FPU'];
|
||||
}
|
||||
|
||||
getDebugInfo?(category: string, state: EmuState) : string {
|
||||
@ -241,6 +241,15 @@ export class ARM32Machine extends BasicScanlineMachine
|
||||
s += 'SPSR ' + hex(c.spsr,8) + '\n';
|
||||
s += 'cycl ' + c.cycles + '\n';
|
||||
return s;
|
||||
case 'FPU':
|
||||
var s = '';
|
||||
var c = state.c as ARMCoreState;
|
||||
for (var i=0; i<16; i++) {
|
||||
//let j = i+16;
|
||||
s += lpad('s'+i, 5) + ' ' + hex(c.ifprs[i],8) + ' ' + c.sfprs[i] + '\n';
|
||||
//s += lpad('s'+j, 5) + ' ' + lpad(c.sfprs[j]+'',8) + '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user