diff --git a/rtl/axis_eth_fcs.v b/rtl/axis_eth_fcs.v new file mode 100644 index 000000000..60a17520f --- /dev/null +++ b/rtl/axis_eth_fcs.v @@ -0,0 +1,89 @@ +/* + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream Ethernet FCS Generator + */ +module axis_eth_fcs +( + input wire clk, + input wire rst, + + /* + * AXI input + */ + input wire [7:0] input_axis_tdata, + input wire input_axis_tvalid, + output wire input_axis_tready, + input wire input_axis_tlast, + input wire input_axis_tuser, + + /* + * FCS output + */ + output wire [31:0] output_fcs, + output wire output_fcs_valid +); + +reg [31:0] crc_state = 32'hFFFFFFFF; +reg [31:0] fcs_reg = 0; +reg fcs_valid_reg = 0; + +wire [31:0] crc_next; + +assign input_axis_tready = 1; +assign output_fcs = fcs_reg; +assign output_fcs_valid = fcs_valid_reg; + +eth_crc_8 +eth_crc_8_inst ( + .data_in(input_axis_tdata), + .crc_state(crc_state), + .crc_next(crc_next) +); + +always @(posedge clk or posedge rst) begin + if (rst) begin + crc_state <= 32'hFFFFFFFF; + fcs_reg <= 0; + fcs_valid_reg <= 0; + end else begin + fcs_valid_reg <= 0; + if (input_axis_tvalid) begin + if (input_axis_tlast) begin + crc_state <= 32'hFFFFFFFF; + fcs_reg <= ~crc_next; + fcs_valid_reg <= 1; + end else begin + crc_state <= crc_next; + end + end + end +end + +endmodule diff --git a/rtl/axis_eth_fcs_64.v b/rtl/axis_eth_fcs_64.v new file mode 100644 index 000000000..539f9dc75 --- /dev/null +++ b/rtl/axis_eth_fcs_64.v @@ -0,0 +1,155 @@ +/* + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream Ethernet FCS Generator (64 bit datapath) + */ +module axis_eth_fcs_64 +( + input wire clk, + input wire rst, + + /* + * AXI input + */ + input wire [63:0] input_axis_tdata, + input wire [7:0] input_axis_tkeep, + input wire input_axis_tvalid, + output wire input_axis_tready, + input wire input_axis_tlast, + input wire input_axis_tuser, + + /* + * FCS output + */ + output wire [31:0] output_fcs, + output wire output_fcs_valid +); + +reg [31:0] crc_state = 32'hFFFFFFFF; +reg [31:0] fcs_reg = 0; +reg fcs_valid_reg = 0; + +wire [31:0] crc_next0; +wire [31:0] crc_next1; +wire [31:0] crc_next2; +wire [31:0] crc_next3; +wire [31:0] crc_next4; +wire [31:0] crc_next5; +wire [31:0] crc_next6; +wire [31:0] crc_next7; + +assign input_axis_tready = 1; +assign output_fcs = fcs_reg; +assign output_fcs_valid = fcs_valid_reg; + +eth_crc_8 +eth_crc_8_inst ( + .data_in(input_axis_tdata[7:0]), + .crc_state(crc_state), + .crc_next(crc_next0) +); + +eth_crc_16 +eth_crc_16_inst ( + .data_in(input_axis_tdata[15:0]), + .crc_state(crc_state), + .crc_next(crc_next1) +); + +eth_crc_24 +eth_crc_24_inst ( + .data_in(input_axis_tdata[23:0]), + .crc_state(crc_state), + .crc_next(crc_next2) +); + +eth_crc_32 +eth_crc_32_inst ( + .data_in(input_axis_tdata[31:0]), + .crc_state(crc_state), + .crc_next(crc_next3) +); + +eth_crc_40 +eth_crc_40_inst ( + .data_in(input_axis_tdata[39:0]), + .crc_state(crc_state), + .crc_next(crc_next4) +); + +eth_crc_48 +eth_crc_48_inst ( + .data_in(input_axis_tdata[47:0]), + .crc_state(crc_state), + .crc_next(crc_next5) +); + +eth_crc_56 +eth_crc_56_inst ( + .data_in(input_axis_tdata[55:0]), + .crc_state(crc_state), + .crc_next(crc_next6) +); + +eth_crc_64 +eth_crc_64_inst ( + .data_in(input_axis_tdata[63:0]), + .crc_state(crc_state), + .crc_next(crc_next7) +); + +always @(posedge clk or posedge rst) begin + if (rst) begin + crc_state <= 32'hFFFFFFFF; + fcs_reg <= 0; + fcs_valid_reg <= 0; + end else begin + fcs_valid_reg <= 0; + if (input_axis_tvalid) begin + if (input_axis_tlast) begin + crc_state <= 32'hFFFFFFFF; + case (input_axis_tkeep) + 8'b00000001: fcs_reg <= ~crc_next0; + 8'b00000011: fcs_reg <= ~crc_next1; + 8'b00000111: fcs_reg <= ~crc_next2; + 8'b00001111: fcs_reg <= ~crc_next3; + 8'b00011111: fcs_reg <= ~crc_next4; + 8'b00111111: fcs_reg <= ~crc_next5; + 8'b01111111: fcs_reg <= ~crc_next6; + 8'b11111111: fcs_reg <= ~crc_next7; + endcase + fcs_valid_reg <= 1; + end else begin + crc_state <= crc_next7; + end + end + end +end + +endmodule diff --git a/tb/test_axis_eth_fcs.py b/tb/test_axis_eth_fcs.py new file mode 100755 index 000000000..6899a6665 --- /dev/null +++ b/tb/test_axis_eth_fcs.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python2 +""" + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os +from Queue import Queue + +import axis_ep +import eth_ep + +module = 'axis_eth_fcs' + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/eth_crc_8.v") +srcs.append("test_%s.v" % module) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o test_%s.vvp %s" % (module, src) + +def dut_axis_eth_fcs(clk, + rst, + current_test, + + input_axis_tdata, + input_axis_tvalid, + input_axis_tready, + input_axis_tlast, + input_axis_tuser, + + output_fcs, + output_fcs_valid): + + if os.system(build_cmd): + raise Exception("Error running build command") + return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module, + clk=clk, + rst=rst, + current_test=current_test, + + input_axis_tdata=input_axis_tdata, + input_axis_tvalid=input_axis_tvalid, + input_axis_tready=input_axis_tready, + input_axis_tlast=input_axis_tlast, + input_axis_tuser=input_axis_tuser, + + output_fcs=output_fcs, + output_fcs_valid=output_fcs_valid) + +def bench(): + + # Parameters + + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + input_axis_tdata = Signal(intbv(0)[8:]) + input_axis_tvalid = Signal(bool(0)) + input_axis_tlast = Signal(bool(0)) + input_axis_tuser = Signal(bool(0)) + + # Outputs + input_axis_tready = Signal(bool(1)) + output_fcs = Signal(intbv(0)[32:]) + output_fcs_valid = Signal(bool(0)) + + # sources and sinks + source_queue = Queue() + source_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_axis_tdata, + tvalid=input_axis_tvalid, + tready=input_axis_tready, + tlast=input_axis_tlast, + tuser=input_axis_tuser, + fifo=source_queue, + pause=source_pause, + name='source') + + # DUT + dut = dut_axis_eth_fcs(clk, + rst, + current_test, + + input_axis_tdata, + input_axis_tvalid, + input_axis_tready, + input_axis_tlast, + input_axis_tuser, + + output_fcs, + output_fcs_valid) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @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,18))+list(range(64,82)): + 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(range(payload_len)) + test_frame.update_fcs() + + axis_frame = test_frame.build_axis() + + source_queue.put(axis_frame) + yield clk.posedge + yield clk.posedge + + yield output_fcs_valid.posedge + + print(hex(int(output_fcs))) + print(hex(test_frame.eth_fcs)) + + assert output_fcs == test_frame.eth_fcs + + yield delay(100) + + raise StopSimulation + + return dut, source, clkgen, check + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/tb/test_axis_eth_fcs.v b/tb/test_axis_eth_fcs.v new file mode 100644 index 000000000..e1a10f78b --- /dev/null +++ b/tb/test_axis_eth_fcs.v @@ -0,0 +1,82 @@ +/* + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for axis_eth_fcs + */ +module test_axis_eth_fcs; + +// Parameters + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [7:0] input_axis_tdata = 0; +reg input_axis_tvalid = 0; +reg input_axis_tlast = 0; +reg input_axis_tuser = 0; + +// Outputs +wire input_axis_tready; +wire [31:0] output_fcs; +wire output_fcs_valid; + +initial begin + // myhdl integration + $from_myhdl(clk, + rst, + current_test, + input_axis_tdata, + input_axis_tvalid, + input_axis_tlast, + input_axis_tuser); + $to_myhdl(input_axis_tready, + output_fcs, + output_fcs_valid); + + // dump file + $dumpfile("test_axis_eth_fcs.lxt"); + $dumpvars(0, test_axis_eth_fcs); +end + +axis_eth_fcs +UUT ( + .clk(clk), + .rst(rst), + .input_axis_tdata(input_axis_tdata), + .input_axis_tvalid(input_axis_tvalid), + .input_axis_tready(input_axis_tready), + .input_axis_tlast(input_axis_tlast), + .input_axis_tuser(input_axis_tuser), + .output_fcs(output_fcs), + .output_fcs_valid(output_fcs_valid) +); + +endmodule diff --git a/tb/test_axis_eth_fcs_64.py b/tb/test_axis_eth_fcs_64.py new file mode 100755 index 000000000..8b4fe0bbf --- /dev/null +++ b/tb/test_axis_eth_fcs_64.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python2 +""" + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os +from Queue import Queue + +import axis_ep +import eth_ep + +module = 'axis_eth_fcs_64' + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/eth_crc_8.v") +srcs.append("../rtl/eth_crc_16.v") +srcs.append("../rtl/eth_crc_24.v") +srcs.append("../rtl/eth_crc_32.v") +srcs.append("../rtl/eth_crc_40.v") +srcs.append("../rtl/eth_crc_48.v") +srcs.append("../rtl/eth_crc_56.v") +srcs.append("../rtl/eth_crc_64.v") +srcs.append("test_%s.v" % module) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o test_%s.vvp %s" % (module, src) + +def dut_axis_eth_fcs_64(clk, + rst, + current_test, + + input_axis_tdata, + input_axis_tkeep, + input_axis_tvalid, + input_axis_tready, + input_axis_tlast, + input_axis_tuser, + + output_fcs, + output_fcs_valid): + + if os.system(build_cmd): + raise Exception("Error running build command") + return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module, + clk=clk, + rst=rst, + current_test=current_test, + + input_axis_tdata=input_axis_tdata, + input_axis_tkeep=input_axis_tkeep, + input_axis_tvalid=input_axis_tvalid, + input_axis_tready=input_axis_tready, + input_axis_tlast=input_axis_tlast, + input_axis_tuser=input_axis_tuser, + + output_fcs=output_fcs, + output_fcs_valid=output_fcs_valid) + +def bench(): + + # Parameters + + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + input_axis_tdata = Signal(intbv(0)[64:]) + input_axis_tkeep = Signal(intbv(0)[8:]) + input_axis_tvalid = Signal(bool(0)) + input_axis_tlast = Signal(bool(0)) + input_axis_tuser = Signal(bool(0)) + + # Outputs + input_axis_tready = Signal(bool(1)) + output_fcs = Signal(intbv(0)[32:]) + output_fcs_valid = Signal(bool(0)) + + # sources and sinks + source_queue = Queue() + source_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_axis_tdata, + tkeep=input_axis_tkeep, + tvalid=input_axis_tvalid, + tready=input_axis_tready, + tlast=input_axis_tlast, + tuser=input_axis_tuser, + fifo=source_queue, + pause=source_pause, + name='source') + + # DUT + dut = dut_axis_eth_fcs_64(clk, + rst, + current_test, + + input_axis_tdata, + input_axis_tkeep, + input_axis_tvalid, + input_axis_tready, + input_axis_tlast, + input_axis_tuser, + + output_fcs, + output_fcs_valid) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @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,18))+list(range(64,82)): + 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(range(payload_len)) + test_frame.update_fcs() + + axis_frame = test_frame.build_axis() + + source_queue.put(axis_frame) + yield clk.posedge + yield clk.posedge + + yield output_fcs_valid.posedge + + print(hex(int(output_fcs))) + print(hex(test_frame.eth_fcs)) + + assert output_fcs == test_frame.eth_fcs + + yield delay(100) + + raise StopSimulation + + return dut, source, clkgen, check + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/tb/test_axis_eth_fcs_64.v b/tb/test_axis_eth_fcs_64.v new file mode 100644 index 000000000..68dd4b0c0 --- /dev/null +++ b/tb/test_axis_eth_fcs_64.v @@ -0,0 +1,85 @@ +/* + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for axis_eth_fcs_64 + */ +module test_axis_eth_fcs_64; + +// Parameters + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [63:0] input_axis_tdata = 0; +reg [7:0] input_axis_tkeep = 0; +reg input_axis_tvalid = 0; +reg input_axis_tlast = 0; +reg input_axis_tuser = 0; + +// Outputs +wire input_axis_tready; +wire [31:0] output_fcs; +wire output_fcs_valid; + +initial begin + // myhdl integration + $from_myhdl(clk, + rst, + current_test, + input_axis_tdata, + input_axis_tkeep, + input_axis_tvalid, + input_axis_tlast, + input_axis_tuser); + $to_myhdl(input_axis_tready, + output_fcs, + output_fcs_valid); + + // dump file + $dumpfile("test_axis_eth_fcs_64.lxt"); + $dumpvars(0, test_axis_eth_fcs_64); +end + +axis_eth_fcs_64 +UUT ( + .clk(clk), + .rst(rst), + .input_axis_tdata(input_axis_tdata), + .input_axis_tkeep(input_axis_tkeep), + .input_axis_tvalid(input_axis_tvalid), + .input_axis_tready(input_axis_tready), + .input_axis_tlast(input_axis_tlast), + .input_axis_tuser(input_axis_tuser), + .output_fcs(output_fcs), + .output_fcs_valid(output_fcs_valid) +); + +endmodule