// // 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