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

verilog: multiple modules, sound, tables, reset, module_top detect

This commit is contained in:
Steven Hugg 2017-11-13 00:24:19 -05:00
parent 014d659558
commit 0ca9f43098
6 changed files with 90 additions and 37 deletions

View File

@ -395,19 +395,23 @@ var SampleAudio = function(clockfreq) {
} }
} }
this.addSingleSample = function(value) {
buffer[bufpos++] = value;
if (bufpos >= buffer.length) {
bufpos = 0;
bufferlist[0] = bufferlist[1];
bufferlist[1] = buffer;
}
}
this.feedSample = function(value, count) { this.feedSample = function(value, count) {
while (count-- > 0) { while (count-- > 0) {
accum += value; accum += value;
sfrac += sinc; sfrac += sinc;
if (sfrac >= 1) { if (sfrac >= 1) {
buffer[bufpos++] = accum / sfrac;
sfrac -= 1; sfrac -= 1;
accum = 0; accum = 0;
if (bufpos >= buffer.length) { this.feedSingleSample(accum / sfrac);
bufpos = 0;
bufferlist[0] = bufferlist[1];
bufferlist[1] = buffer;
}
} }
} }
} }

View File

@ -207,8 +207,7 @@ var AnimationTimer = function(frequencyHz, callback) {
var running; var running;
var lastts = 0; var lastts = 0;
var useReqAnimFrame = window.requestAnimationFrame ? true : false; var useReqAnimFrame = window.requestAnimationFrame ? true : false;
var nframes = 0; var nframes, startts; // for FPS calc
var startts = 0;
function scheduleFrame() { function scheduleFrame() {
if (useReqAnimFrame) if (useReqAnimFrame)
@ -222,8 +221,8 @@ var AnimationTimer = function(frequencyHz, callback) {
lastts += intervalMsec; lastts += intervalMsec;
} else { } else {
lastts = ts; lastts = ts;
startts = ts;
} }
if (nframes == 0) startts = ts;
if (nframes++ == 300) { if (nframes++ == 300) {
console.log("Avg framerate: " + nframes*1000/(ts-startts) + " fps"); console.log("Avg framerate: " + nframes*1000/(ts-startts) + " fps");
} }
@ -240,6 +239,7 @@ var AnimationTimer = function(frequencyHz, callback) {
if (!running) { if (!running) {
running = true; running = true;
lastts = 0; lastts = 0;
nframes = 0;
scheduleFrame(); scheduleFrame();
} }
} }

View File

@ -2,14 +2,30 @@
var VERILOG_PRESETS = [ var VERILOG_PRESETS = [
{id:'hvsync.v', name:'Hello Verilog'}, {id:'hvsync.v', name:'Hello Verilog'},
{id:'pong.v', name:'Pong'},
]; ];
function VerilatorBase() { function VerilatorBase() {
this.VL_RAND_RESET_I = function(bits) { return Math.floor(Math.random() * (1<<bits)); } this.VL_RAND_RESET_I = function(bits) { return Math.floor(Math.random() * (1<<bits)); }
this.tick = function() { function vl_fatal(msg) {
console.log(msg);
}
this.reset2 = function() {
if (this.reset !== 'undefined') {
this.reset = 1;
for (var i=0; i<100; i++)
this.tick2();
this.reset = 0;
}
}
this.tick2 = function() {
this.clk = 0;
this.eval();
this.clk = 1;
this.eval(); this.eval();
this.clk ^= 1;
} }
var vlSymsp = {TOPp:this}; var vlSymsp = {TOPp:this};
@ -29,7 +45,7 @@ function VerilatorBase() {
vlSymsp.__Vm_activity = true; vlSymsp.__Vm_activity = true;
this._eval(vlSymsp); this._eval(vlSymsp);
__Vchange = this._change_request(vlSymsp); __Vchange = this._change_request(vlSymsp);
if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,"Verilated model didn't converge"); if (++__VclockLoop > 100) { vl_fatal("Verilated model didn't converge"); }
} }
if (__VclockLoop > maxVclockLoop) { if (__VclockLoop > maxVclockLoop) {
maxVclockLoop = __VclockLoop; maxVclockLoop = __VclockLoop;
@ -47,26 +63,44 @@ function VerilatorBase() {
this._eval_settle(vlSymsp); this._eval_settle(vlSymsp);
this._eval(vlSymsp); this._eval(vlSymsp);
__Vchange = this._change_request(vlSymsp); __Vchange = this._change_request(vlSymsp);
if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,"Verilated model didn't DC converge"); if (++__VclockLoop > 100) { vl_fatal("Verilated model didn't DC converge"); }
} }
} }
} }
var VerilogPlatform = function(mainElement, options) { var VerilogPlatform = function(mainElement, options) {
var self = this; var self = this;
var video; var video, audio;
var videoWidth=288; var videoWidth=288;
var videoHeight=248; var videoHeight=248;
var idata, timer; var idata, timer;
var gen; var gen;
var frameRate = 60; var frameRate = 60;
var AUDIO_FREQ = 15700;
this.getPresets = function() { return VERILOG_PRESETS; } this.getPresets = function() { return VERILOG_PRESETS; }
function tick2() {
gen.tick2();
audio.addSingleSample(0+gen.audio); // TODO: sync with audio freq
}
var RGBLOOKUP = [
0xff111111,
0xff1111ff,
0xff11ff11,
0xff11ffff,
0xffff1111,
0xffff11ff,
0xffffff11,
0xffffffff,
];
this.start = function() { this.start = function() {
// TODO // TODO
video = new RasterVideo(mainElement,videoWidth,videoHeight); video = new RasterVideo(mainElement,videoWidth,videoHeight);
video.create(); video.create();
audio = new SampleAudio(AUDIO_FREQ);
idata = video.getFrameData(); idata = video.getFrameData();
// TODO: 15.7 kHz? // TODO: 15.7 kHz?
timer = new AnimationTimer(frameRate, function() { timer = new AnimationTimer(frameRate, function() {
@ -75,17 +109,16 @@ var VerilogPlatform = function(mainElement, options) {
var i=0; var i=0;
for (var y=0; y<videoHeight; y++) { for (var y=0; y<videoHeight; y++) {
for (var x=0; x<videoWidth; x++) { for (var x=0; x<videoWidth; x++) {
gen.tick(); tick2();
gen.tick(); idata[i++] = RGBLOOKUP[gen.rgb];
idata[i++] = gen.pixel ? 0xffffffff : 0xff111111;
} }
var z=0; var z=0;
while (gen.hsync && z++<videoWidth*2) gen.tick(); while (gen.hsync && z++<videoWidth) tick2();
while (!gen.hsync && z++<videoWidth*2) gen.tick(); while (!gen.hsync && z++<videoWidth) tick2();
} }
var z=0; var z=0;
while (gen.vsync && z++<videoWidth*160) gen.tick(); while (gen.vsync && z++<videoWidth*80) tick2();
while (!gen.vsync && z++<videoWidth*160) gen.tick(); while (!gen.vsync && z++<videoWidth*80) tick2();
video.updateFrame(); video.updateFrame();
}); });
} }
@ -105,15 +138,16 @@ var VerilogPlatform = function(mainElement, options) {
} }
this.pause = function() { this.pause = function() {
timer.stop(); timer.stop();
//audio.stop(); audio.stop();
} }
this.resume = function() { this.resume = function() {
timer.start(); timer.start();
//audio.start(); audio.start();
} }
this.reset = function() { this.reset = function() {
gen._ctor_var_reset(); gen._ctor_var_reset();
gen.reset2();
} }
this.getToolForFilename = function(fn) { this.getToolForFilename = function(fn) {
return "verilator"; return "verilator";

View File

@ -429,6 +429,7 @@ function setCompileOutput(data) {
compparams = data.params; compparams = data.params;
updatePreset(current_preset_id, editor.getValue()); // update persisted entry updatePreset(current_preset_id, editor.getValue()); // update persisted entry
// errors? // errors?
var lines2errmsg = [];
function addErrorMarker(line, msg) { function addErrorMarker(line, msg) {
var div = document.createElement("div"); var div = document.createElement("div");
div.setAttribute("class", "tooltipbox tooltiperror"); div.setAttribute("class", "tooltipbox tooltiperror");
@ -436,7 +437,9 @@ function setCompileOutput(data) {
div.appendChild(document.createTextNode("\u24cd")); div.appendChild(document.createTextNode("\u24cd"));
var tooltip = document.createElement("span"); var tooltip = document.createElement("span");
tooltip.setAttribute("class", "tooltiptext"); tooltip.setAttribute("class", "tooltiptext");
if (lines2errmsg[line]) msg = lines2errmsg[line] + "\n" + msg;
tooltip.appendChild(document.createTextNode(msg)); tooltip.appendChild(document.createTextNode(msg));
lines2errmsg[line] = msg;
div.appendChild(tooltip); div.appendChild(tooltip);
editor.setGutterMarker(line, "gutter-info", div); editor.setGutterMarker(line, "gutter-info", div);
} }
@ -768,7 +771,6 @@ function resetAndDebug() {
setupBreakpoint(); setupBreakpoint();
platform.runEval(function(c) { return true; }); platform.runEval(function(c) { return true; });
} else { } else {
platform.pause();
platform.reset(); platform.reset();
} }
} }

View File

@ -12,12 +12,10 @@ function parseDecls(text, arr, name, bin, bout) {
ofs:parseInt(m[4]), ofs:parseInt(m[4]),
}); });
} }
//console.log(arr);
} }
function buildModule(o) { function buildModule(o) {
var m = '"use strict";\n'; var m = '"use strict";\n';
//m += 'var ' + o.name + ' = function(base) {\n';
m += '\tvar self = this;\n'; m += '\tvar self = this;\n';
m += '\tvar VL_RAND_RESET_I = base.VL_RAND_RESET_I;\n'; m += '\tvar VL_RAND_RESET_I = base.VL_RAND_RESET_I;\n';
for (var i=0; i<o.ports.length; i++) { for (var i=0; i<o.ports.length; i++) {
@ -29,8 +27,6 @@ function buildModule(o) {
for (var i=0; i<o.funcs.length; i++) { for (var i=0; i<o.funcs.length; i++) {
m += o.funcs[i]; m += o.funcs[i];
} }
//m += "\n}\n";
//m += "return " + o.name + ";\n";
return m; return m;
} }
@ -56,11 +52,20 @@ function translateFunction(text) {
return "function " + text + "\nself." + funcname + " = " + funcname + ";\n"; return "function " + text + "\nself." + funcname + " = " + funcname + ";\n";
} }
function translateStaticVars(text) {
var s = "";
var m;
var re = /VL_ST_SIG(\d+)[(](\w+?)::(\w+).(\d+).,(\d+),(\d+)[)]/g;
while (m = re.exec(text)) {
s += "var " + m[3] + " = this." + m[3] + " = new Uint" + m[1] + "Array(" + m[4] + ");\n";
}
return s;
}
function translateVerilatorOutputToJS(htext, cpptext) { function translateVerilatorOutputToJS(htext, cpptext) {
// parse header file // parse header file
moduleName = /VL_MODULE.(\w+)./.exec(htext)[1]; moduleName = /VL_MODULE.(\w+)./.exec(htext)[1];
symsName = moduleName + "__Syms"; symsName = moduleName + "__Syms";
//console.log(moduleName, symsName);
var ports = []; var ports = [];
parseDecls(htext, ports, 'VL_IN', true, false); parseDecls(htext, ports, 'VL_IN', true, false);
parseDecls(htext, ports, 'VL_OUT', false, true); parseDecls(htext, ports, 'VL_OUT', false, true);
@ -72,9 +77,9 @@ function translateVerilatorOutputToJS(htext, cpptext) {
var re_fnsplit = new RegExp("(?:void|QData) " + moduleName + "::"); var re_fnsplit = new RegExp("(?:void|QData) " + moduleName + "::");
var functexts = cpptext.split(re_fnsplit); var functexts = cpptext.split(re_fnsplit);
var funcs = []; var funcs = [];
funcs.push(translateStaticVars(functexts[0]));
for (var i=4; i<functexts.length; i++) { for (var i=4; i<functexts.length; i++) {
var fntxt = translateFunction(functexts[i]); var fntxt = translateFunction(functexts[i]);
//console.log(fntxt);
funcs.push(fntxt); funcs.push(fntxt);
} }
@ -93,6 +98,7 @@ function translateVerilatorOutputToJS(htext, cpptext) {
//// ////
// TODO: unit test
/* /*
incpp = "obj_dir/Vhvsync_generator.cpp" incpp = "obj_dir/Vhvsync_generator.cpp"
inh = "obj_dir/Vhvsync_generator.h" inh = "obj_dir/Vhvsync_generator.h"

View File

@ -266,9 +266,11 @@ function makeErrorMatcher(errors, regex, iline, imsg) {
var matches = regex.exec(s); var matches = regex.exec(s);
if (matches) { if (matches) {
errors.push({ errors.push({
line:parseInt(matches[iline]), line:parseInt(matches[iline]) || 1,
msg:matches[imsg] msg:matches[imsg]
}); });
} else {
console.log(s);
} }
} }
} }
@ -1033,29 +1035,34 @@ function compileVerilator(code, platform) {
loadWASM("verilator_bin"); loadWASM("verilator_bin");
load("verilator2js"); load("verilator2js");
var errors = []; var errors = [];
var match_fn = makeErrorMatcher(errors, /%Error: main.v:(\d+): (.+)/, 1, 2); var match_fn = makeErrorMatcher(errors, /%Error: (.+?:)?(\d+)?[:]?\s*(.+)/, 2, 3);
var verilator_mod = verilator_bin({ var verilator_mod = verilator_bin({
wasmBinary:wasmBlob['verilator_bin'], wasmBinary:wasmBlob['verilator_bin'],
noInitialRun:true, noInitialRun:true,
print:print_fn, print:print_fn,
printErr:match_fn, printErr:match_fn,
}); });
// detect module_top name
var topmod = "top";
var m = /\bmodule\s+(\w+?_top)/.exec(code);
if (m && m[1]) topmod = m[1];
var FS = verilator_mod['FS']; var FS = verilator_mod['FS'];
//setupFS(FS); //setupFS(FS);
FS.writeFile("main.v", code); FS.writeFile(topmod+".v", code);
starttime(); starttime();
verilator_mod.callMain(["--cc", "-O2", "main.v"]); verilator_mod.callMain(["--cc", "-O3", "--top-module", topmod, topmod+".v"]);
endtime("compile"); endtime("compile");
if (errors.length) return {errors:errors};
try { try {
var h_file = FS.readFile("obj_dir/Vmain.h", {encoding:'utf8'}); var h_file = FS.readFile("obj_dir/V"+topmod+".h", {encoding:'utf8'});
var cpp_file = FS.readFile("obj_dir/Vmain.cpp", {encoding:'utf8'}); var cpp_file = FS.readFile("obj_dir/V"+topmod+".cpp", {encoding:'utf8'});
//console.log(cpp_file)
var rtn = translateVerilatorOutputToJS(h_file, cpp_file); var rtn = translateVerilatorOutputToJS(h_file, cpp_file);
rtn.errors = errors; rtn.errors = errors;
rtn.lines = [];// TODO rtn.lines = [];// TODO
rtn.intermediate = {listing:h_file + cpp_file}; rtn.intermediate = {listing:h_file + cpp_file};
return rtn; return rtn;
} catch(e) { } catch(e) {
console.log(e);
return {errors:errors}; return {errors:errors};
} }
} }