mirror of
https://github.com/steve-m/hsdaoh-fpga.git
synced 2025-12-09 23:34:45 +01:00
92 lines
3.2 KiB
Verilog
92 lines
3.2 KiB
Verilog
// Implementation of HDMI packet ECC calculation.
|
|
// By Sameer Puri https://github.com/sameer
|
|
// source: https://github.com/hdl-util/hdmi/
|
|
// Dual-licensed under Apache License 2.0 and MIT License.
|
|
|
|
// converted to Verilog for hsdaoh
|
|
|
|
module packet_assembler (
|
|
clk_pixel,
|
|
reset,
|
|
data_island_period,
|
|
header, // See Table 5-8 Packet Types
|
|
sub,
|
|
packet_data, // See Figure 5-4 Data Island Packet and ECC Structure
|
|
counter
|
|
);
|
|
input wire clk_pixel;
|
|
input wire reset;
|
|
input wire data_island_period;
|
|
input wire [23:0] header;
|
|
input wire [223:0] sub;
|
|
output wire [8:0] packet_data;
|
|
output reg [4:0] counter = 5'd0;
|
|
|
|
// 32 pixel wrap-around counter. See Section 5.2.3.4 for further information.
|
|
always @(posedge clk_pixel)
|
|
begin
|
|
if (reset)
|
|
counter <= 5'd0;
|
|
else if (data_island_period)
|
|
counter <= counter + 5'd1;
|
|
end
|
|
// BCH packets 0 to 3 are transferred two bits at a time, see Section 5.2.3.4 for further information.
|
|
wire [5:0] counter_t2 = {counter, 1'b0};
|
|
wire [5:0] counter_t2_p1 = {counter, 1'b1};
|
|
|
|
// Initialize parity bits to 0
|
|
reg [39:0] parity = 40'h0000000000;
|
|
|
|
wire [63:0] bch [3:0];
|
|
assign bch[0] = {parity[0+:8], sub[0+:56]};
|
|
assign bch[1] = {parity[8+:8], sub[56+:56]};
|
|
assign bch[2] = {parity[16+:8], sub[112+:56]};
|
|
assign bch[3] = {parity[24+:8], sub[168+:56]};
|
|
wire [31:0] bch4 = {parity[32+:8], header};
|
|
assign packet_data = {bch[3][counter_t2_p1], bch[2][counter_t2_p1], bch[1][counter_t2_p1], bch[0][counter_t2_p1], bch[3][counter_t2], bch[2][counter_t2], bch[1][counter_t2], bch[0][counter_t2], bch4[counter]};
|
|
|
|
// See Figure 5-5 Error Correction Code generator. Generalization of a CRC with binary BCH.
|
|
// See https://web.archive.org/web/20190520020602/http://hamsterworks.co.nz/mediawiki/index.php/Minimal_HDMI#Computing_the_ECC for an explanation of the implementation.
|
|
// See https://en.wikipedia.org/wiki/BCH_code#Systematic_encoding:_The_message_as_a_prefix for further information.
|
|
function automatic [7:0] next_ecc;
|
|
input [7:0] ecc, next_bch_bit;
|
|
begin
|
|
next_ecc = (ecc >> 1) ^ (ecc[0] ^ next_bch_bit ? 8'b10000011 : 8'd0);
|
|
end
|
|
endfunction
|
|
|
|
wire [7:0] parity_next [4:0];
|
|
|
|
// The parity needs to be calculated 2 bits at a time for blocks 0 to 3.
|
|
// There's 56 bits being sent 2 bits at a time over TMDS channels 1 & 2, so the parity bits wouldn't be ready in time otherwise.
|
|
wire [31:0] parity_next_next;
|
|
|
|
genvar i;
|
|
generate
|
|
for (i = 0; i < 5; i = i + 1) begin : parity_calc
|
|
if (i == 4) begin : genblk1
|
|
assign parity_next[i] = next_ecc(parity[i * 8+:8], header[counter]);
|
|
end
|
|
else begin : genblk1
|
|
assign parity_next[i] = next_ecc(parity[i * 8+:8], sub[(i * 56) + counter_t2]);
|
|
assign parity_next_next[i * 8+:8] = next_ecc(parity_next[i], sub[(i * 56) + counter_t2_p1]);
|
|
end
|
|
end
|
|
endgenerate
|
|
always @(posedge clk_pixel)
|
|
begin
|
|
if (reset)
|
|
parity <= 40'h0000000000;
|
|
else if (data_island_period) begin
|
|
if (counter < 5'd28) begin // Compute ECC only on subpacket data, not on itself
|
|
parity[0+:32] <= parity_next_next;
|
|
if (counter < 5'd24) // Header only has 24 bits, whereas subpackets have 56 and 56 / 2 = 28.
|
|
parity[32+:8] <= parity_next[4];
|
|
end
|
|
else if (counter == 5'd31)
|
|
parity <= 40'h0000000000; // Reset ECC for next packet
|
|
end
|
|
else
|
|
parity <= 40'h0000000000;
|
|
end
|
|
endmodule
|