|  | // Copyright (C) 2017-2020  The Project X-Ray Authors. | 
|  | // | 
|  | // Use of this source code is governed by a ISC-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://opensource.org/licenses/ISC | 
|  | // | 
|  | // SPDX-License-Identifier: ISC | 
|  |  | 
|  | `default_nettype none | 
|  |  | 
|  | module error_counter # | 
|  | ( | 
|  | parameter COUNT_WIDTH = 24, | 
|  | parameter DELAY_TAPS  = 32, | 
|  |  | 
|  | parameter TRIGGER_INTERVAL = 20,//100000000, | 
|  | parameter HOLDOFF_TIME     = 4,//10, | 
|  | parameter MEASURE_TIME     = 10//50000 | 
|  | ) | 
|  | ( | 
|  | input  wire CLK, | 
|  | input  wire RST, | 
|  |  | 
|  | input  wire I_STB, | 
|  | input  wire I_ERR, | 
|  |  | 
|  | output wire DLY_LD, | 
|  | output wire [$clog2(DELAY_TAPS)-1:0] DLY_CNT, | 
|  |  | 
|  | output wire O_STB, | 
|  | output wire [COUNT_WIDTH*DELAY_TAPS-1:0] O_DAT | 
|  | ); | 
|  |  | 
|  | // ============================================================================ | 
|  | // FSM | 
|  | integer fsm; | 
|  |  | 
|  | localparam FSM_IDLE     = 'h00; | 
|  | localparam FSM_SETUP    = 'h10; | 
|  | localparam FSM_HOLDOFF  = 'h20; | 
|  | localparam FSM_PREPARE  = 'h30; | 
|  | localparam FSM_MEASURE  = 'h40; | 
|  | localparam FSM_STORE    = 'h50; | 
|  | localparam FSM_OUTPUT   = 'h60; | 
|  |  | 
|  | // ============================================================================ | 
|  | // Counters | 
|  | reg [32:0] ps_cnt; | 
|  | reg [$clog2(DELAY_TAPS)-1:0] dly_cnt; | 
|  |  | 
|  | initial ps_cnt <= TRIGGER_INTERVAL - 1; | 
|  |  | 
|  | always @(posedge CLK) | 
|  | case (fsm) | 
|  |  | 
|  | FSM_IDLE:       ps_cnt <= ps_cnt - 1; | 
|  | FSM_SETUP:      ps_cnt <= HOLDOFF_TIME - 1; | 
|  | FSM_HOLDOFF:    ps_cnt <= ps_cnt - 1; | 
|  | FSM_PREPARE:    ps_cnt <= MEASURE_TIME - 1; | 
|  | FSM_MEASURE:    ps_cnt <= ps_cnt - 1; | 
|  | FSM_OUTPUT:     ps_cnt <= TRIGGER_INTERVAL - 1; | 
|  |  | 
|  | endcase | 
|  |  | 
|  | always @(posedge CLK) | 
|  | case (fsm) | 
|  |  | 
|  | FSM_IDLE:       dly_cnt <= 0; | 
|  | FSM_STORE:      dly_cnt <= dly_cnt + 1; | 
|  |  | 
|  | endcase | 
|  |  | 
|  | // ============================================================================ | 
|  | // IDELAY control | 
|  | assign DLY_LD  = (fsm == FSM_SETUP); | 
|  | assign DLY_CNT = dly_cnt; | 
|  |  | 
|  | // ============================================================================ | 
|  | // Error counter and output shift register | 
|  | reg [(COUNT_WIDTH*DELAY_TAPS)-1:0] o_dat_sr; | 
|  | reg [COUNT_WIDTH-1:0] err_cnt; | 
|  |  | 
|  | always @(posedge CLK) | 
|  | case (fsm) | 
|  |  | 
|  | FSM_PREPARE:           err_cnt <= 0; | 
|  | FSM_MEASURE: if(I_STB) err_cnt <= err_cnt + I_ERR; | 
|  |  | 
|  | endcase | 
|  |  | 
|  | always @(posedge CLK) | 
|  | if (fsm == FSM_STORE) | 
|  | o_dat_sr <= (o_dat_sr << COUNT_WIDTH) | err_cnt; | 
|  |  | 
|  | // ============================================================================ | 
|  | // Control FSM | 
|  | always @(posedge CLK) | 
|  | if (RST) | 
|  | fsm <= FSM_IDLE; | 
|  | else case (fsm) | 
|  |  | 
|  | FSM_IDLE:       if (ps_cnt == 0)  fsm <= FSM_SETUP; | 
|  | FSM_SETUP:      fsm <= FSM_HOLDOFF; | 
|  | FSM_HOLDOFF:    if (ps_cnt == 0)  fsm <= FSM_PREPARE; | 
|  | FSM_PREPARE:    fsm <= FSM_MEASURE; | 
|  | FSM_MEASURE:    if (ps_cnt == 0)  fsm <= FSM_STORE; | 
|  | FSM_STORE:      if (dly_cnt == (DELAY_TAPS-1)) | 
|  | fsm <= FSM_OUTPUT; | 
|  | else | 
|  | fsm <= FSM_SETUP; | 
|  | FSM_OUTPUT:     fsm <= FSM_IDLE; | 
|  |  | 
|  | endcase | 
|  |  | 
|  | // ============================================================================ | 
|  | // Output | 
|  | assign O_STB = (fsm == FSM_OUTPUT); | 
|  | assign O_DAT = o_dat_sr; | 
|  |  | 
|  | endmodule | 
|  |  |