initial verilog

This commit is contained in:
saji 2024-04-28 16:42:41 -05:00
parent a0e1dcbdb0
commit 00ebfa8009
5 changed files with 209 additions and 58 deletions

2
.gitignore vendored
View file

@ -2,3 +2,5 @@
*.o *.o
*.bin *.bin
build/* build/*
*.vcd
*.out

View file

@ -1,4 +1,9 @@
NEXTPNR_FLAGS= --45k --package CABGA381 --speed 6 --freq 65
YOSYS_FLAGS=
.PHONY all clean test

View file

@ -28,15 +28,11 @@ class Hub75Driver(Module):
if base_freq // 2 > 30e6: if base_freq // 2 > 30e6:
raise RuntimeError("hi") raise RuntimeError("hi")
self.phase = Signal() # divider/counter
self.addr = Signal(5) self.addr = Signal(5)
self.latch = Signal() self.latch = Signal()
self.output_en = Signal() self.output_en = Signal()
self.rgb = Signal(6, reset=0b111010) color = Signal(24, reset=0xA0FF00)
self.rgb = Signal(6)
# clk-en acts as a gate.
clock_en = Signal()
self.clock_out = Signal() self.clock_out = Signal()
@ -46,21 +42,34 @@ class Hub75Driver(Module):
counter = Signal(32) counter = Signal(32)
should_expose = (counter < (16 << bcm_value)) & (bcm_value != 0)
# this state both sets the OE low to drive the display with the previous frame
# while also loading the next row
# FIXME: there's a bug on the starting conditions right now, we are losing the lowest bit.
fsm.act("WRITEROW", fsm.act("WRITEROW",
self.output_en.eq(1), self.output_en.eq(~should_expose),
If(counter < 256, self.rgb[0].eq((color >> bcm_value) & 1),
self.clock_out.eq(counter[0]), self.rgb[3].eq((color >> bcm_value) & 1),
self.rgb[1].eq((color >> (bcm_value + 8)) & 1),
self.rgb[4].eq((color >> (bcm_value + 8)) & 1),
self.rgb[2].eq((color >> (bcm_value + 16)) & 1),
self.rgb[5].eq((color >> (bcm_value + 16)) & 1),
NextValue(counter, counter + 1), NextValue(counter, counter + 1),
If(counter[0], NextValue(self.rgb, self.rgb + 3)), If(counter < linedepth * 2,
).Else( self.clock_out.eq(counter[0]),
),
If(~(counter < linedepth * 2) & ~should_expose,
NextValue(counter, 0), NextValue(counter, 0),
NextState("EXPOSE"), NextState("LATCH"),
), ),
) )
fsm.act("EXPOSE", fsm.act("EXPOSE",
self.output_en.eq(0), self.output_en.eq(0),
If(counter < (1000 << bcm_value), If(counter < (16 << bcm_value),
NextValue(counter, counter + 1), NextValue(counter, counter + 1),
).Else( ).Else(
NextValue(counter, 0), NextValue(counter, 0),
@ -70,52 +79,14 @@ class Hub75Driver(Module):
fsm.act("LATCH", fsm.act("LATCH",
self.latch.eq(1), self.latch.eq(1),
self.output_en.eq(1),
NextValue(counter, 0), NextValue(counter, 0),
If(bcm_value == 7, If(bcm_value == 7,
NextValue(bcm_value, 0), NextValue(bcm_value, 0),
NextValue(self.addr, self.addr + 1), NextValue(self.addr, self.addr + 1),
).Else(NextValue(bcm_value, 1)), ).Else(
NextValue(bcm_value, bcm_value + 1),
),
NextState("WRITEROW"), NextState("WRITEROW"),
) )
# fsm.act("ready",
# NextValue(self.output_en, 1),
# NextValue(self.pixnum, linedepth - 1),
# NextValue(self.latch, 0),
# If(self.phase == 1,
# NextValue(self.addr, self.addr + 1),
# NextValue(clock_en, 1),
# NextState("transmit"),
# ),
# # If((self.state_count == 7), NextValue(clock_en, ~clock_en)),
# )
# fsm.act("transmit",
# If(self.phase == 1,
# NextValue(self.pixnum, self.pixnum - 1),
# If(self.pixnum == 0,
# NextState("latch_delay"),
# )
# )
# )
# fsm.act("latch_delay",
# NextValue(clock_en, 0),
# If(self.phase == 1,
# NextState("latchout")
# )
# )
# fsm.act("latchout",
# If(self.phase == 1,
# NextValue(self.latch, 1),
# NextValue(counter, 0),
# NextState("done")
# )
# )
# fsm.act("done",
# NextValue(self.output_en, 0),
# NextValue(self.latch, 0),
# NextValue(counter, counter + 1),
# If(counter == 255, NextState("ready"))
# )
#

125
verilog/hub75e.sv Normal file
View file

@ -0,0 +1,125 @@
module hub75e (
input clk,
input write_trig,
input [1:0][BIT_DEPTH - 1:0] rgb_row[ROW_DEPTH],
output reg [4:0] addr,
output reg [2:0] panel_rgb0,
output reg [2:0] panel_rgb1,
output reg display_clk = 0,
output reg out_enable = 1,
output reg latch = 0,
output reg done = 0
);
parameter integer ROW_DEPTH = 128, BIT_DEPTH = 8;
reg [31:0] counter = 0;
reg [ 3:0] bcm_shift = 7; // which bit of the colors are we currently exposing.
localparam integer StateInit = 0;
localparam integer StateWriteRow = 1;
localparam integer StateLatchout = 2;
// the last data that we clock out for the row won't be exposed
// in the next writerow state because we'll change addresses.
localparam integer StateFinishExpose = 3;
reg [7:0] state = StateInit; // our state
assign addr = 5'b10101;
assign panel_rgb0 = 3'b101;
assign panel_rgb1 = 3'b010;
// initial begin
// state <= StateInit;
// counter <= 0;
// bcm_shift <= 7;
// end
// The FSM is a bit confusing since it's optimized for *speed*
// We can basically display the previous line of data while we write the
// next one. So instead of having WRITEROW -> LATCH -> EXPOSE
// like most modules do, we can instead do (WRITEROW + EXPOSE_PREV) -> LATCH
// There is an edge case for the first/last bits of the color depth.
// When we start writing a line, we can't flash anything since there's no
// previous. Likewise, when we end a line, we have to have an extra expose
// period since there is no next writerow for this address. As a result,
// we want to go MSB to LSB for our BCM so that the trailing expose time is
// short!
wire should_clock, should_expose;
assign should_clock = counter < ROW_DEPTH * 2;
assign should_expose = (counter < (16 << bcm_shift + 1)) && (bcm_shift != 7);
always_ff @(posedge clk) begin
counter <= counter + 1;
case (state)
StateInit: begin
// wait for the signal to write out our lines.
if (write_trig) begin
bcm_shift <= 7;
counter <= 0;
done <= 0;
state <= StateWriteRow;
end
end
StateWriteRow: begin
if (should_clock) begin
// we have data to clock
display_clk <= counter[0];
if (counter[0]) begin
// load the next pixel data. this is the falling edge since the
// previous value is 1.
end
end
if (should_expose) begin
// we are still in our expose state, and our bcm shift is not the
// first one, so we should expose.
out_enable <= 0;
end else begin
out_enable <= 1;
end
// if we're done with our data clock out and also done with exposing
// the previous frame, go next.
if (~should_clock && ~should_expose) begin
counter <= 0;
state <= StateLatchout;
end
end
StateLatchout: begin
// raise latch high; compute next bcm.
latch <= 1;
out_enable <= 1;
counter <= counter + 1;
if (counter > 3) begin
if (bcm_shift == 0) begin
// done with the line. do the last (short) expose
state <= StateFinishExpose;
latch <= 0;
end else begin
bcm_shift <= bcm_shift - 1;
state <= StateWriteRow;
latch <= 0;
end
end
end
StateFinishExpose: begin
assert (bcm_shift == 0);
if (counter < (16 << bcm_shift)) begin
out_enable <= 0;
end else begin
out_enable <= 1;
state <= StateInit;
done <= 1;
// we are done!
end
end
default: begin
end
endcase
end
endmodule

48
verilog/tb/hub75e_tb.sv Normal file
View file

@ -0,0 +1,48 @@
`timescale 1ns / 100ps // 1 ns time unit, 100 ps resolution
module hub75e_tb;
reg clk;
reg write_trig;
reg [1:0][7:0] rgb_row[128];
wire [4:0] addr_out;
wire [2:0] rgb0;
wire [2:0] rgb1;
wire display_clk;
wire out_enable;
wire latch;
wire done;
hub75e dut (
.clk(clk),
.write_trig(write_trig),
.rgb_row(rgb_row),
.addr(addr_out),
.panel_rgb0(rgb0),
.panel_rgb1(rgb1),
.display_clk(display_clk),
.out_enable(out_enable),
.latch(latch),
.done(done)
);
always #5 clk = !clk;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, hub75e_tb);
clk = 0;
write_trig = 1;
repeat (2) @(posedge clk);
write_trig = 0;
@(done);
repeat (20) @(posedge clk);
$finish();
end
initial begin
repeat (100000) @(posedge clk);
$finish();
end
endmodule