From 9a4dfea4f0c7a0a1ba2b62c6ce89682bbcfd9764 Mon Sep 17 00:00:00 2001
From: saji <saji@saji.dev>
Date: Tue, 30 Apr 2024 23:48:10 -0500
Subject: [PATCH] wip: basic pixel generator + coordinator module

coordinator is a high level hub75 controller.
It drives multiple panels by generating the x/y coordinates that would
be displayed on each, then converting those into the BRAM format to be
written quickly.
---
 Makefile                     |  10 ++-
 verilog/bitslicer.sv         |  34 +++++----
 verilog/coordinator.sv       | 144 +++++++++++++++++++++++++++++++++++
 verilog/hub75e.sv            |   3 -
 verilog/pixgen.sv            |  24 ++++++
 verilog/tb/bitslicer_tb.sv   |  43 +++++++++++
 verilog/tb/coordinator_tb.sv |  14 ++++
 7 files changed, 252 insertions(+), 20 deletions(-)
 create mode 100644 verilog/coordinator.sv
 create mode 100644 verilog/pixgen.sv
 create mode 100644 verilog/tb/coordinator_tb.sv

diff --git a/Makefile b/Makefile
index 61e143d..f1ae0e4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,11 @@
 
-
-
-
 .PHONY all clean test
 
+VERILOG_SOURCES := $(join $(wildcard verilog/*.v), $(wildcard verilog/*.sv))
+TESTBENCH_SOURCES := $(wildcard verilog/tb/*.sv)
+ICARUS_ARGS := "-g2012"
 
+%.vcd: %.vvp
+	vvp $^
 
-
+%.vvp: %.sv
diff --git a/verilog/bitslicer.sv b/verilog/bitslicer.sv
index e0342fd..4038ad6 100644
--- a/verilog/bitslicer.sv
+++ b/verilog/bitslicer.sv
@@ -1,7 +1,7 @@
 module bitslicer (
     input clk,
     input [23:0] rgb[2],
-    input [7:0] pixnum,  // x-value of the pixels we are being fed.
+    input [8:0] pixnum,  // x-value of the pixels we are being fed.
     input start_write,
     output reg [5:0] bitplane_data,
     output [10:0] bitplane_addr,
@@ -9,8 +9,16 @@ module bitslicer (
     output reg done
 );
 
-  reg [3:0] bitplane_bit = 0;
+  reg [2:0] bitplane_bit = 0;
   assign bitplane_addr = (pixnum << 3) + bitplane_bit;
+  assign bitplane_data = {
+    rgb[1][bitplane_bit],
+    rgb[1][bitplane_bit+8],
+    rgb[1][bitplane_bit+16],
+    rgb[0][bitplane_bit],
+    rgb[0][bitplane_bit+8],
+    rgb[0][bitplane_bit+16]
+  };
 
   reg [3:0] state = StateInit;
   localparam integer StateInit = 0;
@@ -26,27 +34,27 @@ module bitslicer (
         bitplane_wren <= 0;
         if (start_write) begin
           state <= StateWriteout;
+          bitplane_wren <= 1;
         end
       end
       StateWriteout: begin
-        bitplane_data <= {
-          rgb[1][bitplane_bit],
-          rgb[1][bitplane_bit+8],
-          rgb[1][bitplane_bit+16],
-          rgb[0][bitplane_bit],
-          rgb[0][bitplane_bit+8],
-          rgb[0][bitplane_bit+16]
-        };
-        bitplane_wren <= 1;
+        // bitplane_data <= {
+        //   rgb[1][bitplane_bit],
+        //   rgb[1][bitplane_bit+8],
+        //   rgb[1][bitplane_bit+16],
+        //   rgb[0][bitplane_bit],
+        //   rgb[0][bitplane_bit+8],
+        //   rgb[0][bitplane_bit+16]
+        // };
         bitplane_bit <= bitplane_bit + 1;
 
         if (bitplane_bit == 7) begin
           state <= StateDone;
+          bitplane_wren <= 0;
         end
       end
       StateDone: begin
-        bitplane_wren <= 0;
-        done <= 1; // strobe
+        done <= 1;  // strobe
         state <= StateInit;
       end
       default: begin
diff --git a/verilog/coordinator.sv b/verilog/coordinator.sv
new file mode 100644
index 0000000..8472e80
--- /dev/null
+++ b/verilog/coordinator.sv
@@ -0,0 +1,144 @@
+module coordinator (
+    input clk
+);
+
+  // pixgen signals
+  reg pixgen_start;
+  reg [8:0] x;
+  reg [8:0] y;
+  wire [23:0] pix_rgb[2];
+  wire [1:0] pix_done;
+
+  pixgen pix0 (
+      .clk(clk),
+      .start(pixgen_start),
+      .x(x),
+      .y(y),
+      .rgb(pix_rgb[0]),
+      .done(pix_done[0])
+  );
+  pixgen pix1 (
+      .clk(clk),
+      .start(pixgen_start),
+      .x(x),
+      .y(y + 9'd32),
+      .rgb(pix_rgb[1]),
+      .done(pix_done[1])
+  );
+
+
+  // slicer signals
+  wire bitslice_start;
+  wire [5:0] bitplane_data;
+  wire [10:0] bitplane_addr;
+  wire bitplane_wren;
+  wire bitplane_done;
+
+  bitslicer bslice (
+      .clk(clk),
+      .rgb(pix_rgb),
+      .pixnum(x),
+      .start_write(bitslice_start),
+      .bitplane_data(bitplane_data),
+      .bitplane_addr(bitplane_addr),
+      .bitplane_wren(bitplane_wren),
+      .done(bitplane_done)
+  );
+
+  // bram signals
+
+  wire [8:0] din;
+  wire [10:0] addr_w;
+  wire [8:0] dout;
+  wire [10:0] addr_r;
+  wire read_clk;
+  wire write_clk;
+
+  lineram bram (
+      .write_clk(clk),
+      .read_clk(clk),
+      .addr_w(bitplane_addr),
+      .din({3'b000, bitplane_data}),
+      .write_en(bitplane_wren),
+      .addr_r(addr_r),
+      .dout(dout)
+  );
+
+  // driver
+  reg write_line;
+  wire line_done;
+  wire [2:0] panel_rgb0;
+  wire [2:0] panel_rgb1;
+  wire display_clk;
+  wire out_enable;
+  wire latch;
+
+  hub75e driver (
+      .clk(clk),
+      .write_trig(write_line),
+      .panel_rgb0(panel_rgb0),
+      .panel_rgb1(panel_rgb1),
+      .display_clk(display_clk),
+      .out_enable(out_enable),
+      .latch(latch),
+      .done(line_done),
+      .pixbuf_addr(addr_r),
+      .pixbuf_data(dout)
+  );
+
+
+  reg [4:0] state = 0;
+
+  localparam unsigned StateInit = 0;
+  localparam unsigned StateStartFrame = 1;
+  localparam unsigned StateGenerateLine = 2;
+  localparam unsigned StateShowLine = 3;
+  localparam unsigned StateIncrementLine = 4;
+  // we're gonna try this
+  assign bitslice_start = pix_done[0] & pix_done[1];  // bitslice start when both pix done.
+
+  always @(posedge clk) begin
+    case (state)
+      StateInit: begin
+        x <= 0;
+        y <= 0;
+        state <= StateStartFrame;
+      end
+      StateStartFrame: begin
+        pixgen_start <= 1;
+        state <= StateGenerateLine;
+      end
+      StateGenerateLine: begin
+        pixgen_start <= 0;
+        if (bitplane_done) begin
+          if (x < 127) begin
+            x <= x + 1;
+            pixgen_start <= 1;
+            // generate next
+          end else begin
+            write_line <= 1;
+            state <= StateShowLine;
+          end
+        end
+      end
+      StateShowLine: begin
+          write_line <= 0;
+          if (line_done) begin
+            state <= StateIncrementLine;
+          end
+      end
+      StateIncrementLine: begin
+        x <= 0;
+        y <= y + 1;
+        if (y == 31) begin
+          state <= StateInit;
+        end else begin
+          state <= StateStartFrame;
+        end
+      end
+      default: state <= StateInit;
+    endcase
+  end
+
+
+endmodule
diff --git a/verilog/hub75e.sv b/verilog/hub75e.sv
index f72089d..6c79d31 100644
--- a/verilog/hub75e.sv
+++ b/verilog/hub75e.sv
@@ -1,8 +1,6 @@
 module hub75e (
     input clk,
     input write_trig,
-    input [4:0] addr_in, // only latched in during init.
-    output reg [4:0] addr_out,
     output reg [2:0] panel_rgb0,
     output reg [2:0] panel_rgb1,
     output reg display_clk = 0,
@@ -30,7 +28,6 @@ module hub75e (
   reg [7:0] state = StateInit;  // our state
 
 
-  assign addr = 5'b10101;
 
   // initial begin
   //   state <= StateInit;
diff --git a/verilog/pixgen.sv b/verilog/pixgen.sv
new file mode 100644
index 0000000..b79a0bb
--- /dev/null
+++ b/verilog/pixgen.sv
@@ -0,0 +1,24 @@
+module pixgen #(
+    parameter integer X_DEPTH   = 9,
+    parameter integer Y_DEPTH   = 9,
+    parameter integer RGB_DEPTH = 24
+) (
+    input clk,
+    input start,
+    input [X_DEPTH-1:0] x,
+    input [Y_DEPTH-1:0] y,
+    output reg [RGB_DEPTH-1:0] rgb,
+    output reg done
+);
+
+// given x and y inputs, create an rgb output
+
+always @(posedge clk) begin
+  if (start) begin
+    done <= 1;
+    rgb <= { x[8:0], y[8:0] };
+  end
+  else done <= 0;
+end
+
+endmodule
diff --git a/verilog/tb/bitslicer_tb.sv b/verilog/tb/bitslicer_tb.sv
index e69de29..5df318f 100644
--- a/verilog/tb/bitslicer_tb.sv
+++ b/verilog/tb/bitslicer_tb.sv
@@ -0,0 +1,43 @@
+`timescale 1ns / 100ps  // 1 ns time unit, 100 ps resolution
+
+module bitslicer_tb;
+  reg clk = 0;
+
+  reg [23:0] rgb_in [2];
+  reg start_write = 0;
+  reg [7:0] pixnum = 0;
+  wire [5:0] bitplane_data;
+  wire [10:0] bitplane_addr;
+  wire bitplane_wren;
+  wire done;
+
+  bitslicer dut(
+    .clk(clk),
+    .rgb(rgb_in),
+    .pixnum(pixnum),
+    .start_write(start_write),
+    .bitplane_data(bitplane_data),
+    .bitplane_addr(bitplane_addr),
+    .done(done)
+  );
+
+  always #5 clk = !clk;
+  initial begin
+    $dumpfile("bitslicer_tb.vcd");
+    $dumpvars(0, bitslicer_tb);
+    rgb_in[0] <= 24'hEE8833;
+    rgb_in[1] <= 24'hDD7722;
+    pixnum <= 3;
+    @(posedge clk);
+    start_write <= 1;
+    @(posedge clk);
+    start_write <= 0;
+    @(done);
+    repeat (10) @(posedge clk);
+    $finish();
+  end
+  initial begin
+    repeat (100000) @(posedge clk);
+    $finish();
+  end
+endmodule
diff --git a/verilog/tb/coordinator_tb.sv b/verilog/tb/coordinator_tb.sv
new file mode 100644
index 0000000..17fbc23
--- /dev/null
+++ b/verilog/tb/coordinator_tb.sv
@@ -0,0 +1,14 @@
+`timescale 1ns / 100ps  // 1 ns time unit, 100 ps resolution
+
+module coordinator_tb();
+reg clk = 0;
+coordinator dut(.clk(clk));
+  always #8 clk = !clk;
+  initial begin
+    $dumpfile("coordinator.vcd");
+    $dumpvars(0, coordinator_tb);
+    repeat (10000) @(posedge clk);
+    $finish;
+  end
+endmodule
+