commit b8e750af8434a0880e8b64c878b75586213c45ee
parent 76056d1ce0d78e2b809674e57450beac991483fc
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 6 Feb 2020 15:08:17 -0800
display: dvi/hdmi backend processing
- tidied up from some xilinx projects in 2014
- but without the benefit of 10x gearing w/ xilinx OSERDES
Diffstat:
2 files changed, 200 insertions(+), 0 deletions(-)
diff --git a/hdl/display/dvi-backend.sv b/hdl/display/dvi-backend.sv
@@ -0,0 +1,120 @@
+// Copyright 2014, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+`default_nettype none
+
+module dvi_backend (
+ input pixclk,
+ input pixclk5x,
+
+ // TMDS33 outputs at pixclk5x DDR
+ output wire [3:0]pin_dvi_dp,
+ output wire [3:0]pin_dvi_dn,
+
+ // RGB data input at pixclk
+ input wire hsync,
+ input wire vsync,
+ input wire active,
+ input wire [7:0]red,
+ input wire [7:0]grn,
+ input wire [7:0]blu
+ );
+
+wire [3:0]dvi_dp;
+wire [3:0]dvi_dn;
+
+wire [9:0] ch0, ch1, ch2;
+
+reg [9:0]ch3 = 10'b0000011111;
+
+dvi_encoder enc2(
+ .clk(pixclk),
+ .din(red),
+ .ctrl(0),
+ .active(active),
+ .dout(ch2));
+
+dvi_encoder enc1(
+ .clk(pixclk),
+ .active(active),
+ .din(grn),
+ .ctrl(0),
+ .dout(ch1));
+
+dvi_encoder enc0(
+ .clk(pixclk),
+ .active(active),
+ .din(blu),
+ .ctrl({vsync,hsync}),
+ .dout(ch0));
+
+// shift registers
+reg [9:0]ch0s;
+reg [9:0]ch1s;
+reg [9:0]ch2s;
+reg [9:0]ch3s;
+
+reg [4:0]cycle = 5'b00001;
+
+// TODO ideally cycle[0] would occur on the 4th
+// pixclk5x tick within every pixclk
+//
+always_ff @(posedge pixclk5x) begin
+ cycle <= { cycle[0], cycle[4:1] };
+ ch0s <= cycle[0] ? ch0 : { 2'b0, ch0s[9:2] };
+ ch1s <= cycle[0] ? ch1 : { 2'b0, ch1s[9:2] };
+ ch2s <= cycle[0] ? ch2 : { 2'b0, ch2s[9:2] };
+ ch3s <= cycle[0] ? ch3 : { 2'b0, ch3s[9:2] };
+end
+
+dvi_ddr_out ddo0 (
+ .clk(pixclk5x),
+ .din(ch0s[1:0]),
+ .pin_dp(pin_dvi_dp[0]),
+ .pin_dn(pin_dvi_dn[0]));
+
+dvi_ddr_out ddo1 (
+ .clk(pixclk5x),
+ .din(ch1s[1:0]),
+ .pin_dp(pin_dvi_dp[1]),
+ .pin_dn(pin_dvi_dn[1]));
+
+dvi_ddr_out ddo2 (
+ .clk(pixclk5x),
+ .din(ch2s[1:0]),
+ .pin_dp(pin_dvi_dp[2]),
+ .pin_dn(pin_dvi_dn[2]));
+
+dvi_ddr_out ddo3 (
+ .clk(pixclk5x),
+ .din(ch3s[1:0]),
+ .pin_dp(pin_dvi_dp[3]),
+ .pin_dn(pin_dvi_dn[3]));
+
+endmodule
+
+module dvi_ddr_out(
+ input wire clk,
+ input wire [1:0]din,
+ output wire pin_dp,
+ output wire pin_dn
+);
+
+`ifndef verilator
+ODDRX1F dp(
+ .D0(din[0]),
+ .D1(din[1]),
+ .Q(pin_dp),
+ .SCLK(clk),
+ .RST(0));
+
+ODDRX1F dn(
+ .D0(~din[0]),
+ .D1(~din[1]),
+ .Q(pin_dn),
+ .SCLK(clk),
+ .RST(0));
+`endif
+
+endmodule
+
diff --git a/hdl/display/dvi-encoder.sv b/hdl/display/dvi-encoder.sv
@@ -0,0 +1,80 @@
+// Copyright 2014, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+`default_nettype none
+
+module dvi_encoder(
+ input wire clk,
+ input wire active,
+ input wire [7:0]din,
+ input wire [1:0]ctrl,
+ output reg [9:0]dout
+ );
+
+reg [3:0]acc = 0;
+
+wire [8:0]xo;
+wire [8:0]xn;
+
+assign xn[0] = din[0];
+assign xn[1] = din[1] ~^ xn[0];
+assign xn[2] = din[2] ~^ xn[1];
+assign xn[3] = din[3] ~^ xn[2];
+assign xn[4] = din[4] ~^ xn[3];
+assign xn[5] = din[5] ~^ xn[4];
+assign xn[6] = din[6] ~^ xn[5];
+assign xn[7] = din[7] ~^ xn[6];
+assign xn[8] = 0;
+
+assign xo[0] = din[0];
+assign xo[1] = din[1] ^ xo[0];
+assign xo[2] = din[2] ^ xo[1];
+assign xo[3] = din[3] ^ xo[2];
+assign xo[4] = din[4] ^ xo[3];
+assign xo[5] = din[5] ^ xo[4];
+assign xo[6] = din[6] ^ xo[5];
+assign xo[7] = din[7] ^ xo[6];
+assign xo[8] = 1;
+
+localparam Z3 = 3'd0;
+
+wire [3:0]ones =
+ {Z3,din[0]} + {Z3,din[1]} + {Z3,din[2]} +
+ {Z3,din[3]} + {Z3,din[4]} + {Z3,din[5]} +
+ {Z3,din[6]} + {Z3,din[7]};
+
+wire use_xn = ((ones > 4) | ((ones == 4) & (din[0] == 0)));
+
+wire [8:0]tmp = use_xn ? xn : xo;
+wire [3:0]tmp_ones =
+ {Z3,tmp[0]} + {Z3,tmp[1]} + {Z3,tmp[2]} +
+ {Z3,tmp[3]} + {Z3,tmp[4]} + {Z3,tmp[5]} +
+ {Z3,tmp[6]} + {Z3,tmp[7]};
+
+wire no_bias = (acc == 0) | (tmp_ones == 4);
+
+wire same_sign = (acc[3] == tmp_ones[3]);
+
+wire inv = no_bias ? (~tmp[8]) : same_sign;
+
+wire [9:0]enc = { inv, tmp[8], inv ? ~tmp[7:0] : tmp[7:0] };
+
+always @(posedge clk) begin
+ if (active) begin
+ dout <= enc;
+ acc <= acc - 5 + {Z3,enc[0]} + {Z3,enc[1]} +
+ {Z3,enc[2]} + {Z3,enc[3]} + {Z3,enc[4]} +
+ {Z3,enc[5]} + {Z3,enc[6]} + {Z3,enc[7]} +
+ {Z3,enc[8]} + {Z3,enc[9]};
+ end else begin
+ case (ctrl)
+ 2'b00: dout <= 10'b1101010100;
+ 2'b01: dout <= 10'b0010101011;
+ 2'b10: dout <= 10'b0101010100;
+ 2'b11: dout <= 10'b1010101011;
+ endcase
+ acc <= 0;
+ end
+end
+
+endmodule