gtx_comma_align.v 5.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*******************************************************************************
 * Module: gtx_comma_align
 * Date: 2015-07-11  
 * Author: Alexey     
 * Description: comma aligner implementation
 *
 * Copyright (c) 2015 Elphel, Inc.
 * 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/> .
 *******************************************************************************/
module gtx_comma_align(
    input   wire            rst,
    input   wire            clk,
24 25 26 27
    // 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
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 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
    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;
74
assign  window = {indata[18:0], indata_r};
75 76 77 78

// 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
79
wire    [19:0]  comma_match_p;
80 81 82
reg     [19:0]  aligned_data;
reg     [19:0]  comma_match_prev;
wire            comma_detected;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
83 84
wire    [19:0]  comma_p = 20'b10101010100101111100;
wire    [19:0]  comma_n = 20'b10101010101010000011;
85 86 87 88 89 90

genvar ii;
generate
    for (ii = 0; ii < 20; ii = ii + 1)
    begin: look_for_comma
        assign  subwindow[ii]   = window[ii + 19:ii];
91 92
//        assign  comma_match[ii] = subwindow[ii] == 20'b01010101010011111010 | subwindow[ii] == 20'b01010101011100000101;
        // stream comes inverted
Alexey Grebenkin's avatar
Alexey Grebenkin committed
93 94
        assign  comma_match_p[ii] = subwindow[ii] == comma_p;
        assign  comma_match[ii]   = comma_match_p[ii] | subwindow[ii] == comma_n;
95 96 97 98 99 100 101
    end
endgenerate

assign  comma_detected = |comma_match;

// save the shift count
always @ (posedge clk)
102
    comma_match_prev <= rst ? 20'h1 : comma_detected ? comma_match : comma_match_prev;
103
// shift
Alexey Grebenkin's avatar
Alexey Grebenkin committed
104
/* TODO
105 106
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
107 108 109 110 111 112 113 114 115 116
*/
// 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
117 118
        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
119 120 121 122
    end
endgenerate

assign  shifted_window = comma_detected ? ored_subwindow_comdet[19] : ored_subwindow[19];
123 124 125 126 127 128 129 130 131 132
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