From b878a2e651dc97be1e22439e8f052ad9c986c9e5 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 22 Aug 2019 13:03:03 +0200 Subject: [PATCH] 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