| // 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 | 
 |  | 
 | module idelay_histogram # | 
 | ( | 
 | parameter UART_PRESCALER = 868   // UART prescaler | 
 | ) | 
 | ( | 
 | // Closk & reset | 
 | input  wire CLK, | 
 | input  wire RST, | 
 |  | 
 | // UART | 
 | input  wire UART_RX, | 
 | output wire UART_TX, | 
 |  | 
 | // TEST - internal loopback | 
 | input  wire TEST, | 
 |  | 
 | // Input and output pins | 
 | output wire O, | 
 | input  wire I, | 
 |  | 
 | output wire REF_O, | 
 | output wire REF_I, | 
 |  | 
 | // IDELAY delay setting output | 
 | output wire [4:0] DELAY | 
 | ); | 
 |  | 
 | // ============================================================================ | 
 | // Data generator | 
 | reg [1:0] ce_cnt; | 
 | wire ce; | 
 |  | 
 | always @(posedge CLK) | 
 |     ce_cnt <= ce_cnt + 1; | 
 |  | 
 | assign ce = (ce_cnt == 0); | 
 |  | 
 | // LFSR | 
 | wire [15:0] lfsr_r; | 
 |  | 
 | lfsr lfsr | 
 | ( | 
 | .clk    (CLK), | 
 | .rst    (RST), | 
 | .ce     (ce), | 
 | .r      (lfsr_r) | 
 | ); | 
 |  | 
 | reg  o_stb; | 
 | wire o_dat; | 
 |  | 
 | always @(posedge CLK) | 
 |     if (RST) | 
 |         o_stb <= 1'b0; | 
 |     else | 
 |         o_stb <= ce; | 
 |  | 
 | assign o_dat = lfsr_r[0]; | 
 | assign O     = o_dat; | 
 |  | 
 | // ============================================================================ | 
 | // Data input with IDELAY | 
 | wire dly_dat; | 
 | wire dly_ld; | 
 | wire [5:0] dly_cnt; | 
 |  | 
 | IDELAYE2 # | 
 | ( | 
 | .IDELAY_TYPE    ("VAR_LOAD"), | 
 | .DELAY_SRC      ("IDATAIN") | 
 | ) | 
 | idelay | 
 | ( | 
 | .IDATAIN    (I), | 
 | .DATAOUT    (dly_dat), | 
 |  | 
 | .C          (CLK), | 
 | .LD         (dly_ld), | 
 | .CNTVALUEIN (dly_cnt), | 
 | .CNTVALUEOUT(DELAY) | 
 | ); | 
 |  | 
 | assign OI = dly_dat; | 
 |  | 
 | // ============================================================================ | 
 | // Data comparator | 
 | reg o_dat_r; | 
 |  | 
 | reg cmp_s0_stb; | 
 | reg cmp_s0_o_dat; | 
 | reg cmp_s0_i_dat; | 
 |  | 
 | reg cmp_s1_stb; | 
 | reg cmp_s1_err; | 
 |  | 
 | always @(posedge CLK) | 
 |     o_dat_r <= o_dat; | 
 |  | 
 | always @(posedge CLK) | 
 |     if (RST) | 
 |         cmp_s0_stb <= 1'b0; | 
 |     else | 
 |         cmp_s0_stb <= o_stb; | 
 |  | 
 | always @(posedge CLK) | 
 |     if (o_stb) | 
 |         cmp_s0_o_dat <= o_dat_r; | 
 | always @(posedge CLK) | 
 |     if (o_stb) | 
 |         cmp_s0_i_dat <= (TEST) ? O : dly_dat; | 
 |  | 
 |  | 
 | always @(posedge CLK) | 
 |     if (RST) | 
 |         cmp_s1_stb <= 1'b0; | 
 |     else | 
 |         cmp_s1_stb <= cmp_s0_stb; | 
 |  | 
 | always @(posedge CLK) | 
 |     cmp_s1_err <= cmp_s0_o_dat ^ cmp_s0_i_dat; | 
 |  | 
 | assign REF_O = o_dat_r; | 
 | assign REF_I = dly_dat; | 
 |  | 
 | // ============================================================================ | 
 | // Error counter | 
 | wire             cnt_stb; | 
 | wire [32*24-1:0] cnt_dat; | 
 |  | 
 | error_counter # | 
 | ( | 
 | .COUNT_WIDTH (24), | 
 | .DELAY_TAPS  (32), | 
 |  | 
 | .TRIGGER_INTERVAL   (50000000), | 
 | .HOLDOFF_TIME       (100), | 
 | .MEASURE_TIME       (10000) | 
 | ) | 
 | error_counter | 
 | ( | 
 | .CLK    (CLK), | 
 | .RST    (RST), | 
 |  | 
 | .I_STB  (cmp_s1_stb), | 
 | .I_ERR  (cmp_s1_err), | 
 |  | 
 | .DLY_LD (dly_ld), | 
 | .DLY_CNT(dly_cnt), | 
 |  | 
 | .O_STB  (cnt_stb), | 
 | .O_DAT  (cnt_dat) | 
 | ); | 
 |  | 
 | // ============================================================================ | 
 | // Message formatter | 
 | wire        uart_x_stb; | 
 | wire [7:0]  uart_x_dat; | 
 |  | 
 | message_formatter # | 
 | ( | 
 | .WIDTH       (24), | 
 | .COUNT       (32), | 
 | .TX_INTERVAL (UART_PRESCALER * 11) // 10 bits plus one more. | 
 | ) | 
 | message_formatter | 
 | ( | 
 | .CLK    (CLK), | 
 | .RST    (RST), | 
 |  | 
 | .I_STB  (cnt_stb), | 
 | .I_DAT  (cnt_dat), | 
 |  | 
 | .O_STB  (uart_x_stb), | 
 | .O_DAT  (uart_x_dat) | 
 | ); | 
 |  | 
 | // ============================================================================ | 
 | // UART | 
 |  | 
 | // Baudrate prescaler initializer | 
 | reg  [7:0]  reg_div_we_sr; | 
 | wire        reg_div_we; | 
 |  | 
 | always @(posedge CLK) | 
 |     if (RST)    reg_div_we_sr <= 8'h01; | 
 |     else        reg_div_we_sr <= {reg_div_we_sr[6:0], 1'd0}; | 
 |  | 
 | assign reg_div_we = reg_div_we_sr[7]; | 
 |  | 
 | // The UART | 
 | simpleuart uart | 
 | ( | 
 | .clk            (CLK), | 
 | .resetn         (!RST), | 
 |  | 
 | .ser_rx         (UART_RX), | 
 | .ser_tx         (UART_TX), | 
 |  | 
 | .reg_div_we     ({reg_div_we, reg_div_we, reg_div_we, reg_div_we}), | 
 | .reg_div_di     (UART_PRESCALER), | 
 | .reg_div_do     (), | 
 |  | 
 | .reg_dat_we     (uart_x_stb), | 
 | .reg_dat_re     (1'd0), | 
 | .reg_dat_di     ({24'd0, uart_x_dat}), | 
 | .reg_dat_do     (), | 
 | .reg_dat_wait   () | 
 | ); | 
 |  | 
 | // Debug | 
 | always @(posedge CLK) | 
 |     if (uart_x_stb) | 
 |         $display("%c", uart_x_dat); | 
 |  | 
 | endmodule | 
 |  |