From 2fba433f7a799c9dd3456fcc9c03e335ef52c8c3 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sun, 11 Jul 2021 13:41:20 -0500 Subject: [PATCH] verilog: fixed reset values --- doc/notes.txt | 1 + src/common/hdl/hdlwasm.ts | 7 +- src/platform/verilog.ts | 42 ++- test/cli/verilog/badreset.v | 545 ++++++++++++++++++++++++++++++++++++ 4 files changed, 568 insertions(+), 27 deletions(-) create mode 100644 test/cli/verilog/badreset.v diff --git a/doc/notes.txt b/doc/notes.txt index d50c51d9..5bb0b6ab 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -114,6 +114,7 @@ TODO: - optimize trace log w/ wasm buffer - yosys compatibility - randomize on reset? (https://www.xilinx.com/support/documentation/white_papers/wp272.pdf) + - XML should tell us which values are supposed to reset - single-stepping vector games makes screen fade - break on stack overflow, illegal op, bad access, BRK, etc - show in scope instead? diff --git a/src/common/hdl/hdlwasm.ts b/src/common/hdl/hdlwasm.ts index a696982b..69e11b36 100644 --- a/src/common/hdl/hdlwasm.ts +++ b/src/common/hdl/hdlwasm.ts @@ -1021,10 +1021,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: must be better way to tell non-randomize values + // set clk and reset to known values so values are reset properly + glob.reset = glob.name != 'clk' && glob.name != 'reset' && !glob.name.startsWith("__V"); } - // TODO return this.e2w(e.left, opts); + // we reset values in powercycle() return this.bmod.nop(); } diff --git a/src/platform/verilog.ts b/src/platform/verilog.ts index 3108d75d..c23c0781 100644 --- a/src/platform/verilog.ts +++ b/src/platform/verilog.ts @@ -74,8 +74,8 @@ var VERILOG_KEYCODE_MAP = makeKeycodeMap([ ]); const TRACE_BUFFER_DWORDS = 0x40000; - const CYCLES_PER_FILL = 20; +const SHOW_INTERNAL_SIGNALS = false; // TODO: make this a config value // PLATFORM @@ -159,14 +159,6 @@ var VerilogPlatform = function(mainElement, options) { } } - function doreset() { - top.state.reset = 1; - } - - function unreset() { - top.state.reset = 0; - } - // inner Platform class class _VerilogPlatform extends BasePlatform implements WaveformProvider { @@ -241,7 +233,6 @@ var VerilogPlatform = function(mainElement, options) { while (framey != new_y || clock++ > 200000) { this.setGenInputs(); this.updateVideoFrameCycles(1, true, false); - unreset(); } }); } @@ -280,7 +271,6 @@ var VerilogPlatform = function(mainElement, options) { idata[frameidx] = -1; } //this.restartDebugState(); - unreset(); this.refreshVideoFrame(); // set scope offset if (trace && this.waveview) { @@ -296,7 +286,6 @@ var VerilogPlatform = function(mainElement, options) { advance(novideo : boolean) : number { this.setGenInputs(); this.updateVideoFrameCycles(cyclesPerFrame, true, false); - unreset(); if (!novideo) { this.refreshVideoFrame(); } @@ -519,14 +508,14 @@ var VerilogPlatform = function(mainElement, options) { fillTraceBuffer(count:number) : boolean { var max_index = Math.min(trace_buffer.length - trace_signals.length, trace_index + count); while (trace_index < max_index) { + this.snapshotTrace(); if (!top.isStopped() && !top.isFinished()) { top.tick(); } - this.snapshotTrace(); if (trace_index == 0) break; } - unreset(); + top.state.reset = 0; // need to de-assert reset when using no-video mode return (trace_index == 0); } @@ -604,13 +593,14 @@ var VerilogPlatform = function(mainElement, options) { } } trace_signals = signals; - trace_signals = trace_signals.filter((v) => { return !v.label.startsWith("__V"); }); // remove __Vclklast etc + if (!SHOW_INTERNAL_SIGNALS) { + 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; if (this.hasvideo) { @@ -626,8 +616,9 @@ var VerilogPlatform = function(mainElement, options) { } } } + // randomize values + top.powercycle(); // replace program ROM, if using the assembler - this.reset(); // TODO: fix this, it ain't good if (output.program_rom && output.program_rom_variable) { if (top.state[output.program_rom_variable]) { @@ -644,6 +635,8 @@ var VerilogPlatform = function(mainElement, options) { if (this.waveview) { this.waveview.recreate(); } + // assert reset pin, wait 100 cycles if using video + this.reset(); } restartAudio() { @@ -695,20 +688,21 @@ var VerilogPlatform = function(mainElement, options) { } getFrameRate() { return frameRate; } - poweron() { - if (!top) return; - top.powercycle(); - this.reset(); - } reset() { if (!top) return; // TODO: how do we avoid clobbering user-modified signals? - doreset(); trace_index = 0; if (trace_buffer) trace_buffer.fill(0); if (video) video.setRotate(top.state.rotate ? -90 : 0); $("#verilog_bar").hide(); - if (!this.hasvideo) this.resume(); // TODO? + if (this.hasvideo) { + top.state.reset = 1; + top.tick2(100); + top.state.reset = 0; + } else { + top.state.reset = 1; // reset will be de-asserted later + this.resume(); // TODO? + } } tick() { if (!top) return; diff --git a/test/cli/verilog/badreset.v b/test/cli/verilog/badreset.v new file mode 100644 index 00000000..a4def78e --- /dev/null +++ b/test/cli/verilog/badreset.v @@ -0,0 +1,545 @@ + + +/* +player_stats - Holds two-digit score and one-digit lives counter. +scoreboard_generator - Outputs video signal with score/lives digits. +*/ + +module player_stats(reset, score0, score1, lives, incscore, declives); + + input reset; + output reg [3:0] score0; + output reg [3:0] score1; + input incscore; + output reg [3:0] lives; + input declives; + + always @(posedge incscore or posedge reset) + begin + if (reset) begin + score0 <= 0; + score1 <= 0; + end else if (score0 == 9) begin + score0 <= 0; + score1 <= score1 + 1; + end else begin + score0 <= score0 + 1; + end + end + + always @(posedge declives or posedge reset) + begin + if (reset) + lives <= 3; + else if (lives != 0) + lives <= lives - 1; + end + +endmodule + +module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx); + + input [3:0] score0; + input [3:0] score1; + input [3:0] lives; + input [8:0] vpos; + input [8:0] hpos; + output board_gfx; + + reg [3:0] score_digit; + reg [4:0] score_bits; + + always @(*) + begin + case (hpos[7:5]) + 1: score_digit = score1; + 2: score_digit = score0; + 6: score_digit = lives; + default: score_digit = 15; // no digit + endcase + end + + digits10_array digits( + .digit(score_digit), + .yofs(vpos[4:2]), + .bits(score_bits) + ); + + assign board_gfx = score_bits[hpos[4:2] ^ 3'b111]; + +endmodule + +/* +ROM module with 5x5 bitmaps for the digits 0-9. + +digits10_case - Uses the case statement. +digits10_array - Uses an array and initial block. + +These two modules are functionally equivalent. +*/ + +// module for 10-digit bitmap ROM +module digits10_case(digit, yofs, bits); + + input [3:0] digit; // digit 0-9 + input [2:0] yofs; // vertical offset (0-4) + output reg [4:0] bits; // output (5 bits) + + // combine {digit,yofs} into single ROM address + wire [6:0] caseexpr = {digit,yofs}; + + always @(*) + case (caseexpr)/*{w:5,h:5,count:10}*/ + 7'o00: bits = 5'b11111; + 7'o01: bits = 5'b10001; + 7'o02: bits = 5'b10001; + 7'o03: bits = 5'b10001; + 7'o04: bits = 5'b11111; + + 7'o10: bits = 5'b01100; + 7'o11: bits = 5'b00100; + 7'o12: bits = 5'b00100; + 7'o13: bits = 5'b00100; + 7'o14: bits = 5'b11111; + + 7'o20: bits = 5'b11111; + 7'o21: bits = 5'b00001; + 7'o22: bits = 5'b11111; + 7'o23: bits = 5'b10000; + 7'o24: bits = 5'b11111; + + 7'o30: bits = 5'b11111; + 7'o31: bits = 5'b00001; + 7'o32: bits = 5'b11111; + 7'o33: bits = 5'b00001; + 7'o34: bits = 5'b11111; + + 7'o40: bits = 5'b10001; + 7'o41: bits = 5'b10001; + 7'o42: bits = 5'b11111; + 7'o43: bits = 5'b00001; + 7'o44: bits = 5'b00001; + + 7'o50: bits = 5'b11111; + 7'o51: bits = 5'b10000; + 7'o52: bits = 5'b11111; + 7'o53: bits = 5'b00001; + 7'o54: bits = 5'b11111; + + 7'o60: bits = 5'b11111; + 7'o61: bits = 5'b10000; + 7'o62: bits = 5'b11111; + 7'o63: bits = 5'b10001; + 7'o64: bits = 5'b11111; + + 7'o70: bits = 5'b11111; + 7'o71: bits = 5'b00001; + 7'o72: bits = 5'b00001; + 7'o73: bits = 5'b00001; + 7'o74: bits = 5'b00001; + + 7'o100: bits = 5'b11111; + 7'o101: bits = 5'b10001; + 7'o102: bits = 5'b11111; + 7'o103: bits = 5'b10001; + 7'o104: bits = 5'b11111; + + 7'o110: bits = 5'b11111; + 7'o111: bits = 5'b10001; + 7'o112: bits = 5'b11111; + 7'o113: bits = 5'b00001; + 7'o114: bits = 5'b11111; + + default: bits = 0; + endcase +endmodule + +module digits10_array(digit, yofs, bits); + + input [3:0] digit; // digit 0-9 + input [2:0] yofs; // vertical offset (0-4) + output [4:0] bits; // output (5 bits) + + reg [4:0] bitarray[0:15][0:4]; // ROM array (16 x 5 x 5 bits) + + assign bits = bitarray[digit][yofs]; // assign module output + + integer i,j; + + initial begin/*{w:5,h:5,count:10}*/ + bitarray[0][0] = 5'b11111; + bitarray[0][1] = 5'b10001; + bitarray[0][2] = 5'b10001; + bitarray[0][3] = 5'b10001; + bitarray[0][4] = 5'b11111; + + bitarray[1][0] = 5'b01100; + bitarray[1][1] = 5'b00100; + bitarray[1][2] = 5'b00100; + bitarray[1][3] = 5'b00100; + bitarray[1][4] = 5'b11111; + + bitarray[2][0] = 5'b11111; + bitarray[2][1] = 5'b00001; + bitarray[2][2] = 5'b11111; + bitarray[2][3] = 5'b10000; + bitarray[2][4] = 5'b11111; + + bitarray[3][0] = 5'b11111; + bitarray[3][1] = 5'b00001; + bitarray[3][2] = 5'b11111; + bitarray[3][3] = 5'b00001; + bitarray[3][4] = 5'b11111; + + bitarray[4][0] = 5'b10001; + bitarray[4][1] = 5'b10001; + bitarray[4][2] = 5'b11111; + bitarray[4][3] = 5'b00001; + bitarray[4][4] = 5'b00001; + + bitarray[5][0] = 5'b11111; + bitarray[5][1] = 5'b10000; + bitarray[5][2] = 5'b11111; + bitarray[5][3] = 5'b00001; + bitarray[5][4] = 5'b11111; + + bitarray[6][0] = 5'b11111; + bitarray[6][1] = 5'b10000; + bitarray[6][2] = 5'b11111; + bitarray[6][3] = 5'b10001; + bitarray[6][4] = 5'b11111; + + bitarray[7][0] = 5'b11111; + bitarray[7][1] = 5'b00001; + bitarray[7][2] = 5'b00001; + bitarray[7][3] = 5'b00001; + bitarray[7][4] = 5'b00001; + + bitarray[8][0] = 5'b11111; + bitarray[8][1] = 5'b10001; + bitarray[8][2] = 5'b11111; + bitarray[8][3] = 5'b10001; + bitarray[8][4] = 5'b11111; + + bitarray[9][0] = 5'b11111; + bitarray[9][1] = 5'b10001; + bitarray[9][2] = 5'b11111; + bitarray[9][3] = 5'b00001; + bitarray[9][4] = 5'b11111; + + // clear unused array entries + for (i = 10; i <= 15; i++) + for (j = 0; j <= 4; j++) + bitarray[i][j] = 0; + end +endmodule + + +/* +Video sync generator, used to drive a simulated CRT. +To use: +- Wire the hsync and vsync signals to top level outputs +- Add a 3-bit (or more) "rgb" output to the top level +*/ + +module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos); + + input clk; + input reset; + output reg hsync, vsync; + output display_on; + output reg [8:0] hpos; + output reg [8:0] vpos; + + // declarations for TV-simulator sync parameters + // horizontal constants + parameter H_DISPLAY = 256; // horizontal display width + parameter H_BACK = 23; // horizontal left border (back porch) + parameter H_FRONT = 7; // horizontal right border (front porch) + parameter H_SYNC = 23; // horizontal sync width + // vertical constants + parameter V_DISPLAY = 240; // vertical display height + parameter V_TOP = 5; // vertical top border + parameter V_BOTTOM = 14; // vertical bottom border + parameter V_SYNC = 3; // vertical sync # lines + // derived constants + parameter H_SYNC_START = H_DISPLAY + H_FRONT; + parameter H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1; + parameter H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1; + parameter V_SYNC_START = V_DISPLAY + V_BOTTOM; + parameter V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1; + parameter V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1; + + wire hmaxxed = (hpos == H_MAX) || reset; // set when hpos is maximum + wire vmaxxed = (vpos == V_MAX) || reset; // set when vpos is maximum + + // horizontal position counter + always @(posedge clk) + begin + hsync <= (hpos>=H_SYNC_START && hpos<=H_SYNC_END); + if(hmaxxed) + hpos <= 0; + else + hpos <= hpos + 1; + end + + // vertical position counter + always @(posedge clk) + begin + vsync <= (vpos>=V_SYNC_START && vpos<=V_SYNC_END); + if(hmaxxed) + if (vmaxxed) + vpos <= 0; + else + vpos <= vpos + 1; + end + + // display_on is set when beam is in "safe" visible frame + assign display_on = (hpos