mirror of https://github.com/openXC7/prjxray.git
Merge pull request #1030 from antmicro/iserdes_sdr_ddr_minitest
Minitest for ISERDES (networking SDR and DDR)
This commit is contained in:
commit
85811b96a4
|
|
@ -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,39 @@
|
|||
# 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 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).
|
||||
|
||||
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
|
||||
|
||||
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_iserdes_sdr_ddr.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,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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#!/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
|
||||
|
||||
# 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
|
||||
|
||||
|
|
@ -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,3 @@
|
|||
../src/rom.v
|
||||
../src/serializer.v
|
||||
../src/transmitter.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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/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():
|
||||
|
||||
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 = "\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()
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
`default_nettype none
|
||||
|
||||
// ============================================================================
|
||||
|
||||
module iserdes_sdr_ddr_test #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter DATA_RATE = "SDR"
|
||||
)
|
||||
(
|
||||
// Clock and reset
|
||||
input wire CLK,
|
||||
input wire RST,
|
||||
|
||||
// Data pin
|
||||
inout wire IO_DAT,
|
||||
|
||||
// Error indicator
|
||||
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 [DATA_WIDTH-1:0] tx_dat;
|
||||
|
||||
wire rx_stb;
|
||||
wire [DATA_WIDTH-1:0] rx_dat;
|
||||
wire rx_bitslip;
|
||||
|
||||
wire s_clk;
|
||||
|
||||
// Transmitter
|
||||
transmitter #
|
||||
(
|
||||
.WIDTH (DATA_WIDTH),
|
||||
.MODE (DATA_RATE)
|
||||
)
|
||||
transmitter
|
||||
(
|
||||
.CLK (CLK),
|
||||
.RST (RST),
|
||||
|
||||
.O_STB (tx_stb),
|
||||
.O_DAT (tx_dat),
|
||||
|
||||
.S_CLK (s_clk),
|
||||
.S_DAT (iob_o)
|
||||
);
|
||||
|
||||
// Receiver
|
||||
receiver #
|
||||
(
|
||||
.WIDTH (DATA_WIDTH),
|
||||
.MODE (DATA_RATE)
|
||||
)
|
||||
receiver
|
||||
(
|
||||
.CLK (CLK),
|
||||
.RST (RST),
|
||||
|
||||
.I_CLK (s_clk),
|
||||
.I_DAT (iob_i),
|
||||
|
||||
.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 DATA_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*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 [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*DATA_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 (DATA_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 (O_ERROR)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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