1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-30 08:32:52 +08:00

Add RX checksum module and testbench

This commit is contained in:
Alex Forencich 2019-07-16 00:42:49 -07:00
parent 755c7959be
commit 6100e3ad78
3 changed files with 617 additions and 0 deletions

View File

@ -0,0 +1,198 @@
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Receive checksum offload module
*/
module rx_checksum #
(
parameter DATA_WIDTH = 256,
parameter KEEP_WIDTH = (DATA_WIDTH/8)
)
(
input wire clk,
input wire rst,
/*
* AXI input
*/
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
input wire s_axis_tvalid,
input wire s_axis_tlast,
/*
* Checksum output
*/
output wire [15:0] m_axis_csum,
output wire m_axis_csum_valid
);
// bus width assertions
initial begin
if (DATA_WIDTH != 256) begin
$error("Error: AXI stream interface width must be 256");
$finish;
end
if (KEEP_WIDTH * 8 != DATA_WIDTH) begin
$error("Error: AXI stream interface requires byte (8-bit) granularity");
$finish;
end
end
reg [KEEP_WIDTH-1:0] mask_reg = 32'hffffc000;
reg [DATA_WIDTH-1:0] s_axis_tdata_masked;
reg [16:0] sum_1_1_reg = 0;
reg [16:0] sum_1_2_reg = 0;
reg [16:0] sum_1_3_reg = 0;
reg [16:0] sum_1_4_reg = 0;
reg [16:0] sum_1_5_reg = 0;
reg [16:0] sum_1_6_reg = 0;
reg [16:0] sum_1_7_reg = 0;
reg [16:0] sum_1_8_reg = 0;
reg sum_1_valid_reg = 1'b0;
reg sum_1_last_reg = 1'b0;
reg [17:0] sum_2_1_reg = 0;
reg [17:0] sum_2_2_reg = 0;
reg [17:0] sum_2_3_reg = 0;
reg [17:0] sum_2_4_reg = 0;
reg sum_2_valid_reg = 1'b0;
reg sum_2_last_reg = 1'b0;
reg [18:0] sum_3_1_reg = 0;
reg [18:0] sum_3_2_reg = 0;
reg sum_3_valid_reg = 1'b0;
reg sum_3_last_reg = 1'b0;
reg [19:0] sum_4_reg = 0;
reg sum_4_valid_reg = 1'b0;
reg sum_4_last_reg = 1'b0;
reg [20:0] sum_5_temp = 0;
reg [15:0] sum_5_reg = 0;
reg [15:0] m_axis_csum_reg = 0;
reg m_axis_csum_valid_reg = 1'b0;
assign m_axis_csum = m_axis_csum_reg;
assign m_axis_csum_valid = m_axis_csum_valid_reg;
// Mask input data
integer j;
always @* begin
for (j = 0; j < KEEP_WIDTH; j = j + 1) begin
s_axis_tdata_masked[j*8 +: 8] = (s_axis_tkeep[j] && mask_reg[j]) ? s_axis_tdata[j*8 +: 8] : 8'd0;
end
end
always @(posedge clk) begin
sum_1_valid_reg <= 1'b0;
sum_2_valid_reg <= 1'b0;
sum_3_valid_reg <= 1'b0;
sum_4_valid_reg <= 1'b0;
m_axis_csum_valid_reg <= 1'b0;
if (s_axis_tvalid) begin
sum_1_1_reg <= {s_axis_tdata_masked[ 0*8 +: 8], s_axis_tdata_masked[ 1*8 +: 8]} + {s_axis_tdata_masked[ 2*8 +: 8], s_axis_tdata_masked[ 3*8 +: 8]};
sum_1_2_reg <= {s_axis_tdata_masked[ 4*8 +: 8], s_axis_tdata_masked[ 5*8 +: 8]} + {s_axis_tdata_masked[ 6*8 +: 8], s_axis_tdata_masked[ 7*8 +: 8]};
sum_1_3_reg <= {s_axis_tdata_masked[ 8*8 +: 8], s_axis_tdata_masked[ 9*8 +: 8]} + {s_axis_tdata_masked[10*8 +: 8], s_axis_tdata_masked[11*8 +: 8]};
sum_1_4_reg <= {s_axis_tdata_masked[12*8 +: 8], s_axis_tdata_masked[13*8 +: 8]} + {s_axis_tdata_masked[14*8 +: 8], s_axis_tdata_masked[15*8 +: 8]};
sum_1_5_reg <= {s_axis_tdata_masked[16*8 +: 8], s_axis_tdata_masked[17*8 +: 8]} + {s_axis_tdata_masked[18*8 +: 8], s_axis_tdata_masked[19*8 +: 8]};
sum_1_6_reg <= {s_axis_tdata_masked[20*8 +: 8], s_axis_tdata_masked[21*8 +: 8]} + {s_axis_tdata_masked[22*8 +: 8], s_axis_tdata_masked[23*8 +: 8]};
sum_1_7_reg <= {s_axis_tdata_masked[24*8 +: 8], s_axis_tdata_masked[25*8 +: 8]} + {s_axis_tdata_masked[26*8 +: 8], s_axis_tdata_masked[27*8 +: 8]};
sum_1_8_reg <= {s_axis_tdata_masked[28*8 +: 8], s_axis_tdata_masked[29*8 +: 8]} + {s_axis_tdata_masked[30*8 +: 8], s_axis_tdata_masked[31*8 +: 8]};
sum_1_valid_reg <= 1'b1;
sum_1_last_reg <= s_axis_tlast;
if (s_axis_tlast) begin
mask_reg <= 32'hffffc000;
end else begin
mask_reg <= {KEEP_WIDTH{1'b1}};
end
end
if (sum_1_valid_reg) begin
sum_2_1_reg <= sum_1_1_reg + sum_1_2_reg;
sum_2_2_reg <= sum_1_3_reg + sum_1_4_reg;
sum_2_3_reg <= sum_1_5_reg + sum_1_6_reg;
sum_2_4_reg <= sum_1_7_reg + sum_1_8_reg;
sum_2_valid_reg <= 1'b1;
sum_2_last_reg <= sum_1_last_reg;
end
if (sum_2_valid_reg) begin
sum_3_1_reg <= sum_2_1_reg + sum_2_2_reg;
sum_3_2_reg <= sum_2_3_reg + sum_2_4_reg;
sum_3_valid_reg <= 1'b1;
sum_3_last_reg <= sum_2_last_reg;
end
if (sum_3_valid_reg) begin
sum_4_reg <= sum_3_1_reg + sum_3_2_reg;
sum_4_valid_reg <= 1'b1;
sum_4_last_reg <= sum_3_last_reg;
end
if (sum_4_valid_reg) begin
sum_5_temp = sum_4_reg + sum_5_reg;
sum_5_temp = sum_5_temp[15:0] + sum_5_temp[20:16];
sum_5_temp = sum_5_temp[15:0] + sum_5_temp[16];
if (sum_4_last_reg) begin
m_axis_csum_reg <= sum_5_temp;
m_axis_csum_valid_reg <= 1'b1;
sum_5_reg <= 0;
end else begin
sum_5_reg <= sum_5_temp;
end
end
if (rst) begin
mask_reg <= 32'hffffc000;
sum_1_valid_reg <= 1'b0;
sum_2_valid_reg <= 1'b0;
sum_3_valid_reg <= 1'b0;
sum_4_valid_reg <= 1'b0;
m_axis_csum_valid_reg <= 1'b0;
end
end
endmodule

View File

@ -0,0 +1,322 @@
#!/usr/bin/env python
"""
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
"""
from myhdl import *
import os
import axis_ep
import eth_ep
module = 'rx_checksum'
testbench = 'test_%s' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def frame_checksum(frame):
data = bytearray()
if isinstance(frame, eth_ep.EthFrame):
data = frame.payload.data
elif isinstance(frame, axis_ep.AXIStreamFrame):
data = frame.data[14:]
else:
return None
csum = 0
odd = False
for b in data:
if odd:
csum += b
else:
csum += b << 8
odd = not odd
csum = (csum & 0xffff) + (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16)
return csum
def bench():
# Parameters
DATA_WIDTH = 256
KEEP_WIDTH = (DATA_WIDTH/8)
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
s_axis_tvalid = Signal(bool(0))
s_axis_tlast = Signal(bool(0))
# Outputs
m_axis_csum = Signal(intbv(0)[16:])
m_axis_csum_valid = Signal(bool(0))
# sources and sinks
source_pause = Signal(bool(0))
source = axis_ep.AXIStreamSource()
source_logic = source.create_logic(
clk,
rst,
tdata=s_axis_tdata,
tkeep=s_axis_tkeep,
tvalid=s_axis_tvalid,
tlast=s_axis_tlast,
pause=source_pause,
name='source'
)
sink = axis_ep.AXIStreamSink()
sink_logic = sink.create_logic(
clk,
rst,
tdata=(m_axis_csum,),
tvalid=m_axis_csum_valid,
name='sink'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=clk,
rst=rst,
current_test=current_test,
s_axis_tdata=s_axis_tdata,
s_axis_tkeep=s_axis_tkeep,
s_axis_tvalid=s_axis_tvalid,
s_axis_tlast=s_axis_tlast,
m_axis_csum=m_axis_csum,
m_axis_csum_valid=m_axis_csum_valid
)
@always(delay(4))
def clkgen():
clk.next = not clk
def wait_normal():
while s_axis_tvalid:
yield clk.posedge
def wait_pause_source():
while s_axis_tvalid:
yield clk.posedge
yield clk.posedge
source_pause.next = False
yield clk.posedge
source_pause.next = True
yield clk.posedge
source_pause.next = False
@instance
def check():
yield delay(100)
yield clk.posedge
rst.next = 1
yield clk.posedge
rst.next = 0
yield clk.posedge
yield delay(100)
yield clk.posedge
# testbench stimulus
for payload_len in list(range(1, 128)) + list([1024, 1500, 9000, 9214]):
yield clk.posedge
print("test 1: test packet, length %d" % payload_len)
current_test.next = 1
test_frame = eth_ep.EthFrame()
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
test_frame.eth_src_mac = 0x5A5152535455
test_frame.eth_type = 0x8000
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
axis_frame = test_frame.build_axis()
for wait in wait_normal, wait_pause_source:
source.send(axis_frame)
yield clk.posedge
yield clk.posedge
yield wait()
yield sink.wait()
rx_csum = sink.recv().data[0][0]
print(hex(rx_csum))
csum = frame_checksum(test_frame)
print(hex(csum))
assert rx_csum == csum
assert sink.empty()
yield delay(100)
yield clk.posedge
print("test 2: back-to-back packets, length %d" % payload_len)
current_test.next = 2
test_frame1 = eth_ep.EthFrame()
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
test_frame1.eth_src_mac = 0x5A5152535455
test_frame1.eth_type = 0x8000
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
test_frame2 = eth_ep.EthFrame()
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
test_frame2.eth_src_mac = 0x5A5152535455
test_frame2.eth_type = 0x8000
test_frame2.payload = bytearray((~x%256 for x in range(payload_len)))
axis_frame1 = test_frame1.build_axis()
axis_frame2 = test_frame2.build_axis()
for wait in wait_normal, wait_pause_source:
source.send(axis_frame1)
source.send(axis_frame2)
yield clk.posedge
yield clk.posedge
yield wait()
yield sink.wait()
rx_csum = sink.recv().data[0][0]
print(hex(rx_csum))
csum = frame_checksum(test_frame1)
print(hex(csum))
assert rx_csum == csum
yield sink.wait()
rx_csum = sink.recv().data[0][0]
print(hex(rx_csum))
csum = frame_checksum(test_frame2)
print(hex(csum))
assert rx_csum == csum
assert sink.empty()
yield delay(100)
yield clk.posedge
print("test 3: overflow test")
current_test.next = 3
axis_frame = axis_ep.AXIStreamFrame(bytearray([0xff]*10240))
for wait in wait_normal, wait_pause_source:
source.send(axis_frame)
yield clk.posedge
yield clk.posedge
yield wait()
yield sink.wait()
rx_csum = sink.recv().data[0][0]
print(hex(rx_csum))
csum = frame_checksum(axis_frame)
print(hex(csum))
assert rx_csum == csum
assert sink.empty()
yield delay(100)
yield clk.posedge
print("test 4: checksum test")
current_test.next = 4
test_frame = eth_ep.EthFrame()
test_frame.eth_dest_mac = 0xDA0203040506
test_frame.eth_src_mac = 0xCA0203040506
test_frame.eth_type = 0x005a
test_frame.payload = b'\xab\xcd'+bytearray(range(20, 108))
axis_frame = test_frame.build_axis()
for wait in wait_normal, wait_pause_source:
source.send(axis_frame)
yield clk.posedge
yield clk.posedge
yield wait()
yield sink.wait()
rx_csum = sink.recv().data[0][0]
print(hex(rx_csum))
csum = frame_checksum(test_frame)
print(hex(csum))
assert csum == 0x8ad8
assert rx_csum == csum
assert sink.empty()
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,97 @@
/*
Copyright 2019, The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of The Regents of the University of California.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for rx_checksum
*/
module test_rx_checksum;
// Parameters
parameter DATA_WIDTH = 256;
parameter KEEP_WIDTH = (DATA_WIDTH/8);
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
reg s_axis_tvalid = 0;
reg s_axis_tlast = 0;
// Outputs
wire [15:0] m_axis_csum;
wire m_axis_csum_valid;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_tdata,
s_axis_tkeep,
s_axis_tvalid,
s_axis_tlast
);
$to_myhdl(
m_axis_csum,
m_axis_csum_valid
);
// dump file
$dumpfile("test_rx_checksum.lxt");
$dumpvars(0, test_rx_checksum);
end
rx_checksum #(
.DATA_WIDTH(DATA_WIDTH),
.KEEP_WIDTH(KEEP_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_tdata(s_axis_tdata),
.s_axis_tkeep(s_axis_tkeep),
.s_axis_tvalid(s_axis_tvalid),
.s_axis_tlast(s_axis_tlast),
.m_axis_csum(m_axis_csum),
.m_axis_csum_valid(m_axis_csum_valid)
);
endmodule