hsdaoh_core: add CRC16 checksum support

Output is identical to the implementation in
hsdaoh-rp2350.
This commit is contained in:
Steve Markgraf 2024-12-06 00:21:09 +01:00
parent 8b9e1457ea
commit 1b2d011581
7 changed files with 149 additions and 27 deletions

View file

@ -0,0 +1,86 @@
/* -----------------------------------------------------------------------------------
* Module Name : crc16_ccitt
* Generated by : https://github.com/PXVI/ip_parallel_custom_crc_gerator_verilog
* Author : pxvi
* Description : Parallel CRC( 16-bit ) module with 16-bit data input.
* Polynomial Degrees [ 16 12 5 0 ]
* -----------------------------------------------------------------------------------
*
* MIT License
*
* Copyright (c) 2024 k-sva
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ----------------------------------------------------------------------------------- */
module crc16_ccitt #( parameter RESET_SEED = 'hffff )(
input wire CLK,
input wire RSTn,
input wire [15:0] data_in,
input wire enable,
input wire clear,
output [15:0] CRC
);
reg [16-1:0] Mout_p, Mout_n;
always@( posedge CLK )
begin
Mout_p <= Mout_n;
if( !RSTn )
begin
Mout_p <= RESET_SEED;
end
end
always@( * )
begin
Mout_n = Mout_p;
if( clear )
begin
Mout_n = RESET_SEED;
end
else if( enable )
begin
Mout_n[0] = data_in[0] ^ data_in[4] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ Mout_p[0] ^ Mout_p[4] ^ Mout_p[8] ^ Mout_p[11] ^ Mout_p[12] ;
Mout_n[1] = data_in[1] ^ data_in[5] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ Mout_p[1] ^ Mout_p[5] ^ Mout_p[9] ^ Mout_p[12] ^ Mout_p[13] ;
Mout_n[2] = data_in[2] ^ data_in[6] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ Mout_p[2] ^ Mout_p[6] ^ Mout_p[10] ^ Mout_p[13] ^ Mout_p[14] ;
Mout_n[3] = data_in[3] ^ data_in[7] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ Mout_p[3] ^ Mout_p[7] ^ Mout_p[11] ^ Mout_p[14] ^ Mout_p[15] ;
Mout_n[4] = data_in[4] ^ data_in[8] ^ data_in[12] ^ data_in[15] ^ Mout_p[4] ^ Mout_p[8] ^ Mout_p[12] ^ Mout_p[15] ;
Mout_n[5] = data_in[0] ^ data_in[4] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ Mout_p[0] ^ Mout_p[4] ^ Mout_p[5] ^ Mout_p[8] ^ Mout_p[9] ^ Mout_p[11] ^ Mout_p[12] ^ Mout_p[13] ;
Mout_n[6] = data_in[1] ^ data_in[5] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[12] ^ data_in[13] ^ data_in[14] ^ Mout_p[1] ^ Mout_p[5] ^ Mout_p[6] ^ Mout_p[9] ^ Mout_p[10] ^ Mout_p[12] ^ Mout_p[13] ^ Mout_p[14] ;
Mout_n[7] = data_in[2] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ data_in[13] ^ data_in[14] ^ data_in[15] ^ Mout_p[2] ^ Mout_p[6] ^ Mout_p[7] ^ Mout_p[10] ^ Mout_p[11] ^ Mout_p[13] ^ Mout_p[14] ^ Mout_p[15] ;
Mout_n[8] = data_in[3] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15] ^ Mout_p[3] ^ Mout_p[7] ^ Mout_p[8] ^ Mout_p[11] ^ Mout_p[12] ^ Mout_p[14] ^ Mout_p[15] ;
Mout_n[9] = data_in[4] ^ data_in[8] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[15] ^ Mout_p[4] ^ Mout_p[8] ^ Mout_p[9] ^ Mout_p[12] ^ Mout_p[13] ^ Mout_p[15] ;
Mout_n[10] = data_in[5] ^ data_in[9] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ Mout_p[5] ^ Mout_p[9] ^ Mout_p[10] ^ Mout_p[13] ^ Mout_p[14] ;
Mout_n[11] = data_in[6] ^ data_in[10] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ Mout_p[6] ^ Mout_p[10] ^ Mout_p[11] ^ Mout_p[14] ^ Mout_p[15] ;
Mout_n[12] = data_in[0] ^ data_in[4] ^ data_in[7] ^ data_in[8] ^ data_in[15] ^ Mout_p[0] ^ Mout_p[4] ^ Mout_p[7] ^ Mout_p[8] ^ Mout_p[15] ;
Mout_n[13] = data_in[1] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ Mout_p[1] ^ Mout_p[5] ^ Mout_p[8] ^ Mout_p[9] ;
Mout_n[14] = data_in[2] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ Mout_p[2] ^ Mout_p[6] ^ Mout_p[9] ^ Mout_p[10] ;
Mout_n[15] = data_in[3] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ Mout_p[3] ^ Mout_p[7] ^ Mout_p[10] ^ Mout_p[11] ;
end
end
assign CRC = Mout_p;
endmodule

View file

@ -18,6 +18,21 @@ module hsdaoh_core
input wire [15:0] data_in input wire [15:0] data_in
); );
parameter USE_CRC = 1;
reg crc_enable = 1'b0;
wire [15:0] crc_out;
reg [15:0] last_line_crc;
crc16_ccitt crc16_ccitt (
.CLK(clk_pixel),
.RSTn(rstn),
.data_in({hdmi_data[15:8], hdmi_data[23:16]}),
.enable(crc_enable),
.clear(!crc_enable),
.CRC(crc_out)
);
localparam [31:0] MAGIC = 32'hda7acab1; localparam [31:0] MAGIC = 32'hda7acab1;
reg [23:0] hdmi_data = 24'h000000; reg [23:0] hdmi_data = 24'h000000;
@ -35,40 +50,56 @@ module hsdaoh_core
always @(posedge clk_pixel) begin always @(posedge clk_pixel) begin
if ((cx == screen_width-1) && (cy < screen_height)) begin if (cy < screen_height) begin
// last word of line contains counter of words per line if (USE_CRC && (cx == 0))
hdmi_data <= {status_nibble[3:0], line_word_cnt[11:0], 8'h00}; crc_enable <= 1'b1;
end else if ((cx < screen_width) && (cy < screen_height)) begin if (USE_CRC && (cx == screen_width+1)) begin
if (fifo_read_en && !fifo_empty) begin last_line_crc <= crc_out;
// regular output of FIFO data crc_enable <= 1'b0;
hdmi_data <= {data_in[15:0], 8'h00};
// increment line payload counter
line_word_cnt <= line_word_cnt + 1'b1;
end else begin
// output idle counter
hdmi_data <= {idle_counter[15:8], idle_counter[7:0], 8'h00};
// increment idle counter
idle_counter <= idle_counter + 1'b1;
end end
end else
line_word_cnt <= 16'h0000;
// Enable reading before beginning of next line if (cx == screen_width-1) begin
if ((cx == frame_width-1) && (cy < screen_height-1) && !fifo_empty) // last word of line contains counter of words per line
fifo_read_en = 1'b1; hdmi_data <= {status_nibble[3:0], line_word_cnt[11:0], 8'h00};
end else if (USE_CRC && (cx == screen_width-2)) begin
// second last word contains CRC
hdmi_data <= {last_line_crc, 8'h00};
end else if (cx < screen_width) begin
if (fifo_read_en && !fifo_empty) begin
// regular output of FIFO data
hdmi_data <= {data_in[15:0], 8'h00};
// increment line payload counter
line_word_cnt <= line_word_cnt + 1'b1;
end else begin
// output idle counter
hdmi_data <= {idle_counter[15:8], idle_counter[7:0], 8'h00};
// increment idle counter
idle_counter <= idle_counter + 1'b1;
end
end else
line_word_cnt <= 16'h0000;
// Enable reading before beginning of next line
if ((cx == frame_width-1) && (cy != screen_height-1)) begin
if (!fifo_empty)
fifo_read_en = 1'b1;
end
// switch read off at end of line before sending the word counter
// -2 because the last word is reserved (line_word_cnt and metadata)
if (cx == screen_width-2-USE_CRC)
fifo_read_en = 1'b0;
end
// switch read off during blanking // switch read off during blanking
if (cy > screen_height) if (cy > screen_height)
fifo_read_en = 1'b0; fifo_read_en = 1'b0;
// switch read off at end of line before sending the word counter
// -2 because the last word is reserved (line_word_cnt and metadata)
if ((cx == screen_width-2) && (cy < screen_height))
fifo_read_en = 1'b0;
// switch read off when FIFO has only one word remaining // switch read off when FIFO has only one word remaining
if (fifo_aempty) if (fifo_aempty)
fifo_read_en = 1'b0; fifo_read_en = 1'b0;
@ -97,10 +128,10 @@ always @(posedge clk_pixel) begin
9 : status_nibble <= frame_cnt[7:4]; 9 : status_nibble <= frame_cnt[7:4];
10 : status_nibble <= frame_cnt[11:8]; 10 : status_nibble <= frame_cnt[11:8];
11 : status_nibble <= frame_cnt[15:12]; 11 : status_nibble <= frame_cnt[15:12];
14 : status_nibble <= { 3'b000, USE_CRC };
default : status_nibble <= 4'h0; default : status_nibble <= 4'h0;
endcase endcase
end end
end end
wire tmds_clock; wire tmds_clock;

View file

@ -17,6 +17,7 @@
<File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/> <File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/> <File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/> <File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/crc16_ccitt.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/> <File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano20k_test/top.v" type="file.verilog" enable="1"/> <File path="hsdaoh_nano20k_test/top.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano20k_test/hsdaoh_nano20k_test.cst" type="file.cst" enable="1"/> <File path="hsdaoh_nano20k_test/hsdaoh_nano20k_test.cst" type="file.cst" enable="1"/>

View file

@ -17,6 +17,7 @@
<File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/> <File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/> <File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/> <File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/crc16_ccitt.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/> <File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano4k_test/fifo_hs/fifo_hs.v" type="file.verilog" enable="1"/> <File path="hsdaoh_nano4k_test/fifo_hs/fifo_hs.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano4k_test/top.v" type="file.verilog" enable="1"/> <File path="hsdaoh_nano4k_test/top.v" type="file.verilog" enable="1"/>

View file

@ -17,6 +17,7 @@
<File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/> <File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/> <File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/> <File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/crc16_ccitt.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/> <File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano9k_test/fifo_hs/fifo_hs.v" type="file.verilog" enable="1"/> <File path="hsdaoh_nano9k_test/fifo_hs/fifo_hs.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_nano9k_test/top.v" type="file.verilog" enable="1"/> <File path="hsdaoh_nano9k_test/top.v" type="file.verilog" enable="1"/>

View file

@ -17,6 +17,7 @@
<File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/> <File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/> <File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/> <File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/crc16_ccitt.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/> <File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_primer20k_test/top.v" type="file.verilog" enable="1"/> <File path="hsdaoh_primer20k_test/top.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_primer20k_test/hsdaoh_primer20k_test.cst" type="file.cst" enable="1"/> <File path="hsdaoh_primer20k_test/hsdaoh_primer20k_test.cst" type="file.cst" enable="1"/>

View file

@ -17,6 +17,7 @@
<File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/> <File path="common/hdmi/packet_picker.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/> <File path="common/hdmi/serializer.v" type="file.verilog" enable="1"/>
<File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/> <File path="common/hdmi/tmds_channel.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/crc16_ccitt.v" type="file.verilog" enable="1"/>
<File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/> <File path="common/hsdaoh/hsdaoh_core.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_primer25k_test/top.v" type="file.verilog" enable="1"/> <File path="hsdaoh_primer25k_test/top.v" type="file.verilog" enable="1"/>
<File path="hsdaoh_primer25k_test/hsdaoh_primer25k_test.cst" type="file.cst" enable="1"/> <File path="hsdaoh_primer25k_test/hsdaoh_primer25k_test.cst" type="file.cst" enable="1"/>