From b878a2e651dc97be1e22439e8f052ad9c986c9e5 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 22 Aug 2019 13:03:03 +0200 Subject: [PATCH 1/4] A minitest for ISERDES in NETWORKING SDR/DDR modes. Signed-off-by: Maciej Kurc --- minitests/iserdes.sdr_ddr/Makefile | 38 +++ minitests/iserdes.sdr_ddr/README.md | 43 +++ minitests/iserdes.sdr_ddr/basys3.xdc | 72 +++++ minitests/iserdes.sdr_ddr/basys3_top.v | 266 ++++++++++++++++++ minitests/iserdes.sdr_ddr/par.tcl | 36 +++ minitests/iserdes.sdr_ddr/sim/full_path.v | 62 ++++ minitests/iserdes.sdr_ddr/sim/run_icarus.sh | 26 ++ minitests/iserdes.sdr_ddr/sim/run_vivado.sh | 18 ++ minitests/iserdes.sdr_ddr/sim/sim.tcl | 21 ++ .../iserdes.sdr_ddr/sim/sources.cf.template | 3 + .../iserdes.sdr_ddr/sim/transmitter_tb.v | 63 +++++ minitests/iserdes.sdr_ddr/src/comparator.v | 116 ++++++++ minitests/iserdes.sdr_ddr/src/gen_rom.py | 66 +++++ minitests/iserdes.sdr_ddr/src/receiver.v | 156 ++++++++++ minitests/iserdes.sdr_ddr/src/rom.v | 69 +++++ minitests/iserdes.sdr_ddr/src/serializer.v | 82 ++++++ minitests/iserdes.sdr_ddr/src/transmitter.v | 82 ++++++ minitests/iserdes.sdr_ddr/src/trx_path.v | 138 +++++++++ minitests/iserdes.sdr_ddr/syn.tcl | 11 + 19 files changed, 1368 insertions(+) create mode 100644 minitests/iserdes.sdr_ddr/Makefile create mode 100644 minitests/iserdes.sdr_ddr/README.md create mode 100644 minitests/iserdes.sdr_ddr/basys3.xdc create mode 100644 minitests/iserdes.sdr_ddr/basys3_top.v create mode 100644 minitests/iserdes.sdr_ddr/par.tcl create mode 100644 minitests/iserdes.sdr_ddr/sim/full_path.v create mode 100755 minitests/iserdes.sdr_ddr/sim/run_icarus.sh create mode 100755 minitests/iserdes.sdr_ddr/sim/run_vivado.sh create mode 100644 minitests/iserdes.sdr_ddr/sim/sim.tcl create mode 100644 minitests/iserdes.sdr_ddr/sim/sources.cf.template create mode 100644 minitests/iserdes.sdr_ddr/sim/transmitter_tb.v create mode 100644 minitests/iserdes.sdr_ddr/src/comparator.v create mode 100755 minitests/iserdes.sdr_ddr/src/gen_rom.py create mode 100644 minitests/iserdes.sdr_ddr/src/receiver.v create mode 100644 minitests/iserdes.sdr_ddr/src/rom.v create mode 100644 minitests/iserdes.sdr_ddr/src/serializer.v create mode 100644 minitests/iserdes.sdr_ddr/src/transmitter.v create mode 100644 minitests/iserdes.sdr_ddr/src/trx_path.v create mode 100644 minitests/iserdes.sdr_ddr/syn.tcl diff --git a/minitests/iserdes.sdr_ddr/Makefile b/minitests/iserdes.sdr_ddr/Makefile new file mode 100644 index 00000000..933f190d --- /dev/null +++ b/minitests/iserdes.sdr_ddr/Makefile @@ -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=]" + +.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 + mkdir -p build-syn.$(basename $@) + cd build-syn.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../syn.tcl -nojournal -log ../$@.log + rm -rf *.backup.log + +endif + +%.bit: %.edif par.tcl + mkdir -p build-par.$(basename $@) + cd build-par.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../par.tcl -nojournal -log ../$@.log + rm -rf *.backup.log + diff --git a/minitests/iserdes.sdr_ddr/README.md b/minitests/iserdes.sdr_ddr/README.md new file mode 100644 index 00000000..55e4d9db --- /dev/null +++ b/minitests/iserdes.sdr_ddr/README.md @@ -0,0 +1,43 @@ +# ISERDES minitest for SDR and DDR + +This test allows to verify that ISEDRES is working on hardware. Tested modes are: +- NETWORKING / SDR +- NETWORKING / DDR + +No chaining of two ISERDES bels. + +The design uses JA, JB and JC connectors of the Basys 3 boards to output +serialized data and then receive it using ISERDESes. There is a need to +provide physical loopbacks of pins of those connectors. The clock is being +routed internally. + +The received data is compared against transmitted internally. Errors are +indicated using LEDs. + +The pinout (out, in): +- JB.1, JB.7 - SDR, WIDTH=2 +- JB.2, JB.8 - SDR, WIDTH=3 +- JB.3, JB.9 - SDR, WIDTH=4 +- JB.4, JB.10 - SDR, WIDTH=5 +- JC.1, JC.7 - SDR, WIDTH=6 +- JC.2, JC.8 - SDR, WIDTH=7 +- JC.3, JC.9 - SDR, WIDTH=8 +- JC.4, JC.10 - DDR, WIDTH=4 +- JA.4, JA.10 - DDR, WIDTH=6 +- JA.3, JA.9 - DDR, WIDTH=8 +- JA.2 - Serialized data clock +- JA.1 - Serialized data clock x2 + +LEDs indicate whether data is being received corectly. When a LED is lit then +there is correct reception: +- LED0 - SDR, WIDTH=2 +- LED1 - SDR, WIDTH=3 +- LED2 - SDR, WIDTH=4 +- LED3 - SDR, WIDTH=5 +- LED4 - SDR, WIDTH=6 +- LED5 - SDR, WIDTH=7 +- LED6 - SDR, WIDTH=8 +- LED7 - DDR, WIDTH=4 +- LED8 - DDR, WIDTH=5 +- LED9 - DDR, WIDTH=6 +- LED10 - Blinking diff --git a/minitests/iserdes.sdr_ddr/basys3.xdc b/minitests/iserdes.sdr_ddr/basys3.xdc new file mode 100644 index 00000000..61606f17 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/basys3.xdc @@ -0,0 +1,72 @@ +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]] + +set_property PACKAGE_PIN J1 [get_ports ja1] +set_property PACKAGE_PIN L2 [get_ports ja2] +set_property PACKAGE_PIN J2 [get_ports ja3] +set_property PACKAGE_PIN G2 [get_ports ja4] +set_property PACKAGE_PIN H1 [get_ports ja7] +set_property PACKAGE_PIN K2 [get_ports ja8] +set_property PACKAGE_PIN H2 [get_ports ja9] +set_property PACKAGE_PIN G3 [get_ports ja10] + +set_property PACKAGE_PIN A14 [get_ports jb1] +set_property PACKAGE_PIN A16 [get_ports jb2] +set_property PACKAGE_PIN B15 [get_ports jb3] +set_property PACKAGE_PIN B16 [get_ports jb4] +set_property PACKAGE_PIN A15 [get_ports jb7] +set_property PACKAGE_PIN A17 [get_ports jb8] +set_property PACKAGE_PIN C15 [get_ports jb9] +set_property PACKAGE_PIN C16 [get_ports jb10] + +set_property PACKAGE_PIN K17 [get_ports jc1] +set_property PACKAGE_PIN M18 [get_ports jc2] +set_property PACKAGE_PIN N17 [get_ports jc3] +set_property PACKAGE_PIN P18 [get_ports jc4] +set_property PACKAGE_PIN L17 [get_ports jc7] +set_property PACKAGE_PIN M19 [get_ports jc8] +set_property PACKAGE_PIN P17 [get_ports jc9] +set_property PACKAGE_PIN R18 [get_ports jc10] + +foreach port [get_ports] { + set_property IOSTANDARD LVCMOS33 $port + set_property SLEW FAST $port +} diff --git a/minitests/iserdes.sdr_ddr/basys3_top.v b/minitests/iserdes.sdr_ddr/basys3_top.v new file mode 100644 index 00000000..2738cb6c --- /dev/null +++ b/minitests/iserdes.sdr_ddr/basys3_top.v @@ -0,0 +1,266 @@ +`include "src/rom.v" +`include "src/serializer.v" +`include "src/transmitter.v" +`include "src/receiver.v" +`include "src/comparator.v" +`include "src/trx_path.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, + +output wire ja1, +output wire ja2, +output wire ja3, +output wire ja4, +input wire ja7, +input wire ja8, +input wire ja9, +input wire ja10, + +output wire jb1, +output wire jb2, +output wire jb3, +output wire jb4, +input wire jb7, +input wire jb8, +input wire jb9, +input wire jb10, + +output wire jc1, +output wire jc2, +output wire jc3, +output wire jc4, +input wire jc7, +input wire jc8, +input wire jc9, +input wire jc10 +); + +// ============================================================================ +// Clock & reset +// Divide the input clock to allow for less strict timing requirements. +reg [3:0] rst_sr; +reg [7:0] clk_ps; + +initial rst_sr <= 4'hF; +initial clk_ps <= 0; + +always @(posedge clk) + if (sw[0]) + rst_sr <= 4'hF; + else + rst_sr <= rst_sr >> 1; + +always @(posedge clk) + clk_ps <= clk_ps + 1; + +wire CLK100 = clk; +wire CLK = clk_ps[2]; +wire RST = rst_sr[0]; + +// ============================================================================ +// ISERDES test logic +wire [9:0] error; +wire [9:0] data; + +wire s_clk; + +// ........ + +trx_path # +( +.WIDTH (2), +.MODE ("SDR") +) +path_sdr_2 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[0]), +.O_CLK (s_clk), +.I_DAT (jb7), +.ERROR (error[0]) +); + +trx_path # +( +.WIDTH (3), +.MODE ("SDR") +) +path_sdr_3 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[1]), +.I_DAT (jb8), +.ERROR (error[1]) +); + +trx_path # +( +.WIDTH (4), +.MODE ("SDR") +) +path_sdr_4 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[2]), +.I_DAT (jb9), +.ERROR (error[2]) +); + +trx_path # +( +.WIDTH (5), +.MODE ("SDR") +) +path_sdr_5 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[3]), +.I_DAT (jb10), +.ERROR (error[3]) +); + +// ........ + +trx_path # +( +.WIDTH (6), +.MODE ("SDR") +) +path_sdr_6 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[4]), +.I_DAT (jc7), +.ERROR (error[4]) +); + +trx_path # +( +.WIDTH (7), +.MODE ("SDR") +) +path_sdr_7 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[5]), +.I_DAT (jc8), +.ERROR (error[5]) +); + +trx_path # +( +.WIDTH (8), +.MODE ("SDR") +) +path_sdr_8 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[6]), +.I_DAT (jc9), +.ERROR (error[6]) +); + +trx_path # +( +.WIDTH (4), +.MODE ("DDR") +) +path_ddr_4 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[7]), +.I_DAT (jc10), +.ERROR (error[7]) +); + +// ........ + +trx_path # +( +.WIDTH (6), +.MODE ("DDR") +) +path_ddr_6 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[8]), +.I_DAT (ja10), +.ERROR (error[8]) +); + +trx_path # +( +.WIDTH (8), +.MODE ("DDR") +) +path_ddr_8 +( +.CLK (CLK), +.RST (RST), +.O_DAT (data[9]), +.I_DAT (ja9), +.ERROR (error[9]) +); + +// ============================================================================ +// Delay data by 1 cycle of the 100MHz clock to avoid race condition betweeen +// serialized clock and data edges. We are not using IDELAY to compensate for +// that in this design. In other words the data is delayed at the transmitter +// side. + +reg [9:0] data_dly; + +always @(posedge CLK100) + data_dly <= data; + +// ============================================================================ +// I/O connections + +reg [23:0] heartbeat_cnt; + +always @(posedge CLK100) + heartbeat_cnt <= heartbeat_cnt + 1; + + +assign led[9: 0] = (RST) ? 9'd0 : ~error; +assign led[ 10] = heartbeat_cnt[22]; +assign led[15:11] = 0; + +assign jb1 = data_dly[0]; +assign jb2 = data_dly[1]; +assign jb3 = data_dly[2]; +assign jb4 = data_dly[3]; + +assign jc1 = data_dly[4]; +assign jc2 = data_dly[5]; +assign jc3 = data_dly[6]; +assign jc4 = data_dly[7]; + +assign ja4 = data_dly[8]; +assign ja3 = data_dly[9]; + +assign ja1 = CLK; +assign ja2 = s_clk; + +endmodule diff --git a/minitests/iserdes.sdr_ddr/par.tcl b/minitests/iserdes.sdr_ddr/par.tcl new file mode 100644 index 00000000..e198dd57 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/par.tcl @@ -0,0 +1,36 @@ +create_project -force -name $env(PROJECT_NAME) -part xc7a35tcpg236-1 + +read_edif ../$env(PROJECT_NAME).edif + +link_design -part xc7a35tcpg236-1 +source ../basys3.xdc + +report_timing_summary -file top_timing_synth.rpt +report_utilization -hierarchical -file top_utilization_hierarchical_synth.rpt +report_utilization -file top_utilization_synth.rpt + +opt_design +place_design + +report_utilization -hierarchical -file top_utilization_hierarchical_place.rpt +report_utilization -file top_utilization_place.rpt +report_io -file top_io.rpt +report_control_sets -verbose -file top_control_sets.rpt +report_clock_utilization -file top_clock_utilization.rpt + +route_design +#phys_opt_design + +report_timing_summary -no_header -no_detailed_paths + +write_checkpoint -force ../$env(PROJECT_NAME).dcp + +set_property SEVERITY {Warning} [get_drc_checks UCIO-1] +set_property SEVERITY {Warning} [get_drc_checks NSTD-1] + +report_route_status -file top_route_status.rpt +report_drc -file top_drc.rpt +report_timing_summary -datasheet -max_paths 10 -file top_timing.rpt +report_power -file top_power.rpt + +write_bitstream -force ../$env(PROJECT_NAME).bit diff --git a/minitests/iserdes.sdr_ddr/sim/full_path.v b/minitests/iserdes.sdr_ddr/sim/full_path.v new file mode 100644 index 00000000..1a93d0d4 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/full_path.v @@ -0,0 +1,62 @@ +`include "../src/rom.v" +`include "../src/serializer.v" +`include "../src/transmitter.v" +`include "../src/receiver.v" +`include "../src/comparator.v" +`include "../src/trx_path.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; + +// ============================================================================ +wire s_dat; + +trx_path # +( +.WIDTH (8), +.MODE ("SDR") +) +trx_path +( +.CLK (CLK), +.RST (RST), + +.O_DAT (s_dat), +.I_DAT (s_dat) +); + +endmodule + diff --git a/minitests/iserdes.sdr_ddr/sim/run_icarus.sh b/minitests/iserdes.sdr_ddr/sim/run_icarus.sh new file mode 100755 index 00000000..ee54b06d --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/run_icarus.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +# Check args +if [ "$#" -ne 1 ]; then + echo "Usage: run_vivado.sh " + exit -1 +fi + +# Check if testbench exists +if [ ! -f $1 ]; then + echo "Testbench $1 not found!" + exit -1 +fi + +# Create sources file +cp sources.cf.template sources.cf +echo $1 >> sources.cf + +# Compile +iverilog -v -c sources.cf -g2005 -s tb -o testbench.vvp + +# Run +vvp -v testbench.vvp + diff --git a/minitests/iserdes.sdr_ddr/sim/run_vivado.sh b/minitests/iserdes.sdr_ddr/sim/run_vivado.sh new file mode 100755 index 00000000..9f56cfb0 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/run_vivado.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +# Check args +if [ "$#" -ne 1 ]; then + echo "Usage: run_vivado.sh " + 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 diff --git a/minitests/iserdes.sdr_ddr/sim/sim.tcl b/minitests/iserdes.sdr_ddr/sim/sim.tcl new file mode 100644 index 00000000..a6af032b --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/sim.tcl @@ -0,0 +1,21 @@ +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 + diff --git a/minitests/iserdes.sdr_ddr/sim/sources.cf.template b/minitests/iserdes.sdr_ddr/sim/sources.cf.template new file mode 100644 index 00000000..aaebd21b --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/sources.cf.template @@ -0,0 +1,3 @@ +../src/rom.v +../src/serializer.v +../src/transmitter.v diff --git a/minitests/iserdes.sdr_ddr/sim/transmitter_tb.v b/minitests/iserdes.sdr_ddr/sim/transmitter_tb.v new file mode 100644 index 00000000..fbde9a5d --- /dev/null +++ b/minitests/iserdes.sdr_ddr/sim/transmitter_tb.v @@ -0,0 +1,63 @@ +`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 >= 100) + $finish; + +// ============================================================================ +wire o_stb; +wire [7:0] o_dat; + +wire s_clk; +wire s_ce; +wire s_dat; + +transmitter # +( +.WIDTH (8), +.MODE ("SDR") +) +transmitter +( +.CLK (CLK), +.RST (RST), + +.O_STB (o_stb), +.O_DAT (o_dat), + +.S_CLK (s_clk), +.S_CE (s_ce), +.S_DAT (s_dat) +); + +endmodule diff --git a/minitests/iserdes.sdr_ddr/src/comparator.v b/minitests/iserdes.sdr_ddr/src/comparator.v new file mode 100644 index 00000000..8e7be49f --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/comparator.v @@ -0,0 +1,116 @@ +`default_nettype none + +// ============================================================================ + +module comparator # +( +parameter WIDTH = 8, +parameter ERROR_COUNT = 8, +parameter ERROR_HOLD = 2500000 +) +( +// Clock and reset +input wire CLK, +input wire RST, + +// Transmitted data input port +input wire TX_STB, +input wire [WIDTH-1:0] TX_DAT, + +// Received data input port + bitslip +input wire RX_STB, +input wire [WIDTH-1:0] RX_DAT, +output wire RX_BITSLIP, + +// Error indicator +output wire O_ERROR +); + +// ============================================================================ +// Data latch and comparator +reg [WIDTH-1:0] tx_dat; +reg tx_valid; + +reg [WIDTH-1:0] rx_dat; +reg rx_valid; + +wire i_rdy = rx_valid && rx_valid; + +always @(posedge CLK) + if (!tx_valid && TX_STB) + tx_dat <= TX_DAT; + +always @(posedge CLK) + if (RST) + tx_valid <= 1'b0; + else if (i_rdy) + tx_valid <= 1'b0; + else if (TX_STB) + tx_valid <= 1'b1; + +always @(posedge CLK) + if (!rx_valid && RX_STB) + rx_dat <= RX_DAT; + +always @(posedge CLK) + if (RST) + rx_valid <= 1'b0; + else if (i_rdy) + rx_valid <= 1'b0; + else if (RX_STB) + rx_valid <= 1'b1; + + +reg x_stb; +reg x_error; + +always @(posedge CLK) + if (RST) + x_stb <= 1'b0; + else if(!x_stb && i_rdy) + x_stb <= 1'b1; + else if( x_stb) + x_stb <= 1'b0; + +always @(posedge CLK) + if (i_rdy) + x_error <= (rx_dat != tx_dat); + +// ============================================================================ +// Error counter and bitslip generator +reg [31:0] count_err; +reg o_bitslip; + +always @(posedge CLK) + if (RST) + count_err <= 0; + else if (x_stb && x_error) + count_err <= count_err + 1; + else if (o_bitslip) + count_err <= 0; + +always @(posedge CLK) + if (RST) + o_bitslip <= 1'b0; + else if (!o_bitslip && (count_err >= ERROR_COUNT)) + o_bitslip <= 1'b1; + else if ( o_bitslip) + o_bitslip <= 1'b0; + +assign RX_BITSLIP = o_bitslip; + +// ============================================================================ +// Error output +reg [32:0] o_cnt; + +always @(posedge CLK) + if (RST) + o_cnt <= 0; + else if (x_stb && x_error) + o_cnt <= ERROR_HOLD; + else + o_cnt <= (o_cnt[32]) ? o_cnt : (o_cnt - 1); + +assign O_ERROR = !o_cnt[32]; + +endmodule diff --git a/minitests/iserdes.sdr_ddr/src/gen_rom.py b/minitests/iserdes.sdr_ddr/src/gen_rom.py new file mode 100755 index 00000000..d3849c70 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/gen_rom.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +import random + +def main(): + + template = """ +`default_nettype none + +// ============================================================================ + +module rom +( +input wire CLK, +input wire RST, + +input wire RD, +output wire [{rom_width_minus_one}:0] O +); + +// ============================================================================ + +reg [{rom_width_minus_one}:0] rom[0:{rom_size_minus_one}]; + +initial begin +{rom_data} +end + +reg [{rom_width_minus_one}:0] dat; +reg [{rom_size_bits_minus_one}:0] adr; + +always @(posedge CLK) + if (RST) adr <= 0; + else if (RD) adr <= adr + 1; + +always @(posedge CLK) + if (RD) dat <= rom[adr]; + +assign O = dat; + +// ============================================================================ + +endmodule +""" + + rom_size_bits = 5 + rom_size = 2 ** rom_size_bits + rom_width = 8 + + rom_data = [random.randint(0, 2 ** rom_width - 1) for i in range(rom_size)] + +# rom_data = [] +# for i in range(rom_size // 2): +# rom_data.extend([0x00, 0xFF]) + + rom_data = "\n".join([" rom[%4d] <= %d'd%d;" % (i, rom_width, d) for i, d in enumerate(rom_data)]) + + print(template.format( + rom_size_bits_minus_one=rom_size_bits - 1, + rom_size_minus_one=rom_size - 1, + rom_width_minus_one=rom_width - 1, + rom_data=rom_data + )) + +if __name__ == "__main__": + main() + diff --git a/minitests/iserdes.sdr_ddr/src/receiver.v b/minitests/iserdes.sdr_ddr/src/receiver.v new file mode 100644 index 00000000..4be96172 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/receiver.v @@ -0,0 +1,156 @@ +`default_nettype none + +// ============================================================================ + +module receiver # +( +parameter WIDTH = 8, +parameter MODE = "SDR" +) +( +input wire CLK, +input wire RST, + +input wire I_CLK, +input wire I_DAT, + +output wire O_STB, +output wire [WIDTH-1:0] O_DAT, +input wire O_BITSLIP +); + +// ============================================================================ +// CLKDIV generation using a BUFR +wire i_clkdiv; +wire i_rstdiv; + +// Divider for BUFR +localparam DIVIDE = (MODE == "SDR" && WIDTH == 2) ? "2" : + (MODE == "SDR" && WIDTH == 3) ? "3" : + (MODE == "SDR" && WIDTH == 4) ? "4" : + (MODE == "SDR" && WIDTH == 5) ? "5" : + (MODE == "SDR" && WIDTH == 6) ? "6" : + (MODE == "SDR" && WIDTH == 7) ? "7" : + (MODE == "SDR" && WIDTH == 8) ? "8" : + + (MODE == "DDR" && WIDTH == 4) ? "2" : + (MODE == "DDR" && WIDTH == 6) ? "3" : + (MODE == "DDR" && WIDTH == 8) ? "4" : "BYPASS"; +// BUFR +BUFR # +( +.BUFR_DIVIDE (DIVIDE) +) +bufr_div +( +.I (I_CLK), +.O (i_clkdiv), +.CLR (1'b0), +.CE (1'b1) +); + +// ISERDES reset generator +reg [3:0] rst_sr; +initial rst_sr <= 4'hF; + +always @(posedge i_clkdiv) + if (RST) rst_sr <= 4'hF; + else rst_sr <= rst_sr >> 1; + +assign i_rstdiv = rst_sr[0]; + +// ============================================================================ +// ISERDES +wire [7:0] d_dat; + +(* KEEP, DONT_TOUCH *) +ISERDESE2 # +( +.DATA_RATE (MODE), +.DATA_WIDTH (WIDTH), +.INTERFACE_TYPE ("NETWORKING"), +.IS_CLKB_INVERTED (1'b1) // Do we have bits for that ?? +) +iserdes +( +.CLK (I_CLK), +.CLKB (I_CLK), +.CLKDIV (i_clkdiv), +.CE1 (1'b1), +.CE2 (1'b1), +.RST (i_rstdiv), +.BITSLIP (bitslip), + +.D (I_DAT), +.Q1 (d_dat[0]), +.Q2 (d_dat[1]), +.Q3 (d_dat[2]), +.Q4 (d_dat[3]), +.Q5 (d_dat[4]), +.Q6 (d_dat[5]), +.Q7 (d_dat[6]), +.Q8 (d_dat[7]) +); + +// ============================================================================ +// Generate strobe synchronous to CLK +reg clk_p; +reg tick; + +always @(posedge CLK) + clk_p <= i_clkdiv; + +always @(posedge CLK) + if (RST) + tick <= 1'b0; + else + tick <= !clk_p && i_clkdiv; + +// ============================================================================ +// Bitslip. The bitslip signal should be synchronous to the CLKDIV. Here it is +// asserted for as long as the CLKDIV period but it is not synchronous to it. +reg bitslip_req; +reg bitslip; + +always @(posedge CLK) + if (RST) + bitslip_req <= 1'b0; + else if (!bitslip_req && O_BITSLIP) + bitslip_req <= 1'b1; + else if (tick) + bitslip_req <= 1'b0; + +always @(posedge CLK) + if (RST) + bitslip <= 1'd0; + else if (tick) + bitslip <= bitslip_req; + +// ============================================================================ +// Output sync to CLK +reg x_stb; +reg o_stb; +reg [WIDTH-1:0] o_dat; + +always @(posedge CLK) + if (RST) + x_stb <= 1'b0; + else if(!x_stb && tick) + x_stb <= 1'b1; + else if( x_stb) + x_stb <= 1'b0; + +always @(posedge CLK) + if (RST) + o_stb <= 1'd0; + else + o_stb <= x_stb; + +always @(posedge CLK) + if (x_stb) + o_dat <= d_dat; + +assign O_STB = o_stb; +assign O_DAT = o_dat[WIDTH-1:0]; + +endmodule diff --git a/minitests/iserdes.sdr_ddr/src/rom.v b/minitests/iserdes.sdr_ddr/src/rom.v new file mode 100644 index 00000000..05b93df6 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/rom.v @@ -0,0 +1,69 @@ + +`default_nettype none + +// ============================================================================ + +module rom +( +input wire CLK, +input wire RST, + +input wire RD, +output wire [7:0] O +); + +// ============================================================================ + +reg [7:0] rom[0:31]; + +initial begin + rom[ 0] <= 8'd157; + rom[ 1] <= 8'd254; + rom[ 2] <= 8'd208; + rom[ 3] <= 8'd125; + rom[ 4] <= 8'd39; + rom[ 5] <= 8'd192; + rom[ 6] <= 8'd242; + rom[ 7] <= 8'd117; + rom[ 8] <= 8'd186; + rom[ 9] <= 8'd94; + rom[ 10] <= 8'd201; + rom[ 11] <= 8'd156; + rom[ 12] <= 8'd224; + rom[ 13] <= 8'd120; + rom[ 14] <= 8'd255; + rom[ 15] <= 8'd219; + rom[ 16] <= 8'd12; + rom[ 17] <= 8'd53; + rom[ 18] <= 8'd156; + rom[ 19] <= 8'd93; + rom[ 20] <= 8'd97; + rom[ 21] <= 8'd47; + rom[ 22] <= 8'd9; + rom[ 23] <= 8'd184; + rom[ 24] <= 8'd68; + rom[ 25] <= 8'd235; + rom[ 26] <= 8'd67; + rom[ 27] <= 8'd68; + rom[ 28] <= 8'd216; + rom[ 29] <= 8'd26; + rom[ 30] <= 8'd16; + rom[ 31] <= 8'd93; +end + +reg [7:0] dat; +reg [4:0] adr; + +always @(posedge CLK) + if (RST) adr <= 0; + else if (RD) adr <= adr + 1; + +always @(posedge CLK) + if (RD) dat <= rom[adr]; + +assign O = dat; + +// ============================================================================ + +endmodule + diff --git a/minitests/iserdes.sdr_ddr/src/serializer.v b/minitests/iserdes.sdr_ddr/src/serializer.v new file mode 100644 index 00000000..fd698a54 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/serializer.v @@ -0,0 +1,82 @@ +`default_nettype none + +// ============================================================================ + +module serializer # +( +parameter WIDTH = 4, // Serialization rate +parameter MODE = "SDR" // "SDR" or "DDR" +) +( +// Clock & reset +input wire CLK, +input wire RST, + +// Data input +input wire[WIDTH-1:0] I, +output wire RD, +output wire CE, + +// Serialized output +output wire O_CLK, +output wire O_DAT +); + +// ============================================================================ + +generate if (MODE == "DDR" && (WIDTH & 1)) begin + error for_DDR_mode_the_WIDTH_must_be_even (); +end endgenerate + +// ============================================================================ +// Output clock generation +reg o_clk; +wire ce; + +always @(posedge CLK) + if (RST) o_clk <= 1'd1; + else o_clk <= !o_clk; + +assign ce = !o_clk; + +// ============================================================================ +reg [7:0] count; +reg [WIDTH-1:0] sreg; +wire sreg_ld; + +always @(posedge CLK) + if (RST) count <= 2; + else if (ce) begin + if (count == 0) count <= ((MODE == "DDR") ? (WIDTH/2) : WIDTH) - 1; + else count <= count - 1; + end + +assign sreg_ld = (count == 0); + +always @(posedge CLK) + if (ce) begin + if (sreg_ld) sreg <= I; + else sreg <= sreg << ((MODE == "DDR") ? 2 : 1); + end + +wire [1:0] o_dat = sreg[WIDTH-1:WIDTH-2]; + +// ============================================================================ +// SDR/DDR output FFs +reg o_reg; + +always @(posedge CLK) + if (!o_clk && MODE == "SDR") o_reg <= o_dat[1]; // + + else if (!o_clk && MODE == "DDR") o_reg <= o_dat[0]; // + + else if ( o_clk && MODE == "DDR") o_reg <= o_dat[1]; // - + else o_reg <= o_reg; + +// ============================================================================ + +assign O_DAT = o_reg; +assign O_CLK = o_clk; + +assign RD = (count == 1); +assign CE = ce; + +endmodule diff --git a/minitests/iserdes.sdr_ddr/src/transmitter.v b/minitests/iserdes.sdr_ddr/src/transmitter.v new file mode 100644 index 00000000..1261c903 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/transmitter.v @@ -0,0 +1,82 @@ +`default_nettype none + +// ============================================================================ + +module transmitter # +( +parameter WIDTH = 8, +parameter MODE = "SDR" +) +( +// Input clock and reset +input wire CLK, +input wire RST, + +// Data for comparison +output wire O_STB, +output wire [WIDTH-1:0] O_DAT, + +// Serialized clock and data +output wire S_CLK, +output wire S_CE, +output wire S_DAT +); + +// ============================================================================ +// ROM +wire s_clk; +wire s_ce; +wire s_dat; + +wire [WIDTH-1:0] rom_dat; +wire rom_rd; + +rom rom +( +.CLK (CLK), +.RST (RST), + +.RD (rom_rd & s_ce), +.O (rom_dat) // Truncate bits if WIDTH < 8 here. +); + +// ============================================================================ +// Serializer + +serializer # +( +.WIDTH (WIDTH), +.MODE (MODE) +) +serializer +( +.CLK (CLK), +.RST (RST), + +.I (rom_dat), +.RD (rom_rd), +.CE (s_ce), + +.O_CLK (s_clk), +.O_DAT (s_dat) +); + +assign S_CLK = s_clk; +assign S_CE = s_ce; +assign S_DAT = s_dat; + +// ============================================================================ +// Parallel output (for later comparison) +reg o_stb; + +always @(posedge CLK) + if (RST) o_stb <= 1'b0; + else if (!o_stb && s_ce && rom_rd) o_stb <= 1'b1; + else if ( o_stb) o_stb <= 1'd0; + +assign O_STB = o_stb; +assign O_DAT = rom_dat; + +// ============================================================================ + +endmodule diff --git a/minitests/iserdes.sdr_ddr/src/trx_path.v b/minitests/iserdes.sdr_ddr/src/trx_path.v new file mode 100644 index 00000000..90e6ce90 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/src/trx_path.v @@ -0,0 +1,138 @@ +`default_nettype none + +// ============================================================================ + +module trx_path # +( +parameter WIDTH = 8, +parameter MODE = "SDR" +) +( +// Clock and reset +input wire CLK, +input wire RST, + +// Input and output pins +output wire O_CLK, +output wire O_DAT, +input wire I_DAT, + +// Error indicator +output wire ERROR +); + +// ============================================================================ + +wire tx_stb; +wire [WIDTH-1:0] tx_dat; + +wire rx_stb; +wire [WIDTH-1:0] rx_dat; +wire rx_bitslip; + +wire s_clk; + +// Transmitter +transmitter # +( +.WIDTH (WIDTH), +.MODE (MODE) +) +transmitter +( +.CLK (CLK), +.RST (RST), + +.O_STB (tx_stb), +.O_DAT (tx_dat), + +.S_CLK (s_clk), +.S_DAT (O_DAT) +); + +assign O_CLK = s_clk; + +// Receiver +receiver # +( +.WIDTH (WIDTH), +.MODE (MODE) +) +receiver +( +.CLK (CLK), +.RST (RST), + +.I_CLK (s_clk), +.I_DAT (I_DAT), + +.O_STB (rx_stb), +.O_DAT (rx_dat), +.O_BITSLIP (rx_bitslip) +); + +// The comparator module generates bitslip signal for the receiver. However +// the bitslip can shift only modulo WIDTH. Therefore additional delay is +// added which can delay the transmitted data that we compare to by a number +// of full words. + +// Count bitslip pulses to know how much to delay words +reg [3:0] rx_bitslip_cnt; +always @(posedge CLK) + if (RST) + rx_bitslip_cnt <= 0; + else if (rx_bitslip) begin + if (rx_bitslip_cnt == (2*WIDTH - 1)) + rx_bitslip_cnt <= 0; + else + rx_bitslip_cnt <= rx_bitslip_cnt + 1; + end + +// Word delay +reg [1:0] tx_dly_cnt; +reg [WIDTH-1:0] tx_dat_dly_a; +reg [WIDTH-1:0] tx_dat_dly_b; +reg [WIDTH-1:0] tx_dat_dly_c; +reg [WIDTH-1:0] tx_dat_dly_d; +wire [WIDTH-1:0] tx_dat_dly; + +always @(posedge CLK) + if (RST) + tx_dly_cnt <= 0; + else if(rx_bitslip && rx_bitslip_cnt == (2*WIDTH - 1)) + tx_dly_cnt <= tx_dly_cnt + 1; + +always @(posedge CLK) + if (tx_stb) begin + tx_dat_dly_d <= tx_dat_dly_c; + tx_dat_dly_c <= tx_dat_dly_b; + tx_dat_dly_b <= tx_dat_dly_a; + tx_dat_dly_a <= tx_dat; + end + +assign tx_dat_dly = (tx_dly_cnt == 0) ? tx_dat_dly_a : + (tx_dly_cnt == 1) ? tx_dat_dly_b : + (tx_dly_cnt == 2) ? tx_dat_dly_c : + /*(tx_dly_cnt == 3) ?*/tx_dat_dly_d; + +// Comparator +comparator # +( +.WIDTH (WIDTH) +) +comparator +( +.CLK (CLK), +.RST (RST), + +.TX_STB (tx_stb), +.TX_DAT (tx_dat_dly), + +.RX_STB (rx_stb), +.RX_DAT (rx_dat), +.RX_BITSLIP (rx_bitslip), + +.O_ERROR (ERROR) +); + +endmodule diff --git a/minitests/iserdes.sdr_ddr/syn.tcl b/minitests/iserdes.sdr_ddr/syn.tcl new file mode 100644 index 00000000..c4501ce6 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/syn.tcl @@ -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 From 0ebe592dca26429b3e3b10565f889cbd69b4dcce Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 22 Aug 2019 13:09:28 +0200 Subject: [PATCH 2/4] Updated docs. Signed-off-by: Maciej Kurc --- minitests/iserdes.sdr_ddr/README.md | 12 +++++++++++- minitests/iserdes.sdr_ddr/src/gen_rom.py | 9 ++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/minitests/iserdes.sdr_ddr/README.md b/minitests/iserdes.sdr_ddr/README.md index 55e4d9db..cb40738a 100644 --- a/minitests/iserdes.sdr_ddr/README.md +++ b/minitests/iserdes.sdr_ddr/README.md @@ -12,9 +12,11 @@ provide physical loopbacks of pins of those connectors. The clock is being routed internally. The received data is compared against transmitted internally. Errors are -indicated using LEDs. +indicated using LEDs. The comparator module automatically invokes the bitslip +feature of ISERDES (by brutaly testing all possible combinations). The pinout (out, in): + - JB.1, JB.7 - SDR, WIDTH=2 - JB.2, JB.8 - SDR, WIDTH=3 - JB.3, JB.9 - SDR, WIDTH=4 @@ -30,6 +32,7 @@ The pinout (out, in): LEDs indicate whether data is being received corectly. When a LED is lit then there is correct reception: + - LED0 - SDR, WIDTH=2 - LED1 - SDR, WIDTH=3 - LED2 - SDR, WIDTH=4 @@ -41,3 +44,10 @@ there is correct reception: - LED8 - DDR, WIDTH=5 - LED9 - DDR, WIDTH=6 - LED10 - Blinking + +The switch SW0 is used as reset. + +To build the project run the following command and the bit file will be generated. +``` +make basys3_top.bit +``` diff --git a/minitests/iserdes.sdr_ddr/src/gen_rom.py b/minitests/iserdes.sdr_ddr/src/gen_rom.py index d3849c70..22a4bf4c 100755 --- a/minitests/iserdes.sdr_ddr/src/gen_rom.py +++ b/minitests/iserdes.sdr_ddr/src/gen_rom.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +''' +This script generates a verilog ROM module that contains data to be transmitted +and received. The data is random. +''' import random def main(): @@ -47,11 +51,6 @@ endmodule rom_width = 8 rom_data = [random.randint(0, 2 ** rom_width - 1) for i in range(rom_size)] - -# rom_data = [] -# for i in range(rom_size // 2): -# rom_data.extend([0x00, 0xFF]) - rom_data = "\n".join([" rom[%4d] <= %d'd%d;" % (i, rom_width, d) for i, d in enumerate(rom_data)]) print(template.format( From e722712661ca42285943f101eeb658c074e0d2b3 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 22 Aug 2019 13:29:22 +0200 Subject: [PATCH 3/4] Formatting Signed-off-by: Maciej Kurc --- minitests/iserdes.sdr_ddr/sim/sim.tcl | 1 - minitests/iserdes.sdr_ddr/src/gen_rom.py | 25 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/minitests/iserdes.sdr_ddr/sim/sim.tcl b/minitests/iserdes.sdr_ddr/sim/sim.tcl index a6af032b..e185aa58 100644 --- a/minitests/iserdes.sdr_ddr/sim/sim.tcl +++ b/minitests/iserdes.sdr_ddr/sim/sim.tcl @@ -18,4 +18,3 @@ run -all flush_vcd close_vcd - diff --git a/minitests/iserdes.sdr_ddr/src/gen_rom.py b/minitests/iserdes.sdr_ddr/src/gen_rom.py index 22a4bf4c..5e9acc5f 100755 --- a/minitests/iserdes.sdr_ddr/src/gen_rom.py +++ b/minitests/iserdes.sdr_ddr/src/gen_rom.py @@ -5,6 +5,7 @@ and received. The data is random. ''' import random + def main(): template = """ @@ -47,19 +48,23 @@ endmodule """ rom_size_bits = 5 - rom_size = 2 ** rom_size_bits + rom_size = 2**rom_size_bits rom_width = 8 - rom_data = [random.randint(0, 2 ** rom_width - 1) for i in range(rom_size)] - rom_data = "\n".join([" rom[%4d] <= %d'd%d;" % (i, rom_width, d) for i, d in enumerate(rom_data)]) + rom_data = [random.randint(0, 2**rom_width - 1) for i in range(rom_size)] + rom_data = "\n".join( + [ + " rom[%4d] <= %d'd%d;" % (i, rom_width, d) + for i, d in enumerate(rom_data) + ]) + + print( + template.format( + rom_size_bits_minus_one=rom_size_bits - 1, + rom_size_minus_one=rom_size - 1, + rom_width_minus_one=rom_width - 1, + rom_data=rom_data)) - print(template.format( - rom_size_bits_minus_one=rom_size_bits - 1, - rom_size_minus_one=rom_size - 1, - rom_width_minus_one=rom_width - 1, - rom_data=rom_data - )) if __name__ == "__main__": main() - From 2b3ca04914903cf3ee2be6d67789c4915b117bd3 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 12 Sep 2019 15:03:56 +0200 Subject: [PATCH 4/4] Removed the need for physical pin loopback. The design now transmitts and receives using the same pins. Signed-off-by: Maciej Kurc --- minitests/iserdes.sdr_ddr/Makefile | 8 +- minitests/iserdes.sdr_ddr/README.md | 26 +- minitests/iserdes.sdr_ddr/basys3.xdc | 37 +-- .../iserdes.sdr_ddr/basys3_iserdes_sdr_ddr.v | 89 ++++++ minitests/iserdes.sdr_ddr/basys3_top.v | 266 ------------------ minitests/iserdes.sdr_ddr/par.tcl | 36 --- .../{trx_path.v => iserdes_sdr_ddr_test.v} | 72 +++-- minitests/iserdes.sdr_ddr/tcl/par.tcl | 16 ++ minitests/iserdes.sdr_ddr/{ => tcl}/syn.tcl | 0 9 files changed, 171 insertions(+), 379 deletions(-) create mode 100644 minitests/iserdes.sdr_ddr/basys3_iserdes_sdr_ddr.v delete mode 100644 minitests/iserdes.sdr_ddr/basys3_top.v delete mode 100644 minitests/iserdes.sdr_ddr/par.tcl rename minitests/iserdes.sdr_ddr/src/{trx_path.v => iserdes_sdr_ddr_test.v} (65%) create mode 100644 minitests/iserdes.sdr_ddr/tcl/par.tcl rename minitests/iserdes.sdr_ddr/{ => tcl}/syn.tcl (100%) diff --git a/minitests/iserdes.sdr_ddr/Makefile b/minitests/iserdes.sdr_ddr/Makefile index 933f190d..05d7bfbd 100644 --- a/minitests/iserdes.sdr_ddr/Makefile +++ b/minitests/iserdes.sdr_ddr/Makefile @@ -24,15 +24,15 @@ ifeq ($(SYNTH), yosys) $(YOSYS) -p "read_verilog $< ; synth_xilinx -flatten -nosrl; write_edif -pvector bra -attrprop $@" -l $@.log else ifeq ($(SYNTH), vivado) -%.edif: %.v +%.edif: %.v tcl/syn.tcl mkdir -p build-syn.$(basename $@) - cd build-syn.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../syn.tcl -nojournal -log ../$@.log + 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 par.tcl +%.bit: %.edif tcl/par.tcl mkdir -p build-par.$(basename $@) - cd build-par.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../par.tcl -nojournal -log ../$@.log + cd build-par.$(basename $@) && env PROJECT_NAME=$(basename $@) $(XRAY_VIVADO) -mode batch -source ../tcl/par.tcl -nojournal -log ../$@.log rm -rf *.backup.log diff --git a/minitests/iserdes.sdr_ddr/README.md b/minitests/iserdes.sdr_ddr/README.md index cb40738a..3dae2929 100644 --- a/minitests/iserdes.sdr_ddr/README.md +++ b/minitests/iserdes.sdr_ddr/README.md @@ -1,35 +1,19 @@ # ISERDES minitest for SDR and DDR +## Description + This test allows to verify that ISEDRES is working on hardware. Tested modes are: - NETWORKING / SDR - NETWORKING / DDR No chaining of two ISERDES bels. -The design uses JA, JB and JC connectors of the Basys 3 boards to output -serialized data and then receive it using ISERDESes. There is a need to -provide physical loopbacks of pins of those connectors. The clock is being -routed internally. +The design serializes data using logic for all tested ISERDES modes. The data is presented onto selected pins. The same pins are used to receive the data which is then fed to ISERDES cells. No physical loopback is required. The clock is routed internally. The received data is compared against transmitted internally. Errors are indicated using LEDs. The comparator module automatically invokes the bitslip feature of ISERDES (by brutaly testing all possible combinations). -The pinout (out, in): - -- JB.1, JB.7 - SDR, WIDTH=2 -- JB.2, JB.8 - SDR, WIDTH=3 -- JB.3, JB.9 - SDR, WIDTH=4 -- JB.4, JB.10 - SDR, WIDTH=5 -- JC.1, JC.7 - SDR, WIDTH=6 -- JC.2, JC.8 - SDR, WIDTH=7 -- JC.3, JC.9 - SDR, WIDTH=8 -- JC.4, JC.10 - DDR, WIDTH=4 -- JA.4, JA.10 - DDR, WIDTH=6 -- JA.3, JA.9 - DDR, WIDTH=8 -- JA.2 - Serialized data clock -- JA.1 - Serialized data clock x2 - LEDs indicate whether data is being received corectly. When a LED is lit then there is correct reception: @@ -47,7 +31,9 @@ there is correct reception: 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_top.bit +make basys3_iserdes_sdr_ddr.bit ``` diff --git a/minitests/iserdes.sdr_ddr/basys3.xdc b/minitests/iserdes.sdr_ddr/basys3.xdc index 61606f17..e3ffc516 100644 --- a/minitests/iserdes.sdr_ddr/basys3.xdc +++ b/minitests/iserdes.sdr_ddr/basys3.xdc @@ -39,32 +39,21 @@ 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]] -set_property PACKAGE_PIN J1 [get_ports ja1] -set_property PACKAGE_PIN L2 [get_ports ja2] -set_property PACKAGE_PIN J2 [get_ports ja3] -set_property PACKAGE_PIN G2 [get_ports ja4] -set_property PACKAGE_PIN H1 [get_ports ja7] -set_property PACKAGE_PIN K2 [get_ports ja8] -set_property PACKAGE_PIN H2 [get_ports ja9] -set_property PACKAGE_PIN G3 [get_ports ja10] +# 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]] -set_property PACKAGE_PIN A14 [get_ports jb1] -set_property PACKAGE_PIN A16 [get_ports jb2] -set_property PACKAGE_PIN B15 [get_ports jb3] -set_property PACKAGE_PIN B16 [get_ports jb4] -set_property PACKAGE_PIN A15 [get_ports jb7] -set_property PACKAGE_PIN A17 [get_ports jb8] -set_property PACKAGE_PIN C15 [get_ports jb9] -set_property PACKAGE_PIN C16 [get_ports jb10] +# 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]] -set_property PACKAGE_PIN K17 [get_ports jc1] -set_property PACKAGE_PIN M18 [get_ports jc2] -set_property PACKAGE_PIN N17 [get_ports jc3] -set_property PACKAGE_PIN P18 [get_ports jc4] -set_property PACKAGE_PIN L17 [get_ports jc7] -set_property PACKAGE_PIN M19 [get_ports jc8] -set_property PACKAGE_PIN P17 [get_ports jc9] -set_property PACKAGE_PIN R18 [get_ports jc10] +# 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 diff --git a/minitests/iserdes.sdr_ddr/basys3_iserdes_sdr_ddr.v b/minitests/iserdes.sdr_ddr/basys3_iserdes_sdr_ddr.v new file mode 100644 index 00000000..b4b6708d --- /dev/null +++ b/minitests/iserdes.sdr_ddr/basys3_iserdes_sdr_ddr.v @@ -0,0 +1,89 @@ +`include "src/rom.v" +`include "src/serializer.v" +`include "src/transmitter.v" +`include "src/receiver.v" +`include "src/comparator.v" +`include "src/iserdes_sdr_ddr_test.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]; + +// ============================================================================ +// 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"; + + iserdes_sdr_ddr_test # + ( + .DATA_WIDTH (DATA_WIDTH), + .DATA_RATE (DATA_RATE) + ) + iserdes_test + ( + .CLK (CLK), + .RST (RST), + + .IO_DAT (io[i]), + .O_ERROR (error[i]) + ); + +end endgenerate + +// ============================================================================ +// I/O connections + +reg [23:0] heartbeat_cnt; + +always @(posedge CLK) + heartbeat_cnt <= heartbeat_cnt + 1; + + +assign led[9: 0] = (RST) ? 9'd0 : ~error; +assign led[ 10] = heartbeat_cnt[22]; +assign led[15:11] = 0; + +endmodule diff --git a/minitests/iserdes.sdr_ddr/basys3_top.v b/minitests/iserdes.sdr_ddr/basys3_top.v deleted file mode 100644 index 2738cb6c..00000000 --- a/minitests/iserdes.sdr_ddr/basys3_top.v +++ /dev/null @@ -1,266 +0,0 @@ -`include "src/rom.v" -`include "src/serializer.v" -`include "src/transmitter.v" -`include "src/receiver.v" -`include "src/comparator.v" -`include "src/trx_path.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, - -output wire ja1, -output wire ja2, -output wire ja3, -output wire ja4, -input wire ja7, -input wire ja8, -input wire ja9, -input wire ja10, - -output wire jb1, -output wire jb2, -output wire jb3, -output wire jb4, -input wire jb7, -input wire jb8, -input wire jb9, -input wire jb10, - -output wire jc1, -output wire jc2, -output wire jc3, -output wire jc4, -input wire jc7, -input wire jc8, -input wire jc9, -input wire jc10 -); - -// ============================================================================ -// Clock & reset -// Divide the input clock to allow for less strict timing requirements. -reg [3:0] rst_sr; -reg [7:0] clk_ps; - -initial rst_sr <= 4'hF; -initial clk_ps <= 0; - -always @(posedge clk) - if (sw[0]) - rst_sr <= 4'hF; - else - rst_sr <= rst_sr >> 1; - -always @(posedge clk) - clk_ps <= clk_ps + 1; - -wire CLK100 = clk; -wire CLK = clk_ps[2]; -wire RST = rst_sr[0]; - -// ============================================================================ -// ISERDES test logic -wire [9:0] error; -wire [9:0] data; - -wire s_clk; - -// ........ - -trx_path # -( -.WIDTH (2), -.MODE ("SDR") -) -path_sdr_2 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[0]), -.O_CLK (s_clk), -.I_DAT (jb7), -.ERROR (error[0]) -); - -trx_path # -( -.WIDTH (3), -.MODE ("SDR") -) -path_sdr_3 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[1]), -.I_DAT (jb8), -.ERROR (error[1]) -); - -trx_path # -( -.WIDTH (4), -.MODE ("SDR") -) -path_sdr_4 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[2]), -.I_DAT (jb9), -.ERROR (error[2]) -); - -trx_path # -( -.WIDTH (5), -.MODE ("SDR") -) -path_sdr_5 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[3]), -.I_DAT (jb10), -.ERROR (error[3]) -); - -// ........ - -trx_path # -( -.WIDTH (6), -.MODE ("SDR") -) -path_sdr_6 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[4]), -.I_DAT (jc7), -.ERROR (error[4]) -); - -trx_path # -( -.WIDTH (7), -.MODE ("SDR") -) -path_sdr_7 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[5]), -.I_DAT (jc8), -.ERROR (error[5]) -); - -trx_path # -( -.WIDTH (8), -.MODE ("SDR") -) -path_sdr_8 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[6]), -.I_DAT (jc9), -.ERROR (error[6]) -); - -trx_path # -( -.WIDTH (4), -.MODE ("DDR") -) -path_ddr_4 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[7]), -.I_DAT (jc10), -.ERROR (error[7]) -); - -// ........ - -trx_path # -( -.WIDTH (6), -.MODE ("DDR") -) -path_ddr_6 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[8]), -.I_DAT (ja10), -.ERROR (error[8]) -); - -trx_path # -( -.WIDTH (8), -.MODE ("DDR") -) -path_ddr_8 -( -.CLK (CLK), -.RST (RST), -.O_DAT (data[9]), -.I_DAT (ja9), -.ERROR (error[9]) -); - -// ============================================================================ -// Delay data by 1 cycle of the 100MHz clock to avoid race condition betweeen -// serialized clock and data edges. We are not using IDELAY to compensate for -// that in this design. In other words the data is delayed at the transmitter -// side. - -reg [9:0] data_dly; - -always @(posedge CLK100) - data_dly <= data; - -// ============================================================================ -// I/O connections - -reg [23:0] heartbeat_cnt; - -always @(posedge CLK100) - heartbeat_cnt <= heartbeat_cnt + 1; - - -assign led[9: 0] = (RST) ? 9'd0 : ~error; -assign led[ 10] = heartbeat_cnt[22]; -assign led[15:11] = 0; - -assign jb1 = data_dly[0]; -assign jb2 = data_dly[1]; -assign jb3 = data_dly[2]; -assign jb4 = data_dly[3]; - -assign jc1 = data_dly[4]; -assign jc2 = data_dly[5]; -assign jc3 = data_dly[6]; -assign jc4 = data_dly[7]; - -assign ja4 = data_dly[8]; -assign ja3 = data_dly[9]; - -assign ja1 = CLK; -assign ja2 = s_clk; - -endmodule diff --git a/minitests/iserdes.sdr_ddr/par.tcl b/minitests/iserdes.sdr_ddr/par.tcl deleted file mode 100644 index e198dd57..00000000 --- a/minitests/iserdes.sdr_ddr/par.tcl +++ /dev/null @@ -1,36 +0,0 @@ -create_project -force -name $env(PROJECT_NAME) -part xc7a35tcpg236-1 - -read_edif ../$env(PROJECT_NAME).edif - -link_design -part xc7a35tcpg236-1 -source ../basys3.xdc - -report_timing_summary -file top_timing_synth.rpt -report_utilization -hierarchical -file top_utilization_hierarchical_synth.rpt -report_utilization -file top_utilization_synth.rpt - -opt_design -place_design - -report_utilization -hierarchical -file top_utilization_hierarchical_place.rpt -report_utilization -file top_utilization_place.rpt -report_io -file top_io.rpt -report_control_sets -verbose -file top_control_sets.rpt -report_clock_utilization -file top_clock_utilization.rpt - -route_design -#phys_opt_design - -report_timing_summary -no_header -no_detailed_paths - -write_checkpoint -force ../$env(PROJECT_NAME).dcp - -set_property SEVERITY {Warning} [get_drc_checks UCIO-1] -set_property SEVERITY {Warning} [get_drc_checks NSTD-1] - -report_route_status -file top_route_status.rpt -report_drc -file top_drc.rpt -report_timing_summary -datasheet -max_paths 10 -file top_timing.rpt -report_power -file top_power.rpt - -write_bitstream -force ../$env(PROJECT_NAME).bit diff --git a/minitests/iserdes.sdr_ddr/src/trx_path.v b/minitests/iserdes.sdr_ddr/src/iserdes_sdr_ddr_test.v similarity index 65% rename from minitests/iserdes.sdr_ddr/src/trx_path.v rename to minitests/iserdes.sdr_ddr/src/iserdes_sdr_ddr_test.v index 90e6ce90..94159c2c 100644 --- a/minitests/iserdes.sdr_ddr/src/trx_path.v +++ b/minitests/iserdes.sdr_ddr/src/iserdes_sdr_ddr_test.v @@ -2,32 +2,48 @@ // ============================================================================ -module trx_path # +module iserdes_sdr_ddr_test # ( -parameter WIDTH = 8, -parameter MODE = "SDR" +parameter DATA_WIDTH = 8, +parameter DATA_RATE = "SDR" ) ( // Clock and reset input wire CLK, input wire RST, -// Input and output pins -output wire O_CLK, -output wire O_DAT, -input wire I_DAT, +// Data pin +inout wire IO_DAT, // Error indicator -output wire ERROR +output wire O_ERROR +); + +// ============================================================================ +// IOB +wire iob_o; +wire iob_i; + +OBUFT obuf +( +.I (iob_o), +.T (1'b0), +.O (IO_DAT) +); + +IBUF ibuf +( +.I (IO_DAT), +.O (iob_i) ); // ============================================================================ wire tx_stb; -wire [WIDTH-1:0] tx_dat; +wire [DATA_WIDTH-1:0] tx_dat; wire rx_stb; -wire [WIDTH-1:0] rx_dat; +wire [DATA_WIDTH-1:0] rx_dat; wire rx_bitslip; wire s_clk; @@ -35,8 +51,8 @@ wire s_clk; // Transmitter transmitter # ( -.WIDTH (WIDTH), -.MODE (MODE) +.WIDTH (DATA_WIDTH), +.MODE (DATA_RATE) ) transmitter ( @@ -47,16 +63,14 @@ transmitter .O_DAT (tx_dat), .S_CLK (s_clk), -.S_DAT (O_DAT) +.S_DAT (iob_o) ); -assign O_CLK = s_clk; - // Receiver receiver # ( -.WIDTH (WIDTH), -.MODE (MODE) +.WIDTH (DATA_WIDTH), +.MODE (DATA_RATE) ) receiver ( @@ -64,7 +78,7 @@ receiver .RST (RST), .I_CLK (s_clk), -.I_DAT (I_DAT), +.I_DAT (iob_i), .O_STB (rx_stb), .O_DAT (rx_dat), @@ -72,7 +86,7 @@ receiver ); // The comparator module generates bitslip signal for the receiver. However -// the bitslip can shift only modulo WIDTH. Therefore additional delay is +// the bitslip can shift only modulo DATA_WIDTH. Therefore additional delay is // added which can delay the transmitted data that we compare to by a number // of full words. @@ -82,24 +96,24 @@ always @(posedge CLK) if (RST) rx_bitslip_cnt <= 0; else if (rx_bitslip) begin - if (rx_bitslip_cnt == (2*WIDTH - 1)) + if (rx_bitslip_cnt == (2*DATA_WIDTH - 1)) rx_bitslip_cnt <= 0; else rx_bitslip_cnt <= rx_bitslip_cnt + 1; end // Word delay -reg [1:0] tx_dly_cnt; -reg [WIDTH-1:0] tx_dat_dly_a; -reg [WIDTH-1:0] tx_dat_dly_b; -reg [WIDTH-1:0] tx_dat_dly_c; -reg [WIDTH-1:0] tx_dat_dly_d; -wire [WIDTH-1:0] tx_dat_dly; +reg [1:0] tx_dly_cnt; +reg [DATA_WIDTH-1:0] tx_dat_dly_a; +reg [DATA_WIDTH-1:0] tx_dat_dly_b; +reg [DATA_WIDTH-1:0] tx_dat_dly_c; +reg [DATA_WIDTH-1:0] tx_dat_dly_d; +wire [DATA_WIDTH-1:0] tx_dat_dly; always @(posedge CLK) if (RST) tx_dly_cnt <= 0; - else if(rx_bitslip && rx_bitslip_cnt == (2*WIDTH - 1)) + else if(rx_bitslip && rx_bitslip_cnt == (2*DATA_WIDTH - 1)) tx_dly_cnt <= tx_dly_cnt + 1; always @(posedge CLK) @@ -118,7 +132,7 @@ assign tx_dat_dly = (tx_dly_cnt == 0) ? tx_dat_dly_a : // Comparator comparator # ( -.WIDTH (WIDTH) +.WIDTH (DATA_WIDTH) ) comparator ( @@ -132,7 +146,7 @@ comparator .RX_DAT (rx_dat), .RX_BITSLIP (rx_bitslip), -.O_ERROR (ERROR) +.O_ERROR (O_ERROR) ); endmodule diff --git a/minitests/iserdes.sdr_ddr/tcl/par.tcl b/minitests/iserdes.sdr_ddr/tcl/par.tcl new file mode 100644 index 00000000..60d66e80 --- /dev/null +++ b/minitests/iserdes.sdr_ddr/tcl/par.tcl @@ -0,0 +1,16 @@ +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] + +place_design +route_design + +write_checkpoint -force ../$env(PROJECT_NAME).dcp + +write_bitstream -force ../$env(PROJECT_NAME).bit diff --git a/minitests/iserdes.sdr_ddr/syn.tcl b/minitests/iserdes.sdr_ddr/tcl/syn.tcl similarity index 100% rename from minitests/iserdes.sdr_ddr/syn.tcl rename to minitests/iserdes.sdr_ddr/tcl/syn.tcl