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

verilog: working on 64-bit, debug tree, fix 1-bit sound

This commit is contained in:
Steven Hugg 2021-07-04 12:00:25 -05:00
parent 854a6a2cdc
commit 3ec69792b0
6 changed files with 255 additions and 95 deletions

View File

@ -153,7 +153,7 @@ export class HDLModuleJS implements HDLModuleRunner {
defaultValue(dt: HDLDataType, vardef?: HDLVariableDef) : HDLValue {
if (isLogicType(dt)) {
return 0;
} else if (isArrayType(dt)) {
} else if (isArrayType(dt) && typeof dt.high.cvalue === 'number' && typeof dt.low.cvalue === 'number') {
let arr;
let arrlen = dt.high.cvalue - dt.low.cvalue + 1;
if (arrlen < 0) arrlen = -arrlen; // TODO?
@ -415,6 +415,10 @@ export class HDLModuleJS implements HDLModuleRunner {
return safe_extend(true, {}, this.state);
}
getGlobals() {
return this.saveState();
}
loadState(state) {
safe_extend(true, this.state, state);
}

View File

@ -7,6 +7,7 @@ export interface HDLModuleRunner {
powercycle() : void;
isFinished() : boolean;
isStopped() : boolean;
getGlobals() : {};
saveState() : {};
loadState(state: {}) : void;
dispose() : void;
@ -42,7 +43,8 @@ export function isLogicType(arg:any): arg is HDLLogicType {
}
export function isArrayType(arg:any): arg is HDLUnpackArray {
return arg.subtype != null && arg.low != null && arg.high != null;
return arg.subtype != null && arg.low != null && arg.high != null
&& typeof arg.low.cvalue === 'number' && typeof arg.high.cvalue === 'number';
}
export class HDLFile {
@ -67,6 +69,10 @@ export interface HDLDataTypeObject extends HDLSourceObject {
dtype: HDLDataType;
}
export function hasDataType(arg: any) : arg is HDLDataTypeObject {
return typeof arg.dtype === 'object';
}
export interface HDLModuleDef extends HDLSourceObject {
name: string;
origName: string;
@ -90,13 +96,18 @@ export function isVarDecl(arg:any): arg is HDLVariableDef {
}
export interface HDLConstant extends HDLDataTypeObject {
cvalue: number; //TODO: BigInt?
cvalue: number;
bigvalue: bigint;
}
export function isConstExpr(arg:any): arg is HDLConstant {
return typeof arg.cvalue === 'number';
}
export function isBigConstExpr(arg:any): arg is HDLConstant {
return typeof arg.bigvalue === 'bigint';
}
export interface HDLHierarchyDef extends HDLSourceObject {
name: string;
module: HDLModuleDef;
@ -186,7 +197,7 @@ export interface HDLPort extends HDLSourceObject {
expr: HDLExpr;
}
export interface HDLFuncCall extends HDLSourceObject {
export interface HDLFuncCall extends HDLDataTypeObject {
funcname: string;
args: HDLExpr[];
}

View File

@ -1,5 +1,5 @@
import { HDLBinop, HDLBlock, HDLConstant, HDLDataType, HDLExpr, HDLExtendop, HDLFuncCall, HDLModuleDef, HDLModuleRunner, HDLSourceLocation, HDLTriop, HDLUnop, HDLValue, HDLVariableDef, HDLVarRef, HDLWhileOp, isArrayItem, isArrayType, isBinop, isBlock, isConstExpr, isFuncCall, isLogicType, isTriop, isUnop, isVarDecl, isVarRef, isWhileop } from "./hdltypes";
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');
const VERILATOR_UNIT_FUNCTIONS = [
@ -66,10 +66,10 @@ function getArrayElementSizeFromType(dtype: HDLDataType) : number {
}
function getArrayElementSizeFromExpr(e: HDLExpr) : number {
if (isVarRef(e) && isArrayType(e.dtype)) {
return getDataTypeSize(e.dtype.subtype);
} else if (isBinop(e) && isArrayType(e.dtype)) {
if (hasDataType(e) && isArrayType(e.dtype)) {
return getDataTypeSize(e.dtype.subtype);
} else if (hasDataType(e) && isLogicType(e.dtype) && e.dtype.left > 63) {
return 4; // TODO? for wordsel
}
throw new HDLError(e, `cannot figure out array element size`);
}
@ -82,6 +82,8 @@ function getArrayValueSize(e: HDLExpr) : number {
return getDataTypeSize(dt);
} else if (isBinop(e) && e.op == 'arraysel') {
return getArrayValueSize(e.left);
} else if (isBinop(e) && e.op == 'wordsel') {
return 4; // TODO? for wordsel
}
throw new HDLError(e, `cannot figure out array value size`);
}
@ -105,6 +107,7 @@ interface StructRec {
itype: number;
index: number;
init: HDLBlock;
constval: HDLConstant;
}
class Struct {
@ -118,7 +121,7 @@ class Struct {
var size = getDataTypeSize(vardef.dtype);
var rec = this.addEntry(vardef.name, size, getBinaryenType(size), vardef.dtype, false);
rec.init = vardef.initValue;
if (vardef.constValue) throw new HDLError(vardef, `can't handle constants`);
rec.constval = vardef.constValue;
return rec;
}
@ -137,6 +140,7 @@ class Struct {
index: this.params.length + this.locals.length,
offset: this.len,
init: null,
constval: null,
}
this.len += size;
if (rec.name != null) this.vars[rec.name] = rec;
@ -243,6 +247,20 @@ export class HDLModuleWASM implements HDLModuleRunner {
this.data8.set(state.o as Uint8Array);
}
getGlobals() {
var g = {};
for (const [varname, vardef] of Object.entries(this.hdlmod.vardefs)) {
var o = g;
var toks = varname.split('$');
for (var tok of toks.slice(0, -1)) {
o[tok] = o[tok] || {};
o = o[tok];
}
o[toks[toks.length-1]] = this.state[varname];
}
return g;
}
enableTracing() {
if (this.outputbytes == 0) throw new Error(`outputbytes == 0`);
if (this.outputbytes % 8) throw new Error(`outputbytes must be 8-byte aligned`);
@ -321,7 +339,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
var fscope = new Struct();
fscope.addEntry(GLOBAL, 4, binaryen.i32, null, true); // 1st param to function
// add __req local if change_request function
if (this.funcResult(block) == binaryen.i32) {
if (this.funcResult(block.name) == binaryen.i32) {
fscope.addEntry(CHANGEDET, 1, binaryen.i32, null, false);
}
this.pushScope(fscope);
@ -333,7 +351,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
// create function body
var fbody = this.block2wasm(block, {funcblock:block});
//var fbody = this.bmod.return(this.bmod.i32.const(0));
var fret = this.funcResult(block);
var fret = this.funcResult(block.name);
var fref = this.bmod.addFunction(fnname, fsig, fret, fscope.getLocals(), fbody);
this.popScope();
}
@ -348,8 +366,10 @@ export class HDLModuleWASM implements HDLModuleRunner {
// validate wasm module
//console.log(this.bmod.emitText());
//this.bmod.optimize();
if (!this.bmod.validate())
throw new HDLError(this.bmod.emitText(), `could not validate wasm module`);
if (!this.bmod.validate()) {
console.log(this.bmod.emitText());
throw new HDLError(null, `could not validate wasm module`);
}
}
private async genModule() {
@ -431,6 +451,9 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
//console.log(rec.name, rec.type, arr);
}
if (rec.constval) {
this.state[rec.name] = rec.constval.cvalue || rec.constval.bigvalue;
}
}
}
@ -441,10 +464,11 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
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);
this.bmod.addFunctionImport("$time", "builtins", "$time", binaryen.createType([binaryen.i32]), binaryen.i64);
this.bmod.addFunctionImport("$rand", "builtins", "$rand", binaryen.createType([binaryen.i32]), binaryen.i32);
}
private getImportObject() : {} {
@ -452,8 +476,10 @@ export class HDLModuleWASM implements HDLModuleRunner {
return {
builtins: {
$display: (o) => { if (++n < 100) console.log('...',o); }, // TODO
$finish: (o) => { this.finished = true; },
$stop: (o) => { this.stopped = true; },
$finish: (o) => { console.log('... Finished @', o); this.finished = true; },
$stop: (o) => { console.log('... Stopped @', o); this.stopped = true; },
$time: (o) => BigInt(new Date().getTime()), // TODO: timescale
$rand: (o) => (Math.random() * (65536 * 65536)) | 0,
}
}
}
@ -551,7 +577,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
private makeSetVariableFunction(name: string, value: number) {
var dtype = this.globals.lookup(name).type;
var dest : HDLVarRef = {refname:name, dtype:dtype};
var src : HDLConstant = {cvalue:value, dtype:dtype};
var src : HDLConstant = {cvalue:value, bigvalue:null, dtype:dtype};
return this.assign2wasm(dest, src);
}
@ -569,9 +595,12 @@ export class HDLModuleWASM implements HDLModuleRunner {
], binaryen.i32)
}
private funcResult(func: HDLBlock) {
private funcResult(funcname: string) {
// only _change functions return a result
return func.name.startsWith("_change_request") ? binaryen.i32 : binaryen.none;
if (funcname.startsWith("_change_request")) return binaryen.i32;
else if (funcname == '$time') return binaryen.i64;
else if (funcname == '$rand') return binaryen.i32;
else return binaryen.none;
}
private pushScope(scope: Struct) {
@ -591,6 +620,16 @@ export class HDLModuleWASM implements HDLModuleRunner {
else throw new HDLError(null, `unknown type for i3264 ${type}`);
}
private i3264rel(e: HDLBinop) {
if (hasDataType(e.left) && hasDataType(e.right)) {
var leftsize = getDataTypeSize(e.left.dtype);
var rightsize = getDataTypeSize(e.right.dtype);
// TODO: left size should equal right size, both can be > i32 though
return leftsize > rightsize ? this.i3264(e.left.dtype) : this.i3264(e.right.dtype);
}
return this.i3264(e.dtype);
}
private dataptr() : number {
return this.bmod.local.get(0, binaryen.i32); // 1st param of function == data ptr
}
@ -604,7 +643,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
return this.local2wasm(e, opts);
} else if (isVarRef(e)) {
return this.varref2wasm(e, opts);
} else if (isConstExpr(e)) {
} else if (isConstExpr(e) || isBigConstExpr(e)) {
return this.const2wasm(e, opts);
} else if (isFuncCall(e)) {
return this.funccall2wasm(e, opts);
@ -620,7 +659,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
block2wasm(e: HDLBlock, opts?:Options) : number {
var stmts = e.exprs.map((stmt) => this.e2w(stmt));
var ret = opts && opts.funcblock ? this.funcResult(opts.funcblock) : binaryen.none;
var ret = opts && opts.funcblock ? this.funcResult(opts.funcblock.name) : binaryen.none;
// must have return value for change_request function
if (ret == binaryen.i32) {
stmts.push(this.bmod.return(this.bmod.local.get(this.locals.lookup(CHANGEDET).index, ret)));
@ -634,14 +673,23 @@ export class HDLModuleWASM implements HDLModuleRunner {
funccall2wasm(e: HDLFuncCall, opts?:Options) : number {
var args = [this.dataptr()];
var ret = e.funcname.startsWith("_change_request") ? binaryen.i32 : binaryen.none;
if (e.funcname.startsWith('$')) {
if ((e.funcname == '$stop' || e.funcname == '$finish') && e.$loc) {
args = [this.bmod.i32.const(e.$loc.line)]; // line # of source code
}
}
var ret = this.funcResult(e.funcname);
return this.bmod.call(e.funcname, args, ret);
}
const2wasm(e: HDLConstant, opts: Options) : number {
var size = getDataTypeSize(e.dtype);
if (isLogicType(e.dtype)) {
if (size <= 4)
if (e.bigvalue != null)
return this.i3264(e.dtype).const(
Number(e.bigvalue & BigInt(0xffffffff)),
Number(e.bigvalue >> BigInt(32)));
else 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?
@ -718,7 +766,7 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
address2wasm(e: HDLExpr) : number {
if (isBinop(e) && e.op == 'arraysel') {
if (isBinop(e) && (e.op == 'arraysel' || e.op == 'wordsel')) {
var array = this.address2wasm(e.left);
var elsize = getArrayElementSizeFromExpr(e.left);
var index = this.e2w(e.right);
@ -745,6 +793,10 @@ export class HDLModuleWASM implements HDLModuleRunner {
return this.loadmem(addr, 0, elsize);
}
_wordsel2wasm(e: HDLBinop, opts:Options) : number {
return this._arraysel2wasm(e, opts);
}
_assign2wasm(e: HDLBinop, opts:Options) {
return this.assign2wasm(e.right, e.left);
}
@ -790,12 +842,34 @@ export class HDLModuleWASM implements HDLModuleRunner {
}
_ccast2wasm(e: HDLUnop, opts:Options) {
return this.e2w(e.left, opts);
if (hasDataType(e.left)) {
return this.castexpr(this.e2w(e.left), e.left.dtype, e.dtype);
} else
throw new HDLError(e.left, `no data type for ccast`);
}
castexpr(val: number, tsrc: HDLDataType, tdst: HDLDataType) : number {
if (isLogicType(tsrc) && isLogicType(tdst) && tsrc.right == 0 && tdst.right == 0) {
if (tsrc.left == tdst.left) {
return val;
} else if (tsrc.left <= 31 && tdst.left <= 31) {
return val;
}
// TODO: signed?
else if (tsrc.left <= 31 && tdst.left == 63) { // 32 -> 64
return this.bmod.i64.extend_u(val);
} else if (tsrc.left == 63 && tdst.left <= 31) { // 64 -> 32
return this.bmod.i32.wrap(val);
}
}
throw new HDLError([tsrc, tdst], `cannot cast`);
}
_creset2wasm(e: HDLUnop, opts:Options) {
// TODO return this.e2w(e.left, opts);
return this.bmod.nop();
}
_creturn2wasm(e: HDLUnop, opts:Options) {
return this.bmod.return(this.e2w(e.left, opts));
}
@ -804,10 +878,12 @@ export class HDLModuleWASM implements HDLModuleRunner {
var inst = this.i3264(e.dtype);
return inst.xor(inst.const(-1, -1), this.e2w(e.left, opts));
}
_negate2wasm(e: HDLUnop, opts:Options) {
var inst = this.i3264(e.dtype);
return inst.sub(inst.const(0,0), this.e2w(e.left, opts));
}
_changedet2wasm(e: HDLBinop, opts:Options) {
var req = this.locals.lookup(CHANGEDET);
if (!req) throw new HDLError(e, `no changedet local`);
@ -825,74 +901,114 @@ export class HDLModuleWASM implements HDLModuleRunner {
this.assign2wasm(e.right, e.left)
]);
}
_extends2wasm(e: HDLExtendop, opts:Options) {
var value = this.e2w(e.left);
var inst = this.i3264(e.dtype);
/*
if (e.widthminv == 8) {
return inst.extend8_s(value);
} else if (e.widthminv == 16) {
return inst.extend16_s(value);
} else if (e.widthminv == 32 && e.width == 64) {
return this.bmod.i64.extend32_s(value);
} else */ {
var shift = this.bmod.i32.const(e.width - e.widthminv);
return inst.shr_s(inst.shl(value, shift), shift);
if (this.bmod.getFeatures() & binaryen.Features.SignExt) {
if (e.widthminv == 8) {
return inst.extend8_s(value);
} else if (e.widthminv == 16) {
return inst.extend16_s(value);
} else if (e.widthminv == 32 && e.width == 64) {
return this.bmod.i64.extend32_s(value);
}
}
var shift = inst.const(e.width - e.widthminv, 0);
return inst.shr_s(inst.shl(value, shift), shift);
}
/*
_redxor2wasm(e: HDLUnop, opts:Options) {
//TODO
// TODO: i32/i64
_redxor2wasm(e: HDLUnop) {
if (hasDataType(e.left)) {
var left = this.e2w(e.left);
var inst = this.i3264(e.left.dtype);
var rtn = inst.and(
inst.const(1, 0),
inst.popcnt(left)); // (num_set_bits & 1)
return rtn; //this.castexpr(rtn, e.dtype, e.left.dtype);
} else
throw new HDLError(e, '');
}
*/
_or2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).or(this.e2w(e.left), this.e2w(e.right));
binop(e: HDLBinop, f_op: (a:number, b:number) => number, upcastLeft?: boolean, upcastRight?: boolean) {
var left = this.e2w(e.left);
var right = this.e2w(e.right);
if (hasDataType(e.left) && hasDataType(e.right)) {
var lsize = getDataTypeSize(e.left.dtype);
var rsize = getDataTypeSize(e.right.dtype);
if (lsize < rsize && upcastLeft)
left = this.castexpr(left, e.left.dtype, e.right.dtype);
else if (rsize < lsize && upcastRight)
right = this.castexpr(right, e.right.dtype, e.left.dtype);
}
var rtn = f_op(left, right);
return rtn;
}
_and2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).and(this.e2w(e.left), this.e2w(e.right));
relop(e: HDLBinop, f_op : (a:number,b:number)=>number) {
return f_op(this.e2w(e.left), this.e2w(e.right));
}
_xor2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).xor(this.e2w(e.left), this.e2w(e.right));
_or2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).or);
}
_shiftl2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).shl(this.e2w(e.left), this.e2w(e.right));
_and2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).and);
}
_shiftr2wasm(e: HDLBinop, opts:Options) {
_xor2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).xor);
}
_shiftl2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).shl, false, true);
}
_shiftr2wasm(e: HDLBinop) {
// TODO: signed?
return this.i3264(e.dtype).shr_u(this.e2w(e.left), this.e2w(e.right));
return this.binop(e, this.i3264(e.dtype).shr_u, false, true);
}
_add2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).add(this.e2w(e.left), this.e2w(e.right));
_add2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).add);
}
_sub2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).sub(this.e2w(e.left), this.e2w(e.right));
_sub2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).sub);
}
_moddivs2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).rem_s);
}
_divs2wasm(e: HDLBinop) {
return this.binop(e, this.i3264(e.dtype).div_s);
}
_eq2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).eq(this.e2w(e.left), this.e2w(e.right));
// TODO: i32/i64
_eq2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).eq);
}
_neq2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).ne(this.e2w(e.left), this.e2w(e.right));
_neq2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).ne);
}
_lt2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).lt_u(this.e2w(e.left), this.e2w(e.right));
_lt2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).lt_u);
}
_gt2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).gt_u(this.e2w(e.left), this.e2w(e.right));
_gt2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).gt_u);
}
_lte2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).le_u(this.e2w(e.left), this.e2w(e.right));
_lte2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).le_u);
}
_gte2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).ge_u(this.e2w(e.left), this.e2w(e.right));
_gte2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).ge_u);
}
_gts2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).gt_s(this.e2w(e.left), this.e2w(e.right));
_gts2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).gt_s);
}
_lts2wasm(e: HDLBinop, opts:Options) {
return this.i3264(e.dtype).lt_s(this.e2w(e.left), this.e2w(e.right));
_lts2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).lt_s);
}
_gtes2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).ge_s);
}
_ltes2wasm(e: HDLBinop) {
return this.relop(e, this.i3264rel(e).le_s);
}
}

View File

@ -109,9 +109,12 @@ export class VerilogXMLParser implements HDLUnit {
cur_deferred = [];
constructor() {
// TODO: other types
// TODO: other types?
this.dtypes['QData'] = {left:63, right:0};
this.dtypes['IData'] = {left:31, right:0};
this.dtypes['SData'] = {left:15, right:0};
this.dtypes['CData'] = {left:7, right:0};
this.dtypes['int'] = {left:31, right:0};
}
defer(fn: () => void) {
@ -179,11 +182,15 @@ export class VerilogXMLParser implements HDLUnit {
}
}
parseConstValue(s: string) : number {
parseConstValue(s: string) : number | bigint {
const re_const = /(\d+)'([s]?)h([0-9a-f]+)/i;
var m = re_const.exec(s);
if (m) {
return parseInt(m[3], 16);
var numstr = m[3];
if (numstr.length < 8)
return parseInt(numstr, 16);
else
return BigInt('0x' + numstr);
} else {
throw Error(`could not parse constant "${s}"`);
}
@ -242,10 +249,12 @@ export class VerilogXMLParser implements HDLUnit {
visit_const(node: XMLNode) : HDLConstant {
var name = node.attrs['name'];
var cvalue = this.parseConstValue(name);
var constdef: HDLConstant = {
$loc: this.parseSourceLocation(node),
dtype: null,
cvalue: this.parseConstValue(name)
cvalue: typeof cvalue === 'number' ? cvalue : null,
bigvalue: typeof cvalue === 'bigint' ? cvalue : null,
}
this.deferDataType(node, constdef);
return constdef;
@ -564,11 +573,14 @@ export class VerilogXMLParser implements HDLUnit {
}
__visit_func(node: XMLNode) : HDLFuncCall {
return {
var expr = {
$loc: this.parseSourceLocation(node),
dtype: null,
funcname: node.attrs['func'] || ('$' + node.type),
args: node.children.map(n => n.obj as HDLExpr)
}
this.deferDataType(node, expr);
return expr;
}
visit_not(node: XMLNode) { return this.__visit_unop(node); }

View File

@ -140,7 +140,7 @@ var VerilogPlatform = function(mainElement, options) {
function vidtick() {
top.tick2(1);
if (useAudio) {
audio.feedSample(top.state.spkr * (1.0/255.0), 1);
audio.feedSample(top.state.spkr, 1);
}
if (keycode && keycode >= 128 && top.state.keystrobe) { // keystrobe = clear hi bit of key buffer
keycode = keycode & 0x7f;
@ -424,6 +424,8 @@ var VerilogPlatform = function(mainElement, options) {
// TODO: we can go faster if no paddle/sound
frameidx = 0;
var wasvsync = false;
// audio feed
function spkr() { if (useAudio) audio.feedSample(tmod.trace.spkr, 1); }
// iterate through a frame of scanlines + room for vsync
for (framey=0; framey<videoHeight*2; framey++) {
if (usePaddles) {
@ -438,16 +440,14 @@ var VerilogPlatform = function(mainElement, options) {
for (framex=0; framex<videoWidth; framex++) {
var rgb = tmod.trace.rgb;
idata[frameidx++] = rgb & 0x80000000 ? rgb : RGBLOOKUP[rgb & 15];
if (useAudio) {
audio.feedSample(tmod.trace.spkr * (1.0/255.0), 1);
}
spkr();
tmod.nextTrace();
}
n += videoWidth;
}
// find hsync
while (n < maxLineCycles && !tmod.trace.hsync) { tmod.nextTrace(); n++; }
while (n < maxLineCycles && tmod.trace.hsync) { tmod.nextTrace(); n++; }
while (n < maxLineCycles && !tmod.trace.hsync) { spkr(); tmod.nextTrace(); n++; }
while (n < maxLineCycles && tmod.trace.hsync) { spkr(); tmod.nextTrace(); n++; }
// see if our scanline cycle count is stable
if (n == scanlineCycles) {
// scanline cycle count licked in, reset buffer to improve cache locality
@ -702,9 +702,8 @@ var VerilogPlatform = function(mainElement, options) {
getDebugTree() {
return {
//ast: current_output,
runtime: top,
state: this.saveState().o
state: top.getGlobals()
}
}

View File

@ -1,7 +1,10 @@
var assert = require('assert');
var _path = require('path')
var _cproc = require('child_process');
var fs = require('fs');
var wtu = require('./workertestutils.js');
createTestDOM();
var emu = require('gen/common/emu.js');
@ -61,7 +64,7 @@ function testPerf(msg) {
return platform;
}
function compileVerilator(filename, code, callback, nerrors) {
function compileVerilator(filename, code, callback, nerrors, depends) {
global.postMessage = async function(msg) {
if (msg.errors && msg.errors.length) {
console.log(msg.errors);
@ -77,26 +80,43 @@ function compileVerilator(filename, code, callback, nerrors) {
callback(null, msg);
};
global.onmessage({
data:{code:code, platform:'verilog', tool:'verilator', path:'main.v'}
data:{
updates:[{path:_path.basename(filename), data:code}],
buildsteps:[{path:_path.basename(filename), platform:'verilog', tool:'verilator', files:depends}]
}
});
}
function testVerilator(filename, disables, nerrors) {
function testIcarus(filename) {
_cproc.execSync('iverilog -I./presets/verilog ./' + filename);
}
function testVerilator(filename, disables, nerrors, depends) {
it('should translate '+filename, function(done) {
console.log(filename);
//if (depends) testIcarus(filename);
var csource = ab2str(fs.readFileSync(filename));
for (var i=0; i<(disables||[]).length; i++)
csource = "/* verilator lint_off " + disables[i] + " */\n" + csource;
compileVerilator(filename, csource, done, nerrors||0);
csource = "/* verilator lint_off " + disables[i] + " */ " + csource;
compileVerilator(filename, csource, done, nerrors||0, depends);
});
}
describe('Verilog Worker', function() {
testVerilator('presets/verilog/hvsync_generator.v');
testVerilator('presets/verilog/digits10.v', null, null, ['digits10.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/scoreboard.v', null, null, ['scoreboard.v', 'digits10.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/ball_paddle.v', null, null, ['ball_paddle.v', 'scoreboard.v', 'digits10.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/sprite_rotation.v', null, null, ['sprite_rotation.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/lfsr.v');
testVerilator('presets/verilog/starfield.v', null, null, ['starfield.v', 'lfsr.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/ram.v');
// TODO: how to include files?
testVerilator('presets/verilog/font_cp437_8x8.v');
testVerilator('presets/verilog/sprite_scanline_renderer.v', null, null, ['sprite_scanline_renderer.v', 'ram.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/tile_renderer.v', null, null, ['tile_renderer.v', 'font_cp437_8x8.v', 'ram.v', 'hvsync_generator.v']);
testVerilator('presets/verilog/cpu6502.v');
// TODO: how to include files? have to pass buildsteps + files
//testVerilator('test/cli/verilog/t_tri_gate.v');
testVerilator('test/cli/verilog/t_tri_gen.v', ['UNDRIVEN']);
@ -109,13 +129,13 @@ describe('Verilog Worker', function() {
testVerilator('test/cli/verilog/t_tri_unconn.v', ['PINCONNECTEMPTY']);
testVerilator('test/cli/verilog/t_tri_various.v', ['UNDRIVEN']);
/* TODO: fix tests
testVerilator('test/cli/verilog/t_order_doubleloop.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_alw_combdly.v');
testVerilator('test/cli/verilog/t_math_const.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_clk_gen.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_alw_combdly.v');
testVerilator('test/cli/verilog/t_clk_first.v', ['UNDRIVEN','SYNCASYNCNET']);
/* TODO: fix tests
testVerilator('test/cli/verilog/t_clk_gen.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_clk_2in.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_order_doubleloop.v', ['BLKSEQ']);
testVerilator('test/cli/verilog/t_order_comboclkloop.v');
*/
testVerilator('test/cli/verilog/t_gen_alw.v');
@ -144,7 +164,7 @@ describe('Verilog Worker', function() {
testVerilator('test/cli/verilog/t_math_arith.v', ['BLKSEQ']);
//testVerilator('test/cli/verilog/t_math_div.v');
testVerilator('test/cli/verilog/t_math_div0.v');
//testVerilator('test/cli/verilog/t_math_div0.v');
testVerilator('test/cli/verilog/t_clk_powerdn.v', ['BLKSEQ','SYNCASYNCNET']);
//testVerilator('test/cli/verilog/t_clk_latchgate.v', ['BLKSEQ']);
@ -155,8 +175,6 @@ describe('Verilog Worker', function() {
testVerilator('test/cli/verilog/t_clk_condflop_nord.v');
testVerilator('test/cli/verilog/t_clk_condflop.v', ['BLKSEQ']);
testVerilator('presets/verilog/hvsync_generator.v');
testVerilator('presets/verilog/cpu6502.v');
/*
it('should compile verilog example', function(done) {
var csource = ab2str(fs.readFileSync('presets/verilog/hvsync_generator.v'));