spinal.lib.graphic.hdmi.TmdsEncoder.scala Maven / Gradle / Ivy
package spinal.lib.graphic.hdmi
import spinal.core._
import spinal.lib._
object TmdsEncoder{
def apply(VD : UInt, CD : Bits, VDE : Bool, TMDS :Bits) : TmdsEncoder = {
val ret = TmdsEncoder()
ret.io.VD := VD
ret.io.CD := CD
ret.io.VDE := VDE
TMDS := ret.io.TMDS
ret
}
}
case class TmdsEncoder() extends Component{
val io = new Bundle {
val VD = in UInt(8 bits)
val CD = in Bits(2 bits)
val VDE = in Bool()
val TMDS = out (Reg(Bits(10 bits)))
}
val dc_bias = Reg(UInt(4 bits)) randBoot()
val ones = io.VD.asBools.map(_.asUInt(4 bits)).reduceBalancedTree(_ + _)
val XNOR = (ones > 4) || (ones === 4 && io.VD(0) === False)
val dw = Vec(Bool(), 9)
dw(8) := ~XNOR;
dw(7) := dw(6) ^ io.VD(7) ^ XNOR;
dw(6) := dw(5) ^ io.VD(6) ^ XNOR;
dw(5) := dw(4) ^ io.VD(5) ^ XNOR;
dw(4) := dw(3) ^ io.VD(4) ^ XNOR;
dw(3) := dw(2) ^ io.VD(3) ^ XNOR;
dw(2) := dw(1) ^ io.VD(2) ^ XNOR;
dw(1) := dw(0) ^ io.VD(1) ^ XNOR;
dw(0) := io.VD(0);
val dw_disp = dw.take(8).map(_.asUInt(4 bits)).reduceBalancedTree(_ + _) + 12
val sign_eq = dw_disp(3) === dc_bias(3)
val delta = dw_disp - U((dw(8) ^ ~sign_eq) & ~(dw_disp===0 || dc_bias===0));
val inv_dw = (dw_disp === 0 || dc_bias === 0) ? ~dw(8) | sign_eq;
val dc_bias_d = inv_dw ? (dc_bias - delta) | (dc_bias + delta)
val TMDS_data = inv_dw ## dw(8) ## (dw.take(8).asBits ^ (inv_dw ? B(255) | B(0)))
val TMDS_code = io.CD(1) ? (io.CD(0) ? B"b1010101011" | B"b0101010100") | (io.CD(0) ? B"b0010101011" | B"b1101010100")
io.TMDS := (io.VDE ? TMDS_data | TMDS_code);
dc_bias := (io.VDE ? dc_bias_d | 0)
}
// Not my own, based on : third party verilog
// DVI-D 10b8b TMDS encoder module
//
//module TMDS_encoder(
// input clk, // pix clock
// input [7:0] VD, // video data (red, green or blue)
// input [1:0] CD, // control data
// input VDE, // video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)
// output reg [9:0] TMDS = 0
//);
//
// reg [3:0] dc_bias = 0;
//
// // compute data word
// wire [3:0] ones = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];
// wire XNOR = (ones>4'd4) || (ones==4'd4 && VD[0]==1'b0);
// wire [8:0] dw;
// assign dw[8] = ~XNOR;
// assign dw[7] = dw[6] ^ VD[7] ^ XNOR;
// assign dw[6] = dw[5] ^ VD[6] ^ XNOR;
// assign dw[5] = dw[4] ^ VD[5] ^ XNOR;
// assign dw[4] = dw[3] ^ VD[4] ^ XNOR;
// assign dw[3] = dw[2] ^ VD[3] ^ XNOR;
// assign dw[2] = dw[1] ^ VD[2] ^ XNOR;
// assign dw[1] = dw[0] ^ VD[1] ^ XNOR;
// assign dw[0] = VD[0];
//
// // calculate 1/0 disparity & invert as needed to minimize dc bias
// wire [3:0] dw_disp = dw[0] + dw[1] + dw[2] + dw[3] + dw[4] + dw[5] + dw[6] + dw[7] + 4'b1100;
// wire sign_eq = (dw_disp[3] == dc_bias[3]);
//
// wire [3:0] delta = dw_disp - ({dw[8] ^ ~sign_eq} & ~(dw_disp==0 || dc_bias==0));
// wire inv_dw = (dw_disp==0 || dc_bias==0) ? ~dw[8] : sign_eq;
//
// wire [3:0] dc_bias_d = inv_dw ? dc_bias - delta : dc_bias + delta;
//
// // set output signals
// wire [9:0] TMDS_data = { inv_dw, dw[8], dw[7:0] ^ {8{inv_dw}} };
// wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100)
// : (CD[0] ? 10'b0010101011 : 10'b1101010100);
//
// always @(posedge clk) TMDS <= VDE ? TMDS_data : TMDS_code;
// always @(posedge clk) dc_bias <= VDE ? dc_bias_d : 0;
//
//endmodule