////////////////////////////////////////////////////////////////////////////// // // Xilinx, Inc. 2010 www.xilinx.com // // XAPP xxx - TMDS serial stream phase aligner // ////////////////////////////////////////////////////////////////////////////// // // File name : phasealigner.v // // Description : This module determines whether the Spartan-6 IOSERDES // has validate the incoming TMDS data stream // // // Note: // // Author : Bob Feng // // Disclaimer: LIMITED WARRANTY AND DISCLAMER. These designs are // provided to you "as is". Xilinx and its licensors make and you // receive no warranties or conditions, express, implied, // statutory or otherwise, and Xilinx specifically disclaims any // implied warranties of merchantability, non-infringement,or // fitness for a particular purpose. Xilinx does not warrant that // the functions contained in these designs will meet your // requirements, or that the operation of these designs will be // uninterrupted or error free, or that defects in the Designs // will be corrected. Furthermore, Xilinx does not warrantor // make any representations regarding use or the results of the // use of the designs in terms of correctness, accuracy, // reliability, or otherwise. // // LIMITATION OF LIABILITY. In no event will Xilinx or its // licensors be liable for any loss of data, lost profits,cost // or procurement of substitute goods or services, or for any // special, incidental, consequential, or indirect damages // arising from the use or operation of the designs or // accompanying documentation, however caused and on any theory // of liability. This limitation will apply even if Xilinx // has been advised of the possibility of such damage. This // limitation shall apply not-withstanding the failure of the // essential purpose of any limited remedies herein. // // Copyright © 2006 Xilinx, Inc. // All rights reserved // ////////////////////////////////////////////////////////////////////////////// // Modifications copyright (c) 2011, Andrew "bunnie" Huang // All rights reserved as permitted by law. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation and/or // other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////// // `timescale 1 ns / 1ps `define SIMULATION 1 // here's what this module does. // 1. searches for an incoming control token // 2. when it finds one, makes sure it sticks around at least CTKNCNTWD. // 3. if it can't find one within SRCHTIMERWD, try a new bitslip and/or gearbox setting. // keep on trying bitslips and gear settings over and over again ewvery SRCHTIMERWD // until we've found a CTKNCNTWD. // 4. once the token has stuck around for the pre-determined number of cycles, repeat // the search to confirm it. (this function is degenerate in this implementation) // 5. once setting has been confirmed, assume it never changes. module phsaligner # ( parameter OPENEYE_CNT_WD = 3, // valid open eye counter width // parameter CTKNCNTWD = 7, // Control Token Counter Width (dvi spec is 128) parameter CTKNCNTWD = 3, // Control Token Counter Width (hdmi spec is 8) parameter SRCHTIMERWD = 12 // Idle Timer Width ) ( input wire rst, input wire clk, input wire [9:0] sdata, // 10 bit serial stream sync. to clk output reg flipgear, output reg bitslip, output reg psaligned // FSM output ); parameter CTRLTOKEN0 = 10'b1101010100; parameter CTRLTOKEN1 = 10'b0010101011; parameter CTRLTOKEN2 = 10'b0101010100; parameter CTRLTOKEN3 = 10'b1010101011; /////////////////////////////////////////////////////// // Control Token Detection /////////////////////////////////////////////////////// reg rcvd_ctkn, rcvd_ctkn_q; reg blnkbgn; //blank period begins always @ (posedge clk) begin rcvd_ctkn <=#1 ((sdata == CTRLTOKEN0) || (sdata == CTRLTOKEN1) || (sdata == CTRLTOKEN2) || (sdata == CTRLTOKEN3)); rcvd_ctkn_q <=#1 rcvd_ctkn; blnkbgn <=#1 !rcvd_ctkn_q & rcvd_ctkn; end ///////////////////////////////////////////////////// // Control Token Search Timer // // DVI 1.0 Spec. says periodic blanking should start // no less than every 50ms or 20HZ // 2^24 of 74.25MHZ cycles is about 200ms ///////////////////////////////////////////////////// reg [(SRCHTIMERWD-1):0] ctkn_srh_timer; reg ctkn_srh_rst; //FSM output always @ (posedge clk) begin if (ctkn_srh_rst) ctkn_srh_timer <=#1 {SRCHTIMERWD{1'b0}}; else ctkn_srh_timer <=#1 ctkn_srh_timer + 1'b1; end reg ctkn_srh_tout; always @ (posedge clk) begin ctkn_srh_tout <=#1 (ctkn_srh_timer == {SRCHTIMERWD{1'b1}}); end ///////////////////////////////////////////////////// // Contorl Token Event Counter // // DVI 1.0 Spec. says the minimal blanking period // is at least 128 pixels long in order to achieve // synchronization // // HDMI reduces this to as little as 8 ///////////////////////////////////////////////////// reg [(CTKNCNTWD-1):0] ctkn_counter; reg ctkn_cnt_rst; //FSM output always @ (posedge clk) begin if(ctkn_cnt_rst) ctkn_counter <=#1 {CTKNCNTWD{1'b0}}; else ctkn_counter <=#1 ctkn_counter + 1'b1; end reg ctkn_cnt_tout; always @ (posedge clk) begin ctkn_cnt_tout <=#1 (ctkn_counter == {CTKNCNTWD{1'b1}}); end ////////////////////////////////////////////////////////// // Below starts the phase alignment state machine ////////////////////////////////////////////////////////// parameter INIT = 6'b1 << 0; parameter SEARCH = 6'b1 << 1; // Searching for control tokens parameter BITSLIP = 6'b1 << 2; parameter RCVDCTKN = 6'b1 << 3; // Received at one Control Token and check for more parameter BLNKPRD = 6'b1 << 4; parameter PSALGND = 6'b1 << 5; // Phase alignment achieved parameter nSTATES = 6; reg [(nSTATES-1):0] cstate = {{(nSTATES-1){1'b0}}, 1'b1}; //current and next states reg [(nSTATES-1):0] nstate; `ifdef SIMULATION // synthesis translate_off reg [8*20:1] state_ascii = "INIT "; always @(cstate) begin if (cstate == INIT ) state_ascii <= "INIT "; else if (cstate == SEARCH ) state_ascii <= "SEARCH "; else if (cstate == BITSLIP ) state_ascii <= "BITSLIP "; else if (cstate == RCVDCTKN ) state_ascii <= "RCVDCTKN "; else if (cstate == BLNKPRD ) state_ascii <= "BLNKPRD "; else state_ascii <= "PSALGND "; end // synthesis translate_on `endif always @ (posedge clk or posedge rst) begin if (rst) cstate <= INIT; else cstate <=#1 nstate; end ////////////////////////////////////////////////////////// // Counter counts number of blank period detected // in order to qualify the bitslip position ////////////////////////////////////////////////////////// parameter BLNKPRD_CNT_WD = 1; reg [(BLNKPRD_CNT_WD-1):0] blnkprd_cnt = {BLNKPRD_CNT_WD{1'b0}}; always @ (*) begin case (cstate) //synthesis parallel_case full_case INIT: begin nstate = (ctkn_srh_tout) ? SEARCH : INIT; end SEARCH: begin if(blnkbgn) nstate = RCVDCTKN; else nstate = (ctkn_srh_tout) ? BITSLIP : SEARCH; end BITSLIP: begin nstate = SEARCH; end RCVDCTKN: begin if(rcvd_ctkn) nstate = (ctkn_cnt_tout) ? BLNKPRD : RCVDCTKN; else nstate = SEARCH; end BLNKPRD: begin nstate = (blnkprd_cnt == {BLNKPRD_CNT_WD{1'b1}}) ? PSALGND : SEARCH; end PSALGND: begin nstate = PSALGND; // Phase aligned so hang around here end endcase end reg [2:0] bitslip_cnt; always @ (posedge clk or posedge rst) begin if(rst) begin psaligned <=#1 1'b0; //phase alignment success flag bitslip <=#1 1'b0; ctkn_srh_rst <=#1 1'b1; //control token search timer reset ctkn_cnt_rst <=#1 1'b1; //control token counter reset bitslip <=#1 1'b0; bitslip_cnt <=#1 3'h0; flipgear <=#1 1'b0; blnkprd_cnt <=#1 {BLNKPRD_CNT_WD{1'b0}}; end else begin case (cstate) // synthesis parallel_case full_case INIT: begin ctkn_srh_rst <=#1 1'b0; ctkn_cnt_rst <=#1 1'b1; bitslip <=#1 1'b0; psaligned <=#1 1'b0; bitslip <=#1 1'b0; bitslip_cnt <=#1 3'h0; flipgear <=#1 1'b0; blnkprd_cnt <=#1 {BLNKPRD_CNT_WD{1'b0}}; end SEARCH: begin ctkn_srh_rst <=#1 1'b0; ctkn_cnt_rst <=#1 1'b1; bitslip <=#1 1'b0; psaligned <=#1 1'b0; end BITSLIP: begin ctkn_srh_rst <=#1 1'b1; bitslip <=#1 1'b1; bitslip_cnt <=#1 bitslip_cnt + 1'b1; flipgear <=#1 bitslip_cnt[2]; //bitslip has toggled for 4 times end RCVDCTKN: begin ctkn_srh_rst <=#1 1'b0; ctkn_cnt_rst <=#1 1'b0; end BLNKPRD: begin blnkprd_cnt <=#1 blnkprd_cnt + 1'b1; end PSALGND: begin psaligned <=#1 1'b1; end endcase end end endmodule