mirror of https://github.com/openXC7/prjxray.git
OSERDES minitest without the need for hardware loopbacks.
Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
parent
a7a3431ceb
commit
b31345010c
|
|
@ -0,0 +1,38 @@
|
|||
SYNTH ?= vivado
|
||||
YOSYS = $(XRAY_DIR)/third_party/yosys/yosys
|
||||
PART = xc7a35tcsg324-1
|
||||
|
||||
clean:
|
||||
@find . -name "build-par.*" | xargs rm -rf
|
||||
@find . -name "build-syn.*" | xargs rm -rf
|
||||
@rm -f *.edif
|
||||
@rm -f *.bit
|
||||
@rm -f *.bin
|
||||
@rm -f *.log
|
||||
@rm -f *.dcp
|
||||
|
||||
help:
|
||||
@echo "Usage: make all [SYNTH=<vivado/yosys>]"
|
||||
|
||||
.PHONY: clean help
|
||||
|
||||
$(YOSYS):
|
||||
cd $(XRAY_DIR)/third_party/yosys && make config-gcc && make -j$(shell nproc)
|
||||
|
||||
ifeq ($(SYNTH), yosys)
|
||||
%.edif: %.v $(YOSYS)
|
||||
$(YOSYS) -p "read_verilog $< ; synth_xilinx -flatten -nosrl; write_edif -pvector bra -attrprop $@" -l $@.log
|
||||
|
||||
else ifeq ($(SYNTH), vivado)
|
||||
%.edif: %.v tcl/syn.tcl
|
||||
mkdir -p build-syn.$(basename $@)
|
||||
cd build-syn.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../tcl/syn.tcl -nojournal -log ../$@.log
|
||||
rm -rf *.backup.log
|
||||
|
||||
endif
|
||||
|
||||
%.bit: %.edif tcl/par.tcl
|
||||
mkdir -p build-par.$(basename $@)
|
||||
cd build-par.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../tcl/par.tcl -nojournal -log ../$@.log
|
||||
rm -rf *.backup.log
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# Minitest for OSERDES
|
||||
|
||||
## Description
|
||||
|
||||
This test allows to verify that OSERDES is working on hardware. Tested modes are:
|
||||
|
||||
- SDR 2:1
|
||||
- SDR 3:1
|
||||
- SDR 4:1
|
||||
- SDR 5:1
|
||||
- SDR 6:1
|
||||
- SDR 7:1
|
||||
- SDR 8:1
|
||||
- DDR 4:1
|
||||
- DDR 6:1
|
||||
- DDR 8:1
|
||||
|
||||
No chaining of two OSERDES bels.
|
||||
|
||||
A pseudo random sequence of words is generated by a LFSR. The sequence is then serialized by the OSERDES and the output bitstream goes to the output pin. The pin is using 3-state buffer which is constantly on. This allows to read serialized data from the same pin without the need of hardware pin loopback connection.
|
||||
|
||||
Simultaneously to the OSERDES operation, the word sequence is serialized internally by the FPGA logic. Both bitstreams are then compared and an error indication signal is generated. In order to mitigate for the OSERDES latency, the reference bitstream is delayed by a number of clock cycles which is adaptively changed.
|
||||
|
||||
LEDs indicate whether data is being received corectly. When a LED is lit then
|
||||
there is correct reception:
|
||||
|
||||
- LED0 - SDR 2:1
|
||||
- LED1 - SDR 3:1
|
||||
- LED2 - SDR 4:1
|
||||
- LED3 - SDR 5:1
|
||||
- LED4 - SDR 6:1
|
||||
- LED5 - SDR 7:1
|
||||
- LED6 - SDR 8:1
|
||||
- LED7 - DDR 4:1
|
||||
- LED8 - DDR 6:1
|
||||
- LED9 - DDR 8:1
|
||||
- LED10 - Blinking continuously
|
||||
|
||||
The switch SW0 is used as reset.
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run the following command and the bit file will be generated.
|
||||
```
|
||||
make basys3_oserdes_rates.bit
|
||||
```
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
create_clock -period 10.000 -name clk [get_ports clk]
|
||||
|
||||
set_property PACKAGE_PIN W5 [get_ports clk]
|
||||
|
||||
set_property PACKAGE_PIN B18 [get_ports rx]
|
||||
set_property PACKAGE_PIN A18 [get_ports tx]
|
||||
|
||||
set_property PACKAGE_PIN V17 [get_ports sw[ 0]]
|
||||
set_property PACKAGE_PIN V16 [get_ports sw[ 1]]
|
||||
set_property PACKAGE_PIN W16 [get_ports sw[ 2]]
|
||||
set_property PACKAGE_PIN W17 [get_ports sw[ 3]]
|
||||
set_property PACKAGE_PIN W15 [get_ports sw[ 4]]
|
||||
set_property PACKAGE_PIN V15 [get_ports sw[ 5]]
|
||||
set_property PACKAGE_PIN W14 [get_ports sw[ 6]]
|
||||
set_property PACKAGE_PIN W13 [get_ports sw[ 7]]
|
||||
set_property PACKAGE_PIN V2 [get_ports sw[ 8]]
|
||||
set_property PACKAGE_PIN T3 [get_ports sw[ 9]]
|
||||
set_property PACKAGE_PIN T2 [get_ports sw[10]]
|
||||
set_property PACKAGE_PIN R3 [get_ports sw[11]]
|
||||
set_property PACKAGE_PIN W2 [get_ports sw[12]]
|
||||
set_property PACKAGE_PIN U1 [get_ports sw[13]]
|
||||
set_property PACKAGE_PIN T1 [get_ports sw[14]]
|
||||
set_property PACKAGE_PIN R2 [get_ports sw[15]]
|
||||
|
||||
set_property PACKAGE_PIN U16 [get_ports led[ 0]]
|
||||
set_property PACKAGE_PIN E19 [get_ports led[ 1]]
|
||||
set_property PACKAGE_PIN U19 [get_ports led[ 2]]
|
||||
set_property PACKAGE_PIN V19 [get_ports led[ 3]]
|
||||
set_property PACKAGE_PIN W18 [get_ports led[ 4]]
|
||||
set_property PACKAGE_PIN U15 [get_ports led[ 5]]
|
||||
set_property PACKAGE_PIN U14 [get_ports led[ 6]]
|
||||
set_property PACKAGE_PIN V14 [get_ports led[ 7]]
|
||||
set_property PACKAGE_PIN V13 [get_ports led[ 8]]
|
||||
set_property PACKAGE_PIN V3 [get_ports led[ 9]]
|
||||
set_property PACKAGE_PIN W3 [get_ports led[10]]
|
||||
set_property PACKAGE_PIN U3 [get_ports led[11]]
|
||||
set_property PACKAGE_PIN P3 [get_ports led[12]]
|
||||
set_property PACKAGE_PIN N3 [get_ports led[13]]
|
||||
set_property PACKAGE_PIN P1 [get_ports led[14]]
|
||||
set_property PACKAGE_PIN L1 [get_ports led[15]]
|
||||
|
||||
# JA (X1Y1)
|
||||
set_property PACKAGE_PIN J1 [get_ports io[0]]
|
||||
set_property PACKAGE_PIN L2 [get_ports io[1]]
|
||||
set_property PACKAGE_PIN J2 [get_ports io[2]]
|
||||
set_property PACKAGE_PIN G2 [get_ports io[3]]
|
||||
|
||||
# JB (X0Y2)
|
||||
set_property PACKAGE_PIN A14 [get_ports io[4]]
|
||||
set_property PACKAGE_PIN A16 [get_ports io[5]]
|
||||
set_property PACKAGE_PIN B15 [get_ports io[6]]
|
||||
|
||||
# JC (X0Y0)
|
||||
set_property PACKAGE_PIN K17 [get_ports io[7]]
|
||||
set_property PACKAGE_PIN M18 [get_ports io[8]]
|
||||
set_property PACKAGE_PIN N17 [get_ports io[9]]
|
||||
|
||||
foreach port [get_ports] {
|
||||
set_property IOSTANDARD LVCMOS33 $port
|
||||
set_property SLEW FAST $port
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
`include "src/lfsr.v"
|
||||
`include "src/oserdes_test.v"
|
||||
`include "src/comparator.v"
|
||||
|
||||
`default_nettype none
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module top
|
||||
(
|
||||
input wire clk,
|
||||
|
||||
input wire rx,
|
||||
output wire tx,
|
||||
|
||||
input wire [15:0] sw,
|
||||
output wire [15:0] led,
|
||||
|
||||
inout wire [9:0] io
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Clock & reset
|
||||
reg [3:0] rst_sr;
|
||||
|
||||
initial rst_sr <= 4'hF;
|
||||
|
||||
always @(posedge clk)
|
||||
if (sw[0])
|
||||
rst_sr <= 4'hF;
|
||||
else
|
||||
rst_sr <= rst_sr >> 1;
|
||||
|
||||
wire CLK = clk;
|
||||
wire RST = rst_sr[0];
|
||||
|
||||
// ============================================================================
|
||||
// Clocks for OSERDES
|
||||
|
||||
wire CLK1_X0Y0;
|
||||
wire CLK2_X0Y0;
|
||||
|
||||
wire CLK1_X0Y2;
|
||||
wire CLK2_X0Y2;
|
||||
|
||||
wire CLK1_X1Y1;
|
||||
wire CLK2_X1Y1;
|
||||
|
||||
reg clk_r;
|
||||
always @(posedge CLK)
|
||||
if (RST) clk_r <= 1'b0;
|
||||
else clk_r <= !clk_r;
|
||||
|
||||
BUFMR mr_buf_x1y1_1 (.I(CLK), .O(CLK1_X1Y1));
|
||||
BUFMR mr_buf_x1y1_2 (.I(clk_r), .O(CLK2_X1Y1));
|
||||
|
||||
BUFMR mr_buf_x0y2_1 (.I(CLK), .O(CLK1_X0Y2));
|
||||
BUFMR mr_buf_x0y2_2 (.I(clk_r), .O(CLK2_X0Y2));
|
||||
|
||||
BUFMR mr_buf_x0y0_1 (.I(CLK), .O(CLK1_X0Y0));
|
||||
BUFMR mr_buf_x0y0_2 (.I(clk_r), .O(CLK2_X0Y0));
|
||||
|
||||
// ============================================================================
|
||||
// Test uints
|
||||
wire [9:0] error;
|
||||
|
||||
genvar i;
|
||||
generate for (i=0; i<10; i=i+1) begin
|
||||
|
||||
localparam DATA_WIDTH = (i == 0) ? 2 :
|
||||
(i == 1) ? 3 :
|
||||
(i == 2) ? 4 :
|
||||
(i == 3) ? 5 :
|
||||
(i == 4) ? 6 :
|
||||
(i == 5) ? 7 :
|
||||
(i == 6) ? 8 :
|
||||
(i == 7) ? 4 :
|
||||
(i == 8) ? 6 :
|
||||
/*(i == 9) ?*/ 8;
|
||||
|
||||
localparam DATA_RATE = (i < 7) ? "SDR" : "DDR";
|
||||
|
||||
wire CLK1 = (i >= 0 && i < 4) ? CLK1_X1Y1 :
|
||||
(i >= 4 && i < 7) ? CLK1_X0Y2 :
|
||||
CLK1_X0Y0;
|
||||
|
||||
wire CLK2 = (i >= 0 && i < 4) ? CLK2_X1Y1 :
|
||||
(i >= 4 && i < 7) ? CLK2_X0Y2 :
|
||||
CLK2_X0Y0;
|
||||
|
||||
oserdes_test #
|
||||
(
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
.DATA_RATE (DATA_RATE)
|
||||
)
|
||||
oserdes_test
|
||||
(
|
||||
.CLK (CLK),
|
||||
.CLK1 (CLK1),
|
||||
.CLK2 (CLK2),
|
||||
.RST (RST),
|
||||
|
||||
.IO_DAT (io[i]),
|
||||
.O_ERROR (error[i])
|
||||
);
|
||||
|
||||
end endgenerate
|
||||
|
||||
// ============================================================================
|
||||
// IOs
|
||||
reg [24:0] heartbeat_cnt;
|
||||
|
||||
always @(posedge CLK)
|
||||
heartbeat_cnt <= heartbeat_cnt + 1;
|
||||
|
||||
assign led[ 0] = !error[0];
|
||||
assign led[ 1] = !error[1];
|
||||
assign led[ 2] = !error[2];
|
||||
assign led[ 3] = !error[3];
|
||||
assign led[ 4] = !error[4];
|
||||
assign led[ 5] = !error[5];
|
||||
assign led[ 6] = !error[6];
|
||||
assign led[ 7] = !error[7];
|
||||
assign led[ 8] = !error[8];
|
||||
assign led[ 9] = !error[9];
|
||||
assign led[10] = heartbeat_cnt[23];
|
||||
assign led[11] = 1'b0;
|
||||
assign led[12] = 1'b0;
|
||||
assign led[13] = 1'b0;
|
||||
assign led[14] = 1'b0;
|
||||
assign led[15] = 1'b0;
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Check args
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: run_vivado.sh <testbench file>"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Check if testbench exists
|
||||
if [ ! -f $1 ]; then
|
||||
echo "Testbench $1 not found!"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Run Vivado
|
||||
TESTBENCH_TITLE=$(basename $1 .v) ${XRAY_VIVADO} -mode batch -source sim.tcl -nojournal -verbose -log vivado.log
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
create_project -force -part xc7a35ticsg324-1L $::env(TESTBENCH_TITLE) $::env(TESTBENCH_TITLE)
|
||||
|
||||
read_verilog $::env(TESTBENCH_TITLE).v
|
||||
|
||||
set_property top tb [get_filesets sim_1]
|
||||
|
||||
synth_design -top tb -verbose
|
||||
|
||||
set_property xsim.simulate.log_all_signals true [get_filesets sim_1]
|
||||
set_property xsim.simulate.runtime 0 [get_filesets sim_1]
|
||||
|
||||
launch_simulation -verbose
|
||||
restart
|
||||
|
||||
open_vcd ../../../../waveforms.vcd
|
||||
|
||||
run -all
|
||||
|
||||
flush_vcd
|
||||
close_vcd
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
`include "../src/oserdes_test.v"
|
||||
`include "../src/lfsr.v"
|
||||
`include "../src/comparator.v"
|
||||
|
||||
`default_nettype none
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module tb;
|
||||
|
||||
// ============================================================================
|
||||
|
||||
reg CLK;
|
||||
initial CLK <= 1'b0;
|
||||
always #0.5 CLK <= !CLK;
|
||||
|
||||
reg [3:0] rst_sr;
|
||||
initial rst_sr <= 4'hF;
|
||||
always @(posedge CLK) rst_sr <= rst_sr >> 1;
|
||||
wire RST;
|
||||
assign RST = rst_sr[0];
|
||||
|
||||
// ============================================================================
|
||||
|
||||
initial begin
|
||||
$dumpfile("waveforms.vcd");
|
||||
$dumpvars;
|
||||
end
|
||||
|
||||
integer cycle_cnt;
|
||||
initial cycle_cnt <= 0;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (!RST) cycle_cnt <= cycle_cnt + 1;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (!RST && cycle_cnt >= 10000)
|
||||
$finish;
|
||||
|
||||
// ============================================================================
|
||||
|
||||
reg clk_r;
|
||||
always @(posedge CLK)
|
||||
if (RST) clk_r <= 1'b0;
|
||||
else clk_r <= !clk_r;
|
||||
|
||||
wire CLK1 = CLK;
|
||||
wire CLK2 = clk_r;
|
||||
|
||||
// ============================================================================
|
||||
wire s_dat;
|
||||
|
||||
oserdes_test #
|
||||
(
|
||||
.DATA_WIDTH (8),
|
||||
.DATA_RATE ("SDR"),
|
||||
.ERROR_HOLD (4)
|
||||
)
|
||||
trx_path
|
||||
(
|
||||
.CLK (CLK),
|
||||
.CLK1 (CLK1),
|
||||
.CLK2 (CLK2),
|
||||
.RST (RST),
|
||||
|
||||
.IO_DAT (s_dat)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// This module compares two bitstreams and automatically determines their
|
||||
// offset. This is done by iteratively changing bit delay for I_DAT_REF
|
||||
// every time the number of errors exceeds ERROR_COUNT. The output O_ERROR
|
||||
// signal is high for at least ERROR_HOLD cycles.
|
||||
|
||||
`default_nettype none
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module comparator #
|
||||
(
|
||||
parameter ERROR_COUNT = 8,
|
||||
parameter ERROR_HOLD = 2500000
|
||||
)
|
||||
(
|
||||
input wire CLK,
|
||||
input wire RST,
|
||||
|
||||
input wire I_DAT_REF,
|
||||
input wire I_DAT_IOB,
|
||||
|
||||
output wire O_ERROR
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Data latch
|
||||
reg [2:0] i_dat_ref_sr;
|
||||
reg [2:0] i_dat_iob_sr;
|
||||
|
||||
always @(posedge CLK)
|
||||
i_dat_ref_sr <= (i_dat_ref_sr << 1) | I_DAT_REF;
|
||||
always @(posedge CLK)
|
||||
i_dat_iob_sr <= (i_dat_iob_sr << 1) | I_DAT_IOB;
|
||||
|
||||
wire i_dat_ref = i_dat_ref_sr[2];
|
||||
wire i_dat_iob = i_dat_iob_sr[2];
|
||||
|
||||
// ============================================================================
|
||||
// Shift register for reference data, shift strobe generator.
|
||||
reg [31:0] sreg;
|
||||
reg [ 4:0] sreg_sel;
|
||||
wire sreg_dat;
|
||||
reg sreg_sh;
|
||||
|
||||
always @(posedge CLK)
|
||||
sreg <= (sreg << 1) | i_dat_ref;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
sreg_sel <= 0;
|
||||
else if(sreg_sh)
|
||||
sreg_sel <= sreg_sel + 1;
|
||||
|
||||
assign sreg_dat = sreg[sreg_sel];
|
||||
|
||||
// ============================================================================
|
||||
// Comparator and error counter
|
||||
wire cmp_err;
|
||||
reg [31:0] err_cnt;
|
||||
|
||||
assign cmp_err = sreg_dat ^ i_dat_iob;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
err_cnt <= 0;
|
||||
else if(sreg_sh)
|
||||
err_cnt <= 0;
|
||||
else if(cmp_err)
|
||||
err_cnt <= err_cnt + 1;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
sreg_sh <= 0;
|
||||
else if(~sreg_sh && (err_cnt == ERROR_COUNT))
|
||||
sreg_sh <= 1;
|
||||
else
|
||||
sreg_sh <= 0;
|
||||
|
||||
// ============================================================================
|
||||
// Output generator
|
||||
reg [24:0] o_cnt;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
o_cnt <= -1;
|
||||
else if (cmp_err)
|
||||
o_cnt <= ERROR_HOLD - 2;
|
||||
else if (~o_cnt[24])
|
||||
o_cnt <= o_cnt - 1;
|
||||
|
||||
assign O_ERROR = !o_cnt[24];
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
`default_nettype none
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module lfsr #
|
||||
(
|
||||
parameter WIDTH = 16, // LFSR width
|
||||
parameter [WIDTH-1:0] POLY = 16'hD008, // Polynomial
|
||||
parameter [WIDTH-1:0] SEED = 1 // Initial value
|
||||
)
|
||||
(
|
||||
input wire CLK,
|
||||
input wire CE,
|
||||
input wire RST,
|
||||
|
||||
output reg [WIDTH-1:0] O
|
||||
);
|
||||
|
||||
wire feedback = ^(O & POLY);
|
||||
|
||||
always @(posedge CLK) begin
|
||||
if(RST) begin
|
||||
O <= SEED;
|
||||
end else if(CE) begin
|
||||
O <= {O[WIDTH-2:0], feedback};
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
`default_nettype none
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module oserdes_test #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter DATA_RATE = "SDR",
|
||||
parameter ERROR_HOLD = 2500000
|
||||
)
|
||||
(
|
||||
// "Hi speed" clock and reset
|
||||
input wire CLK,
|
||||
input wire RST,
|
||||
|
||||
// OSERDES clocks
|
||||
input wire CLK1,
|
||||
input wire CLK2,
|
||||
|
||||
// Data pin
|
||||
inout wire IO_DAT,
|
||||
|
||||
// Error indicator
|
||||
output wire O_ERROR
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Generate CLK2 and CLKDIV for OSERDES using BUFRs
|
||||
|
||||
localparam CLKDIV_DIVIDE =
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 2) ? "2" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 3) ? "3" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 4) ? "4" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 5) ? "5" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 6) ? "6" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 7) ? "7" :
|
||||
(DATA_RATE == "SDR" && DATA_WIDTH == 8) ? "8" :
|
||||
|
||||
(DATA_RATE == "DDR" && DATA_WIDTH == 4) ? "4" :
|
||||
(DATA_RATE == "DDR" && DATA_WIDTH == 6) ? "6" :
|
||||
(DATA_RATE == "DDR" && DATA_WIDTH == 8) ? "8" : "BYPASS";
|
||||
|
||||
wire CLKX;
|
||||
wire CLKDIV;
|
||||
|
||||
BUFIO io_buf (.I((DATA_RATE == "DDR") ? CLK2 : CLK1), .O(CLKX));
|
||||
|
||||
BUFR #
|
||||
(
|
||||
.BUFR_DIVIDE (CLKDIV_DIVIDE)
|
||||
)
|
||||
bufr_clkdiv
|
||||
(
|
||||
.I (CLK1),
|
||||
.O (CLKDIV),
|
||||
.CLR (RST),
|
||||
.CE (1'd1)
|
||||
);
|
||||
|
||||
// The clock enable signal for the "hi speed" clock domain.
|
||||
reg clkdiv_r;
|
||||
wire ce;
|
||||
|
||||
always @(posedge CLK)
|
||||
clkdiv_r <= CLKDIV;
|
||||
|
||||
assign ce = clkdiv_r && !CLKDIV;
|
||||
|
||||
// ============================================================================
|
||||
// Data source
|
||||
reg lfsr_stb;
|
||||
wire [7:0] lfsr_dat;
|
||||
|
||||
lfsr lfsr
|
||||
(
|
||||
.CLK (CLK),
|
||||
.RST (RST),
|
||||
.CE (ce),
|
||||
|
||||
.O (lfsr_dat)
|
||||
);
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
lfsr_stb <= 1'b0;
|
||||
else
|
||||
lfsr_stb <= ce;
|
||||
|
||||
// Synchronize generated data wordst to the CLKDIV
|
||||
reg [7:0] ser_dat;
|
||||
|
||||
always @(posedge CLKDIV)
|
||||
ser_dat <= lfsr_dat;
|
||||
|
||||
// ============================================================================
|
||||
// OSERDES
|
||||
|
||||
// OSERDES reset generator (required for it to work properly!)
|
||||
reg [3:0] ser_rst_sr;
|
||||
initial ser_rst_sr <= 4'hF;
|
||||
|
||||
always @(posedge CLKDIV or posedge RST)
|
||||
if (RST) ser_rst_sr <= 4'hF;
|
||||
else ser_rst_sr <= ser_rst_sr >> 1;
|
||||
|
||||
wire ser_rst = ser_rst_sr[0];
|
||||
|
||||
// OSERDES
|
||||
wire ser_oq;
|
||||
wire ser_tq;
|
||||
|
||||
OSERDESE2 #
|
||||
(
|
||||
.DATA_RATE_OQ (DATA_RATE),
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
.DATA_RATE_TQ ((DATA_RATE == "DDR" && DATA_WIDTH == 4) ? "DDR" : "SDR"),
|
||||
.TRISTATE_WIDTH ((DATA_RATE == "DDR" && DATA_WIDTH == 4) ? 4 : 1)
|
||||
)
|
||||
oserdes
|
||||
(
|
||||
.CLK (CLKX),
|
||||
.CLKDIV (CLKDIV),
|
||||
.RST (ser_rst),
|
||||
|
||||
.OCE (1'b1),
|
||||
.D1 (ser_dat[0]),
|
||||
.D2 (ser_dat[1]),
|
||||
.D3 (ser_dat[2]),
|
||||
.D4 (ser_dat[3]),
|
||||
.D5 (ser_dat[4]),
|
||||
.D6 (ser_dat[5]),
|
||||
.D7 (ser_dat[6]),
|
||||
.D8 (ser_dat[7]),
|
||||
.OQ (ser_oq),
|
||||
|
||||
.TCE (1'b1),
|
||||
.T1 (1'b0), // All 0 to keep OBUFT always on.
|
||||
.T2 (1'b0),
|
||||
.T3 (1'b0),
|
||||
.T4 (1'b0),
|
||||
.TQ (ser_tq)
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// IOB
|
||||
wire iob_i;
|
||||
|
||||
OBUFT obuf
|
||||
(
|
||||
.I (ser_oq),
|
||||
.T (ser_tq),
|
||||
.O (IO_DAT)
|
||||
);
|
||||
|
||||
IBUF ibuf
|
||||
(
|
||||
.I (IO_DAT),
|
||||
.O (iob_i)
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Reference data serializer
|
||||
reg [7:0] ref_sr;
|
||||
wire ref_o;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (RST)
|
||||
ref_sr <= 0;
|
||||
else if (ce)
|
||||
ref_sr <= lfsr_dat;
|
||||
else
|
||||
ref_sr <= ref_sr >> 1;
|
||||
|
||||
assign ref_o = ref_sr[0];
|
||||
|
||||
// ============================================================================
|
||||
// Data comparator
|
||||
|
||||
comparator #
|
||||
(
|
||||
.ERROR_COUNT (16),
|
||||
.ERROR_HOLD (ERROR_HOLD)
|
||||
)
|
||||
comparator
|
||||
(
|
||||
.CLK (CLK),
|
||||
.RST (RST),
|
||||
|
||||
.I_DAT_REF (ref_o),
|
||||
.I_DAT_IOB (iob_i),
|
||||
|
||||
.O_ERROR (O_ERROR)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
create_project -force -name $env(PROJECT_NAME) -part xc7a35tcpg236-1
|
||||
|
||||
read_edif ../$env(PROJECT_NAME).edif
|
||||
|
||||
link_design -part xc7a35tcpg236-1
|
||||
source ../basys3.xdc
|
||||
|
||||
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]
|
||||
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
|
||||
set_property SEVERITY {Warning} [get_drc_checks REQP-1936]
|
||||
|
||||
place_design
|
||||
route_design
|
||||
|
||||
write_checkpoint -force ../$env(PROJECT_NAME).dcp
|
||||
|
||||
write_bitstream -force ../$env(PROJECT_NAME).bit
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
create_project -force -name $env(PROJECT_NAME) -part xc7a35tcpg236-1
|
||||
|
||||
read_verilog ../$env(PROJECT_NAME).v
|
||||
|
||||
synth_design -top top
|
||||
|
||||
report_timing_summary -file top_timing_synth.rpt
|
||||
report_utilization -hierarchical -file top_utilization_hierarchical_synth.rpt
|
||||
report_utilization -file top_utilization_synth.rpt
|
||||
|
||||
write_edif -force ../$env(PROJECT_NAME).edif
|
||||
Loading…
Reference in New Issue