gtx_comma_align.v 6.17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>gtx_comma_align
 * @file gtx_comma_align.v
 * @date  2015-07-11  
 * @author Alexey     
 *
 * @brief comma aligner implementation
 *
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * gtx_comma_align.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * gtx_comma_align.v file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
25 26 27 28 29 30 31 32 33 34 35 36 37
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
 * files and/or simulating the code, the copyright holders of this Program give
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
 * charge, and there is no dependence on any encrypted modules for simulating of
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
38
 */
39 40 41
module gtx_comma_align(
    input   wire            rst,
    input   wire            clk,
42 43 44 45
    // input data comes this way (standart 8/10 bit notation)
    // cycle 0: {[hgfedcba]=1st byte,[hgfedcba]=0st byte}
    // cycle 1: {[hgfedcba]=3rd byte,[hgfedcba]=2dn byte}
    // => {[cycle1 data], [cycle0 data]} = as if we were reading by dwords
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    input   wire    [19:0]  indata,
    output  wire    [19:0]  outdata,
    // outdata contains comma
    output  wire            comma,
    // pulse, indicating that stream was once again adjusted to a comma
    // if asserted after link was down - OK
    // if asserted during a work - most likely indicates an error in a stream
    output  wire            realign
    // asserted when input stream looks like comma, but it is not
    // later on after 10/8 it would get something link NOTINTHETABLE error anyways
//    output  wire            error
);
// only comma character = K28.5, has 5 '1's or 5 '0's in a row. 
// after we met it, call it a comma group, we could compare other symbols
/*
// create a window
reg     [19:0]  indata_r;
wire    [23:0]  window;
always @ (posedge clk)
    indata_r <= indata;
assign  window = {indata_r[17:0], indata[19:14]};

// search for a comma group - parallel 24-bit window into 20 5-bit words
// transposed -> 5 x 20-bit words
wire    [19:0] lane0;
wire    [19:0] lane1;
wire    [19:0] lane2;
wire    [19:0] lane3;
wire    [19:0] lane4;
assign  lane0 = window[19:0];
assign  lane1 = window[20:1];
assign  lane2 = window[21:2];
assign  lane3 = window[22:3];
assign  lane4 = window[23:4];
// calcute at what position in a window comma group is detected, 
// so the position in actual {indata_r, indata} would be +2 from the left side
wire    [19:0] comma_pos;
assign  comma_pos = lane0 & lane1 & lane2 & lane3 & lane4;
*/

// seach for a comma
// TODO make it less expensive
reg     [19:0] indata_r;
wire    [38:0] window;
always @ (posedge clk)
    indata_r <= indata;
92
assign  window = {indata[18:0], indata_r};
93 94 95 96

// there is only 1 matched subwindow due to 20-bit comma's non-repetative pattern
wire    [19:0]  subwindow [19:0];
wire    [19:0]  comma_match;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
97
wire    [19:0]  comma_match_p;
98 99 100
reg     [19:0]  aligned_data;
reg     [19:0]  comma_match_prev;
wire            comma_detected;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
101 102
wire    [19:0]  comma_p = 20'b10101010100101111100;
wire    [19:0]  comma_n = 20'b10101010101010000011;
103 104 105 106 107 108

genvar ii;
generate
    for (ii = 0; ii < 20; ii = ii + 1)
    begin: look_for_comma
        assign  subwindow[ii]   = window[ii + 19:ii];
109 110
//        assign  comma_match[ii] = subwindow[ii] == 20'b01010101010011111010 | subwindow[ii] == 20'b01010101011100000101;
        // stream comes inverted
Alexey Grebenkin's avatar
Alexey Grebenkin committed
111 112
        assign  comma_match_p[ii] = subwindow[ii] == comma_p;
        assign  comma_match[ii]   = comma_match_p[ii] | subwindow[ii] == comma_n;
113 114 115 116 117 118 119
    end
endgenerate

assign  comma_detected = |comma_match;

// save the shift count
always @ (posedge clk)
120
    comma_match_prev <= rst ? 20'h1 : comma_detected ? comma_match : comma_match_prev;
121
// shift
Alexey Grebenkin's avatar
Alexey Grebenkin committed
122
/* TODO
123 124
wire    [38:0] shifted_window;
assign  shifted_window = comma_detected ? {window >> (comma_match - 1)} : {window >> (comma_match_prev - 1)};
Alexey Grebenkin's avatar
Alexey Grebenkin committed
125 126 127 128 129 130 131 132 133 134
*/
// temp shift
wire    [19:0]  shifted_window;
wire    [19:0]  ored_subwindow [19:0];
wire    [19:0]  ored_subwindow_comdet [19:0];
assign  ored_subwindow_comdet[0] = {20{comma_match_p[0]}} & comma_p | {20{~comma_match_p[0] & comma_match[0]}} & comma_n;
assign  ored_subwindow[0]       = {20{comma_match_prev[0]}} & subwindow[0];
generate
    for (ii = 1; ii < 20; ii = ii + 1)
    begin: or_all_possible_windows
135 136
        assign ored_subwindow_comdet[ii] = {20{comma_match_p[ii]}} & comma_p | {20{~comma_match_p[ii] & comma_match[ii]}} & comma_n | ored_subwindow_comdet[ii-1];  // SuppressThisWarning VEditor -warning would be fixed in future releases
        assign ored_subwindow[ii]        = {20{comma_match_prev[ii]}} & subwindow[ii] | ored_subwindow[ii-1];                                                       // SuppressThisWarning VEditor -warning would be fixed in future releases
Alexey Grebenkin's avatar
Alexey Grebenkin committed
137 138 139 140
    end
endgenerate

assign  shifted_window = comma_detected ? ored_subwindow_comdet[19] : ored_subwindow[19];
141 142 143 144 145 146 147 148 149 150
always @ (posedge clk)
//    aligned_data <= comma_detected ? {window >> (comma_match - 1)}[19:0] : {window >> (comma_match_prev - 1)}[19:0];
    aligned_data <= shifted_window[19:0];

// form outputs
assign  comma   = comma_detected;
assign  realign = comma_detected & |(comma_match_prev ^ comma_match);
assign  outdata = aligned_data;

endmodule