Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
dafbe3385This file is pinned to the selected release. Download the original to open it in your design tool.
`timescale 1ns / 1ps
`default_nettype none
// Project F: Display TMDS Encoder for DVI
// (C)2019 Will Green, Open source hardware released under the MIT License
// Learn more at https://projectf.io
module tmds_encoder_dvi(
input wire i_clk, // clock
input wire i_rst, // reset (active high)
input wire [7:0] i_data, // colour data
input wire [1:0] i_ctrl, // control data
input wire i_de, // display enable (active high)
output reg [9:0] o_tmds // encoded TMDS data
);
// select basic encoding based on the ones in the input data
wire [3:0] d_ones = {3'b0,i_data[0]} + {3'b0,i_data[1]} + {3'b0,i_data[2]}
+ {3'b0,i_data[3]} + {3'b0,i_data[4]} + {3'b0,i_data[5]}
+ {3'b0,i_data[6]} + {3'b0,i_data[7]};
wire use_xnor = (d_ones > 4'd4) || ((d_ones == 4'd4) && (i_data[0] == 0));
// encode colour data with xor/xnor
/* verilator lint_off UNOPTFLAT */
wire [8:0] enc_qm;
assign enc_qm[0] = i_data[0];
assign enc_qm[1] = (use_xnor) ? (enc_qm[0] ~^ i_data[1]) : (enc_qm[0] ^ i_data[1]);
assign enc_qm[2] = (use_xnor) ? (enc_qm[1] ~^ i_data[2]) : (enc_qm[1] ^ i_data[2]);
assign enc_qm[3] = (use_xnor) ? (enc_qm[2] ~^ i_data[3]) : (enc_qm[2] ^ i_data[3]);
assign enc_qm[4] = (use_xnor) ? (enc_qm[3] ~^ i_data[4]) : (enc_qm[3] ^ i_data[4]);
assign enc_qm[5] = (use_xnor) ? (enc_qm[4] ~^ i_data[5]) : (enc_qm[4] ^ i_data[5]);
assign enc_qm[6] = (use_xnor) ? (enc_qm[5] ~^ i_data[6]) : (enc_qm[5] ^ i_data[6]);
assign enc_qm[7] = (use_xnor) ? (enc_qm[6] ~^ i_data[7]) : (enc_qm[6] ^ i_data[7]);
assign enc_qm[8] = (use_xnor) ? 0 : 1;
/* verilator lint_on UNOPTFLAT */
// disparity in encoded data for DC balancing: needs to cover -8 to +8
wire signed [4:0] ones = {4'b0,enc_qm[0]} + {4'b0,enc_qm[1]}
+ {4'b0,enc_qm[2]} + {4'b0,enc_qm[3]} + {4'b0,enc_qm[4]}
+ {4'b0,enc_qm[5]} + {4'b0,enc_qm[6]} + {4'b0,enc_qm[7]};
wire signed [4:0] zeros = 5'b01000 - ones;
wire signed [4:0] balance = ones - zeros;
// record ongoing DC bias
reg signed [4:0] bias;
always @ (posedge i_clk)
begin
if (i_rst)
begin
o_tmds <= 10'b1101010100; // equivalent to ctrl 2'b00
bias <= 5'sb00000;
end
else if (i_de == 0) // send control data in blanking interval
begin
case (i_ctrl) // ctrl sequences (always have 7 transitions)
2'b00: o_tmds <= 10'b1101010100;
2'b01: o_tmds <= 10'b0010101011;
2'b10: o_tmds <= 10'b0101010100;
default: o_tmds <= 10'b1010101011;
endcase
bias <= 5'sb00000;
end
else // send pixel colour data (at most 5 transitions)
begin
if (bias == 0 || balance == 0) // no prior bias or disparity
begin
if (enc_qm[8] == 0)
begin
$display("\t%d %b %d, %d, A1", i_data, enc_qm, ones, bias);
o_tmds[9:0] <= {2'b10, ~enc_qm[7:0]};
bias <= bias - balance;
end
else begin
$display("\t%d %b %d, %d, A0", i_data, enc_qm, ones, bias);
o_tmds[9:0] <= {2'b01, enc_qm[7:0]};
bias <= bias + balance;
end
end
else if ((bias > 0 && balance > 0) || (bias < 0 && balance < 0))
begin
$display("\t%d %b %d, %d, B1", i_data, enc_qm, ones, bias);
o_tmds[9:0] <= {1'b1, enc_qm[8], ~enc_qm[7:0]};
bias <= bias + {3'b0, enc_qm[8], 1'b0} - balance;
end
else
begin
$display("\t%d %b %d, %d, B0", i_data, enc_qm, ones, bias);
o_tmds[9:0] <= {1'b0, enc_qm[8], enc_qm[7:0]};
bias <= bias - {3'b0, ~enc_qm[8], 1'b0} + balance;
end
end
end
endmodule