1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-05-28 23:41:32 +00:00

verilog: fixed wasm array views, compare test, loadROM async?

This commit is contained in:
Steven Hugg 2021-07-03 09:49:03 -05:00
parent f4d8435c59
commit 854a6a2cdc
7 changed files with 107 additions and 21 deletions

View File

@ -90,7 +90,7 @@ export function isVarDecl(arg:any): arg is HDLVariableDef {
}
export interface HDLConstant extends HDLDataTypeObject {
cvalue: number;
cvalue: number; //TODO: BigInt?
}
export function isConstExpr(arg:any): arg is HDLConstant {

View File

@ -17,7 +17,7 @@ interface Options {
}
const GLOBALOFS = 0;
const MEMORY = "0";
const MEMORY = "$$MEM";
const GLOBAL = "$$GLOBAL";
const CHANGEDET = "$$CHANGE";
const TRACERECLEN = "$$treclen";
@ -191,7 +191,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
this.bmod = new binaryen.Module();
this.genTypes();
var membytes = this.globals.len;
var memblks = Math.ceil(membytes / 65536) + 1;
var memblks = Math.ceil(membytes / 65536);
this.bmod.setMemory(memblks, memblks, MEMORY); // memory is in 64k chunks
this.genFuncs();
}
@ -223,9 +223,8 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
tick() {
// TODO: faster, save state
this.state.clk ^= 1;
(this.instance.exports as any).eval(GLOBALOFS);
this.eval();
}
tick2(iters: number) {
@ -245,6 +244,9 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
enableTracing() {
if (this.outputbytes == 0) throw new Error(`outputbytes == 0`);
if (this.outputbytes % 8) throw new Error(`outputbytes must be 8-byte aligned`);
if (this.traceBufferSize % 8) throw new Error(`trace buffer size must be 8-byte aligned`);
this.traceStartOffset = this.globals.lookup(TRACEBUF).offset;
this.traceEndOffset = this.traceStartOffset + this.traceBufferSize - this.outputbytes;
this.state[TRACEEND] = this.traceEndOffset;
@ -287,6 +289,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
for (const [varname, vardef] of Object.entries(this.hdlmod.vardefs)) {
if (vardef.isOutput) state.addVar(vardef);
}
if (state.len == 0) state.addEntry("___", 1); // ensure as least 8 output bytes for trace buffer
state.alignTo(8);
this.outputbytes = state.len;
// followed by inputs and internal vars
@ -340,7 +343,9 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
// create helper functions
this.addHelperFunctions();
// create wasm module
// link imported functions
this.addImportedFunctions();
// validate wasm module
//console.log(this.bmod.emitText());
//this.bmod.optimize();
if (!this.bmod.validate())
@ -351,7 +356,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
//console.log(this.bmod.emitText());
var wasmData = this.bmod.emitBinary();
var compiled = await WebAssembly.compile(wasmData);
this.instance = await WebAssembly.instantiate(compiled, {});
this.instance = await WebAssembly.instantiate(compiled, this.getImportObject());
this.databuf = (this.instance.exports[MEMORY] as any).buffer;
this.data8 = new Uint8Array(this.databuf);
this.data16 = new Uint16Array(this.databuf);
@ -372,9 +377,9 @@ export class HDLModuleWASM implements HDLModuleRunner {
if (elsize == 1) {
return new Uint8Array(this.databuf, base + vref.offset, vref.size);
} else if (elsize == 2) {
return new Uint16Array(this.databuf, (base + vref.offset) >> 1, vref.size >> 1);
return new Uint16Array(this.databuf, (base>>1) + vref.offset, vref.size >> 1);
} else if (elsize == 4) {
return new Uint32Array(this.databuf, (base + vref.offset) >> 2, vref.size >> 2);
return new Uint32Array(this.databuf, (base>>2) + vref.offset, vref.size >> 2);
}
} else {
if (vref.size == 1) {
@ -433,7 +438,24 @@ export class HDLModuleWASM implements HDLModuleRunner {
this.addCopyTraceRecFunction();
this.addEvalFunction();
this.addTick2Function();
}
private addImportedFunctions() {
// TODO: this.bmod.addFunctionImport("$$rand", "builtins", "$$rand", binaryen.createType([]), binaryen.i64);
this.bmod.addFunctionImport("$display", "builtins", "$display", binaryen.createType([binaryen.i32]), binaryen.none);
this.bmod.addFunctionImport("$finish", "builtins", "$finish", binaryen.createType([binaryen.i32]), binaryen.none);
this.bmod.addFunctionImport("$stop", "builtins", "$stop", binaryen.createType([binaryen.i32]), binaryen.none);
}
private getImportObject() : {} {
var n = 0;
return {
builtins: {
$display: (o) => { if (++n < 100) console.log('...',o); }, // TODO
$finish: (o) => { this.finished = true; },
$stop: (o) => { this.stopped = true; },
}
}
}
private addCopyTraceRecFunction() {
@ -621,8 +643,10 @@ export class HDLModuleWASM implements HDLModuleRunner {
if (isLogicType(e.dtype)) {
if (size <= 4)
return this.bmod.i32.const(e.cvalue);
else if (size <= 8)
return this.bmod.i64.const(e.cvalue, e.cvalue >> 32); // TODO: bigint?
else
throw new HDLError(e, `constants > 32 bits not supported`)
throw new HDLError(e, `constants > 64 bits not supported`)
} else {
throw new HDLError(e, `non-logic constants not supported`)
}
@ -817,6 +841,12 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
}
/*
_redxor2wasm(e: HDLUnop, opts:Options) {
//TODO
}
*/
_or2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).or(this.e2w(e.left), this.e2w(e.right));
}
@ -864,5 +894,6 @@ export class HDLModuleWASM implements HDLModuleRunner {
_lts2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).lt_s(this.e2w(e.left), this.e2w(e.right));
}
}

View File

@ -110,6 +110,7 @@ export class VerilogXMLParser implements HDLUnit {
constructor() {
// TODO: other types
this.dtypes['QData'] = {left:63, right:0};
this.dtypes['IData'] = {left:31, right:0};
}
@ -602,6 +603,7 @@ export class VerilogXMLParser implements HDLUnit {
visit_concat(node: XMLNode) { return this.__visit_binop(node); } // TODO?
visit_shiftl(node: XMLNode) { return this.__visit_binop(node); }
visit_shiftr(node: XMLNode) { return this.__visit_binop(node); }
visit_shiftrs(node: XMLNode) { return this.__visit_binop(node); }
visit_mul(node: XMLNode) { return this.__visit_binop(node); }
visit_div(node: XMLNode) { return this.__visit_binop(node); }

View File

@ -1,4 +1,5 @@
import { arrayCompare } from "../util";
import { HDLModuleJS } from "./hdlruntime";
import { HDLModuleWASM } from "./hdlwasm";
import { VerilogXMLParser } from "./vxmlparser";
@ -13,7 +14,7 @@ try {
console.log(parser.cur_node);
throw e;
}
console.log(parser);
//console.log(parser);
var modname = 'TOP'; //process.argv[3];
async function testWASM() {
@ -58,5 +59,54 @@ async function testJS() {
//console.log(emitter);
}
testWASM().then(testJS);
async function testJSvsWASM() {
const top = parser.modules[modname];
const constpool = parser.modules['@CONST-POOL@'];
var jmod = new HDLModuleJS(top, constpool);
jmod.init();
jmod.powercycle();
var bmod = new HDLModuleWASM(top, constpool);
await bmod.init();
bmod.powercycle();
var varnames = Object.keys(top.vardefs);
var exit = false;
for (var i=0; i<100000000; i++) {
for (var vname of varnames) {
var jvalue = jmod.state[vname];
var bvalue = bmod.state[vname];
if (typeof jvalue === 'number') {
if (jvalue != bvalue) {
console.log('*** Value for', vname, 'differs', jvalue, bvalue);
exit = true;
}
} else if ((jvalue as any).buffer != null) {
if (!arrayCompare(jvalue as any, bvalue as any)) {
console.log('*** Value for', vname, 'differs', jvalue, bvalue);
exit = true;
}
}
}
if (jmod.isFinished() || bmod.isFinished()) {
if (jmod.isFinished() != bmod.isFinished()) {
console.log('*** Abnormal finish', jmod.isFinished(), bmod.isFinished());
}
exit = true;
}
if (jmod.isStopped() || bmod.isStopped()) {
if (jmod.isStopped() != bmod.isStopped()) {
console.log('*** Abnormal stop', jmod.isStopped(), bmod.isStopped());
}
exit = true;
}
if (exit) {
console.log('exit iteration', i);
break;
}
jmod.tick2(1);
bmod.tick2(1);
}
}
testJSvsWASM();
//testWASM().then(testJS);

View File

@ -1178,7 +1178,7 @@ function setCompileOutput(data: WorkerResult) {
try {
clearBreakpoint(); // so we can replace memory (TODO: change toolbar btn)
_resetRecording();
platform.loadROM(getCurrentPresetTitle(), rom);
platform.loadROM(getCurrentPresetTitle(), rom); // TODO: should be async?
current_output = rom;
if (!userPaused) _resume();
measureBuildTime();

View File

@ -292,6 +292,9 @@ var VerilogPlatform = function(mainElement, options) {
if (!novideo) {
this.refreshVideoFrame();
}
if (this.isBlocked()) {
this.pause();
}
return cyclesPerFrame; //TODO?
}
@ -529,6 +532,7 @@ var VerilogPlatform = function(mainElement, options) {
}
}
// TODO: can this be async?
async loadROM(title:string, output:any) {
var unit = output as HDLUnit;
var topmod = unit.modules['TOP'];

View File

@ -12,15 +12,14 @@ Object.assign(global, verilog); // copy global VL_* properties
// TODO: must define $
function loadPlatform(msg) {
async function loadPlatform(msg) {
var platform = new VerilogPlatform();
platform.resume = function() { }; // prevent resume after reset
try {
//console.log(msg.output.ports);
//console.log(msg.output.signals);
platform.loadROM("ROM", msg.output);
platform.loadROM("ROM", msg.output);
platform.loadROM("ROM", msg.output);
await platform.loadROM("ROM", msg.output);
await platform.loadROM("ROM", msg.output);
for (var i=0; i<100000 && !platform.isBlocked(); i++) {
platform.tick();
}
@ -47,7 +46,7 @@ function testPerf(msg) {
var niters = 5000000;
console.time("before");
for (var i=0; i<niters; i++)
for (var i=0; i<niters && !platform.isBlocked(); i++)
platform.tick();
console.timeEnd("before");
@ -55,7 +54,7 @@ function testPerf(msg) {
platform.reset();
platform.loadState(state);
console.time("after");
for (var i=0; i<niters; i++)
for (var i=0; i<niters && !platform.isBlocked(); i++)
platform.tick();
console.timeEnd("after");
@ -63,13 +62,13 @@ function testPerf(msg) {
}
function compileVerilator(filename, code, callback, nerrors) {
global.postMessage = function(msg) {
global.postMessage = async function(msg) {
if (msg.errors && msg.errors.length) {
console.log(msg.errors);
assert.equal(nerrors||0, msg.errors.length, "errors");
} else {
assert.equal(nerrors||0, 0, "errors");
loadPlatform(msg);
await loadPlatform(msg);
//testPerf(msg);
if (filename.indexOf('t_') >= 0) {
//assert.ok(verilog.vl_finished);