blob: a36aea7828eb1169e1263620bd3529ee5fb00744 [file] [log] [blame]
// 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