Merge pull request #1030 from antmicro/iserdes_sdr_ddr_minitest

Minitest for ISERDES (networking SDR and DDR)
This commit is contained in:
litghost 2019-09-12 09:21:16 -07:00 committed by GitHub
commit 85811b96a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1173 additions and 0 deletions

View File

@ -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

View File

@ -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
```

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
../src/rom.v
../src/serializer.v
../src/transmitter.v

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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