File size: 3,985 Bytes
d8afd6f 8d577f5 d8afd6f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | // JS wrapper around the WebAssembly Xtensa core (wasm/xtensa.c). Exposes the same surface as XtensaCPU (xtensa.js).
const I = {
AR: 0, F: 64, PC: 80, PS: 81, WB: 82, WS: 83, WB4: 84, SAR: 85, BR: 86, LBEG: 87, LEND: 88, LCOUNT: 89, SCOMPARE1: 90, ACCLO: 91, ACCHI: 92, M: 93,
DEPC: 97, EXCCAUSE: 98, EXCVADDR: 99, VECBASE: 100, INTENABLE: 101, INTSET: 102, INTPINS: 103, CPENABLE: 104, THREADPTR: 105, FCR: 106, FSR: 107,
ATOMCTL: 108, MEMCTL: 109, CCOMPARE: 110, CCOUNTOFF: 113, MISC: 114, DDR: 118, ICOUNT: 119, DEBUGCAUSE: 120, EPC: 121, EPS: 129, EXCSAVE: 137,
HALTED: 145, STALLED: 146, CHKINT: 147, WINLIM: 148, OWB: 149, ID: 150, SR: 160, CYC: 416, CYCBASE: 418, SLICELEN: 420, N: 421, RDP: 422, WRP: 423, HOOKPC: 424, HOOKS: 425,
};
export const STATE_WORDS = 1024;
export class XtensaCPUWasm {
constructor(soc, id, buffer, stateOff, rdOff, wrOff, exports) {
this.soc = soc; this.id = id; this.ex = exports;
this.S = new Int32Array(buffer, stateOff, STATE_WORDS);
this.D = new Float64Array(buffer, stateOff, STATE_WORDS / 2);
this.ar = this.S.subarray(I.AR, I.AR + 64);
this.f = new Float32Array(buffer, stateOff + I.F * 4, 16);
this.epc = this.S.subarray(I.EPC, I.EPC + 8); this.eps = this.S.subarray(I.EPS, I.EPS + 8); this.excsave = this.S.subarray(I.EXCSAVE, I.EXCSAVE + 8);
this.ccompare = this.S.subarray(I.CCOMPARE, I.CCOMPARE + 3); this.m = this.S.subarray(I.M, I.M + 4); this.misc = this.S.subarray(I.MISC, I.MISC + 4);
this.rd = new Int32Array(buffer, rdOff, 1 << 20); this.wr = new Int32Array(buffer, wrOff, 1 << 20);
this.rdOff = rdOff; this.wrOff = wrOff; this.stateOff = stateOff;
exports.xt_set_state(id, stateOff);
this.reset();
}
reset() {
const S = this.S; S.fill(0);
S[I.PC] = 0x40000400; S[I.PS] = 0x1F; S[I.WS] = 1; S[I.VECBASE] = 0x40000000; S[I.CHKINT] = 1; S[I.WINLIM] = 3; S[I.ID] = this.id;
S[I.RDP] = this.rdOff; S[I.WRP] = this.wrOff; S[I.HOOKS] = this.soc.hooks && this.soc.hooks.size ? 1 : 0;
}
run(budget) { this.S[I.HOOKS] = this.soc.hooks.size ? 1 : 0; this.ex.xt_run(this.id, budget); }
curCycles() { return this.D[I.CYCBASE >> 1] + this.S[I.SLICELEN] - this.S[I.N]; }
get ccount() { return (this.curCycles() + this.S[I.CCOUNTOFF]) >>> 0; }
get interrupt() { return (this.S[I.INTPINS] | this.S[I.INTSET]) | 0; }
pendingLevel() { return this.ex.xt_pending(this.id); }
deliverNow() { this.ex.xt_deliver(this.id); }
checkWake() { if (this.pendingLevel() > 0) this.S[I.HALTED] = 0; }
raiseIntSet(mask) { this.S[I.INTSET] |= mask; this.S[I.CHKINT] = 1; if (this.S[I.HALTED]) this.checkWake(); }
get cyc() { return this.D[I.CYC >> 1]; } set cyc(v) { this.D[I.CYC >> 1] = v; }
get cycBase() { return this.D[I.CYCBASE >> 1]; } set cycBase(v) { this.D[I.CYCBASE >> 1] = v; }
get halted() { return this.S[I.HALTED] !== 0; } set halted(v) { this.S[I.HALTED] = v ? 1 : 0; }
get stalled() { return this.S[I.STALLED] !== 0; } set stalled(v) { this.S[I.STALLED] = v ? 1 : 0; }
get chkInt() { return this.S[I.CHKINT] !== 0; } set chkInt(v) { this.S[I.CHKINT] = v ? 1 : 0; }
}
for (const [name, idx] of [['pc', I.PC], ['ps', I.PS], ['wb', I.WB], ['ws', I.WS], ['wb4', I.WB4], ['sar', I.SAR], ['br', I.BR], ['lbeg', I.LBEG], ['lend', I.LEND], ['lcount', I.LCOUNT],
['scompare1', I.SCOMPARE1], ['acclo', I.ACCLO], ['acchi', I.ACCHI], ['depc', I.DEPC], ['exccause', I.EXCCAUSE], ['excvaddr', I.EXCVADDR], ['vecbase', I.VECBASE],
['intenable', I.INTENABLE], ['intSet', I.INTSET], ['intPins', I.INTPINS], ['cpenable', I.CPENABLE], ['threadptr', I.THREADPTR], ['fcr', I.FCR], ['fsr', I.FSR],
['atomctl', I.ATOMCTL], ['memctl', I.MEMCTL], ['ccountOff', I.CCOUNTOFF], ['ddr', I.DDR], ['icount', I.ICOUNT], ['debugcause', I.DEBUGCAUSE], ['winLim', I.WINLIM],
['owb', I.OWB], ['sliceLen', I.SLICELEN], ['n', I.N], ['hookPc', I.HOOKPC]]) {
Object.defineProperty(XtensaCPUWasm.prototype, name, { get() { return this.S[idx]; }, set(v) { this.S[idx] = v; } });
}
|