aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/io_cap_gen/cap_pattern_verifier.v
blob: 0d4877187d71b715c50234d5956405f1bcfa42a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//
// Copyright 2015 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// Synthesizable test pattern checker
//

module cap_pattern_verifier #(
  parameter WIDTH       = 16,       //Width of data bus
  parameter PATTERN     = "RAMP",   //Pattern to detect. Choose from {RAMP, ONES, ZEROS, TOGGLE, LEFT_BARREL, RIGHT_BARREL}
  parameter RAMP_START  = 'h0000,   //Start value for ramp (PATTERN=RAMP only)
  parameter RAMP_STOP   = 'hFFFF,   //Stop value for ramp (PATTERN=RAMP only)
  parameter RAMP_INCR   = 'h0001,   //Increment for ramp (PATTERN=RAMP only)
  parameter BARREL_INIT = 'h0001,   //Initial value for the barrel shifter (PATTERN=*_BARREL only)
  parameter HOLD_CYCLES = 1         //Number of cycles to hold each value in the pattern
) (
  input             clk,
  input             rst,

  //Data input
  input             valid,
  input [WIDTH-1:0] data,

  //Status output (2 cycle latency)
  output reg [31:0] count,
  output reg [31:0] errors,
  output            locked,
  output            failed
);

  //Create a synchronous version of rst
  wire sync_rst;
  reset_sync reset_sync_i (
    .clk(clk), .reset_in(rst), .reset_out(sync_rst));

  // Register the data to minimize fanout at source
  reg [WIDTH-1:0] data_reg;
  reg             valid_reg;
  always @(posedge clk)
    {data_reg, valid_reg} <= {data, valid};

  // Define pattern start and next states
  wire [WIDTH-1:0]  patt_start, patt_next;
  reg [WIDTH-1:0]   patt_next_reg;
  generate if (PATTERN == "RAMP") begin
    assign patt_start = RAMP_START;
    assign patt_next  = (data_reg==RAMP_STOP) ? RAMP_START : data_reg+RAMP_INCR;
  end else if (PATTERN == "ZEROS") begin
    assign patt_start = {WIDTH{1'b0}};
    assign patt_next  = {WIDTH{1'b0}};
  end else if (PATTERN == "ONES") begin
    assign patt_start = {WIDTH{1'b1}};
    assign patt_next  = {WIDTH{1'b1}};
  end else if (PATTERN == "TOGGLE") begin
    assign patt_start = {(WIDTH/2){2'b10}};
    assign patt_next  = ~data_reg;
  end else if (PATTERN == "LEFT_BARREL") begin
    assign patt_start = BARREL_INIT;
    assign patt_next  = {data_reg[WIDTH-2:0],data_reg[WIDTH-1]};
  end else if (PATTERN == "RIGHT_BARREL") begin
    assign patt_start = BARREL_INIT;
    assign patt_next  = {data_reg[0],data_reg[WIDTH-1:1]};
  end endgenerate

  reg [1:0] state;
  localparam ST_IDLE    = 2'd0;
  localparam ST_LOCKED  = 2'd1;

  reg [7:0] cyc_count;

  //All registers in this state machine need to have an
  //asynchronous reset because the "data" and "valid" can
  //be metastable coming into this module, and can possibly
  //corrupt "state".
  always @(posedge clk or posedge rst) begin
    if (rst) begin            //Asynchronous reset
      count         <= 32'd0;
      errors        <= 32'd0;
      state         <= ST_IDLE;
      cyc_count     <= 8'd0;
      patt_next_reg <= {WIDTH{1'b0}};
    end else begin
      //Only do something if data is valid
      if (valid_reg & ~sync_rst) begin
        case (state)
          ST_IDLE: begin
            //Trigger on start of pattern
            //We use a case equality here to ensure that this module
            //does the right thing in simulation. In HW this should
            //infer a "=="
            if (data_reg === patt_start) begin
              state     <= ST_LOCKED;
              count     <= 32'd1;
              cyc_count <= HOLD_CYCLES - 1;
            end
          end
          ST_LOCKED: begin
            if (cyc_count == 0) begin           //Hold counter has expired. Check next word
              count <= count + 32'd1;
              //We use a case equality here to ensure that this module
              //does the right thing in simulation. In HW this should
              //infer a "!="
              if (data_reg !== patt_next_reg) begin
                errors <= errors + 32'd1;
              end
              cyc_count <= HOLD_CYCLES - 1;
            end else begin                      //Hold until the next update
              cyc_count <= cyc_count - 1;
            end
          end
        endcase
        patt_next_reg <= patt_next;             //Update next pattern
      end
    end
  end  

  assign locked = (state == ST_LOCKED);
  assign failed = (errors != 32'd0) && locked;

endmodule