module dvi_serdes_datain (
    input  wire reset,            //
    input  wire pclk,             //  pixel clock
    input  wire pclkx2,           //  double pixel rate for gear box
    input  wire pclkx10,          //  IOCLK
    input  wire serdesstrobe,     //  serdesstrobe for iserdes2
    input  wire din_p,            //  data from dvi cable
    input  wire din_n,            //  data from dvi cable
    input  wire other_ch0_vld,    //  other channel0 has valid data now
    input  wire other_ch1_vld,    //  other channel1 has valid data now
    input  wire other_ch0_rdy,    //  other channel0 has detected a valid starting pixel
    input  wire other_ch1_rdy,    //  other channel1 has detected a valid starting pixel

    output wire iamvld,           //  I have valid data now
    output wire iamrdy,           //  I have detected a valid new pixel
    output wire psalgnerr,        //  Phase alignment error
    output reg  c0,
    output reg  c1,
    output reg  de,     
    output reg [9:0] sdout,
    output reg [7:0] dout
);

    ////////////////////////////////
    //
    // 5-bit to 10-bit gear box
    //
    ////////////////////////////////
    wire flipgear;
    reg flipgearx2;

    always @ (posedge pclkx2) begin
        flipgearx2 <= flipgear;
    end

    reg toggle = 1'b0;

    always @ (posedge pclkx2 or posedge reset)
        if (reset == 1'b1) begin
            toggle <= 1'b0;
        end else begin
            toggle <= ~toggle;
        end
  
    wire rx_toggle;

    assign rx_toggle = toggle ^ flipgearx2; //reverse hi-lo position

    wire [4:0] raw5bit;
    reg [4:0] raw5bit_q;
    reg [9:0] rawword;

    always @ (posedge pclkx2) begin
        raw5bit_q <= raw5bit;

        if (rx_toggle) //gear from 5 bit to 10 bit
            rawword <= {raw5bit, raw5bit_q};
    end

    ////////////////////////////////
    //
    // bitslip signal sync to pclkx2
    //
    ////////////////////////////////
    reg bitslipx2 = 1'b0;
    reg bitslip_q = 1'b0;
    wire bitslip;

    always @ (posedge pclkx2) begin
        bitslip_q <= bitslip;
        bitslipx2 <= bitslip & !bitslip_q;
    end 

    /////////////////////////////////////////////
    //
    // 1:5 de-serializer working at x2 pclk rate
    //
    /////////////////////////////////////////////
    serdes_1_to_5_diff_data # (
        .DIFF_TERM("FALSE"),
        .BITSLIP_ENABLE("TRUE")
    ) des_0 (
        .use_phase_detector(1'b1),
        .datain_p(din_p),
        .datain_n(din_n),
        .rxioclk(pclkx10),
        .rxserdesstrobe(serdesstrobe),
        .reset(reset),
        .gclk(pclkx2),
        .bitslip(bitslipx2),
        .data_out(raw5bit)
    );

    /////////////////////////////////////////////////////
    // Doing word boundary detection here
    /////////////////////////////////////////////////////
    wire [9:0] rawdata = rawword;

    ///////////////////////////////////////
    // Phase Alignment Instance
    ///////////////////////////////////////
    phsaligner phsalgn_0 (
        .rst(reset),
        .clk(pclk),
        .sdata(rawdata),
        .bitslip(bitslip),
        .flipgear(flipgear),
        .psaligned(iamvld)
    );

    assign psalgnerr = 1'b0;

    ///////////////////////////////////////
    // Per Channel De-skew Instance
    ///////////////////////////////////////
    wire [9:0] sdata;
    chnlbond cbnd (
        .clk(pclk),
        .rawdata(rawdata),
        .iamvld(iamvld),
        .other_ch0_vld(other_ch0_vld),
        .other_ch1_vld(other_ch1_vld),
        .other_ch0_rdy(other_ch0_rdy),
        .other_ch1_rdy(other_ch1_rdy),
        .iamrdy(iamrdy),
        .sdata(sdata)
    );

    /////////////////////////////////////////////////////////////////
    // Below performs the 10B-8B decoding function defined in DVI 1.0
    // Specification: Section 3.3.3, Figure 3-6, page 31. 
    /////////////////////////////////////////////////////////////////
    // Distinct Control Tokens
    parameter CTRLTOKEN0 = 10'b1101010100;
    parameter CTRLTOKEN1 = 10'b0010101011;
    parameter CTRLTOKEN2 = 10'b0101010100;
    parameter CTRLTOKEN3 = 10'b1010101011;

    wire [7:0] data;
    assign data = (sdata[9]) ? ~sdata[7:0] : sdata[7:0]; 

    always @ (posedge pclk) begin
        if(iamrdy && other_ch0_rdy && other_ch1_rdy) begin
            case (sdata) 
            CTRLTOKEN0: begin
                c0 <= 1'b0;
                c1 <= 1'b0;
                de <= 1'b0;
            end

            CTRLTOKEN1: begin
                c0 <= 1'b1;
                c1 <= 1'b0;
                de <= 1'b0;
            end

            CTRLTOKEN2: begin
                c0 <= 1'b0;
                c1 <= 1'b1;
                de <= 1'b0;
            end
                
            CTRLTOKEN3: begin
                c0 <= 1'b1;
                c1 <= 1'b1;
                de <= 1'b0;
            end
                
            default: begin 
                dout[0] <= data[0];
                dout[1] <= (sdata[8]) ? (data[1] ^ data[0]) : (data[1] ~^ data[0]);
                dout[2] <= (sdata[8]) ? (data[2] ^ data[1]) : (data[2] ~^ data[1]);
                dout[3] <= (sdata[8]) ? (data[3] ^ data[2]) : (data[3] ~^ data[2]);
                dout[4] <= (sdata[8]) ? (data[4] ^ data[3]) : (data[4] ~^ data[3]);
                dout[5] <= (sdata[8]) ? (data[5] ^ data[4]) : (data[5] ~^ data[4]);
                dout[6] <= (sdata[8]) ? (data[6] ^ data[5]) : (data[6] ~^ data[5]);
                dout[7] <= (sdata[8]) ? (data[7] ^ data[6]) : (data[7] ~^ data[6]);

                de <= 1'b1;
            end                                                                      
            endcase                                                                    

            sdout <= sdata;
        end else begin
            c0 <= 1'b0;
            c1 <= 1'b0;
            de <= 1'b0;
            dout <= 8'h0;
            sdout <= 10'h0;
        end
    end
endmodule