From 27a9076cb503c6d5a3c82213daceff4dfc10a273 Mon Sep 17 00:00:00 2001
From: Steven Hugg <hugg@fasterlight.com>
Date: Sat, 18 Nov 2017 14:51:25 -0500
Subject: [PATCH] verilog: 2d array; digits; score; reset w/ no init; more
 warnings

---
 presets/verilog/ball_paddle.v      | 132 +++++++++++++++++----
 presets/verilog/digits10.v         | 184 +++++++++++++++++++++++++++++
 presets/verilog/hvsync_generator.v |   4 +
 src/platform/verilog.js            |   3 +
 src/worker/verilator2js.js         |  34 ++++--
 src/worker/workermain.js           |   4 +-
 6 files changed, 330 insertions(+), 31 deletions(-)
 create mode 100644 presets/verilog/digits10.v

diff --git a/presets/verilog/ball_paddle.v b/presets/verilog/ball_paddle.v
index 3fb925f5..04ee206c 100644
--- a/presets/verilog/ball_paddle.v
+++ b/presets/verilog/ball_paddle.v
@@ -1,4 +1,36 @@
 `include "hvsync_generator.v"
+`include "digits10.v"
+
+module player_stats(reset, score, lives, incscore, declives);
+  
+  input reset;
+  output [3:0] score[2];
+  input incscore;
+  output [3:0] lives;
+  input declives;
+
+  always @(posedge incscore or posedge reset)
+    begin
+      if (reset) begin
+        score[0] <= 0;
+        score[1] <= 0;
+      end else if (score[0] == 9) begin
+        score[0] <= 0;
+        score[1] <= score[1] + 1;
+      end else begin
+        score[0] <= score[0] + 1;
+      end
+    end
+
+  always @(posedge declives or posedge reset)
+    begin
+      if (reset)
+        lives <= 3;
+      else if (lives != 0)
+        lives <= lives - 1;
+    end
+
+endmodule
 
 module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
 
@@ -20,6 +52,11 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
   reg ball_dir_y;
   
   reg brick_array [BRICKS_H * BRICKS_V];
+
+  wire [3:0] score[2];
+  wire [3:0] lives;
+  reg incscore;
+  reg declives;
   
   localparam BRICKS_H = 16;
   localparam BRICKS_V = 8;
@@ -41,6 +78,32 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
     .hpos(hpos),
     .vpos(vpos)
   );
+  
+  // scoreboard
+
+  player_stats stats(.reset(reset), .score(score), .lives(lives),
+                     .incscore(incscore), .declives(declives));
+
+  wire [3:0] score_digit;
+  wire [4:0] score_bits;
+  
+  always @(*)
+    begin
+      case (hpos[7:5])
+        1: score_digit = score[1];
+        2: score_digit = score[0];
+        6: score_digit = lives;
+        default: score_digit = 15; // no digit
+      endcase
+    end
+  
+  digits10_case numbers(
+    .digit(score_digit),
+    .yofs(vpos[4:2]),
+    .bits(score_bits)
+  );
+
+  wire score_gfx = display_on && score_bits[hpos[4:2] ^ 3'b111];
 
   // TODO: only works when paddle at bottom of screen!
   always @(posedge hsync)
@@ -54,27 +117,32 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
   // TODO: unsigned compare doesn't work in JS
   wire [8:0] paddle_rel_x = ((hpos-paddle_pos) & 9'h1ff);
   wire paddle_gfx = (vcell == 28) && (paddle_rel_x < PADDLE_WIDTH);
-  
+
   wire [8:0] ball_rel_x = (hpos-ball_x);
   wire [8:0] ball_rel_y = (vpos-ball_y);
   
   wire ball_gfx = ball_rel_x < BALL_SIZE
   	       && ball_rel_y < BALL_SIZE;
-  
+
   reg main_gfx;
   reg brick_present;
   reg [6:0] brick_index;
-  
+
+  // compute main_gfx and locate bricks
   always @(posedge clk)
   begin
-    if (vpos[8:6] == 1 && !lr_border) // 8 rows
+    // see if we are scanning brick area
+    if (vpos[8:6] == 1 && !lr_border)
     begin
-      // compute brick index
+      // every 16th pixel, starting at 8
       if (hpos[3:0] == 8) begin
+        // compute brick index
         brick_index <= {vpos[5:3], hpos[7:4]};
         main_gfx <= 0; // 2 pixel horiz spacing between bricks
-      // load brick bit from array
-      end else if (hpos[3:0] == 9) begin
+      end
+      // every 17th pixel
+      else if (hpos[3:0] == 9) begin
+        // load brick bit from array
         brick_present <= brick_array[brick_index];
       end else begin
         main_gfx <= brick_present && vpos[2:0] != 0; // 1 pixel vert. spacing
@@ -82,6 +150,10 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
     end else begin
       brick_present <= 0;
       case (vpos[8:3])
+        0: main_gfx <= score_gfx; // scoreboard
+        1: main_gfx <= score_gfx;
+        2: main_gfx <= score_gfx;
+        3: main_gfx <= 0;
         4: main_gfx <= 1; // top border
         //14: main_gfx <= hpos[4];
         //21: main_gfx <= hpos[5];
@@ -98,26 +170,40 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
   reg [5:0] ball_collide_bits = 0;
   /* verilator lint_on MULTIDRIVEN */
 
+  // compute ball collisions with paddle and playfield
   always @(posedge clk)
     if (ball_pixel_collide) begin
-      if (paddle_gfx) // did we collide w/ paddle?
-        ball_collide_bits[4] <= 1;
-      else if (brick_present)
-        brick_array[brick_index] <= 0;
-      // ball has 4 collision quadrants
-      if (!ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[0] <= 1;
-      if (ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[1] <= 1;
-      if (!ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[2] <= 1;
-      if (ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[3] <= 1;
+      if (paddle_gfx) begin
+        // did we collide w/ paddle?
+        ball_collide_bits[4] <= 1; // bit 4 == paddle collide
+      end else begin
+        // ball has 4 collision quadrants
+        if (!ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[0] <= 1;
+        if (ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[1] <= 1;
+        if (!ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[2] <= 1;
+        if (ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[3] <= 1;
+      end
     end
 
+  // compute ball collisions with brick
+  always @(posedge clk)
+    if (ball_pixel_collide && brick_present) begin
+      brick_array[brick_index] <= 0;
+      incscore <= 1; // increment score
+    end else begin
+      incscore <= 0; // reset incscore
+    end
+
+  wire signed [8:0] ball_paddle_dx = ball_x - paddle_pos + 8;
+
+  // compute ball new position and velocity
   always @(posedge vsync or posedge reset)
     begin
       if (reset) begin
         ball_dir_y <= BALL_DIR_DOWN;
       end else
-      if (ball_collide_bits[4]) begin // collided with paddle?
-        reg signed [8:0] ball_paddle_dx = ball_x - paddle_pos + 8;
+      // ball collided with paddle?
+      if (ball_collide_bits[4]) begin 
         // bounces upward off of paddle
         ball_dir_y <= BALL_DIR_UP;
         // which side of paddle, left/right?
@@ -127,6 +213,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
       end else begin
         // collided with playfield
         // TODO: can still slip through corners
+        // compute left/right bounce
         casez (ball_collide_bits[3:0])
           4'b01?1: ball_dir_x <= BALL_DIR_RIGHT; // left edge/corner
           4'b1101: ball_dir_x <= BALL_DIR_RIGHT; // left corner
@@ -134,6 +221,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
           4'b1110: ball_dir_x <= BALL_DIR_LEFT; // right corner
           default: ;
         endcase
+        // compute top/bottom bounce
         casez (ball_collide_bits[3:0])
           4'b1011: ball_dir_y <= BALL_DIR_DOWN;
           4'b0111: ball_dir_y <= BALL_DIR_DOWN;
@@ -146,7 +234,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
           default: ;
         endcase
       end
-      ball_collide_bits <= 0;
+      ball_collide_bits <= 0; // clear all collide bits for frame
     end
   
   always @(negedge vsync or posedge reset)
@@ -164,10 +252,10 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
     end
   
   wire grid_gfx = (((hpos&7)==0) || ((vpos&7)==0));
-
-  wire r = display_on && (grid_gfx | ball_gfx);
+  
+  wire r = display_on && (ball_gfx | paddle_gfx);
   wire g = display_on && (main_gfx | ball_gfx);
-  wire b = display_on && (ball_gfx | brick_present);
+  wire b = display_on && (grid_gfx | ball_gfx | brick_present);
   assign rgb = {b,g,r};
 
 endmodule
diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v
new file mode 100644
index 00000000..e2500810
--- /dev/null
+++ b/presets/verilog/digits10.v
@@ -0,0 +1,184 @@
+`include "hvsync_generator.v"
+
+module digits10_case(digit, yofs, bits);
+  
+  input [3:0] digit;
+  input [2:0] yofs;
+  output [4:0] bits;
+
+  wire [6:0] caseexpr = {digit,yofs};
+  always @(*)
+    case (caseexpr)
+      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;
+  input [2:0] yofs;
+  output [4:0] bits;
+  
+  reg [4:0] bitarray[10][5];
+
+  always @(*)
+    bits = bitarray[digit][yofs];
+  
+  initial
+  begin
+    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;
+  end
+endmodule
+
+module test_numbers_top(clk, hsync, vsync, rgb);
+
+  input clk;
+  output hsync, vsync;
+  output [2:0] rgb;
+  wire display_on;
+  wire [8:0] hpos;
+  wire [8:0] vpos;
+  
+  hvsync_generator hvsync_gen(
+    .clk(clk),
+    .hsync(hsync),
+    .vsync(vsync),
+    .display_on(display_on),
+    .hpos(hpos),
+    .vpos(vpos)
+  );
+  
+  wire [3:0] digit = hpos[6:3];
+  wire [2:0] yofs = vpos[2:0];
+  wire [4:0] bits;
+  
+  digits10_array numbers(
+    .digit(digit),
+    .yofs(yofs),
+    .bits(bits)
+  );
+
+  wire r = display_on && 0;
+  wire g = display_on && bits[hpos[2:0] ^ 3'b111];
+  wire b = display_on && 0;
+  assign rgb = {b,g,r};
+
+endmodule
diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v
index 3415412d..f1976e01 100644
--- a/presets/verilog/hvsync_generator.v
+++ b/presets/verilog/hvsync_generator.v
@@ -1,3 +1,5 @@
+`ifndef HVSYNC_GENERATOR_H
+`define HVSYNC_GENERATOR_H
 
 module hvsync_generator(
   clk, hsync, vsync, display_on, hpos, vpos);
@@ -57,3 +59,5 @@ module hvsync_generator(
   assign vsync = ~vga_VS;
 
 endmodule
+
+`endif
diff --git a/src/platform/verilog.js b/src/platform/verilog.js
index 1c2593ca..fe3a8199 100644
--- a/src/platform/verilog.js
+++ b/src/platform/verilog.js
@@ -5,6 +5,7 @@ var VERILOG_PRESETS = [
   {id:'hvsync_generator.v', name:'Video Sync Generator'},
   {id:'test_hvsync.v', name:'Test Pattern'},
   {id:'lfsr.v', name:'Linear Feedback Shift Register'},
+  {id:'digits10.v', name:'Digits'},
   {id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'},
   {id:'ball_paddle.v', name:'Brick Smash Game'},
   //{id:'pong.v', name:'Pong'},
@@ -69,6 +70,8 @@ function VerilatorBase() {
 
   this.reset2 = function() {
     if (this.reset !== undefined) {
+      this.reset = 0;
+      this.tick2();
       this.reset = 1;
       for (var i=0; i<RESET_TICKS; i++)
         this.tick2();
diff --git a/src/worker/verilator2js.js b/src/worker/verilator2js.js
index 51815ea4..d6981db3 100644
--- a/src/worker/verilator2js.js
+++ b/src/worker/verilator2js.js
@@ -18,11 +18,22 @@ function parseDecls(text, arr, name, bin, bout) {
     arr.push({
       wordlen:parseInt(m[1]),
       name:m[2],
-      arrlen:parseInt(m[3]),
+      arrdim:[parseInt(m[3])],
       len:parseInt(m[4]),
       ofs:parseInt(m[5]),
     });
   }
+  re = new RegExp(name + "(\\d+)[(](\\w+)\\[(\\d+)\\]\\[(\\d+)\\],(\\d+),(\\d+)[)]", 'gm');
+  var m;
+  while ((m = re.exec(text))) {
+    arr.push({
+      wordlen:parseInt(m[1]),
+      name:m[2],
+      arrdim:[parseInt(m[3]), parseInt(m[4])],
+      len:parseInt(m[5]),
+      ofs:parseInt(m[6]),
+    });
+  }
 }
 
 function buildModule(o) {
@@ -33,10 +44,17 @@ function buildModule(o) {
     m += "\tself." + o.ports[i].name + ";\n";
   }
   for (var i=0; i<o.signals.length; i++) {
-    if (o.signals[i].arrlen)
-      m += "\tvar " + o.signals[i].name + " = self." + o.signals[i].name + " = [];\n";
-    else
-      m += "\tself." + o.signals[i].name + ";\n";
+    var sig = o.signals[i];
+    if (sig.arrdim) {
+      if (sig.arrdim.length == 1) {
+        m += "\tvar " + sig.name + " = self." + sig.name + " = [];\n";
+      } else if (sig.arrdim.length == 2) {
+        m += "\tvar " + sig.name + " = self." + sig.name + " = [];\n";
+        m += "\tfor(var i=0; i<" + sig.arrdim[0] + "; i++) { " + sig.name + "[i] = []; }\n";
+      }
+    } else {
+      m += "\tself." + sig.name + ";\n";
+    }
   }
   for (var i=0; i<o.funcs.length; i++) {
     m += o.funcs[i];
@@ -56,9 +74,9 @@ function translateFunction(text) {
   text = text.replace(/[(]IData[)]/g, '');
   text = text.replace(/\b(0x[0-9a-f]+)U/gi, '$1');
   text = text.replace(/\b([0-9]+)U/gi, '$1');
-  text = text.replace(/\bQData /, 'var ');
-  text = text.replace(/\bbool /, '');
-  text = text.replace(/\bint /, 'var ');
+  text = text.replace(/\bQData /g, 'var ');
+  text = text.replace(/\bbool /g, '');
+  text = text.replace(/\bint /g, 'var ');
   text = text.replace(/(\w+ = VL_RAND_RESET_I)/g, 'self.$1');
   //text = text.replace(/(\w+\[\w+\] = VL_RAND_RESET_I)/g, 'self.$1');
   text = text.replace(/^#/gm, '//#');
diff --git a/src/worker/workermain.js b/src/worker/workermain.js
index 7b07523b..08a2286d 100644
--- a/src/worker/workermain.js
+++ b/src/worker/workermain.js
@@ -1058,7 +1058,9 @@ function compileVerilator(code, platform, options) {
   FS.writeFile(topmod+".v", code);
   writeDependencies(options.dependencies, FS, errors);
   starttime();
-  verilator_mod.callMain(["--cc", "-O3", "--x-assign", "fast", "--noassert", "--pins-bv", "33",
+  verilator_mod.callMain(["--cc", "-O3",
+    "-Wall", "-Wno-DECLFILENAME", "-Wno-UNUSED",
+    "--x-assign", "fast", "--noassert", "--pins-bv", "33",
     "--top-module", topmod, topmod+".v"]);
   endtime("compile");
   if (errors.length) return {errors:errors};