diff --git a/doc/notes.txt b/doc/notes.txt index ba6d7c17..d50c51d9 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -113,7 +113,7 @@ TODO: - multidim arrays - optimize trace log w/ wasm buffer - yosys compatibility - + - randomize on reset? (https://www.xilinx.com/support/documentation/white_papers/wp272.pdf) - single-stepping vector games makes screen fade - break on stack overflow, illegal op, bad access, BRK, etc - show in scope instead? diff --git a/presets/verilog/chardisplay.v b/presets/verilog/chardisplay.v index 133bc07c..daf4813f 100644 --- a/presets/verilog/chardisplay.v +++ b/presets/verilog/chardisplay.v @@ -80,5 +80,5 @@ module test_ram1_top(clk, reset, hsync, vsync, rgb); ram_writeenable <= 0; end endcase - + endmodule diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v index f1ad4e27..0a1903e3 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -163,11 +163,9 @@ module digits10_array(digit, yofs, bits); bitarray[9][4] = 5'b11111; // clear unused array entries - /* TODO for (i = 10; i <= 15; i++) for (j = 0; j <= 4; j++) bitarray[i][j] = 0; - */ end endmodule diff --git a/src/common/hdl/hdlwasm.ts b/src/common/hdl/hdlwasm.ts index cac71624..a696982b 100644 --- a/src/common/hdl/hdlwasm.ts +++ b/src/common/hdl/hdlwasm.ts @@ -111,6 +111,7 @@ interface StructRec { index: number; init: HDLBlock; constval: HDLConstant; + reset: boolean; } class Struct { @@ -144,6 +145,7 @@ class Struct { offset: this.len, init: null, constval: null, + reset: false, } this.len += size; if (rec.name != null) this.vars[rec.name] = rec; @@ -196,6 +198,7 @@ export class HDLModuleWASM implements HDLModuleRunner { traceEndOffset: number; trace: any; + randomizeOnReset: boolean = false; finished: boolean; stopped: boolean; resetStartTimeMsec : number; @@ -211,7 +214,6 @@ export class HDLModuleWASM implements HDLModuleRunner { async init() { await this.genModule(); - this.genInitData(); this.enableTracing(); } @@ -220,6 +222,8 @@ export class HDLModuleWASM implements HDLModuleRunner { this.resetStartTimeMsec = new Date().getTime() - 1; this.finished = false; this.stopped = false; + this.clearMutableState(); + this.setInitialValues(); (this.instance.exports as any)._ctor_var_reset(GLOBALOFS); (this.instance.exports as any)._eval_initial(GLOBALOFS); for (var i=0; i<100; i++) { @@ -258,6 +262,7 @@ export class HDLModuleWASM implements HDLModuleRunner { this.data8.set(state.o as Uint8Array); } + // get tree of global variables for debugging getGlobals() { var g = {}; for (const [varname, vardef] of Object.entries(this.hdlmod.vardefs)) { @@ -329,8 +334,10 @@ export class HDLModuleWASM implements HDLModuleRunner { // generate global variables var state = new Struct(); this.globals = state; + // separate vars and constants + var vardefs = Object.values(this.hdlmod.vardefs).filter(vd => vd.constValue == null); + var constdefs = Object.values(this.hdlmod.vardefs).filter(vd => vd.constValue != null); // sort globals by output flag and size - var vardefs = Object.values(this.hdlmod.vardefs); function getVarDefSortKey(vdef: HDLVariableDef) { var val = getDataTypeSize(vdef.dtype); // sort by size if (!vdef.isOutput) val += 1000000; // outputs are first in list @@ -353,8 +360,11 @@ export class HDLModuleWASM implements HDLModuleRunner { } state.alignTo(8); this.statebytes = state.len; - // followed by constant pool + // followed by constants and constant pool if (this.constpool) { + for (const vardef of Object.values(constdefs)) { + state.addVar(vardef); + } for (const vardef of Object.values(this.constpool.vardefs)) { state.addVar(vardef); } @@ -444,11 +454,22 @@ export class HDLModuleWASM implements HDLModuleRunner { private defineProperty(proxy, basefn: () => number, vref: StructRec) { var _this = this; + // precompute some things + var elsize = vref.type && getArrayElementSizeFromType(vref.type); + var eltype = vref.type; + while (eltype && isArrayType(eltype)) { + eltype = eltype.subtype; + } + var mask = -1; // set all bits + if (eltype && isLogicType(eltype) && eltype.left < 31) { + mask = (1 << (eltype.left+1)) - 1; // set partial bits + } + // define get/set on proxy object Object.defineProperty(proxy, vref.name, { get() { let base = basefn(); if (vref.type && isArrayType(vref.type)) { - var elsize = getArrayElementSizeFromType(vref.type); + // TODO: can't mask unused bits in array if (elsize == 1) { return new Uint8Array(_this.databuf, base + vref.offset, vref.size); } else if (elsize == 2) { @@ -470,13 +491,13 @@ export class HDLModuleWASM implements HDLModuleRunner { set(value) { var base = basefn(); if (vref.size == 1) { - _this.data8[(base + vref.offset)] = value; + _this.data8[(base + vref.offset)] = value & mask; return true; } else if (vref.size == 2) { - _this.data16[(base + vref.offset) >> 1] = value; + _this.data16[(base + vref.offset) >> 1] = value & mask; return true; } else if (vref.size == 4) { - _this.data32[(base + vref.offset) >> 2] = value; + _this.data32[(base + vref.offset) >> 2] = value & mask; return true; } else { throw new HDLError(vref, `can't set property ${vref.name}`); @@ -495,27 +516,46 @@ export class HDLModuleWASM implements HDLModuleRunner { return proxy; } - private genInitData() { + setInitialValues() { for (var rec of this.globals.locals) { - if (rec.init) { - var arr = this.state[rec.name]; - if (!arr) throw new HDLError(rec, `no array to init`); - for (let i=0; i> 2); + } + private addHelperFunctions() { this.addCopyTraceRecFunction(); this.addEvalFunction(); @@ -979,6 +1019,11 @@ export class HDLModuleWASM implements HDLModuleRunner { } _creset2wasm(e: HDLUnop, opts:Options) { + if (isVarRef(e.left)) { + var glob = this.globals.lookup(e.left.refname); + // TOOD: must be better way to tell non-randomize values + if (glob && !glob.name.startsWith("__")) glob.reset = true; + } // TODO return this.e2w(e.left, opts); return this.bmod.nop(); } diff --git a/src/ide/embedui.ts b/src/ide/embedui.ts index ebd1ce3a..f5fea861 100644 --- a/src/ide/embedui.ts +++ b/src/ide/embedui.ts @@ -66,13 +66,13 @@ function addPageFocusHandlers() { }); } -function startROM(title, rom) { +async function startROM(title, rom) { if (!rom ) { alert("No ROM found."); return; } console.log(rom.length + ' bytes'); - platform.loadROM(title, rom); + await platform.loadROM(title, rom); platform.resume(); } diff --git a/src/ide/ui.ts b/src/ide/ui.ts index 88e47ce7..111b7551 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -1156,7 +1156,7 @@ function measureBuildTime() { //gaEvent('build', platform_id); } -function setCompileOutput(data: WorkerResult) { +async function setCompileOutput(data: WorkerResult) { // errors? mark them in editor if (data && data.errors && data.errors.length > 0) { toolbar.addClass("has-errors"); @@ -1178,7 +1178,7 @@ function setCompileOutput(data: WorkerResult) { try { clearBreakpoint(); // so we can replace memory (TODO: change toolbar btn) _resetRecording(); - platform.loadROM(getCurrentPresetTitle(), rom); // TODO: should be async? + await platform.loadROM(getCurrentPresetTitle(), rom); current_output = rom; if (!userPaused) _resume(); measureBuildTime(); diff --git a/src/platform/verilog.ts b/src/platform/verilog.ts index 1062a369..3108d75d 100644 --- a/src/platform/verilog.ts +++ b/src/platform/verilog.ts @@ -190,7 +190,7 @@ var VerilogPlatform = function(mainElement, options) { await loadScript('./gen/common/hdl/hdltypes.js'); await loadScript('./gen/common/hdl/hdlruntime.js'); await loadScript('./gen/common/hdl/hdlwasm.js'); - await loadScript('./lib/binaryen.js'); // TODO: path? + await loadScript('./lib/binaryen.js'); video = new RasterVideo(mainElement,videoWidth,videoHeight,{overscan:true}); video.create(); poller = setKeyboardFromMap(video, switches, VERILOG_KEYCODE_MAP, (o,key,code,flags) => { @@ -275,7 +275,7 @@ var VerilogPlatform = function(mainElement, options) { } // paint into frame, synched with vsync if full speed var trace = this.isScopeVisible(); - this.updateVideoFrameCycles(cyclesPerFrame * fps/60 + 1, sync, trace); + this.updateVideoFrameCycles(Math.ceil(cyclesPerFrame * fps/60), sync, trace); if (fps < 0.25) { idata[frameidx] = -1; } @@ -431,9 +431,7 @@ var VerilogPlatform = function(mainElement, options) { if (scanlineCycles <= 0) throw new Error(`scanlineCycles must be > 0`); var maxLineCycles = 1009; // prime number so we eventually sync up var nextlineCycles = scanlineCycles || maxLineCycles; - // 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 @@ -446,7 +444,6 @@ var VerilogPlatform = function(mainElement, options) { if (nextlineCycles > 0) { top.tick2(nextlineCycles); } - // TODO: this has to be done more quickly resetKbdStrobe(); // convert trace buffer to video/audio var n = 0; @@ -496,10 +493,12 @@ var VerilogPlatform = function(mainElement, options) { tmod.resetTrace(); // exit when vsync starts and then stops if (tmod.trace.vsync) { - wasvsync = true; + framevsync = true; top.state.hpaddle = 0; top.state.vpaddle = 0; - } else if (wasvsync) { + framex = framey = frameidx = 0; + } else if (framevsync) { + framevsync = false; break; } } @@ -577,7 +576,6 @@ 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']; @@ -589,7 +587,6 @@ var VerilogPlatform = function(mainElement, options) { var _top = new topcons(topmod, unit.modules['@CONST-POOL@']); _top.getFileData = (path) => current_project.filedata[path]; // external file provider await _top.init(); - _top.powercycle(); this.dispose(); top = _top; // create signal array @@ -610,6 +607,9 @@ var VerilogPlatform = function(mainElement, options) { trace_signals = trace_signals.filter((v) => { return !v.label.startsWith("__V"); }); // remove __Vclklast etc trace_index = 0; // reset + if (top instanceof HDLModuleWASM) { + top.randomizeOnReset = true; + } this.poweron(); // query output signals -- video or not? this.hasvideo = top.state.vsync != null && top.state.hsync != null && top.state.rgb != null; @@ -702,7 +702,7 @@ var VerilogPlatform = function(mainElement, options) { } reset() { if (!top) return; - //top.reset(); // to avoid clobbering user inputs + // TODO: how do we avoid clobbering user-modified signals? doreset(); trace_index = 0; if (trace_buffer) trace_buffer.fill(0); @@ -754,7 +754,6 @@ var VerilogPlatform = function(mainElement, options) { } } - // TODO: bind() a function to avoid depot? saveState() { return {o: top && top.saveState()}; } @@ -782,7 +781,6 @@ var VerilogPlatform = function(mainElement, options) { keycode = state.keycode; } getDownloadFile() { - // TODO: WASM code too? if (top instanceof HDLModuleJS) { return { extension:".js", @@ -795,6 +793,9 @@ var VerilogPlatform = function(mainElement, options) { }; } } + getHDLModuleRunner() { + return top; + } } // end of inner class return new _VerilogPlatform(); diff --git a/test/cli/testverilog.js b/test/cli/testverilog.js index b4ad7a57..d58a2725 100644 --- a/test/cli/testverilog.js +++ b/test/cli/testverilog.js @@ -28,6 +28,8 @@ async function loadPlatform(msg) { //console.log(msg.output.ports); //console.log(msg.output.signals); await platform.loadROM("ROM", msg.output); + platform.getHDLModuleRunner().randomizeOnReset = false; + platform.getHDLModuleRunner().powercycle(); //await platform.loadROM("ROM", msg.output); for (var i=0; i<100000 && !platform.isBlocked(); i++) { platform.tick();