mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-21 21:29:17 +00:00
verilog: randomizeOnReset = true except for unit tests (only <=32 bit values reset)
This commit is contained in:
parent
876d66e6de
commit
10d04f9114
@ -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?
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<rec.init.exprs.length; i++) {
|
||||
let e = rec.init.exprs[i];
|
||||
if (isArrayItem(e) && isConstExpr(e.expr)) {
|
||||
arr[e.index] = e.expr.cvalue;
|
||||
} else {
|
||||
throw new HDLError(e, `non-const expr in initarray (multidimensional arrays not supported)`);
|
||||
}
|
||||
this.setInitialValue(rec);
|
||||
}
|
||||
}
|
||||
|
||||
private setInitialValue(rec: StructRec) {
|
||||
var arr = this.state[rec.name];
|
||||
if (rec.init) {
|
||||
if (!arr) throw new HDLError(rec, `no array to init`);
|
||||
for (let i=0; i<rec.init.exprs.length; i++) {
|
||||
let e = rec.init.exprs[i];
|
||||
if (isArrayItem(e) && isConstExpr(e.expr)) {
|
||||
arr[e.index] = e.expr.cvalue;
|
||||
} else {
|
||||
throw new HDLError(e, `non-const expr in initarray (multidimensional arrays not supported)`);
|
||||
}
|
||||
//console.log(rec.name, rec.type, arr);
|
||||
}
|
||||
if (rec.constval) {
|
||||
this.state[rec.name] = rec.constval.cvalue || rec.constval.bigvalue;
|
||||
//console.log(rec.name, rec.type, arr);
|
||||
} else if (rec.constval) {
|
||||
this.state[rec.name] = rec.constval.cvalue || rec.constval.bigvalue;
|
||||
} else if (rec.type && rec.reset && this.randomizeOnReset) {
|
||||
if (isLogicType(rec.type) && typeof arr === 'number') {
|
||||
this.state[rec.name] = Math.random() * 4294967296; // don't need to mask
|
||||
} else if (isArrayType(rec.type) && isLogicType(rec.type.subtype)) {
|
||||
// array types are't mask-protected yet
|
||||
var mask = (1 << (rec.type.subtype.left + 1)) - 1;
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
arr[i] = (Math.random() * 4294967296) & mask;
|
||||
}
|
||||
} else {
|
||||
console.log(`could not reset ${rec.name}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearMutableState() {
|
||||
this.data32.fill(0, 0, this.statebytes >> 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user