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