96 lines
3.9 KiB
Coq
96 lines
3.9 KiB
Coq
|
`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
|