v0.1.5: fix bump_version.py BOM/encoding/CRLF, fix double banner on power-up
This commit is contained in:
126
top.v
126
top.v
@@ -6,31 +6,40 @@
|
||||
// clk_50mhz - onboard oscillator
|
||||
// rx_clk - DS90CF386 RxCLKOUT (~72 MHz pixel clock)
|
||||
// de - DS90CF386 RxOUT24
|
||||
// vsync - DS90CF386 RxOUT25 (currently unused, brought in for future use)
|
||||
// hsync - DS90CF386 RxOUT26 (currently unused, brought in for future use)
|
||||
// vsync - DS90CF386 RxOUT25 (unused, kept for pin assignment)
|
||||
// hsync - DS90CF386 RxOUT26 (unused, kept for pin assignment)
|
||||
// cntl - DS90CF386 RxOUT27 (unused, kept for pin assignment)
|
||||
// red[7:0] - DS90CF386 red channel
|
||||
// green[7:0]- DS90CF386 green channel
|
||||
// blue[7:0] - DS90CF386 blue channel
|
||||
// rst_n_pin - optional external reset (tie high if not used)
|
||||
//
|
||||
// Output:
|
||||
// uart_tx_pin - to CH340 RX
|
||||
//
|
||||
// Frame reports:
|
||||
// - On a clean frame, sends "OK\n" once every HEARTBEAT_FRAMES frames.
|
||||
// - On a clean frame, sends "OK\r\n" once every HEARTBEAT_FRAMES frames.
|
||||
// - On an anomalous frame, immediately sends
|
||||
// "ERR lines=NNNN width=NNNN\n"
|
||||
// where NNNN are zero-padded 4-digit decimals.
|
||||
// "ERR lines=NNNN width=NNNN R=RR G=GG B=BB\r\n"
|
||||
// where NNNN are zero-padded 4-digit decimals and RR/GG/BB are
|
||||
// 2-digit uppercase hex of the first pixel of the anomalous frame.
|
||||
|
||||
module top (
|
||||
input wire clk_50mhz,
|
||||
input wire rx_clk,
|
||||
input wire de,
|
||||
input wire vsync,
|
||||
input wire hsync,
|
||||
input wire rst_n_pin,
|
||||
output wire uart_tx_pin
|
||||
input wire clk_50mhz,
|
||||
input wire rx_clk,
|
||||
input wire de,
|
||||
input wire vsync,
|
||||
input wire hsync,
|
||||
input wire cntl,
|
||||
input wire [7:0] red,
|
||||
input wire [7:0] green,
|
||||
input wire [7:0] blue,
|
||||
input wire rst_n_pin,
|
||||
output wire uart_tx_pin
|
||||
);
|
||||
|
||||
// unused for now — keep ports alive so pin assignments stick
|
||||
wire _unused = &{1'b0, vsync, hsync, 1'b0};
|
||||
// keep undriven ports alive so pin assignments stick
|
||||
wire _unused = &{1'b0, vsync, hsync, cntl, 1'b0};
|
||||
|
||||
localparam integer HEARTBEAT_FRAMES = 60;
|
||||
|
||||
@@ -65,6 +74,9 @@ module top (
|
||||
wire [15:0] lines_pix;
|
||||
wire [15:0] width_pix;
|
||||
wire anomaly_pix;
|
||||
wire [7:0] first_r_pix;
|
||||
wire [7:0] first_g_pix;
|
||||
wire [7:0] first_b_pix;
|
||||
|
||||
de_monitor #(
|
||||
.EXPECTED_LINES (16'd800),
|
||||
@@ -74,10 +86,16 @@ module top (
|
||||
.pix_clk (rx_clk),
|
||||
.rst_n (rst_n_pix),
|
||||
.de (de),
|
||||
.red (red),
|
||||
.green (green),
|
||||
.blue (blue),
|
||||
.frame_done (frame_done_pix),
|
||||
.lines_o (lines_pix),
|
||||
.width_o (width_pix),
|
||||
.anomaly_o (anomaly_pix)
|
||||
.anomaly_o (anomaly_pix),
|
||||
.first_r (first_r_pix),
|
||||
.first_g (first_g_pix),
|
||||
.first_b (first_b_pix)
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
@@ -87,8 +105,11 @@ module top (
|
||||
reg [15:0] width_lat;
|
||||
reg anomaly_lat;
|
||||
reg heartbeat_lat;
|
||||
reg [7:0] fr_lat;
|
||||
reg [7:0] fg_lat;
|
||||
reg [7:0] fb_lat;
|
||||
reg req_tog;
|
||||
reg [7:0] hb_count; // up to 255 — plenty for HEARTBEAT_FRAMES=60
|
||||
reg [7:0] hb_count; // up to 255 — plenty for HEARTBEAT_FRAMES=60
|
||||
|
||||
always @(posedge rx_clk or negedge rst_n_pix) begin
|
||||
if (!rst_n_pix) begin
|
||||
@@ -96,12 +117,18 @@ module top (
|
||||
width_lat <= 16'd0;
|
||||
anomaly_lat <= 1'b0;
|
||||
heartbeat_lat <= 1'b0;
|
||||
fr_lat <= 8'd0;
|
||||
fg_lat <= 8'd0;
|
||||
fb_lat <= 8'd0;
|
||||
req_tog <= 1'b0;
|
||||
hb_count <= 8'd0;
|
||||
end else if (frame_done_pix) begin
|
||||
lines_lat <= lines_pix;
|
||||
width_lat <= width_pix;
|
||||
anomaly_lat <= anomaly_pix;
|
||||
fr_lat <= first_r_pix;
|
||||
fg_lat <= first_g_pix;
|
||||
fb_lat <= first_b_pix;
|
||||
|
||||
if (hb_count == HEARTBEAT_FRAMES - 1) begin
|
||||
hb_count <= 8'd0;
|
||||
@@ -131,8 +158,11 @@ module top (
|
||||
reg [15:0] width_u;
|
||||
reg anomaly_u;
|
||||
reg heartbeat_u;
|
||||
reg [7:0] fr_u;
|
||||
reg [7:0] fg_u;
|
||||
reg [7:0] fb_u;
|
||||
|
||||
// BCD digit registers — computed in F_CONVERT before transmission
|
||||
// BCD digit registers — computed in F_CONVERT before transmission
|
||||
reg [3:0] L0_r, L1_r, L2_r, L3_r;
|
||||
reg [3:0] W0_r, W1_r, W2_r, W3_r;
|
||||
reg [1:0] conv_step;
|
||||
@@ -140,18 +170,24 @@ module top (
|
||||
|
||||
// Sample latched fields when req_edge fires. Data is stable in
|
||||
// pix domain until the next frame_done (~16 ms), far longer than we
|
||||
// need for the handful of µs of UART setup.
|
||||
// need for the handful of µs of UART setup.
|
||||
always @(posedge clk_uart or negedge rst_n_uart) begin
|
||||
if (!rst_n_uart) begin
|
||||
lines_u <= 16'd0;
|
||||
width_u <= 16'd0;
|
||||
anomaly_u <= 1'b0;
|
||||
heartbeat_u <= 1'b0;
|
||||
fr_u <= 8'd0;
|
||||
fg_u <= 8'd0;
|
||||
fb_u <= 8'd0;
|
||||
end else if (req_edge) begin
|
||||
lines_u <= lines_lat;
|
||||
width_u <= width_lat;
|
||||
anomaly_u <= anomaly_lat;
|
||||
heartbeat_u <= heartbeat_lat;
|
||||
fr_u <= fr_lat;
|
||||
fg_u <= fg_lat;
|
||||
fb_u <= fb_lat;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -159,8 +195,7 @@ module top (
|
||||
localparam [2:0] F_IDLE = 3'd0,
|
||||
F_CONVERT = 3'd1,
|
||||
F_LOAD = 3'd2,
|
||||
F_WAIT = 3'd3,
|
||||
F_BANNER = 3'd4;
|
||||
F_WAIT = 3'd3;
|
||||
|
||||
// Banner: ESC[2J ESC[H ESC[33m + 2x51-dash separators + info lines + ESC[0m
|
||||
localparam [8:0] BANNER_LEN = 9'd411;
|
||||
@@ -174,7 +209,15 @@ module top (
|
||||
reg [7:0] tx_byte;
|
||||
wire tx_busy;
|
||||
|
||||
// ERR layout: ESC[31m + "ERR lines=LLLL width=WWWW" + ESC[0m + \r\n (36 bytes)
|
||||
// Nibble (0-15) to uppercase ASCII hex digit
|
||||
function [7:0] hex_char(input [3:0] n);
|
||||
hex_char = (n <= 4'd9) ? ("0" + {4'h0, n}) : ("A" - 8'd10 + {4'h0, n});
|
||||
endfunction
|
||||
|
||||
// ERR layout (51 bytes):
|
||||
// ESC[31m(5) + "ERR lines="(10) + LLLL(4) + " width="(7) + WWWW(4)
|
||||
// + " R="(3) + RR(2) + " G="(3) + GG(2) + " B="(3) + BB(2)
|
||||
// + ESC[0m(4) + \r\n(2)
|
||||
function [7:0] err_char(input [7:0] i);
|
||||
case (i)
|
||||
8'd0: err_char = 8'h1B;
|
||||
@@ -207,12 +250,27 @@ module top (
|
||||
8'd27: err_char = "0" + W1_r;
|
||||
8'd28: err_char = "0" + W2_r;
|
||||
8'd29: err_char = "0" + W3_r;
|
||||
8'd30: err_char = 8'h1B;
|
||||
8'd31: err_char = "[";
|
||||
8'd32: err_char = "0";
|
||||
8'd33: err_char = "m";
|
||||
8'd34: err_char = 8'h0D;
|
||||
8'd35: err_char = 8'h0A;
|
||||
8'd30: err_char = " ";
|
||||
8'd31: err_char = "R";
|
||||
8'd32: err_char = "=";
|
||||
8'd33: err_char = hex_char(fr_u[7:4]);
|
||||
8'd34: err_char = hex_char(fr_u[3:0]);
|
||||
8'd35: err_char = " ";
|
||||
8'd36: err_char = "G";
|
||||
8'd37: err_char = "=";
|
||||
8'd38: err_char = hex_char(fg_u[7:4]);
|
||||
8'd39: err_char = hex_char(fg_u[3:0]);
|
||||
8'd40: err_char = " ";
|
||||
8'd41: err_char = "B";
|
||||
8'd42: err_char = "=";
|
||||
8'd43: err_char = hex_char(fb_u[7:4]);
|
||||
8'd44: err_char = hex_char(fb_u[3:0]);
|
||||
8'd45: err_char = 8'h1B;
|
||||
8'd46: err_char = "[";
|
||||
8'd47: err_char = "0";
|
||||
8'd48: err_char = "m";
|
||||
8'd49: err_char = 8'h0D;
|
||||
8'd50: err_char = 8'h0A;
|
||||
default: err_char = 8'h00;
|
||||
endcase
|
||||
endfunction
|
||||
@@ -576,7 +634,7 @@ module top (
|
||||
9'd344: banner_char = ".";
|
||||
9'd345: banner_char = "1";
|
||||
9'd346: banner_char = ".";
|
||||
9'd347: banner_char = "0";
|
||||
9'd347: banner_char = "5";
|
||||
9'd348: banner_char = " ";
|
||||
9'd349: banner_char = " ";
|
||||
9'd350: banner_char = " ";
|
||||
@@ -605,7 +663,7 @@ module top (
|
||||
|
||||
always @(posedge clk_uart or negedge rst_n_uart) begin
|
||||
if (!rst_n_uart) begin
|
||||
fstate <= F_BANNER;
|
||||
fstate <= F_LOAD;
|
||||
idx <= 9'd0;
|
||||
msg_len <= BANNER_LEN;
|
||||
is_banner <= 1'b1;
|
||||
@@ -620,16 +678,12 @@ module top (
|
||||
end else begin
|
||||
tx_start <= 1'b0;
|
||||
case (fstate)
|
||||
F_BANNER: begin
|
||||
// idx/msg_len/is_banner already set in reset block; kick off load
|
||||
fstate <= F_LOAD;
|
||||
end
|
||||
F_IDLE: begin
|
||||
is_banner <= 1'b0;
|
||||
if (req_edge_q && (anomaly_u || heartbeat_u)) begin
|
||||
if (req_edge_q && (anomaly_u || heartbeat_u) && !is_banner) begin
|
||||
idx <= 9'd0;
|
||||
is_err_msg <= anomaly_u;
|
||||
msg_len <= anomaly_u ? 9'd36 : 9'd13;
|
||||
msg_len <= anomaly_u ? 9'd51 : 9'd13;
|
||||
l_rem <= lines_u;
|
||||
w_rem <= width_u;
|
||||
conv_step <= 2'd0;
|
||||
@@ -705,7 +759,7 @@ module top (
|
||||
else if (w_rem >= 16'd10) begin W2_r <= 4'd1; w_rem <= w_rem - 16'd10; end
|
||||
else W2_r <= 4'd0;
|
||||
end
|
||||
2'd3: begin // units — remainder is 0-9 by construction
|
||||
2'd3: begin // units — remainder is 0-9 by construction
|
||||
L3_r <= l_rem[3:0];
|
||||
W3_r <= w_rem[3:0];
|
||||
fstate <= F_LOAD;
|
||||
|
||||
Reference in New Issue
Block a user