1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-08 08:33:32 +00:00

verilog: fuzzhdl

This commit is contained in:
Steven Hugg 2021-07-06 13:50:16 -05:00
parent ac55082863
commit 1ab0d290f8
6 changed files with 151 additions and 77 deletions

View File

@ -63,6 +63,7 @@
"test-web": "nightwatch -e chrome test/web", "test-web": "nightwatch -e chrome test/web",
"start": "electron .", "start": "electron .",
"fuzzbasic": "jsfuzz gen/common/basic/fuzz.js ~/basic/corpus/ --versifier false", "fuzzbasic": "jsfuzz gen/common/basic/fuzz.js ~/basic/corpus/ --versifier false",
"fuzzhdl": "jsfuzz -r binaryen gen/common/hdl/fuzz.js ~/verilator/corpus/ --versifier false",
"machine": "node gen/tools/runmachine.js", "machine": "node gen/tools/runmachine.js",
"mkdoc": "typedoc --out web/jsdoc src/common/" "mkdoc": "typedoc --out web/jsdoc src/common/"
}, },

35
src/common/hdl/fuzz.ts Normal file
View File

@ -0,0 +1,35 @@
//import binaryen = require('binaryen');
import { HDLModuleJS } from "./hdlruntime";
import { HDLModuleWASM } from "./hdlwasm";
import { CompileError, VerilogXMLParser } from "./vxmlparser";
export function fuzz(buf) {
var parser = new VerilogXMLParser();
var str = buf.toString();
try {
parser.parse(str);
} catch (e) {
if (e instanceof CompileError) return;
throw e;
}
/*
if (0) {
var wmod = new HDLModuleWASM(parser.modules['TOP'], parser.modules['@CONST-POOL@']);
wmod.traceBufferSize = 0x8000;
wmod.maxMemoryMB = 0.25;
wmod.init().then(() => {
wmod.powercycle();
wmod.tick2(10000);
wmod.dispose();
})
}
*/
if (1) {
var jmod = new HDLModuleJS(parser.modules['TOP'], parser.modules['@CONST-POOL@']);
jmod.init();
jmod.powercycle();
jmod.tick2(10000);
jmod.dispose();
}
}

View File

@ -1,6 +1,6 @@
import { byteArrayToString, safe_extend } from "../util"; import { byteArrayToString, safe_extend } from "../util";
import { HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLExpr, HDLExtendop, HDLFuncCall, HDLModuleDef, HDLModuleRunner, HDLTriop, HDLUnop, HDLValue, HDLVariableDef, HDLVarRef, isArrayItem, isArrayType, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef, isWhileop } from "./hdltypes"; import { HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLExpr, HDLExtendop, HDLFuncCall, HDLModuleDef, HDLModuleRunner, HDLSourceLocation, HDLTriop, HDLUnop, HDLValue, HDLVariableDef, HDLVarRef, isArrayItem, isArrayType, isBigConstExpr, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef, isWhileop } from "./hdltypes";
interface VerilatorUnit { interface VerilatorUnit {
_ctor_var_reset(state) : void; _ctor_var_reset(state) : void;
@ -10,6 +10,18 @@ interface VerilatorUnit {
_change_request(state) : boolean; _change_request(state) : boolean;
} }
export class HDLError extends Error {
obj: any;
$loc: HDLSourceLocation;
constructor(obj: any, msg: string) {
super(msg);
Object.setPrototypeOf(this, HDLError.prototype);
this.obj = obj;
if (obj && obj.$loc) this.$loc = obj.$loc;
if (obj) console.log(obj);
}
}
export class HDLModuleJS implements HDLModuleRunner { export class HDLModuleJS implements HDLModuleRunner {
mod: HDLModuleDef; mod: HDLModuleDef;
@ -114,7 +126,7 @@ export class HDLModuleJS implements HDLModuleRunner {
return; return;
} }
} }
throw new Error(`model did not converge on reset()`) throw new HDLError(null, `model did not converge on reset()`)
} }
eval() { eval() {
@ -139,7 +151,7 @@ export class HDLModuleJS implements HDLModuleRunner {
return; return;
} }
} }
throw new Error(`model did not converge on eval()`) throw new HDLError(null, `model did not converge on eval()`)
} }
tick2(iters: number) { tick2(iters: number) {
@ -180,20 +192,20 @@ export class HDLModuleJS implements HDLModuleRunner {
if (isArrayItem(e) && isConstExpr(e.expr)) { if (isArrayItem(e) && isConstExpr(e.expr)) {
arr[e.index] = e.expr.cvalue; arr[e.index] = e.expr.cvalue;
} else { } else {
throw new Error(`non-const expr in initarray`); throw new HDLError(dt, `non-const expr in initarray`);
} }
} }
} }
return arr; return arr;
} }
throw new Error(`no default value for var type: ${vardef.name}`); throw new HDLError(dt, `no default value for var type: ${vardef.name}`);
} }
constValue(expr: HDLExpr) : number { constValue(expr: HDLExpr) : number {
if (isConstExpr(expr)) { if (isConstExpr(expr)) {
return expr.cvalue; return expr.cvalue;
} else { } else {
throw new Error(`no const value for expr`); throw new HDLError(expr, `no const value for expr`);
} }
} }
@ -220,7 +232,7 @@ export class HDLModuleJS implements HDLModuleRunner {
s += ` = ${this.constValue(e)}`; // TODO? s += ` = ${this.constValue(e)}`; // TODO?
} else if (e.initValue != null) { } else if (e.initValue != null) {
// TODO? // TODO?
throw new Error(`can't init array here`); throw new HDLError(e, `can't init array here`);
} else if (isLogicType(e.dtype) && e.dtype.left > 31) { } else if (isLogicType(e.dtype) && e.dtype.left > 31) {
// TODO: hack for big ints ($readmem) // TODO: hack for big ints ($readmem)
s += ` = []`; s += ` = []`;
@ -228,6 +240,8 @@ export class HDLModuleJS implements HDLModuleRunner {
return s; return s;
} else if (isConstExpr(e)) { } else if (isConstExpr(e)) {
return `0x${e.cvalue.toString(16)}`; return `0x${e.cvalue.toString(16)}`;
} else if (isBigConstExpr(e)) {
return e.bigvalue.toString(); // TODO?
} else if (isTriop(e)) { } else if (isTriop(e)) {
switch (e.op) { switch (e.op) {
case 'if': case 'if':
@ -239,8 +253,7 @@ export class HDLModuleJS implements HDLModuleRunner {
case 'condbound': case 'condbound':
return `(${this.expr2js(e.cond, {cond:true})} ? ${this.expr2js(e.left)} : ${this.expr2js(e.right)})`; return `(${this.expr2js(e.cond, {cond:true})} ? ${this.expr2js(e.left)} : ${this.expr2js(e.right)})`;
default: default:
console.log(e); throw new HDLError(e, `unknown triop ${e.op}`);
throw Error(`unknown triop ${e.op}`);
} }
} else if (isBinop(e)) { } else if (isBinop(e)) {
switch (e.op) { switch (e.op) {
@ -260,8 +273,7 @@ export class HDLModuleJS implements HDLModuleRunner {
default: default:
var jsop = OP2JS[e.op]; var jsop = OP2JS[e.op];
if (!jsop) { if (!jsop) {
console.log(e); throw new HDLError(e, `unknown binop ${e.op}`)
throw Error(`unknown binop ${e.op}`)
} }
if (jsop.startsWith('?')) { if (jsop.startsWith('?')) {
jsop = jsop.substr(1); jsop = jsop.substr(1);
@ -287,9 +299,10 @@ export class HDLModuleJS implements HDLModuleRunner {
case 'extends': case 'extends':
let shift = 32 - (e as HDLExtendop).widthminv; let shift = 32 - (e as HDLExtendop).widthminv;
return `((${this.expr2js(e.left)} << ${shift}) >> ${shift})`; return `((${this.expr2js(e.left)} << ${shift}) >> ${shift})`;
case 'redxor':
return `this.$$${e.op}(${this.expr2js(e.left)})`;
default: default:
console.log(e); throw new HDLError(e, `unknown unop ${e.op}`);
throw Error(`unknown unop ${e.op}`);
} }
} else if (isBlock(e)) { } else if (isBlock(e)) {
// TODO: { e } ? // TODO: { e } ?
@ -330,11 +343,11 @@ export class HDLModuleJS implements HDLModuleRunner {
return `${this.expr2js(e)}.forEach((a) => a.fill(0))` return `${this.expr2js(e)}.forEach((a) => a.fill(0))`
} else { } else {
// TODO: 3d arrays? // TODO: 3d arrays?
throw Error(`unsupported data type for reset: ${JSON.stringify(e.dtype)}`); throw new HDLError(e, `unsupported data type for reset: ${JSON.stringify(e.dtype)}`);
} }
} }
} else { } else {
throw Error(`can only reset var refs`); throw new HDLError(e, `can only reset var refs`);
} }
} }
@ -379,16 +392,27 @@ export class HDLModuleJS implements HDLModuleRunner {
var strfn = byteArrayToString(barr); // convert to string var strfn = byteArrayToString(barr); // convert to string
// parse hex/binary file // parse hex/binary file
var strdata = this.getFileData(strfn) as string; var strdata = this.getFileData(strfn) as string;
if (strdata == null) throw Error("Could not $readmem '" + strfn + "'"); if (strdata == null) throw new HDLError(null, "Could not $readmem '" + strfn + "'");
var data = strdata.split('\n').filter(s => s !== '').map(s => parseInt(s, ishex ? 16 : 2)); var data = strdata.split('\n').filter(s => s !== '').map(s => parseInt(s, ishex ? 16 : 2));
console.log('$readmem', ishex, strfn, data.length); console.log('$readmem', ishex, strfn, data.length);
// copy into destination array // copy into destination array
if (memp === null) throw Error("No destination array to $readmem " + strfn); if (memp === null) throw new HDLError(null, "No destination array to $readmem " + strfn);
if (memp.length < data.length) throw Error("Destination array too small to $readmem " + strfn); if (memp.length < data.length) throw new HDLError(null, "Destination array too small to $readmem " + strfn);
for (i=0; i<data.length; i++) for (i=0; i<data.length; i++)
memp[i] = data[i]; memp[i] = data[i];
} }
$time(o) {
return new Date().getTime();
}
$$redxor(r: number) : number {
r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); r=(r^(r>>16));
return r;
}
//
isStopped() { return this.stopped; } isStopped() { return this.stopped; }
isFinished() { return this.finished; } isFinished() { return this.finished; }

View File

@ -1,6 +1,7 @@
import { hasDataType, HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLDataTypeObject, HDLExpr, HDLExtendop, HDLFuncCall, HDLModuleDef, HDLModuleRunner, HDLSourceLocation, HDLTriop, HDLUnop, HDLValue, HDLVariableDef, HDLVarRef, HDLWhileOp, isArrayItem, isArrayType, isBigConstExpr, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef, isWhileop } from "./hdltypes";
import binaryen = require('binaryen'); import binaryen = require('binaryen');
import { hasDataType, HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLDataTypeObject, HDLExpr, HDLExtendop, HDLFuncCall, HDLModuleDef, HDLModuleRunner, HDLSourceLocation, HDLTriop, HDLUnop, HDLValue, HDLVariableDef, HDLVarRef, HDLWhileOp, isArrayItem, isArrayType, isBigConstExpr, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef, isWhileop } from "./hdltypes";
import { HDLError } from "./hdlruntime";
const VERILATOR_UNIT_FUNCTIONS = [ const VERILATOR_UNIT_FUNCTIONS = [
"_ctor_var_reset", "_ctor_var_reset",
@ -27,18 +28,6 @@ const TRACEBUF = "$$tbuf";
/// ///
export class HDLError extends Error {
obj: any;
$loc: HDLSourceLocation;
constructor(obj: any, msg: string) {
super(msg);
Object.setPrototypeOf(this, HDLError.prototype);
this.obj = obj;
if (obj && obj.$loc) this.$loc = obj.$loc;
if (obj) console.log(obj);
}
}
function getDataTypeSize(dt: HDLDataType) : number { function getDataTypeSize(dt: HDLDataType) : number {
if (isLogicType(dt)) { if (isLogicType(dt)) {
if (dt.left <= 7) if (dt.left <= 7)
@ -195,15 +184,13 @@ export class HDLModuleWASM implements HDLModuleRunner {
traceEndOffset: number; traceEndOffset: number;
trace: any; trace: any;
getFileData = null; getFileData = null;
maxMemoryMB : number;
constructor(moddef: HDLModuleDef, constpool: HDLModuleDef) { constructor(moddef: HDLModuleDef, constpool: HDLModuleDef, maxMemoryMB?: number) {
this.hdlmod = moddef; this.hdlmod = moddef;
this.constpool = constpool; this.constpool = constpool;
this.bmod = new binaryen.Module(); this.maxMemoryMB = maxMemoryMB || 16;
this.genTypes(); this.genMemory();
var membytes = this.globals.len;
var memblks = Math.ceil(membytes / 65536);
this.bmod.setMemory(memblks, memblks, MEMORY); // memory is in 64k chunks
this.genFuncs(); this.genFuncs();
} }
@ -300,11 +287,26 @@ export class HDLModuleWASM implements HDLModuleRunner {
if (this.bmod) { if (this.bmod) {
this.bmod.dispose(); this.bmod.dispose();
this.bmod = null; this.bmod = null;
this.instance = null;
this.databuf = null;
this.data8 = null;
this.data16 = null;
this.data32 = null;
} }
} }
// //
private genMemory() {
this.bmod = new binaryen.Module();
this.genTypes();
var membytes = this.globals.len;
if (membytes > this.maxMemoryMB*1024*1024)
throw new HDLError(null, `cannot allocate ${membytes} bytes, limit is ${this.maxMemoryMB} MB`);
var memblks = Math.ceil(membytes / 65536);
this.bmod.setMemory(memblks, memblks, MEMORY); // memory is in 64k chunks
}
private genTypes() { private genTypes() {
// generate global variables // generate global variables
var state = new Struct(); var state = new Struct();

View File

@ -1,4 +1,5 @@
import { HDLError } from "./hdlruntime";
import { HDLAlwaysBlock, HDLArrayItem, HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLDataTypeObject, HDLExpr, HDLExtendop, HDLFile, HDLFuncCall, HDLHierarchyDef, HDLInstanceDef, HDLLogicType, HDLModuleDef, HDLNativeType, HDLPort, HDLSensItem, HDLSourceLocation, HDLTriop, HDLUnit, HDLUnop, HDLUnpackArray, HDLValue, HDLVariableDef, HDLVarRef, HDLWhileOp, isArrayType, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef } from "./hdltypes"; import { HDLAlwaysBlock, HDLArrayItem, HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLDataTypeObject, HDLExpr, HDLExtendop, HDLFile, HDLFuncCall, HDLHierarchyDef, HDLInstanceDef, HDLLogicType, HDLModuleDef, HDLNativeType, HDLPort, HDLSensItem, HDLSourceLocation, HDLTriop, HDLUnit, HDLUnop, HDLUnpackArray, HDLValue, HDLVariableDef, HDLVarRef, HDLWhileOp, isArrayType, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef } from "./hdltypes";
/** /**
@ -16,6 +17,13 @@ import { HDLAlwaysBlock, HDLArrayItem, HDLBinop, HDLBlock, HDLConstant, HDLDataT
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
*/ */
export class CompileError extends Error {
constructor(obj: HDLSourceLocation|XMLNode, msg: string) {
super(msg);
Object.setPrototypeOf(this, CompileError.prototype);
}
}
interface XMLNode { interface XMLNode {
type: string; type: string;
text: string | null; text: string | null;
@ -47,10 +55,11 @@ function parseXMLPoorly(s: string, openfn?: XMLVisitFunction, closefn?: XMLVisit
function closetop() { function closetop() {
top = stack.pop(); top = stack.pop();
if (top.type != ident) throw Error("mismatch close tag: " + ident); if (top == null || top.type != ident) throw new CompileError(node, "mismatch close tag: " + ident);
if (closefn) { if (closefn) {
top.obj = closefn(top); top.obj = closefn(top);
} }
if (stack.length == 0) throw new CompileError(null, "close tag without open: " + ident);
stack[stack.length - 1].children.push(top); stack[stack.length - 1].children.push(top);
} }
function parseattrs(as: string): { [id: string]: string } { function parseattrs(as: string): { [id: string]: string } {
@ -79,24 +88,16 @@ function parseXMLPoorly(s: string, openfn?: XMLVisitFunction, closefn?: XMLVisit
} }
if (attrs && attrs.endsWith('/')) closetop(); if (attrs && attrs.endsWith('/')) closetop();
} else if (content != null) { } else if (content != null) {
if (stack.length == 0) throw new CompileError(null, "content without element");
var txt = escapeXML(content as string).trim(); var txt = escapeXML(content as string).trim();
if (txt.length) stack[stack.length - 1].text = txt; if (txt.length) stack[stack.length - 1].text = txt;
} }
} }
if (stack.length != 1) throw Error("tag not closed"); if (stack.length != 1) throw new CompileError(null, "tag not closed");
if (stack[0].type != '?xml') throw Error("?xml needs to be first element"); if (stack[0].type != '?xml') throw new CompileError(null, "?xml needs to be first element");
return top; return top;
} }
export class CompileError extends Error {
$loc : HDLSourceLocation;
constructor(msg: string, loc: HDLSourceLocation) {
super(msg);
Object.setPrototypeOf(this, CompileError.prototype);
this.$loc = loc;
}
}
export class VerilogXMLParser implements HDLUnit { export class VerilogXMLParser implements HDLUnit {
files: { [id: string]: HDLFile } = {}; files: { [id: string]: HDLFile } = {};
@ -131,12 +132,13 @@ export class VerilogXMLParser implements HDLUnit {
} }
name2js(s: string) { name2js(s: string) {
if (s == null) throw new CompileError(null, `no name`);
return s.replace(/[^a-z0-9_]/gi, '$'); return s.replace(/[^a-z0-9_]/gi, '$');
} }
findChildren(node: XMLNode, type: string, required: boolean) : XMLNode[] { findChildren(node: XMLNode, type: string, required: boolean) : XMLNode[] {
var arr = node.children.filter((n) => n.type == type); var arr = node.children.filter((n) => n.type == type);
if (arr.length == 0 && required) throw Error(`no child of type ${type}`); if (arr.length == 0 && required) throw new CompileError(node, `no child of type ${type}`);
return arr; return arr;
} }
@ -165,7 +167,7 @@ export class VerilogXMLParser implements HDLUnit {
instances: [], instances: [],
vardefs: {}, vardefs: {},
} }
if (this.cur_module) throw new Error(`nested modules not supported`); if (this.cur_module) throw new CompileError(node, `nested modules not supported`);
this.cur_module = module; this.cur_module = module;
return module; return module;
} }
@ -176,8 +178,7 @@ export class VerilogXMLParser implements HDLUnit {
this.defer(() => { this.defer(() => {
def.dtype = this.dtypes[dtype_id]; def.dtype = this.dtypes[dtype_id];
if (!def.dtype) { if (!def.dtype) {
console.log(node); throw new CompileError(node, `Unknown data type ${dtype_id} for ${node.type}`);
throw Error(`Unknown data type ${dtype_id} for ${node.type}`);
} }
}) })
} }
@ -193,19 +194,19 @@ export class VerilogXMLParser implements HDLUnit {
else else
return BigInt('0x' + numstr); return BigInt('0x' + numstr);
} else { } else {
throw Error(`could not parse constant "${s}"`); throw new CompileError(null, `could not parse constant "${s}"`);
} }
} }
resolveVar(s: string, mod: HDLModuleDef) : HDLVariableDef { resolveVar(s: string, mod: HDLModuleDef) : HDLVariableDef {
var def = mod.vardefs[s]; var def = mod.vardefs[s];
if (def == null) throw Error(`could not resolve variable "${s}"`); if (def == null) throw new CompileError(null, `could not resolve variable "${s}"`);
return def; return def;
} }
resolveModule(s: string) : HDLModuleDef { resolveModule(s: string) : HDLModuleDef {
var mod = this.modules[s]; var mod = this.modules[s];
if (mod == null) throw Error(`could not resolve module "${s}"`); if (mod == null) throw new CompileError(null, `could not resolve module "${s}"`);
return mod; return mod;
} }
@ -325,7 +326,7 @@ export class VerilogXMLParser implements HDLUnit {
} }
visit_inititem(node: XMLNode) : HDLArrayItem { visit_inititem(node: XMLNode) : HDLArrayItem {
if (node.children.length != 1) throw Error('expected 1 children'); this.expectChildren(node, 1, 1);
return { return {
index: parseInt(node.attrs['index']), index: parseInt(node.attrs['index']),
expr: node.children[0].obj expr: node.children[0].obj
@ -334,7 +335,7 @@ export class VerilogXMLParser implements HDLUnit {
visit_cfunc(node: XMLNode) : HDLBlock { visit_cfunc(node: XMLNode) : HDLBlock {
if (this.cur_module == null) { // TODO? if (this.cur_module == null) { // TODO?
console.log('no module open, skipping', node); //console.log('no module open, skipping', node);
return; return;
} }
var block = this.visit_begin(node); var block = this.visit_begin(node);
@ -363,7 +364,7 @@ export class VerilogXMLParser implements HDLUnit {
} }
visit_port(node: XMLNode) : HDLPort { visit_port(node: XMLNode) : HDLPort {
if (node.children.length != 1) throw Error('expected 1 children'); this.expectChildren(node, 1, 1);
var varref: HDLPort = { var varref: HDLPort = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
name: node.attrs['name'], name: node.attrs['name'],
@ -379,7 +380,12 @@ export class VerilogXMLParser implements HDLUnit {
} }
visit_module_files(node: XMLNode) { visit_module_files(node: XMLNode) {
node.children.forEach((n) => this.files[(n.obj as HDLFile).id].isModule = true); node.children.forEach((n) => {
if (n.obj) {
var file = this.files[(n.obj as HDLFile).id];
if (file) file.isModule = true;
}
});
} }
visit_file(node: XMLNode) { visit_file(node: XMLNode) {
@ -404,9 +410,12 @@ export class VerilogXMLParser implements HDLUnit {
} }
visit_cells(node: XMLNode) { visit_cells(node: XMLNode) {
this.expectChildren(node, 1, 9999);
var hier = node.children[0].obj as HDLHierarchyDef; var hier = node.children[0].obj as HDLHierarchyDef;
var hiername = hier.name; if (hier != null) {
this.hierarchies[hiername] = hier; var hiername = hier.name;
this.hierarchies[hiername] = hier;
}
} }
visit_cell(node: XMLNode) : HDLHierarchyDef { visit_cell(node: XMLNode) : HDLHierarchyDef {
@ -449,8 +458,7 @@ export class VerilogXMLParser implements HDLUnit {
default: default:
dtype = this.dtypes[dtypename]; dtype = this.dtypes[dtypename];
if (dtype == null) { if (dtype == null) {
console.log(node); throw new CompileError(node, `unknown data type ${dtypename}`);
throw Error(`unknown data type ${dtypename}`);
} }
} }
this.dtypes[id] = dtype; this.dtypes[id] = dtype;
@ -471,18 +479,18 @@ export class VerilogXMLParser implements HDLUnit {
this.dtypes[id] = dtype; this.dtypes[id] = dtype;
this.defer(() => { this.defer(() => {
dtype.subtype = this.dtypes[sub_dtype_id]; dtype.subtype = this.dtypes[sub_dtype_id];
if (!dtype.subtype) throw Error(`Unknown data type ${sub_dtype_id} for array`); if (!dtype.subtype) throw new CompileError(node, `Unknown data type ${sub_dtype_id} for array`);
}) })
return dtype; return dtype;
} else { } else {
throw Error(`could not parse constant exprs in array`) throw new CompileError(node, `could not parse constant exprs in array`)
} }
} }
visit_senitem(node: XMLNode) : HDLSensItem { visit_senitem(node: XMLNode) : HDLSensItem {
var edgeType = node.attrs['edgeType']; var edgeType = node.attrs['edgeType'];
if (edgeType != "POS" && edgeType != "NEG") if (edgeType != "POS" && edgeType != "NEG")
throw Error("POS/NEG required") throw new CompileError(node, "POS/NEG required")
return { return {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
edgeType: edgeType, edgeType: edgeType,
@ -505,8 +513,13 @@ export class VerilogXMLParser implements HDLUnit {
visit_constpool(node: XMLNode) { visit_constpool(node: XMLNode) {
} }
expectChildren(node: XMLNode, low: number, high: number) {
if (node.children.length < low || node.children.length > high)
throw new CompileError(node, `expected between ${low} and ${high} children`);
}
__visit_unop(node: XMLNode) : HDLUnop { __visit_unop(node: XMLNode) : HDLUnop {
if (node.children.length != 1) throw Error('expected 1 children'); this.expectChildren(node, 1, 1);
var expr: HDLUnop = { var expr: HDLUnop = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
op: node.type, op: node.type,
@ -521,12 +534,12 @@ export class VerilogXMLParser implements HDLUnit {
var unop = this.__visit_unop(node) as HDLExtendop; var unop = this.__visit_unop(node) as HDLExtendop;
unop.width = parseInt(node.attrs['width']); unop.width = parseInt(node.attrs['width']);
unop.widthminv = parseInt(node.attrs['widthminv']); unop.widthminv = parseInt(node.attrs['widthminv']);
if (unop.width != 32) throw Error(`extends width ${unop.width} != 32`) if (unop.width != 32) throw new CompileError(node, `extends width ${unop.width} != 32`)
return unop; return unop;
} }
__visit_binop(node: XMLNode) : HDLBinop { __visit_binop(node: XMLNode) : HDLBinop {
if (node.children.length != 2) throw Error('expected 2 children'); this.expectChildren(node, 2, 2);
var expr: HDLBinop = { var expr: HDLBinop = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
op: node.type, op: node.type,
@ -539,7 +552,7 @@ export class VerilogXMLParser implements HDLUnit {
} }
visit_if(node: XMLNode) : HDLTriop { visit_if(node: XMLNode) : HDLTriop {
if (node.children.length < 2 || node.children.length > 3) throw Error('expected 2 or 3 children'); this.expectChildren(node, 2, 3);
var expr: HDLTriop = { var expr: HDLTriop = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
op: 'if', op: 'if',
@ -553,7 +566,7 @@ export class VerilogXMLParser implements HDLUnit {
// while and for loops // while and for loops
visit_while(node: XMLNode) : HDLWhileOp { visit_while(node: XMLNode) : HDLWhileOp {
if (node.children.length < 2 || node.children.length > 4) throw Error('expected 2-4 children'); this.expectChildren(node, 2, 4);
var expr: HDLWhileOp = { var expr: HDLWhileOp = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
op: 'while', op: 'while',
@ -567,7 +580,7 @@ export class VerilogXMLParser implements HDLUnit {
} }
__visit_triop(node: XMLNode) : HDLBinop { __visit_triop(node: XMLNode) : HDLBinop {
if (node.children.length != 3) throw Error('expected 2 children'); this.expectChildren(node, 3, 3);
var expr: HDLTriop = { var expr: HDLTriop = {
$loc: this.parseSourceLocation(node), $loc: this.parseSourceLocation(node),
op: node.type, op: node.type,
@ -677,8 +690,7 @@ export class VerilogXMLParser implements HDLUnit {
if (method) { if (method) {
return method.bind(this)(node); return method.bind(this)(node);
} else { } else {
console.log(node); throw new CompileError(node, `no visitor for ${node.type}`)
throw Error(`no visitor for ${node.type}`)
} }
} }

View File

@ -107,6 +107,6 @@ async function testJSvsWASM() {
} }
} }
testJSvsWASM(); //testJSvsWASM();
//testWASM().then(testJS); testWASM().then(testJS).then(testJSvsWASM);