2024-04-28 21:42:41 +00:00
|
|
|
module hub75e (
|
|
|
|
input clk,
|
|
|
|
input write_trig,
|
|
|
|
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,
|
2024-04-29 06:16:36 +00:00
|
|
|
output reg done = 0,
|
|
|
|
|
|
|
|
// bram interface (using clk)
|
2024-05-01 21:14:32 +00:00
|
|
|
output [10:0] pixbuf_addr,
|
|
|
|
input [ 8:0] pixbuf_data
|
2024-04-28 21:42:41 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
2024-05-03 01:30:51 +00:00
|
|
|
assign should_clock = (counter < ROW_DEPTH * 2 + 1); // the plus 1 is for the falling edge!
|
2024-04-28 21:42:41 +00:00
|
|
|
assign should_expose = (counter < (16 << bcm_shift + 1)) && (bcm_shift != 7);
|
|
|
|
|
2024-05-01 21:14:32 +00:00
|
|
|
reg [7:0] pixnum;
|
|
|
|
assign pixbuf_addr = {bcm_shift, pixnum};
|
2024-05-03 01:30:51 +00:00
|
|
|
always @(*) begin
|
|
|
|
panel_rgb0 = pixbuf_data[2:0];
|
|
|
|
panel_rgb1 = pixbuf_data[5:3];
|
|
|
|
end
|
2024-05-01 21:14:32 +00:00
|
|
|
|
2024-04-28 21:42:41 +00:00
|
|
|
always_ff @(posedge clk) begin
|
|
|
|
counter <= counter + 1;
|
|
|
|
case (state)
|
|
|
|
StateInit: begin
|
2024-04-29 06:16:36 +00:00
|
|
|
bcm_shift <= 7;
|
|
|
|
counter <= 0;
|
|
|
|
done <= 0;
|
2024-05-01 21:14:32 +00:00
|
|
|
pixnum <= ROW_DEPTH - 1;
|
2024-04-28 21:42:41 +00:00
|
|
|
// wait for the signal to write out our lines.
|
|
|
|
if (write_trig) begin
|
|
|
|
state <= StateWriteRow;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
StateWriteRow: begin
|
|
|
|
if (should_clock) begin
|
|
|
|
// we have data to clock
|
|
|
|
display_clk <= counter[0];
|
2024-04-29 06:16:36 +00:00
|
|
|
if (~counter[0]) begin
|
|
|
|
// the data from the previous cycle is now ready.
|
2024-05-03 01:30:51 +00:00
|
|
|
// panel_rgb0 <= pixbuf_data[2:0];
|
|
|
|
// panel_rgb1 <= pixbuf_data[5:3];
|
2024-04-29 06:16:36 +00:00
|
|
|
// write it out!
|
|
|
|
end else begin
|
|
|
|
// update the bram address so it's ready at the next clock cycle.
|
2024-05-01 21:14:32 +00:00
|
|
|
pixnum <= pixnum - 1;
|
2024-04-28 21:42:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
if (should_expose) begin
|
|
|
|
out_enable <= 0;
|
|
|
|
end else begin
|
|
|
|
out_enable <= 1;
|
|
|
|
end
|
|
|
|
// if we're done with our data clock out and also done with exposing
|
2024-04-29 06:16:36 +00:00
|
|
|
// the previous line, go to the latchout stage.
|
2024-04-28 21:42:41 +00:00
|
|
|
if (~should_clock && ~should_expose) begin
|
|
|
|
counter <= 0;
|
2024-05-01 21:14:32 +00:00
|
|
|
pixnum <= 0;
|
2024-05-03 01:30:51 +00:00
|
|
|
state <= StateLatchout;
|
2024-05-01 21:14:32 +00:00
|
|
|
display_clk <= 0;
|
2024-04-28 21:42:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
StateLatchout: begin
|
|
|
|
// raise latch high; compute next bcm.
|
|
|
|
latch <= 1;
|
|
|
|
out_enable <= 1;
|
2024-05-01 21:14:32 +00:00
|
|
|
pixnum <= ROW_DEPTH - 1;
|
2024-04-28 21:42:41 +00:00
|
|
|
counter <= counter + 1;
|
|
|
|
if (counter > 3) begin
|
2024-05-01 21:14:32 +00:00
|
|
|
counter <= 0;
|
2024-04-28 21:42:41 +00:00
|
|
|
if (bcm_shift == 0) begin
|
2024-04-29 06:16:36 +00:00
|
|
|
// we've reached the lsb of this data, go to the next one!
|
2024-04-28 21:42:41 +00:00
|
|
|
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
|
2024-05-01 21:14:32 +00:00
|
|
|
state <= StateInit;
|
2024-04-28 21:42:41 +00:00
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|