├── .gitignore ├── README.md ├── LICENSE ├── dualmem_widen.sv ├── dualmem_widen8.sv ├── eth_mac_1g.sv ├── rgmii_core.sv ├── oddr.sv ├── iddr.sv ├── ssio_ddr_in.sv ├── rgmii_soc.sv ├── eth_mac_1g_rgmii.sv ├── rgmii_phy_if.sv ├── eth_mac_1g_rgmii_fifo.sv ├── axis_gmii_rx.sv ├── axis_gmii_tx.sv ├── framing_top.sv ├── axis_async_fifo.sv └── rgmii_lfsr.sv /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | test/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a port of the Alex Forencich GHz RGMII Ethernet MAC to the Digilent Genesys2 board. 2 | It is intended for use with https://github.com/pulp-platform/ariane (a RISCV Linux-capable soft core). 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2019 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dualmem_widen.sv: -------------------------------------------------------------------------------- 1 | 2 | module dualmem_widen(clka, clkb, dina, dinb, addra, addrb, wea, web, douta, doutb, ena, enb); 3 | 4 | input wire clka, clkb; 5 | input [15:0] dina; 6 | input [63:0] dinb; 7 | input [10:0] addra; 8 | input [8:0] addrb; 9 | input [1:0] wea; 10 | input [1:0] web; 11 | input [0:0] ena, enb; 12 | output [15:0] douta; 13 | output [63:0] doutb; 14 | 15 | genvar r; 16 | wire [47:0] dout; 17 | 18 | /* 19 | `ifndef verilator 20 | `define RAMB16 21 | `endif 22 | */ 23 | 24 | `ifdef GENESYSII 25 | `define RAMB16 26 | `endif 27 | 28 | `ifdef RAMB16 29 | 30 | generate for (r = 0; r < 2; r=r+1) 31 | RAMB16_S9_S36 32 | RAMB16_S9_S36_inst 33 | ( 34 | .CLKA ( clka ), // Port A Clock 35 | .DOA ( douta[r*8 +: 8] ), // Port A 1-bit Data Output 36 | .DOPA ( ), 37 | .ADDRA ( addra ), // Port A 14-bit Address Input 38 | .DIA ( dina[r*8 +: 8] ), // Port A 1-bit Data Input 39 | .DIPA ( 1'b0 ), 40 | .ENA ( ena ), // Port A RAM Enable Input 41 | .SSRA ( 1'b0 ), // Port A Synchronous Set/Reset Input 42 | .WEA ( wea[r] ), // Port A Write Enable Input 43 | .CLKB ( clkb ), // Port B Clock 44 | .DOB ( doutb[r*32 +: 32] ), // Port B 1-bit Data Output 45 | .DOPB ( ), 46 | .ADDRB ( addrb ), // Port B 14-bit Address Input 47 | .DIB ( dinb[r*32 +: 32] ), // Port B 1-bit Data Input 48 | .DIPB ( 4'b0 ), 49 | .ENB ( enb ), // Port B RAM Enable Input 50 | .SSRB ( 1'b0 ), // Port B Synchronous Set/Reset Input 51 | .WEB ( web[r] ) // Port B Write Enable Input 52 | ); 53 | endgenerate 54 | 55 | `else // !`ifdef RAMB16 56 | 57 | // This bit is a placeholder 58 | 59 | infer_dpram #(.RAM_SIZE(11), .BYTE_WIDTH(8)) ram1 // RAM_SIZE is in words 60 | ( 61 | .ram_clk_a(clka), 62 | .ram_en_a(|ena), 63 | .ram_we_a({wea[1],wea[1],wea[1],wea[1],wea[0],wea[0],wea[0],wea[0]}), 64 | .ram_addr_a(addra), 65 | .ram_wrdata_a({dina,dina,dina,dina}), 66 | .ram_rddata_a({dout,douta}), 67 | .ram_clk_b(clkb), 68 | .ram_en_b(|enb), 69 | .ram_we_b({web[1],web[1],web[1],web[1],web[0],web[0],web[0],web[0]}), 70 | .ram_addr_b({2'b0,addrb}), 71 | .ram_wrdata_b(dinb), 72 | .ram_rddata_b(doutb) 73 | ); 74 | 75 | `endif 76 | 77 | endmodule // dualmem 78 | -------------------------------------------------------------------------------- /dualmem_widen8.sv: -------------------------------------------------------------------------------- 1 | 2 | module dualmem_widen8(clka, clkb, dina, dinb, addra, addrb, wea, web, douta, doutb, ena, enb); 3 | 4 | input wire clka, clkb; 5 | input [15:0] dina; 6 | input [63:0] dinb; 7 | input [12:0] addra; 8 | input [10:0] addrb; 9 | input [1:0] wea; 10 | input [1:0] web; 11 | input [0:0] ena, enb; 12 | output [15:0] douta; 13 | output [63:0] doutb; 14 | 15 | genvar r; 16 | wire [63:0] dout0; 17 | wire [255:0] dout1; 18 | wire [7:0] we0, we1, en0, en1; 19 | wire [63:0] din0; 20 | wire [255:0] din1; 21 | 22 | reg [12:0] addra_dly; 23 | reg [10:0] addrb_dly; 24 | 25 | /* 26 | `ifndef verilator 27 | `define RAMB16 28 | `endif 29 | */ 30 | 31 | `ifdef GENESYSII 32 | `define RAMB16 33 | `endif 34 | 35 | `ifdef RAMB16 36 | 37 | assign douta = dout0 >> {addra_dly[12:11],4'b0000}; 38 | assign doutb = dout1 >> {addrb_dly[10:9],6'b000000}; 39 | assign we0 = wea << {addra[12:11],1'b0}; 40 | assign we1 = web << {addrb[10:9],1'b0}; 41 | assign en0 = {ena,ena} << {addra[12:11],1'b0}; 42 | assign en1 = {enb,enb} << {addrb[10:9],1'b0}; 43 | assign din0 = {dina,dina,dina,dina}; 44 | assign din1 = {dinb,dinb,dinb,dinb}; 45 | 46 | always @(posedge clka) 47 | begin 48 | addra_dly <= addra; 49 | addrb_dly <= addrb; 50 | end 51 | 52 | generate for (r = 0; r < 8; r=r+1) 53 | RAMB16_S9_S36 54 | RAMB16_S9_S36_inst 55 | ( 56 | .CLKA ( clka ), // Port A Clock 57 | .DOA ( dout0[r*8 +: 8] ), // Port A 1-bit Data Output 58 | .DOPA ( ), 59 | .ADDRA ( addra[10:0] ), // Port A 14-bit Address Input 60 | .DIA ( din0[r*8 +: 8] ), // Port A 1-bit Data Input 61 | .DIPA ( 1'b0 ), 62 | .ENA ( en0[r] ), // Port A RAM Enable Input 63 | .SSRA ( 1'b0 ), // Port A Synchronous Set/Reset Input 64 | .WEA ( we0[r] ), // Port A Write Enable Input 65 | .CLKB ( clkb ), // Port B Clock 66 | .DOB ( dout1[r*32 +: 32] ), // Port B 1-bit Data Output 67 | .DOPB ( ), 68 | .ADDRB ( addrb[8:0] ), // Port B 14-bit Address Input 69 | .DIB ( din1[r*32 +: 32] ), // Port B 1-bit Data Input 70 | .DIPB ( 4'b0 ), 71 | .ENB ( en1[r] ), // Port B RAM Enable Input 72 | .SSRB ( 1'b0 ), // Port B Synchronous Set/Reset Input 73 | .WEB ( we1[r] ) // Port B Write Enable Input 74 | ); 75 | endgenerate 76 | 77 | `else // !`ifdef RAMB16 78 | 79 | // This bit is a placeholder 80 | 81 | infer_dpram #(.RAM_SIZE(11), .BYTE_WIDTH(8)) ram1 // RAM_SIZE is in words 82 | ( 83 | .ram_clk_a(clka), 84 | .ram_en_a(|ena), 85 | .ram_we_a({wea[1],wea[1],wea[1],wea[1],wea[0],wea[0],wea[0],wea[0]}), 86 | .ram_addr_a(addra), 87 | .ram_wrdata_a({dina,dina,dina,dina}), 88 | .ram_rddata_a({dout,douta}), 89 | .ram_clk_b(clkb), 90 | .ram_en_b(|enb), 91 | .ram_we_b({web[1],web[1],web[1],web[1],web[0],web[0],web[0],web[0]}), 92 | .ram_addr_b({2'b0,addrb}), 93 | .ram_wrdata_b(dinb), 94 | .ram_rddata_b(doutb) 95 | ); 96 | 97 | `endif 98 | 99 | endmodule // dualmem 100 | -------------------------------------------------------------------------------- /eth_mac_1g.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * 1G Ethernet MAC 29 | */ 30 | module eth_mac_1g # 31 | ( 32 | parameter ENABLE_PADDING = 1, 33 | parameter MIN_FRAME_LENGTH = 64 34 | ) 35 | ( 36 | input wire rx_clk, 37 | input wire rx_rst, 38 | input wire tx_clk, 39 | input wire tx_rst, 40 | 41 | /* 42 | * AXI input 43 | */ 44 | input wire [7:0] tx_axis_tdata, 45 | input wire tx_axis_tvalid, 46 | output wire tx_axis_tready, 47 | input wire tx_axis_tlast, 48 | input wire tx_axis_tuser, 49 | 50 | /* 51 | * AXI output 52 | */ 53 | output wire [7:0] rx_axis_tdata, 54 | output wire rx_axis_tvalid, 55 | output wire rx_axis_tlast, 56 | output wire rx_axis_tuser, 57 | 58 | /* 59 | * GMII interface 60 | */ 61 | input wire [7:0] gmii_rxd, 62 | input wire gmii_rx_dv, 63 | input wire gmii_rx_er, 64 | output wire [7:0] gmii_txd, 65 | output wire gmii_tx_en, 66 | output wire gmii_tx_er, 67 | 68 | /* 69 | * Control 70 | */ 71 | input wire rx_clk_enable, 72 | input wire tx_clk_enable, 73 | input wire rx_mii_select, 74 | input wire tx_mii_select, 75 | 76 | /* 77 | * Status 78 | */ 79 | output wire rx_error_bad_frame, 80 | output wire rx_error_bad_fcs, 81 | output wire [31:0] rx_fcs_reg, 82 | output wire [31:0] tx_fcs_reg, 83 | 84 | /* 85 | * Configuration 86 | */ 87 | input wire [7:0] ifg_delay 88 | ); 89 | 90 | axis_gmii_rx 91 | axis_gmii_rx_inst ( 92 | .clk(rx_clk), 93 | .rst(rx_rst), 94 | .gmii_rxd(gmii_rxd), 95 | .gmii_rx_dv(gmii_rx_dv), 96 | .gmii_rx_er(gmii_rx_er), 97 | .m_axis_tdata(rx_axis_tdata), 98 | .m_axis_tvalid(rx_axis_tvalid), 99 | .m_axis_tlast(rx_axis_tlast), 100 | .m_axis_tuser(rx_axis_tuser), 101 | .clk_enable(rx_clk_enable), 102 | .mii_select(rx_mii_select), 103 | .error_bad_frame(rx_error_bad_frame), 104 | .error_bad_fcs(rx_error_bad_fcs), 105 | .fcs_reg(rx_fcs_reg) 106 | ); 107 | 108 | axis_gmii_tx #( 109 | .ENABLE_PADDING(ENABLE_PADDING), 110 | .MIN_FRAME_LENGTH(MIN_FRAME_LENGTH) 111 | ) 112 | axis_gmii_tx_inst ( 113 | .clk(tx_clk), 114 | .rst(tx_rst), 115 | .s_axis_tdata(tx_axis_tdata), 116 | .s_axis_tvalid(tx_axis_tvalid), 117 | .s_axis_tready(tx_axis_tready), 118 | .s_axis_tlast(tx_axis_tlast), 119 | .s_axis_tuser(tx_axis_tuser), 120 | .gmii_txd(gmii_txd), 121 | .gmii_tx_en(gmii_tx_en), 122 | .gmii_tx_er(gmii_tx_er), 123 | .clk_enable(tx_clk_enable), 124 | .mii_select(tx_mii_select), 125 | .ifg_delay(ifg_delay), 126 | .fcs_reg(tx_fcs_reg) 127 | ); 128 | 129 | endmodule 130 | -------------------------------------------------------------------------------- /rgmii_core.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2014-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * FPGA core logic 29 | */ 30 | module rgmii_core # 31 | ( 32 | parameter TARGET = "XILINX" 33 | ) 34 | ( 35 | /* 36 | * Clock: 125MHz 37 | * Synchronous reset 38 | */ 39 | input wire clk, 40 | input wire clk90, 41 | input wire rst, 42 | 43 | /* 44 | * Ethernet: 1000BASE-T RGMII 45 | */ 46 | input wire phy_rx_clk, 47 | input wire [3:0] phy_rxd, 48 | input wire phy_rx_ctl, 49 | output wire phy_tx_clk, 50 | output wire [3:0] phy_txd, 51 | output wire phy_tx_ctl, 52 | output wire phy_reset_n, 53 | input wire phy_int_n, 54 | input wire phy_pme_n, 55 | output wire mac_gmii_tx_en, 56 | 57 | /* 58 | * AXI input 59 | */ 60 | 61 | input wire tx_axis_tvalid, 62 | input wire tx_axis_tlast, 63 | input wire [7:0] tx_axis_tdata, 64 | output wire tx_axis_tready, 65 | input wire tx_axis_tuser, 66 | 67 | /* 68 | * AXI output 69 | */ 70 | 71 | output wire [7:0] rx_axis_tdata, 72 | output wire rx_axis_tvalid, 73 | output wire rx_axis_tlast, 74 | output wire rx_axis_tuser, 75 | 76 | /* 77 | * Status 78 | */ 79 | 80 | output wire [31:0] rx_fcs_reg, 81 | output wire [31:0] tx_fcs_reg 82 | 83 | ); 84 | 85 | assign phy_reset_n = !rst; 86 | 87 | eth_mac_1g_rgmii_fifo #( 88 | .TARGET(TARGET), 89 | .IODDR_STYLE("IODDR"), 90 | .CLOCK_INPUT_STYLE("BUFR"), 91 | .USE_CLK90("TRUE"), 92 | .ENABLE_PADDING(1), 93 | .MIN_FRAME_LENGTH(64), 94 | .TX_FIFO_ADDR_WIDTH(12), 95 | .TX_FRAME_FIFO(1), 96 | .RX_FIFO_ADDR_WIDTH(12), 97 | .RX_FRAME_FIFO(1) 98 | ) 99 | eth_mac_inst ( 100 | .gtx_clk(clk), 101 | .gtx_clk90(clk90), 102 | .gtx_rst(rst), 103 | .logic_clk(clk), 104 | .logic_rst(rst), 105 | 106 | .tx_axis_tdata(tx_axis_tdata), 107 | .tx_axis_tvalid(tx_axis_tvalid), 108 | .tx_axis_tready(tx_axis_tready), 109 | .tx_axis_tlast(tx_axis_tlast), 110 | .tx_axis_tuser(tx_axis_tuser), 111 | 112 | .rx_axis_tdata(rx_axis_tdata), 113 | .rx_axis_tvalid(rx_axis_tvalid), 114 | .rx_axis_tready(1'b1), 115 | .rx_axis_tlast(rx_axis_tlast), 116 | .rx_axis_tuser(rx_axis_tuser), 117 | 118 | .rgmii_rx_clk(phy_rx_clk), 119 | .rgmii_rxd(phy_rxd), 120 | .rgmii_rx_ctl(phy_rx_ctl), 121 | .rgmii_tx_clk(phy_tx_clk), 122 | .rgmii_txd(phy_txd), 123 | .rgmii_tx_ctl(phy_tx_ctl), 124 | .mac_gmii_tx_en(mac_gmii_tx_en), 125 | 126 | .tx_fifo_overflow(), 127 | .tx_fifo_bad_frame(), 128 | .tx_fifo_good_frame(), 129 | .rx_error_bad_frame(), 130 | .rx_error_bad_fcs(), 131 | .rx_fcs_reg(rx_fcs_reg), 132 | .tx_fcs_reg(tx_fcs_reg), 133 | .rx_fifo_overflow(), 134 | .rx_fifo_bad_frame(), 135 | .rx_fifo_good_frame(), 136 | .speed(), 137 | 138 | .ifg_delay(12) 139 | ); 140 | 141 | endmodule 142 | -------------------------------------------------------------------------------- /oddr.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2016-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * Generic ODDR module 29 | */ 30 | module oddr # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Width of register in bits 39 | parameter WIDTH = 1 40 | ) 41 | ( 42 | input wire clk, 43 | 44 | input wire [WIDTH-1:0] d1, 45 | input wire [WIDTH-1:0] d2, 46 | 47 | output wire [WIDTH-1:0] q 48 | ); 49 | 50 | /* 51 | 52 | Provides a consistent output DDR flip flop across multiple FPGA families 53 | _____ _____ _____ _____ 54 | clk ____/ \_____/ \_____/ \_____/ \_____ 55 | _ ___________ ___________ ___________ ___________ __ 56 | d1 _X____D0_____X____D2_____X____D4_____X____D6_____X__ 57 | _ ___________ ___________ ___________ ___________ __ 58 | d2 _X____D1_____X____D3_____X____D5_____X____D7_____X__ 59 | _____ _____ _____ _____ _____ _____ _____ _____ ____ 60 | d _____X_D0__X_D1__X_D2__X_D3__X_D4__X_D5__X_D6__X_D7_ 61 | 62 | */ 63 | 64 | genvar n; 65 | 66 | generate 67 | 68 | if (TARGET == "XILINX") begin 69 | for (n = 0; n < WIDTH; n = n + 1) begin : oddr 70 | if (IODDR_STYLE == "IODDR") begin 71 | ODDR #( 72 | .DDR_CLK_EDGE("SAME_EDGE"), 73 | .SRTYPE("ASYNC") 74 | ) 75 | oddr_inst ( 76 | .Q(q[n]), 77 | .C(clk), 78 | .CE(1'b1), 79 | .D1(d1[n]), 80 | .D2(d2[n]), 81 | .R(1'b0), 82 | .S(1'b0) 83 | ); 84 | end else if (IODDR_STYLE == "IODDR2") begin 85 | ODDR2 #( 86 | .DDR_ALIGNMENT("C0"), 87 | .SRTYPE("ASYNC") 88 | ) 89 | oddr_inst ( 90 | .Q(q[n]), 91 | .C0(clk), 92 | .C1(~clk), 93 | .CE(1'b1), 94 | .D0(d1[n]), 95 | .D1(d2[n]), 96 | .R(1'b0), 97 | .S(1'b0) 98 | ); 99 | end 100 | end 101 | end else if (TARGET == "ALTERA") begin 102 | altddio_out #( 103 | .WIDTH(WIDTH), 104 | .POWER_UP_HIGH("OFF"), 105 | .OE_REG("UNUSED") 106 | ) 107 | altddio_out_inst ( 108 | .aset(1'b0), 109 | .datain_h(d1), 110 | .datain_l(d2), 111 | .outclocken(1'b1), 112 | .outclock(clk), 113 | .aclr(1'b0), 114 | .dataout(q) 115 | ); 116 | end else begin 117 | reg [WIDTH-1:0] d_reg_1 = {WIDTH{1'b0}}; 118 | reg [WIDTH-1:0] d_reg_2 = {WIDTH{1'b0}}; 119 | 120 | reg [WIDTH-1:0] q_reg = {WIDTH{1'b0}}; 121 | 122 | always @(posedge clk) begin 123 | d_reg_1 <= d1; 124 | d_reg_2 <= d2; 125 | end 126 | 127 | always @(posedge clk) begin 128 | q_reg <= d1; 129 | end 130 | 131 | always @(negedge clk) begin 132 | q_reg <= d_reg_2; 133 | end 134 | 135 | assign q = q_reg; 136 | end 137 | 138 | endgenerate 139 | 140 | endmodule 141 | -------------------------------------------------------------------------------- /iddr.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2016-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * Generic IDDR module 29 | */ 30 | module iddr # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Width of register in bits 39 | parameter WIDTH = 1 40 | ) 41 | ( 42 | input wire clk, 43 | 44 | input wire [WIDTH-1:0] d, 45 | 46 | output wire [WIDTH-1:0] q1, 47 | output wire [WIDTH-1:0] q2 48 | ); 49 | 50 | /* 51 | 52 | Provides a consistent input DDR flip flop across multiple FPGA families 53 | _____ _____ _____ _____ ____ 54 | clk ____/ \_____/ \_____/ \_____/ \_____/ 55 | _ _____ _____ _____ _____ _____ _____ _____ _____ _____ _ 56 | d _X_D0__X_D1__X_D2__X_D3__X_D4__X_D5__X_D6__X_D7__X_D8__X_ 57 | _______ ___________ ___________ ___________ ___________ _ 58 | q1 _______X___________X____D0_____X____D2_____X____D4_____X_ 59 | _______ ___________ ___________ ___________ ___________ _ 60 | q2 _______X___________X____D1_____X____D3_____X____D5_____X_ 61 | 62 | */ 63 | 64 | genvar n; 65 | 66 | generate 67 | 68 | if (TARGET == "XILINX") begin 69 | for (n = 0; n < WIDTH; n = n + 1) begin : iddr 70 | if (IODDR_STYLE == "IODDR") begin 71 | IDDR #( 72 | .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), 73 | .SRTYPE("ASYNC") 74 | ) 75 | iddr_inst ( 76 | .Q1(q1[n]), 77 | .Q2(q2[n]), 78 | .C(clk), 79 | .CE(1'b1), 80 | .D(d[n]), 81 | .R(1'b0), 82 | .S(1'b0) 83 | ); 84 | end else if (IODDR_STYLE == "IODDR2") begin 85 | IDDR2 #( 86 | .DDR_ALIGNMENT("C0") 87 | ) 88 | iddr_inst ( 89 | .Q0(q1[n]), 90 | .Q1(q2[n]), 91 | .C0(clk), 92 | .C1(~clk), 93 | .CE(1'b1), 94 | .D(d[n]), 95 | .R(1'b0), 96 | .S(1'b0) 97 | ); 98 | end 99 | end 100 | end else if (TARGET == "ALTERA") begin 101 | wire [WIDTH-1:0] q1_int; 102 | reg [WIDTH-1:0] q1_delay; 103 | 104 | altddio_in #( 105 | .WIDTH(WIDTH), 106 | .POWER_UP_HIGH("OFF") 107 | ) 108 | altddio_in_inst ( 109 | .aset(1'b0), 110 | .datain(d), 111 | .inclocken(1'b1), 112 | .inclock(clk), 113 | .aclr(1'b0), 114 | .dataout_h(q1_int), 115 | .dataout_l(q2) 116 | ); 117 | 118 | always @(posedge clk) begin 119 | q1_delay <= q1_int; 120 | end 121 | 122 | assign q1 = q1_delay; 123 | end else begin 124 | reg [WIDTH-1:0] d_reg_1 = {WIDTH{1'b0}}; 125 | reg [WIDTH-1:0] d_reg_2 = {WIDTH{1'b0}}; 126 | 127 | reg [WIDTH-1:0] q_reg_1 = {WIDTH{1'b0}}; 128 | reg [WIDTH-1:0] q_reg_2 = {WIDTH{1'b0}}; 129 | 130 | always @(posedge clk) begin 131 | d_reg_1 <= d; 132 | end 133 | 134 | always @(negedge clk) begin 135 | d_reg_2 <= d; 136 | end 137 | 138 | always @(posedge clk) begin 139 | q_reg_1 <= d_reg_1; 140 | q_reg_2 <= d_reg_2; 141 | end 142 | 143 | assign q1 = q_reg_1; 144 | assign q2 = q_reg_2; 145 | end 146 | 147 | endgenerate 148 | 149 | endmodule 150 | -------------------------------------------------------------------------------- /ssio_ddr_in.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2016-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * Generic source synchronous DDR input 29 | */ 30 | module ssio_ddr_in # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2") 39 | // Use BUFR for Virtex-5, Virtex-6, 7-series 40 | // Use BUFG for Ultrascale 41 | // Use BUFIO2 for Spartan-6 42 | parameter CLOCK_INPUT_STYLE = "BUFIO2", 43 | // Width of register in bits 44 | parameter WIDTH = 1 45 | ) 46 | ( 47 | input wire input_clk, 48 | 49 | input wire [WIDTH-1:0] input_d, 50 | 51 | output wire output_clk, 52 | 53 | output wire [WIDTH-1:0] output_q1, 54 | output wire [WIDTH-1:0] output_q2 55 | ); 56 | 57 | wire clk_int; 58 | wire clk_io; 59 | 60 | generate 61 | 62 | if (TARGET == "XILINX") begin 63 | 64 | // use Xilinx clocking primitives 65 | 66 | if (CLOCK_INPUT_STYLE == "BUFG") begin 67 | 68 | // buffer RX clock 69 | BUFG 70 | clk_bufg ( 71 | .I(input_clk), 72 | .O(clk_int) 73 | ); 74 | 75 | // pass through RX clock to logic and input buffers 76 | assign clk_io = clk_int; 77 | assign output_clk = clk_int; 78 | 79 | end else if (CLOCK_INPUT_STYLE == "BUFR") begin 80 | 81 | assign clk_int = input_clk; 82 | 83 | // pass through RX clock to input buffers 84 | BUFIO 85 | clk_bufio ( 86 | .I(clk_int), 87 | .O(clk_io) 88 | ); 89 | 90 | // pass through RX clock to logic 91 | BUFR #( 92 | .BUFR_DIVIDE("BYPASS") 93 | ) 94 | clk_bufr ( 95 | .I(clk_int), 96 | .O(output_clk), 97 | .CE(1'b1), 98 | .CLR(1'b0) 99 | ); 100 | 101 | end else if (CLOCK_INPUT_STYLE == "BUFIO") begin 102 | 103 | assign clk_int = input_clk; 104 | 105 | // pass through RX clock to input buffers 106 | BUFIO 107 | clk_bufio ( 108 | .I(clk_int), 109 | .O(clk_io) 110 | ); 111 | 112 | // pass through RX clock to MAC 113 | BUFG 114 | clk_bufg ( 115 | .I(clk_int), 116 | .O(output_clk) 117 | ); 118 | 119 | end else if (CLOCK_INPUT_STYLE == "BUFIO2") begin 120 | 121 | // pass through RX clock to input buffers 122 | BUFIO2 #( 123 | .DIVIDE(1), 124 | .DIVIDE_BYPASS("TRUE"), 125 | .I_INVERT("FALSE"), 126 | .USE_DOUBLER("FALSE") 127 | ) 128 | clk_bufio ( 129 | .I(input_clk), 130 | .DIVCLK(clk_int), 131 | .IOCLK(clk_io), 132 | .SERDESSTROBE() 133 | ); 134 | 135 | // pass through RX clock to MAC 136 | BUFG 137 | clk_bufg ( 138 | .I(clk_int), 139 | .O(output_clk) 140 | ); 141 | 142 | end 143 | 144 | end else begin 145 | 146 | // pass through RX clock to input buffers 147 | assign clk_io = input_clk; 148 | 149 | // pass through RX clock to logic 150 | assign clk_int = input_clk; 151 | assign output_clk = clk_int; 152 | 153 | end 154 | 155 | endgenerate 156 | 157 | iddr #( 158 | .TARGET(TARGET), 159 | .IODDR_STYLE(IODDR_STYLE), 160 | .WIDTH(WIDTH) 161 | ) 162 | data_iddr_inst ( 163 | .clk(clk_io), 164 | .d(input_d), 165 | .q1(output_q1), 166 | .q2(output_q2) 167 | ); 168 | 169 | endmodule 170 | -------------------------------------------------------------------------------- /rgmii_soc.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2014-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | based on fpga.v 24 | 25 | */ 26 | 27 | // Language: Verilog 2001 28 | 29 | /* 30 | * RGMII top-level module 31 | */ 32 | 33 | module rgmii_soc ( 34 | // Internal 125 MHz clock 35 | input clk_int, 36 | input rst_int, 37 | input clk90_int, 38 | input clk_200_int, 39 | 40 | /* 41 | * Ethernet: 1000BASE-T RGMII 42 | */ 43 | input wire phy_rx_clk, 44 | input wire [3:0] phy_rxd, 45 | input wire phy_rx_ctl, 46 | output wire phy_tx_clk, 47 | output wire [3:0] phy_txd, 48 | output wire phy_tx_ctl, 49 | output wire phy_reset_n, 50 | input wire phy_int_n, 51 | input wire phy_pme_n, 52 | output wire mac_gmii_tx_en, 53 | 54 | /* 55 | * AXI input 56 | */ 57 | input wire tx_axis_tvalid, 58 | input wire tx_axis_tlast, 59 | input wire [7:0] tx_axis_tdata, 60 | output wire tx_axis_tready, 61 | input wire tx_axis_tuser, 62 | 63 | /* 64 | * AXI output 65 | */ 66 | output wire [7:0] rx_axis_tdata, 67 | output wire rx_axis_tvalid, 68 | output wire rx_axis_tlast, 69 | output rx_axis_tuser, 70 | 71 | /* 72 | * Status 73 | */ 74 | 75 | output wire [31:0] rx_fcs_reg, 76 | output wire [31:0] tx_fcs_reg 77 | 78 | ); 79 | 80 | // IODELAY elements for RGMII interface to PHY 81 | wire [3:0] phy_rxd_delay; 82 | wire phy_rx_ctl_delay; 83 | 84 | IDELAYCTRL 85 | idelayctrl_inst 86 | ( 87 | .REFCLK(clk_200_int), 88 | .RST(rst_int), 89 | .RDY() 90 | ); 91 | 92 | IDELAYE2 #( 93 | .IDELAY_TYPE("FIXED") 94 | ) 95 | phy_rxd_idelay_0 96 | ( 97 | .IDATAIN(phy_rxd[0]), 98 | .DATAOUT(phy_rxd_delay[0]), 99 | .DATAIN(1'b0), 100 | .C(1'b0), 101 | .CE(1'b0), 102 | .INC(1'b0), 103 | .CINVCTRL(1'b0), 104 | .CNTVALUEIN(5'd0), 105 | .CNTVALUEOUT(), 106 | .LD(1'b0), 107 | .LDPIPEEN(1'b0), 108 | .REGRST(1'b0) 109 | ); 110 | 111 | IDELAYE2 #( 112 | .IDELAY_TYPE("FIXED") 113 | ) 114 | phy_rxd_idelay_1 115 | ( 116 | .IDATAIN(phy_rxd[1]), 117 | .DATAOUT(phy_rxd_delay[1]), 118 | .DATAIN(1'b0), 119 | .C(1'b0), 120 | .CE(1'b0), 121 | .INC(1'b0), 122 | .CINVCTRL(1'b0), 123 | .CNTVALUEIN(5'd0), 124 | .CNTVALUEOUT(), 125 | .LD(1'b0), 126 | .LDPIPEEN(1'b0), 127 | .REGRST(1'b0) 128 | ); 129 | 130 | IDELAYE2 #( 131 | .IDELAY_TYPE("FIXED") 132 | ) 133 | phy_rxd_idelay_2 134 | ( 135 | .IDATAIN(phy_rxd[2]), 136 | .DATAOUT(phy_rxd_delay[2]), 137 | .DATAIN(1'b0), 138 | .C(1'b0), 139 | .CE(1'b0), 140 | .INC(1'b0), 141 | .CINVCTRL(1'b0), 142 | .CNTVALUEIN(5'd0), 143 | .CNTVALUEOUT(), 144 | .LD(1'b0), 145 | .LDPIPEEN(1'b0), 146 | .REGRST(1'b0) 147 | ); 148 | 149 | IDELAYE2 #( 150 | .IDELAY_TYPE("FIXED") 151 | ) 152 | phy_rxd_idelay_3 153 | ( 154 | .IDATAIN(phy_rxd[3]), 155 | .DATAOUT(phy_rxd_delay[3]), 156 | .DATAIN(1'b0), 157 | .C(1'b0), 158 | .CE(1'b0), 159 | .INC(1'b0), 160 | .CINVCTRL(1'b0), 161 | .CNTVALUEIN(5'd0), 162 | .CNTVALUEOUT(), 163 | .LD(1'b0), 164 | .LDPIPEEN(1'b0), 165 | .REGRST(1'b0) 166 | ); 167 | 168 | IDELAYE2 #( 169 | .IDELAY_VALUE(0), 170 | .IDELAY_TYPE("FIXED") 171 | ) 172 | phy_rx_ctl_idelay 173 | ( 174 | .IDATAIN(phy_rx_ctl), 175 | .DATAOUT(phy_rx_ctl_delay), 176 | .DATAIN(1'b0), 177 | .C(1'b0), 178 | .CE(1'b0), 179 | .INC(1'b0), 180 | .CINVCTRL(1'b0), 181 | .CNTVALUEIN(5'd0), 182 | .CNTVALUEOUT(), 183 | .LD(1'b0), 184 | .LDPIPEEN(1'b0), 185 | .REGRST(1'b0) 186 | ); 187 | 188 | rgmii_core 189 | core_inst ( 190 | /* 191 | * Clock: 125MHz 192 | * Synchronous reset 193 | */ 194 | .clk(clk_int), 195 | .clk90(clk90_int), 196 | .rst(rst_int), 197 | /* 198 | * Ethernet: 1000BASE-T RGMII 199 | */ 200 | .phy_rx_clk(phy_rx_clk), 201 | .phy_rxd(phy_rxd_delay), 202 | .phy_rx_ctl(phy_rx_ctl_delay), 203 | .phy_tx_clk(phy_tx_clk), 204 | .phy_txd(phy_txd), 205 | .phy_tx_ctl(phy_tx_ctl), 206 | .phy_reset_n(phy_reset_n), 207 | .phy_int_n(phy_int_n), 208 | .phy_pme_n(phy_pme_n), 209 | .mac_gmii_tx_en(mac_gmii_tx_en), 210 | .tx_axis_tdata(tx_axis_tdata), 211 | .tx_axis_tvalid(tx_axis_tvalid), 212 | .tx_axis_tready(tx_axis_tready), 213 | .tx_axis_tlast(tx_axis_tlast), 214 | .tx_axis_tuser(tx_axis_tuser), 215 | .rx_axis_tdata(rx_axis_tdata), 216 | .rx_axis_tvalid(rx_axis_tvalid), 217 | .rx_axis_tlast(rx_axis_tlast), 218 | .rx_axis_tuser(rx_axis_tuser), 219 | .rx_fcs_reg(rx_fcs_reg), 220 | .tx_fcs_reg(tx_fcs_reg) 221 | ); 222 | 223 | endmodule 224 | -------------------------------------------------------------------------------- /eth_mac_1g_rgmii.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * 1G Ethernet MAC with RGMII interface 29 | */ 30 | module eth_mac_1g_rgmii # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2") 39 | // Use BUFR for Virtex-5, Virtex-6, 7-series 40 | // Use BUFG for Ultrascale 41 | // Use BUFIO2 for Spartan-6 42 | parameter CLOCK_INPUT_STYLE = "BUFIO2", 43 | // Use 90 degree clock for RGMII transmit ("TRUE", "FALSE") 44 | parameter USE_CLK90 = "TRUE", 45 | parameter ENABLE_PADDING = 1, 46 | parameter MIN_FRAME_LENGTH = 64 47 | ) 48 | ( 49 | input wire gtx_clk, 50 | input wire gtx_clk90, 51 | input wire gtx_rst, 52 | output wire rx_clk, 53 | output wire rx_rst, 54 | output wire tx_clk, 55 | output wire tx_rst, 56 | 57 | /* 58 | * AXI input 59 | */ 60 | input wire [7:0] tx_axis_tdata, 61 | input wire tx_axis_tvalid, 62 | output wire tx_axis_tready, 63 | input wire tx_axis_tlast, 64 | input wire tx_axis_tuser, 65 | 66 | /* 67 | * AXI output 68 | */ 69 | output wire [7:0] rx_axis_tdata, 70 | output wire rx_axis_tvalid, 71 | output wire rx_axis_tlast, 72 | output wire rx_axis_tuser, 73 | 74 | /* 75 | * RGMII interface 76 | */ 77 | input wire rgmii_rx_clk, 78 | input wire [3:0] rgmii_rxd, 79 | input wire rgmii_rx_ctl, 80 | output wire rgmii_tx_clk, 81 | output wire [3:0] rgmii_txd, 82 | output wire rgmii_tx_ctl, 83 | output wire mac_gmii_tx_en, 84 | 85 | /* 86 | * Status 87 | */ 88 | output wire rx_error_bad_frame, 89 | output wire rx_error_bad_fcs, 90 | output wire [1:0] speed, 91 | output wire [31:0] rx_fcs_reg, 92 | output wire [31:0] tx_fcs_reg, 93 | 94 | /* 95 | * Configuration 96 | */ 97 | input wire [7:0] ifg_delay 98 | ); 99 | 100 | wire [7:0] mac_gmii_rxd; 101 | wire mac_gmii_rx_dv; 102 | wire mac_gmii_rx_er; 103 | wire mac_gmii_tx_clk_en; 104 | wire [7:0] mac_gmii_txd; 105 | wire mac_gmii_tx_er; 106 | 107 | reg [1:0] speed_reg; 108 | wire mii_select; 109 | 110 | reg tx_mii_select_1; 111 | reg tx_mii_select_2; 112 | reg tx_mii_select_3; 113 | 114 | always @(posedge tx_clk) begin 115 | tx_mii_select_1 <= mii_select; 116 | tx_mii_select_2 <= tx_mii_select_1; 117 | tx_mii_select_3 <= tx_mii_select_2; 118 | end 119 | 120 | reg rx_mii_select_1; 121 | reg rx_mii_select_2; 122 | reg rx_mii_select_3; 123 | 124 | always @(posedge rx_clk) begin 125 | rx_mii_select_1 <= mii_select; 126 | rx_mii_select_2 <= rx_mii_select_1; 127 | rx_mii_select_3 <= rx_mii_select_2; 128 | end 129 | 130 | // PHY speed detection 131 | reg [2:0] rx_prescale; 132 | 133 | always @(posedge rx_clk) begin 134 | rx_prescale <= rx_prescale + 3'd1; 135 | end 136 | 137 | reg rx_prescale_sync_1; 138 | reg rx_prescale_sync_2; 139 | reg rx_prescale_sync_3; 140 | 141 | always @(posedge gtx_clk) begin 142 | rx_prescale_sync_1 <= rx_prescale[2]; 143 | rx_prescale_sync_2 <= rx_prescale_sync_1; 144 | rx_prescale_sync_3 <= rx_prescale_sync_2; 145 | end 146 | 147 | reg [6:0] rx_speed_count_1; 148 | reg [1:0] rx_speed_count_2; 149 | 150 | always @(posedge gtx_clk) begin 151 | if (gtx_rst) begin 152 | rx_speed_count_1 <= 0; 153 | rx_speed_count_2 <= 0; 154 | speed_reg <= 2'b10; 155 | end else begin 156 | rx_speed_count_1 <= rx_speed_count_1 + 1; 157 | 158 | if (rx_prescale_sync_2 ^ rx_prescale_sync_3) begin 159 | rx_speed_count_2 <= rx_speed_count_2 + 1; 160 | end 161 | 162 | if (&rx_speed_count_1) begin 163 | // reference count overflow - 10M 164 | rx_speed_count_1 <= 0; 165 | rx_speed_count_2 <= 0; 166 | speed_reg <= 2'b00; 167 | end 168 | 169 | if (&rx_speed_count_2) begin 170 | // prescaled count overflow - 100M or 1000M 171 | rx_speed_count_1 <= 0; 172 | rx_speed_count_2 <= 0; 173 | if (rx_speed_count_1[6:5]) begin 174 | // large reference count - 100M 175 | speed_reg <= 2'b01; 176 | end else begin 177 | // small reference count - 1000M 178 | speed_reg <= 2'b10; 179 | end 180 | end 181 | end 182 | end 183 | 184 | assign speed = speed_reg; 185 | assign mii_select = speed != 2'b10; 186 | 187 | rgmii_phy_if #( 188 | .TARGET(TARGET), 189 | .IODDR_STYLE(IODDR_STYLE), 190 | .CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE), 191 | .USE_CLK90(USE_CLK90) 192 | ) 193 | rgmii_phy_if_inst ( 194 | .clk(gtx_clk), 195 | .clk90(gtx_clk90), 196 | .rst(gtx_rst), 197 | 198 | .mac_gmii_rx_clk(rx_clk), 199 | .mac_gmii_rx_rst(rx_rst), 200 | .mac_gmii_rxd(mac_gmii_rxd), 201 | .mac_gmii_rx_dv(mac_gmii_rx_dv), 202 | .mac_gmii_rx_er(mac_gmii_rx_er), 203 | .mac_gmii_tx_clk(tx_clk), 204 | .mac_gmii_tx_rst(tx_rst), 205 | .mac_gmii_tx_clk_en(mac_gmii_tx_clk_en), 206 | .mac_gmii_txd(mac_gmii_txd), 207 | .mac_gmii_tx_en(mac_gmii_tx_en), 208 | .mac_gmii_tx_er(mac_gmii_tx_er), 209 | 210 | .phy_rgmii_rx_clk(rgmii_rx_clk), 211 | .phy_rgmii_rxd(rgmii_rxd), 212 | .phy_rgmii_rx_ctl(rgmii_rx_ctl), 213 | .phy_rgmii_tx_clk(rgmii_tx_clk), 214 | .phy_rgmii_txd(rgmii_txd), 215 | .phy_rgmii_tx_ctl(rgmii_tx_ctl), 216 | 217 | .speed(speed) 218 | ); 219 | 220 | eth_mac_1g #( 221 | .ENABLE_PADDING(ENABLE_PADDING), 222 | .MIN_FRAME_LENGTH(MIN_FRAME_LENGTH) 223 | ) 224 | eth_mac_1g_inst ( 225 | .tx_clk(tx_clk), 226 | .tx_rst(tx_rst), 227 | .rx_clk(rx_clk), 228 | .rx_rst(rx_rst), 229 | .tx_axis_tdata(tx_axis_tdata), 230 | .tx_axis_tvalid(tx_axis_tvalid), 231 | .tx_axis_tready(tx_axis_tready), 232 | .tx_axis_tlast(tx_axis_tlast), 233 | .tx_axis_tuser(tx_axis_tuser), 234 | .rx_axis_tdata(rx_axis_tdata), 235 | .rx_axis_tvalid(rx_axis_tvalid), 236 | .rx_axis_tlast(rx_axis_tlast), 237 | .rx_axis_tuser(rx_axis_tuser), 238 | .gmii_rxd(mac_gmii_rxd), 239 | .gmii_rx_dv(mac_gmii_rx_dv), 240 | .gmii_rx_er(mac_gmii_rx_er), 241 | .gmii_txd(mac_gmii_txd), 242 | .gmii_tx_en(mac_gmii_tx_en), 243 | .gmii_tx_er(mac_gmii_tx_er), 244 | .rx_clk_enable(1'b1), 245 | .tx_clk_enable(mac_gmii_tx_clk_en), 246 | .rx_mii_select(rx_mii_select_3), 247 | .tx_mii_select(tx_mii_select_3), 248 | .rx_error_bad_frame(rx_error_bad_frame), 249 | .rx_error_bad_fcs(rx_error_bad_fcs), 250 | .rx_fcs_reg(rx_fcs_reg), 251 | .tx_fcs_reg(tx_fcs_reg), 252 | .ifg_delay(ifg_delay) 253 | ); 254 | 255 | endmodule 256 | -------------------------------------------------------------------------------- /rgmii_phy_if.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * RGMII PHY interface 29 | */ 30 | module rgmii_phy_if # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2") 39 | // Use BUFR for Virtex-5, Virtex-6, 7-series 40 | // Use BUFG for Ultrascale 41 | // Use BUFIO2 for Spartan-6 42 | parameter CLOCK_INPUT_STYLE = "BUFIO2", 43 | // Use 90 degree clock for RGMII transmit ("TRUE", "FALSE") 44 | parameter USE_CLK90 = "TRUE" 45 | ) 46 | ( 47 | input wire clk, 48 | input wire clk90, 49 | input wire rst, 50 | 51 | /* 52 | * GMII interface to MAC 53 | */ 54 | output wire mac_gmii_rx_clk, 55 | output wire mac_gmii_rx_rst, 56 | output wire [7:0] mac_gmii_rxd, 57 | output wire mac_gmii_rx_dv, 58 | output wire mac_gmii_rx_er, 59 | output wire mac_gmii_tx_clk, 60 | output wire mac_gmii_tx_rst, 61 | output wire mac_gmii_tx_clk_en, 62 | input wire [7:0] mac_gmii_txd, 63 | input wire mac_gmii_tx_en, 64 | input wire mac_gmii_tx_er, 65 | 66 | /* 67 | * RGMII interface to PHY 68 | */ 69 | input wire phy_rgmii_rx_clk, 70 | input wire [3:0] phy_rgmii_rxd, 71 | input wire phy_rgmii_rx_ctl, 72 | output wire phy_rgmii_tx_clk, 73 | output wire [3:0] phy_rgmii_txd, 74 | output wire phy_rgmii_tx_ctl, 75 | 76 | /* 77 | * Control 78 | */ 79 | input wire [1:0] speed 80 | ); 81 | 82 | // receive 83 | 84 | wire rgmii_rx_ctl_1; 85 | wire rgmii_rx_ctl_2; 86 | 87 | ssio_ddr_in # 88 | ( 89 | .TARGET(TARGET), 90 | .CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE), 91 | .IODDR_STYLE(IODDR_STYLE), 92 | .WIDTH(5) 93 | ) 94 | rx_ssio_ddr_inst ( 95 | .input_clk(phy_rgmii_rx_clk), 96 | .input_d({phy_rgmii_rxd, phy_rgmii_rx_ctl}), 97 | .output_clk(mac_gmii_rx_clk), 98 | .output_q1({mac_gmii_rxd[3:0], rgmii_rx_ctl_1}), 99 | .output_q2({mac_gmii_rxd[7:4], rgmii_rx_ctl_2}) 100 | ); 101 | 102 | assign mac_gmii_rx_dv = rgmii_rx_ctl_1; 103 | assign mac_gmii_rx_er = rgmii_rx_ctl_1 ^ rgmii_rx_ctl_2; 104 | 105 | // transmit 106 | 107 | reg rgmii_tx_clk_1; 108 | reg rgmii_tx_clk_2; 109 | reg rgmii_tx_clk_rise; 110 | reg rgmii_tx_clk_fall; 111 | 112 | reg [5:0] count_reg, count_next; 113 | 114 | always @(posedge clk) begin 115 | if (rst) begin 116 | rgmii_tx_clk_1 <= 1'b1; 117 | rgmii_tx_clk_2 <= 1'b0; 118 | rgmii_tx_clk_rise <= 1'b1; 119 | rgmii_tx_clk_fall <= 1'b1; 120 | count_reg <= 0; 121 | end else begin 122 | rgmii_tx_clk_1 <= rgmii_tx_clk_2; 123 | 124 | if (speed == 2'b00) begin 125 | // 10M 126 | count_reg <= count_reg + 1; 127 | rgmii_tx_clk_rise <= 1'b0; 128 | rgmii_tx_clk_fall <= 1'b0; 129 | if (count_reg == 24) begin 130 | rgmii_tx_clk_1 <= 1'b1; 131 | rgmii_tx_clk_2 <= 1'b1; 132 | rgmii_tx_clk_rise <= 1'b1; 133 | end else if (count_reg >= 49) begin 134 | rgmii_tx_clk_1 <= 1'b0; 135 | rgmii_tx_clk_2 <= 1'b0; 136 | rgmii_tx_clk_fall <= 1'b1; 137 | count_reg <= 0; 138 | end 139 | end else if (speed == 2'b01) begin 140 | // 100M 141 | count_reg <= count_reg + 1; 142 | rgmii_tx_clk_rise <= 1'b0; 143 | rgmii_tx_clk_fall <= 1'b0; 144 | if (count_reg == 2) begin 145 | rgmii_tx_clk_1 <= 1'b1; 146 | rgmii_tx_clk_2 <= 1'b1; 147 | rgmii_tx_clk_rise <= 1'b1; 148 | end else if (count_reg >= 4) begin 149 | rgmii_tx_clk_2 <= 1'b0; 150 | rgmii_tx_clk_fall <= 1'b1; 151 | count_reg <= 0; 152 | end 153 | end else begin 154 | // 1000M 155 | rgmii_tx_clk_1 <= 1'b1; 156 | rgmii_tx_clk_2 <= 1'b0; 157 | rgmii_tx_clk_rise <= 1'b1; 158 | rgmii_tx_clk_fall <= 1'b1; 159 | end 160 | end 161 | end 162 | 163 | reg [3:0] rgmii_txd_1; 164 | reg [3:0] rgmii_txd_2; 165 | reg rgmii_tx_ctl_1; 166 | reg rgmii_tx_ctl_2; 167 | 168 | reg gmii_clk_en; 169 | 170 | always @* begin 171 | if (speed == 2'b00) begin 172 | // 10M 173 | rgmii_txd_1 = mac_gmii_txd[3:0]; 174 | rgmii_txd_2 = mac_gmii_txd[3:0]; 175 | if (rgmii_tx_clk_2) begin 176 | rgmii_tx_ctl_1 = mac_gmii_tx_en; 177 | rgmii_tx_ctl_2 = mac_gmii_tx_en; 178 | end else begin 179 | rgmii_tx_ctl_1 = mac_gmii_tx_en ^ mac_gmii_tx_er; 180 | rgmii_tx_ctl_2 = mac_gmii_tx_en ^ mac_gmii_tx_er; 181 | end 182 | gmii_clk_en = rgmii_tx_clk_fall; 183 | end else if (speed == 2'b01) begin 184 | // 100M 185 | rgmii_txd_1 = mac_gmii_txd[3:0]; 186 | rgmii_txd_2 = mac_gmii_txd[3:0]; 187 | if (rgmii_tx_clk_2) begin 188 | rgmii_tx_ctl_1 = mac_gmii_tx_en; 189 | rgmii_tx_ctl_2 = mac_gmii_tx_en; 190 | end else begin 191 | rgmii_tx_ctl_1 = mac_gmii_tx_en ^ mac_gmii_tx_er; 192 | rgmii_tx_ctl_2 = mac_gmii_tx_en ^ mac_gmii_tx_er; 193 | end 194 | gmii_clk_en = rgmii_tx_clk_fall; 195 | end else begin 196 | // 1000M 197 | rgmii_txd_1 = mac_gmii_txd[3:0]; 198 | rgmii_txd_2 = mac_gmii_txd[7:4]; 199 | rgmii_tx_ctl_1 = mac_gmii_tx_en; 200 | rgmii_tx_ctl_2 = mac_gmii_tx_en ^ mac_gmii_tx_er; 201 | gmii_clk_en = 1; 202 | end 203 | end 204 | 205 | wire phy_rgmii_tx_clk_new; 206 | wire [3:0] phy_rgmii_txd_new; 207 | wire phy_rgmii_tx_ctl_new; 208 | 209 | oddr #( 210 | .TARGET(TARGET), 211 | .IODDR_STYLE(IODDR_STYLE), 212 | .WIDTH(1) 213 | ) 214 | clk_oddr_inst ( 215 | .clk(USE_CLK90 == "TRUE" ? clk90 : clk), 216 | .d1(rgmii_tx_clk_1), 217 | .d2(rgmii_tx_clk_2), 218 | .q(phy_rgmii_tx_clk) 219 | ); 220 | 221 | oddr #( 222 | .TARGET(TARGET), 223 | .IODDR_STYLE(IODDR_STYLE), 224 | .WIDTH(5) 225 | ) 226 | data_oddr_inst ( 227 | .clk(clk), 228 | .d1({rgmii_txd_1, rgmii_tx_ctl_1}), 229 | .d2({rgmii_txd_2, rgmii_tx_ctl_2}), 230 | .q({phy_rgmii_txd, phy_rgmii_tx_ctl}) 231 | ); 232 | 233 | assign mac_gmii_tx_clk = clk; 234 | 235 | assign mac_gmii_tx_clk_en = gmii_clk_en; 236 | 237 | // reset sync 238 | reg [3:0] tx_rst_reg; 239 | assign mac_gmii_tx_rst = tx_rst_reg[0]; 240 | 241 | always @(posedge mac_gmii_tx_clk or posedge rst) begin 242 | if (rst) begin 243 | tx_rst_reg <= 4'hf; 244 | end else begin 245 | tx_rst_reg <= {1'b0, tx_rst_reg[3:1]}; 246 | end 247 | end 248 | 249 | reg [3:0] rx_rst_reg; 250 | assign mac_gmii_rx_rst = rx_rst_reg[0]; 251 | 252 | always @(posedge mac_gmii_rx_clk or posedge rst) begin 253 | if (rst) begin 254 | rx_rst_reg <= 4'hf; 255 | end else begin 256 | rx_rst_reg <= {1'b0, rx_rst_reg[3:1]}; 257 | end 258 | end 259 | 260 | endmodule 261 | -------------------------------------------------------------------------------- /eth_mac_1g_rgmii_fifo.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * 1G Ethernet MAC with RGMII interface and TX and RX FIFOs 29 | */ 30 | module eth_mac_1g_rgmii_fifo # 31 | ( 32 | // target ("SIM", "GENERIC", "XILINX", "ALTERA") 33 | parameter TARGET = "GENERIC", 34 | // IODDR style ("IODDR", "IODDR2") 35 | // Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale 36 | // Use IODDR2 for Spartan-6 37 | parameter IODDR_STYLE = "IODDR2", 38 | // Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2") 39 | // Use BUFR for Virtex-5, Virtex-6, 7-series 40 | // Use BUFG for Ultrascale 41 | // Use BUFIO2 for Spartan-6 42 | parameter CLOCK_INPUT_STYLE = "BUFIO2", 43 | // Use 90 degree clock for RGMII transmit ("TRUE", "FALSE") 44 | parameter USE_CLK90 = "TRUE", 45 | parameter ENABLE_PADDING = 1, 46 | parameter MIN_FRAME_LENGTH = 64, 47 | parameter TX_FIFO_ADDR_WIDTH = 12, 48 | parameter TX_FRAME_FIFO = 1, 49 | parameter TX_DROP_BAD_FRAME = TX_FRAME_FIFO, 50 | parameter TX_DROP_WHEN_FULL = 0, 51 | parameter RX_FIFO_ADDR_WIDTH = 12, 52 | parameter RX_FRAME_FIFO = 1, 53 | parameter RX_DROP_BAD_FRAME = RX_FRAME_FIFO, 54 | parameter RX_DROP_WHEN_FULL = RX_FRAME_FIFO 55 | ) 56 | ( 57 | input wire gtx_clk, 58 | input wire gtx_clk90, 59 | input wire gtx_rst, 60 | input wire logic_clk, 61 | input wire logic_rst, 62 | 63 | /* 64 | * AXI input 65 | */ 66 | input wire [7:0] tx_axis_tdata, 67 | input wire tx_axis_tvalid, 68 | output wire tx_axis_tready, 69 | input wire tx_axis_tlast, 70 | input wire tx_axis_tuser, 71 | 72 | /* 73 | * AXI output 74 | */ 75 | output wire [7:0] rx_axis_tdata, 76 | output wire rx_axis_tvalid, 77 | input wire rx_axis_tready, 78 | output wire rx_axis_tlast, 79 | output wire rx_axis_tuser, 80 | 81 | /* 82 | * RGMII interface 83 | */ 84 | input wire rgmii_rx_clk, 85 | input wire [3:0] rgmii_rxd, 86 | input wire rgmii_rx_ctl, 87 | output wire rgmii_tx_clk, 88 | output wire [3:0] rgmii_txd, 89 | output wire rgmii_tx_ctl, 90 | output wire mac_gmii_tx_en, 91 | 92 | /* 93 | * Status 94 | */ 95 | output wire tx_fifo_overflow, 96 | output wire tx_fifo_bad_frame, 97 | output wire tx_fifo_good_frame, 98 | output wire rx_error_bad_frame, 99 | output wire rx_error_bad_fcs, 100 | output wire rx_fifo_overflow, 101 | output wire rx_fifo_bad_frame, 102 | output wire rx_fifo_good_frame, 103 | output wire [1:0] speed, 104 | output wire [31:0] rx_fcs_reg, 105 | output wire [31:0] tx_fcs_reg, 106 | 107 | /* 108 | * Configuration 109 | */ 110 | input wire [7:0] ifg_delay 111 | ); 112 | 113 | wire tx_clk; 114 | wire rx_clk; 115 | wire tx_rst; 116 | wire rx_rst; 117 | 118 | wire [7:0] tx_fifo_axis_tdata; 119 | wire tx_fifo_axis_tvalid; 120 | wire tx_fifo_axis_tready; 121 | wire tx_fifo_axis_tlast; 122 | wire tx_fifo_axis_tuser; 123 | 124 | wire [7:0] rx_fifo_axis_tdata; 125 | wire rx_fifo_axis_tvalid; 126 | wire rx_fifo_axis_tlast; 127 | wire rx_fifo_axis_tuser; 128 | // synchronize MAC status signals into logic clock domain 129 | wire rx_error_bad_frame_int; 130 | wire rx_error_bad_fcs_int; 131 | 132 | reg [1:0] rx_sync_reg_1; 133 | reg [1:0] rx_sync_reg_2; 134 | reg [1:0] rx_sync_reg_3; 135 | reg [1:0] rx_sync_reg_4; 136 | 137 | assign rx_error_bad_frame = rx_sync_reg_3[0] ^ rx_sync_reg_4[0]; 138 | assign rx_error_bad_fcs = rx_sync_reg_3[1] ^ rx_sync_reg_4[1]; 139 | 140 | always @(posedge rx_clk or posedge rx_rst) begin 141 | if (rx_rst) begin 142 | rx_sync_reg_1 <= 2'd0; 143 | end else begin 144 | rx_sync_reg_1 <= rx_sync_reg_1 ^ {rx_error_bad_frame_int, rx_error_bad_frame_int}; 145 | end 146 | end 147 | 148 | always @(posedge logic_clk or posedge logic_rst) begin 149 | if (logic_rst) begin 150 | rx_sync_reg_2 <= 2'd0; 151 | rx_sync_reg_3 <= 2'd0; 152 | rx_sync_reg_4 <= 2'd0; 153 | end else begin 154 | rx_sync_reg_2 <= rx_sync_reg_1; 155 | rx_sync_reg_3 <= rx_sync_reg_2; 156 | rx_sync_reg_4 <= rx_sync_reg_3; 157 | end 158 | end 159 | 160 | 161 | wire [1:0] speed_int; 162 | 163 | reg [1:0] speed_sync_reg_1; 164 | reg [1:0] speed_sync_reg_2; 165 | 166 | assign speed = speed_sync_reg_2; 167 | 168 | always @(posedge logic_clk) begin 169 | speed_sync_reg_1 <= speed_int; 170 | speed_sync_reg_2 <= speed_sync_reg_1; 171 | end 172 | 173 | eth_mac_1g_rgmii #( 174 | .TARGET(TARGET), 175 | .IODDR_STYLE(IODDR_STYLE), 176 | .CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE), 177 | .USE_CLK90(USE_CLK90), 178 | .ENABLE_PADDING(ENABLE_PADDING), 179 | .MIN_FRAME_LENGTH(MIN_FRAME_LENGTH) 180 | ) 181 | eth_mac_1g_rgmii_inst ( 182 | .gtx_clk(gtx_clk), 183 | .gtx_clk90(gtx_clk90), 184 | .gtx_rst(gtx_rst), 185 | .tx_clk(tx_clk), 186 | .tx_rst(tx_rst), 187 | .rx_clk(rx_clk), 188 | .rx_rst(rx_rst), 189 | .tx_axis_tdata(tx_fifo_axis_tdata), 190 | .tx_axis_tvalid(tx_fifo_axis_tvalid), 191 | .tx_axis_tready(tx_fifo_axis_tready), 192 | .tx_axis_tlast(tx_fifo_axis_tlast), 193 | .tx_axis_tuser(tx_fifo_axis_tuser), 194 | .rx_axis_tdata(rx_fifo_axis_tdata), 195 | .rx_axis_tvalid(rx_fifo_axis_tvalid), 196 | .rx_axis_tlast(rx_fifo_axis_tlast), 197 | .rx_axis_tuser(rx_fifo_axis_tuser), 198 | .rgmii_rx_clk(rgmii_rx_clk), 199 | .rgmii_rxd(rgmii_rxd), 200 | .rgmii_rx_ctl(rgmii_rx_ctl), 201 | .rgmii_tx_clk(rgmii_tx_clk), 202 | .rgmii_txd(rgmii_txd), 203 | .rgmii_tx_ctl(rgmii_tx_ctl), 204 | .mac_gmii_tx_en(mac_gmii_tx_en), 205 | .rx_error_bad_frame(rx_error_bad_frame_int), 206 | .rx_error_bad_fcs(rx_error_bad_fcs_int), 207 | .rx_fcs_reg(rx_fcs_reg), 208 | .tx_fcs_reg(tx_fcs_reg), 209 | .speed(speed_int), 210 | .ifg_delay(ifg_delay) 211 | ); 212 | 213 | axis_async_fifo #( 214 | .ADDR_WIDTH(TX_FIFO_ADDR_WIDTH), 215 | .DATA_WIDTH(8), 216 | .KEEP_ENABLE(0), 217 | .LAST_ENABLE(1), 218 | .ID_ENABLE(0), 219 | .DEST_ENABLE(0), 220 | .USER_ENABLE(1), 221 | .USER_WIDTH(1), 222 | .FRAME_FIFO(TX_FRAME_FIFO), 223 | .USER_BAD_FRAME_VALUE(1'b1), 224 | .USER_BAD_FRAME_MASK(1'b1), 225 | .DROP_BAD_FRAME(TX_DROP_BAD_FRAME), 226 | .DROP_WHEN_FULL(TX_DROP_WHEN_FULL) 227 | ) 228 | tx_fifo ( 229 | // Common reset 230 | .async_rst(logic_rst | tx_rst), 231 | // AXI input 232 | .s_clk(logic_clk), 233 | .s_axis_tdata(tx_axis_tdata), 234 | .s_axis_tkeep(0), 235 | .s_axis_tvalid(tx_axis_tvalid), 236 | .s_axis_tready(tx_axis_tready), 237 | .s_axis_tlast(tx_axis_tlast), 238 | .s_axis_tid(0), 239 | .s_axis_tdest(0), 240 | .s_axis_tuser(tx_axis_tuser), 241 | // AXI output 242 | .m_clk(tx_clk), 243 | .m_axis_tdata(tx_fifo_axis_tdata), 244 | .m_axis_tkeep(), 245 | .m_axis_tvalid(tx_fifo_axis_tvalid), 246 | .m_axis_tready(tx_fifo_axis_tready), 247 | .m_axis_tlast(tx_fifo_axis_tlast), 248 | .m_axis_tid(), 249 | .m_axis_tdest(), 250 | .m_axis_tuser(tx_fifo_axis_tuser), 251 | // Status 252 | .s_status_overflow(tx_fifo_overflow), 253 | .s_status_bad_frame(tx_fifo_bad_frame), 254 | .s_status_good_frame(tx_fifo_good_frame), 255 | .m_status_overflow(), 256 | .m_status_bad_frame(), 257 | .m_status_good_frame() 258 | ); 259 | 260 | axis_async_fifo #( 261 | .ADDR_WIDTH(RX_FIFO_ADDR_WIDTH), 262 | .DATA_WIDTH(8), 263 | .KEEP_ENABLE(0), 264 | .LAST_ENABLE(1), 265 | .ID_ENABLE(0), 266 | .DEST_ENABLE(0), 267 | .USER_ENABLE(1), 268 | .USER_WIDTH(1), 269 | .FRAME_FIFO(TX_FRAME_FIFO), 270 | .USER_BAD_FRAME_VALUE(1'b1), 271 | .USER_BAD_FRAME_MASK(1'b1), 272 | .DROP_BAD_FRAME(TX_DROP_BAD_FRAME), 273 | .DROP_WHEN_FULL(TX_DROP_WHEN_FULL) 274 | ) 275 | rx_fifo ( 276 | // Common reset 277 | .async_rst(rx_rst | logic_rst), 278 | // AXI input 279 | .s_clk(rx_clk), 280 | .s_axis_tdata(rx_fifo_axis_tdata), 281 | .s_axis_tkeep(0), 282 | .s_axis_tvalid(rx_fifo_axis_tvalid), 283 | .s_axis_tready(), 284 | .s_axis_tlast(rx_fifo_axis_tlast), 285 | .s_axis_tid(0), 286 | .s_axis_tdest(0), 287 | .s_axis_tuser(rx_fifo_axis_tuser), 288 | // AXI output 289 | .m_clk(logic_clk), 290 | .m_axis_tdata(rx_axis_tdata), 291 | .m_axis_tkeep(), 292 | .m_axis_tvalid(rx_axis_tvalid), 293 | .m_axis_tready(rx_axis_tready), 294 | .m_axis_tlast(rx_axis_tlast), 295 | .m_axis_tid(), 296 | .m_axis_tdest(), 297 | .m_axis_tuser(rx_axis_tuser), 298 | // Status 299 | .s_status_overflow(), 300 | .s_status_bad_frame(), 301 | .s_status_good_frame(), 302 | .m_status_overflow(rx_fifo_overflow), 303 | .m_status_bad_frame(rx_fifo_bad_frame), 304 | .m_status_good_frame(rx_fifo_good_frame) 305 | ); 306 | 307 | endmodule 308 | -------------------------------------------------------------------------------- /axis_gmii_rx.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | origin https://github.com/alexforencich/verilog-ethernet.git 24 | commit ebe31e811cee9db615a7d5ec8472f972f3368b90 25 | Author: Alex Forencich 26 | Date: Thu Nov 8 13:15:47 2018 -0800 27 | 28 | Modified by Jonathan Kimmitt to extract CRC bytes 29 | 30 | lfsr submodule renamed rgmii_lfsr to avoid name clash with main project 31 | */ 32 | 33 | // Language: Verilog 2001 34 | 35 | /* 36 | * AXI4-Stream GMII frame receiver (GMII in, AXI out) 37 | */ 38 | module axis_gmii_rx 39 | ( 40 | input wire clk, 41 | input wire rst, 42 | 43 | /* 44 | * GMII input 45 | */ 46 | input wire [7:0] gmii_rxd, 47 | input wire gmii_rx_dv, 48 | input wire gmii_rx_er, 49 | 50 | /* 51 | * AXI output 52 | */ 53 | output wire [7:0] m_axis_tdata, 54 | output wire m_axis_tvalid, 55 | output wire m_axis_tlast, 56 | output wire m_axis_tuser, 57 | 58 | /* 59 | * Control 60 | */ 61 | input wire clk_enable, 62 | input wire mii_select, 63 | 64 | /* 65 | * Status 66 | */ 67 | output wire error_bad_frame, 68 | output wire error_bad_fcs, 69 | 70 | /* debug */ 71 | output reg [31:0] fcs_reg 72 | ); 73 | 74 | localparam [7:0] 75 | ETH_PRE = 8'h55, 76 | ETH_SFD = 8'hD5; 77 | 78 | localparam [2:0] 79 | STATE_IDLE = 3'd0, 80 | STATE_PAYLOAD = 3'd1, 81 | STATE_WAIT_LAST = 3'd2, 82 | STATE_CRC = 3'd3; 83 | 84 | reg [2:0] state_reg, state_next; 85 | 86 | // datapath control signals 87 | reg reset_crc; 88 | reg update_crc; 89 | 90 | reg mii_odd; 91 | reg mii_locked; 92 | 93 | reg [7:0] gmii_rxd_d0; 94 | reg [7:0] gmii_rxd_d1; 95 | reg [7:0] gmii_rxd_d2; 96 | reg [7:0] gmii_rxd_d3; 97 | reg [7:0] gmii_rxd_d4; 98 | 99 | reg gmii_rx_dv_d0; 100 | reg gmii_rx_dv_d1; 101 | reg gmii_rx_dv_d2; 102 | reg gmii_rx_dv_d3; 103 | reg gmii_rx_dv_d4; 104 | 105 | reg gmii_rx_er_d0; 106 | reg gmii_rx_er_d1; 107 | reg gmii_rx_er_d2; 108 | reg gmii_rx_er_d3; 109 | reg gmii_rx_er_d4; 110 | 111 | reg [7:0] m_axis_tdata_reg, m_axis_tdata_next; 112 | reg m_axis_tvalid_reg, m_axis_tvalid_next; 113 | reg m_axis_tlast_reg, m_axis_tlast_next; 114 | reg m_axis_tuser_reg, m_axis_tuser_next; 115 | 116 | reg error_bad_frame_reg, error_bad_frame_next; 117 | reg error_bad_fcs_reg, error_bad_fcs_next; 118 | reg [31:0] fcs_next; 119 | reg [31:0] crc_state; 120 | reg [1:0] crc_cnt, crc_cnt_next; 121 | 122 | wire [31:0] crc_next; 123 | 124 | assign m_axis_tdata = m_axis_tdata_reg; 125 | assign m_axis_tvalid = m_axis_tvalid_reg; 126 | assign m_axis_tlast = m_axis_tlast_reg; 127 | assign m_axis_tuser = m_axis_tuser_reg; 128 | 129 | assign error_bad_frame = error_bad_frame_reg; 130 | assign error_bad_fcs = error_bad_fcs_reg; 131 | 132 | rgmii_lfsr #( 133 | .LFSR_WIDTH(32), 134 | .LFSR_POLY(32'h4c11db7), 135 | .LFSR_CONFIG("GALOIS"), 136 | .LFSR_FEED_FORWARD(0), 137 | .REVERSE(1), 138 | .DATA_WIDTH(8), 139 | .STYLE("AUTO") 140 | ) 141 | eth_crc_8 ( 142 | .data_in(gmii_rxd_d4), 143 | .state_in(crc_state), 144 | .data_out(), 145 | .state_out(crc_next) 146 | ); 147 | 148 | always @* begin 149 | state_next = STATE_IDLE; 150 | 151 | reset_crc = 1'b0; 152 | update_crc = 1'b0; 153 | 154 | m_axis_tdata_next = 8'd0; 155 | m_axis_tvalid_next = 1'b0; 156 | m_axis_tlast_next = 1'b0; 157 | m_axis_tuser_next = 1'b0; 158 | 159 | error_bad_frame_next = 1'b0; 160 | error_bad_fcs_next = 1'b0; 161 | fcs_next = fcs_reg; 162 | crc_cnt_next = crc_cnt; 163 | 164 | if (!clk_enable) begin 165 | // clock disabled - hold state 166 | state_next = state_reg; 167 | end else if (mii_select && !mii_odd) begin 168 | // MII even cycle - hold state 169 | state_next = state_reg; 170 | end else begin 171 | case (state_reg) 172 | STATE_IDLE: begin 173 | // idle state - wait for packet 174 | reset_crc = 1'b1; 175 | 176 | if (gmii_rx_dv_d4 && !gmii_rx_er_d4 && gmii_rxd_d4 == ETH_SFD) begin 177 | state_next = STATE_PAYLOAD; 178 | end else begin 179 | state_next = STATE_IDLE; 180 | end 181 | end 182 | STATE_PAYLOAD: begin 183 | // read payload 184 | update_crc = 1'b1; 185 | 186 | m_axis_tdata_next = gmii_rxd_d4; 187 | m_axis_tvalid_next = 1'b1; 188 | 189 | if (gmii_rx_dv_d4 && gmii_rx_er_d4) begin 190 | // error 191 | m_axis_tlast_next = 1'b1; 192 | m_axis_tuser_next = 1'b1; 193 | error_bad_frame_next = 1'b1; 194 | fcs_next = 32'HDEADBEEF; 195 | state_next = STATE_WAIT_LAST; 196 | end else if (!gmii_rx_dv) begin 197 | // end of packet 198 | if (gmii_rx_er_d0 || gmii_rx_er_d1 || gmii_rx_er_d2 || gmii_rx_er_d3) begin 199 | // error received in FCS bytes 200 | m_axis_tuser_next = 1'b1; 201 | error_bad_frame_next = 1'b1; 202 | end else if ({gmii_rxd_d0, gmii_rxd_d1, gmii_rxd_d2, gmii_rxd_d3} == ~crc_next) begin 203 | // FCS good 204 | m_axis_tuser_next = 1'b0; 205 | end else begin 206 | // FCS bad 207 | m_axis_tuser_next = 1'b1; 208 | error_bad_frame_next = 1'b1; 209 | error_bad_fcs_next = 1'b1; 210 | end 211 | crc_cnt_next = 2'b0; 212 | state_next = STATE_CRC; 213 | end else begin 214 | state_next = STATE_PAYLOAD; 215 | end 216 | end 217 | STATE_CRC: begin 218 | // wait for CRC 219 | update_crc = 1'b1; 220 | 221 | m_axis_tdata_next = gmii_rxd_d4; 222 | m_axis_tvalid_next = 1'b1; 223 | 224 | crc_cnt_next = crc_cnt + 1; 225 | if (&crc_cnt) begin 226 | // end of packet + CRC bytes 227 | fcs_next = crc_next; 228 | m_axis_tlast_next = 1'b1; 229 | state_next = STATE_IDLE; 230 | end else begin 231 | fcs_next = 32'b0; 232 | state_next = STATE_CRC; 233 | end 234 | end 235 | STATE_WAIT_LAST: begin 236 | // wait for end of packet 237 | 238 | if (~gmii_rx_dv) begin 239 | state_next = STATE_IDLE; 240 | end else begin 241 | state_next = STATE_WAIT_LAST; 242 | end 243 | end 244 | default:; 245 | endcase 246 | end 247 | end 248 | 249 | always @(posedge clk) begin 250 | if (rst) begin 251 | state_reg <= STATE_IDLE; 252 | 253 | m_axis_tvalid_reg <= 1'b0; 254 | 255 | error_bad_frame_reg <= 1'b0; 256 | error_bad_fcs_reg <= 1'b0; 257 | 258 | fcs_reg <= 32'hFFFFFFFF; 259 | crc_state <= 32'hFFFFFFFF; 260 | crc_cnt <= 2'b0; 261 | 262 | mii_locked <= 1'b0; 263 | mii_odd <= 1'b0; 264 | 265 | gmii_rx_dv_d0 <= 1'b0; 266 | gmii_rx_dv_d1 <= 1'b0; 267 | gmii_rx_dv_d2 <= 1'b0; 268 | gmii_rx_dv_d3 <= 1'b0; 269 | gmii_rx_dv_d4 <= 1'b0; 270 | end else begin 271 | state_reg <= state_next; 272 | 273 | m_axis_tvalid_reg <= m_axis_tvalid_next; 274 | 275 | error_bad_frame_reg <= error_bad_frame_next; 276 | error_bad_fcs_reg <= error_bad_fcs_next; 277 | 278 | fcs_reg <= fcs_next; 279 | crc_cnt <= crc_cnt_next; 280 | // datapath 281 | if (reset_crc) begin 282 | crc_state <= 32'hFFFFFFFF; 283 | end else if (update_crc) begin 284 | crc_state <= crc_next; 285 | end 286 | 287 | if (clk_enable) begin 288 | if (mii_select) begin 289 | mii_odd <= !mii_odd; 290 | 291 | if (mii_locked) begin 292 | mii_locked <= gmii_rx_dv; 293 | end else if (gmii_rx_dv && {gmii_rxd[3:0], gmii_rxd_d0[7:4]} == ETH_SFD) begin 294 | mii_locked <= 1'b1; 295 | mii_odd <= 1'b1; 296 | end 297 | 298 | if (mii_odd) begin 299 | gmii_rx_dv_d0 <= gmii_rx_dv & gmii_rx_dv_d0; 300 | gmii_rx_dv_d1 <= gmii_rx_dv_d0 & gmii_rx_dv; 301 | gmii_rx_dv_d2 <= gmii_rx_dv_d1 & gmii_rx_dv; 302 | gmii_rx_dv_d3 <= gmii_rx_dv_d2 & gmii_rx_dv; 303 | gmii_rx_dv_d4 <= gmii_rx_dv_d3 & gmii_rx_dv; 304 | end else begin 305 | gmii_rx_dv_d0 <= gmii_rx_dv; 306 | end 307 | end else begin 308 | gmii_rx_dv_d0 <= gmii_rx_dv; 309 | gmii_rx_dv_d1 <= gmii_rx_dv_d0 & gmii_rx_dv; 310 | gmii_rx_dv_d2 <= gmii_rx_dv_d1 & gmii_rx_dv; 311 | gmii_rx_dv_d3 <= gmii_rx_dv_d2 & gmii_rx_dv; 312 | gmii_rx_dv_d4 <= gmii_rx_dv_d3 & gmii_rx_dv; 313 | end 314 | end 315 | end 316 | 317 | m_axis_tdata_reg <= m_axis_tdata_next; 318 | m_axis_tlast_reg <= m_axis_tlast_next; 319 | m_axis_tuser_reg <= m_axis_tuser_next; 320 | 321 | // delay input 322 | if (clk_enable) begin 323 | if (mii_select) begin 324 | gmii_rxd_d0 <= {gmii_rxd[3:0], gmii_rxd_d0[7:4]}; 325 | 326 | if (mii_odd) begin 327 | gmii_rxd_d1 <= gmii_rxd_d0; 328 | gmii_rxd_d2 <= gmii_rxd_d1; 329 | gmii_rxd_d3 <= gmii_rxd_d2; 330 | gmii_rxd_d4 <= gmii_rxd_d3; 331 | 332 | gmii_rx_er_d0 <= gmii_rx_er | gmii_rx_er_d0; 333 | gmii_rx_er_d1 <= gmii_rx_er_d0; 334 | gmii_rx_er_d2 <= gmii_rx_er_d1; 335 | gmii_rx_er_d3 <= gmii_rx_er_d2; 336 | gmii_rx_er_d4 <= gmii_rx_er_d3; 337 | end else begin 338 | gmii_rx_er_d0 <= gmii_rx_er; 339 | end 340 | end else begin 341 | gmii_rxd_d0 <= gmii_rxd; 342 | gmii_rxd_d1 <= gmii_rxd_d0; 343 | gmii_rxd_d2 <= gmii_rxd_d1; 344 | gmii_rxd_d3 <= gmii_rxd_d2; 345 | gmii_rxd_d4 <= gmii_rxd_d3; 346 | 347 | gmii_rx_er_d0 <= gmii_rx_er; 348 | gmii_rx_er_d1 <= gmii_rx_er_d0; 349 | gmii_rx_er_d2 <= gmii_rx_er_d1; 350 | gmii_rx_er_d3 <= gmii_rx_er_d2; 351 | gmii_rx_er_d4 <= gmii_rx_er_d3; 352 | end 353 | end 354 | end 355 | 356 | endmodule 357 | -------------------------------------------------------------------------------- /axis_gmii_tx.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | origin https://github.com/alexforencich/verilog-ethernet.git 24 | commit ebe31e811cee9db615a7d5ec8472f972f3368b90 25 | Author: Alex Forencich 26 | Date: Thu Nov 8 13:15:47 2018 -0800 27 | 28 | Modified by Jonathan Kimmitt to extract CRC bytes 29 | 30 | lfsr submodule renamed rgmii_lfsr to avoid name clash with main project 31 | */ 32 | 33 | // Language: Verilog 2001 34 | 35 | /* 36 | * AXI4-Stream GMII frame transmitter (AXI in, GMII out) 37 | */ 38 | module axis_gmii_tx # 39 | ( 40 | parameter ENABLE_PADDING = 1, 41 | parameter MIN_FRAME_LENGTH = 64 42 | ) 43 | ( 44 | input wire clk, 45 | input wire rst, 46 | 47 | /* 48 | * AXI input 49 | */ 50 | input wire [7:0] s_axis_tdata, 51 | input wire s_axis_tvalid, 52 | output wire s_axis_tready, 53 | input wire s_axis_tlast, 54 | input wire s_axis_tuser, 55 | 56 | /* 57 | * GMII output 58 | */ 59 | output wire [7:0] gmii_txd, 60 | output wire gmii_tx_en, 61 | output wire gmii_tx_er, 62 | 63 | /* 64 | * Control 65 | */ 66 | input wire clk_enable, 67 | input wire mii_select, 68 | 69 | /* 70 | * Configuration 71 | */ 72 | input wire [7:0] ifg_delay, 73 | 74 | /* debug */ 75 | output reg [31:0] fcs_reg 76 | ); 77 | 78 | localparam [7:0] 79 | ETH_PRE = 8'h55, 80 | ETH_SFD = 8'hD5; 81 | 82 | localparam [2:0] 83 | STATE_IDLE = 3'd0, 84 | STATE_PREAMBLE = 3'd1, 85 | STATE_PAYLOAD = 3'd2, 86 | STATE_LAST = 3'd3, 87 | STATE_PAD = 3'd4, 88 | STATE_FCS = 3'd5, 89 | STATE_WAIT_END = 3'd6, 90 | STATE_IFG = 3'd7; 91 | 92 | reg [2:0] state_reg, state_next; 93 | 94 | // datapath control signals 95 | reg reset_crc; 96 | reg update_crc; 97 | 98 | reg [7:0] s_tdata_reg, s_tdata_next, ifg_reg, ifg_next; 99 | 100 | reg mii_odd_reg, mii_odd_next; 101 | reg [3:0] mii_msn_reg, mii_msn_next; 102 | 103 | reg [15:0] frame_ptr_reg, frame_ptr_next; 104 | 105 | reg [7:0] gmii_txd_reg, gmii_txd_next; 106 | reg gmii_tx_en_reg, gmii_tx_en_next; 107 | reg gmii_tx_er_reg, gmii_tx_er_next; 108 | 109 | reg s_axis_tready_reg, s_axis_tready_next; 110 | reg [31:0] crc_state, fcs_next; 111 | 112 | wire [31:0] crc_next; 113 | 114 | assign s_axis_tready = s_axis_tready_reg; 115 | 116 | assign gmii_txd = gmii_txd_reg; 117 | assign gmii_tx_en = gmii_tx_en_reg; 118 | assign gmii_tx_er = gmii_tx_er_reg; 119 | 120 | rgmii_lfsr #( 121 | .LFSR_WIDTH(32), 122 | .LFSR_POLY(32'h4c11db7), 123 | .LFSR_CONFIG("GALOIS"), 124 | .LFSR_FEED_FORWARD(0), 125 | .REVERSE(1), 126 | .DATA_WIDTH(8), 127 | .STYLE("AUTO") 128 | ) 129 | eth_crc_8 ( 130 | .data_in(s_tdata_reg), 131 | .state_in(crc_state), 132 | .data_out(), 133 | .state_out(crc_next) 134 | ); 135 | 136 | always @* begin 137 | state_next = STATE_IDLE; 138 | 139 | reset_crc = 1'b0; 140 | update_crc = 1'b0; 141 | 142 | mii_odd_next = mii_odd_reg; 143 | mii_msn_next = mii_msn_reg; 144 | 145 | frame_ptr_next = frame_ptr_reg; 146 | fcs_next = fcs_reg; 147 | ifg_next = ifg_reg; 148 | 149 | s_axis_tready_next = 1'b0; 150 | 151 | s_tdata_next = s_tdata_reg; 152 | 153 | gmii_txd_next = 8'd0; 154 | gmii_tx_en_next = 1'b0; 155 | gmii_tx_er_next = 1'b0; 156 | 157 | if (!clk_enable) begin 158 | // clock disabled - hold state and outputs 159 | gmii_txd_next = gmii_txd_reg; 160 | gmii_tx_en_next = gmii_tx_en_reg; 161 | gmii_tx_er_next = gmii_tx_er_reg; 162 | state_next = state_reg; 163 | end else if (mii_select && mii_odd_reg) begin 164 | // MII odd cycle - hold state, output MSN 165 | mii_odd_next = 1'b0; 166 | gmii_txd_next = {4'd0, mii_msn_reg}; 167 | gmii_tx_en_next = gmii_tx_en_reg; 168 | gmii_tx_er_next = gmii_tx_er_reg; 169 | state_next = state_reg; 170 | end else begin 171 | case (state_reg) 172 | STATE_IDLE: begin 173 | // idle state - wait for packet 174 | reset_crc = 1'b1; 175 | mii_odd_next = 1'b0; 176 | 177 | if (s_axis_tvalid) begin 178 | mii_odd_next = 1'b1; 179 | frame_ptr_next = 16'd1; 180 | gmii_txd_next = ETH_PRE; 181 | gmii_tx_en_next = 1'b1; 182 | state_next = STATE_PREAMBLE; 183 | end else begin 184 | state_next = STATE_IDLE; 185 | end 186 | end 187 | STATE_PREAMBLE: begin 188 | // send preamble 189 | reset_crc = 1'b1; 190 | 191 | mii_odd_next = 1'b1; 192 | frame_ptr_next = frame_ptr_reg + 16'd1; 193 | 194 | gmii_txd_next = ETH_PRE; 195 | gmii_tx_en_next = 1'b1; 196 | 197 | if (frame_ptr_reg == 16'd6) begin 198 | s_axis_tready_next = 1'b1; 199 | s_tdata_next = s_axis_tdata; 200 | state_next = STATE_PREAMBLE; 201 | end else if (frame_ptr_reg == 16'd7) begin 202 | // end of preamble; start payload 203 | frame_ptr_next = 16'd0; 204 | if (s_axis_tready_reg) begin 205 | s_axis_tready_next = 1'b1; 206 | s_tdata_next = s_axis_tdata; 207 | end 208 | gmii_txd_next = ETH_SFD; 209 | state_next = STATE_PAYLOAD; 210 | end else begin 211 | state_next = STATE_PREAMBLE; 212 | end 213 | end 214 | STATE_PAYLOAD: begin 215 | // send payload 216 | 217 | update_crc = 1'b1; 218 | s_axis_tready_next = 1'b1; 219 | 220 | mii_odd_next = 1'b1; 221 | frame_ptr_next = frame_ptr_reg + 16'd1; 222 | 223 | gmii_txd_next = s_tdata_reg; 224 | gmii_tx_en_next = 1'b1; 225 | 226 | s_tdata_next = s_axis_tdata; 227 | 228 | if (s_axis_tvalid) begin 229 | if (s_axis_tlast) begin 230 | s_axis_tready_next = !s_axis_tready_reg; 231 | if (s_axis_tuser) begin 232 | gmii_tx_er_next = 1'b1; 233 | frame_ptr_next = 1'b0; 234 | state_next = STATE_IFG; 235 | end else begin 236 | state_next = STATE_LAST; 237 | end 238 | end else begin 239 | state_next = STATE_PAYLOAD; 240 | end 241 | end else begin 242 | // tvalid deassert, fail frame 243 | gmii_tx_er_next = 1'b1; 244 | frame_ptr_next = 16'd0; 245 | state_next = STATE_WAIT_END; 246 | end 247 | end 248 | STATE_LAST: begin 249 | // last payload word 250 | 251 | update_crc = 1'b1; 252 | 253 | mii_odd_next = 1'b1; 254 | frame_ptr_next = frame_ptr_reg + 16'd1; 255 | 256 | gmii_txd_next = s_tdata_reg; 257 | gmii_tx_en_next = 1'b1; 258 | 259 | if (ENABLE_PADDING && frame_ptr_reg < MIN_FRAME_LENGTH-5) begin 260 | s_tdata_next = 8'd0; 261 | state_next = STATE_PAD; 262 | end else begin 263 | frame_ptr_next = 16'd0; 264 | state_next = STATE_FCS; 265 | end 266 | end 267 | STATE_PAD: begin 268 | // send padding 269 | 270 | update_crc = 1'b1; 271 | mii_odd_next = 1'b1; 272 | frame_ptr_next = frame_ptr_reg + 16'd1; 273 | 274 | gmii_txd_next = 8'd0; 275 | gmii_tx_en_next = 1'b1; 276 | 277 | s_tdata_next = 8'd0; 278 | 279 | if (frame_ptr_reg < MIN_FRAME_LENGTH-5) begin 280 | state_next = STATE_PAD; 281 | end else begin 282 | frame_ptr_next = 16'd0; 283 | state_next = STATE_FCS; 284 | end 285 | end 286 | STATE_FCS: begin 287 | // send FCS 288 | 289 | mii_odd_next = 1'b1; 290 | frame_ptr_next = frame_ptr_reg + 16'd1; 291 | 292 | case (frame_ptr_reg) 293 | 2'd0: gmii_txd_next = ~crc_state[7:0]; 294 | 2'd1: gmii_txd_next = ~crc_state[15:8]; 295 | 2'd2: gmii_txd_next = ~crc_state[23:16]; 296 | 2'd3: gmii_txd_next = ~crc_state[31:24]; 297 | default:; 298 | endcase 299 | gmii_tx_en_next = 1'b1; 300 | 301 | if (frame_ptr_reg < 3) begin 302 | state_next = STATE_FCS; 303 | end else begin 304 | frame_ptr_next = 16'd0; 305 | fcs_next = crc_state; 306 | state_next = STATE_IFG; 307 | end 308 | end 309 | STATE_WAIT_END: begin 310 | // wait for end of frame 311 | 312 | reset_crc = 1'b1; 313 | 314 | mii_odd_next = 1'b1; 315 | frame_ptr_next = frame_ptr_reg + 16'd1; 316 | s_axis_tready_next = 1'b1; 317 | 318 | if (s_axis_tvalid) begin 319 | if (s_axis_tlast) begin 320 | s_axis_tready_next = 1'b0; 321 | ifg_next = 8'b0; 322 | state_next = STATE_IFG; 323 | end else begin 324 | state_next = STATE_WAIT_END; 325 | end 326 | end else begin 327 | state_next = STATE_WAIT_END; 328 | end 329 | end 330 | STATE_IFG: begin 331 | // send IFG 332 | 333 | reset_crc = 1'b1; 334 | 335 | mii_odd_next = 1'b1; 336 | frame_ptr_next = frame_ptr_reg + 16'd1; 337 | 338 | if (ifg_reg < ifg_delay-1) begin 339 | ifg_next = ifg_reg + 1; 340 | state_next = STATE_IFG; 341 | end else begin 342 | state_next = STATE_IDLE; 343 | end 344 | end 345 | endcase 346 | 347 | if (mii_select) begin 348 | mii_msn_next = gmii_txd_next[7:4]; 349 | gmii_txd_next[7:4] = 4'd0; 350 | end 351 | end 352 | end 353 | 354 | always @(posedge clk) begin 355 | if (rst) begin 356 | state_reg <= STATE_IDLE; 357 | 358 | frame_ptr_reg <= 16'd0; 359 | 360 | s_axis_tready_reg <= 1'b0; 361 | 362 | gmii_tx_en_reg <= 1'b0; 363 | gmii_tx_er_reg <= 1'b0; 364 | 365 | crc_state <= 32'hFFFFFFFF; 366 | fcs_reg <= 32'hFFFFFFFF; 367 | end else begin 368 | state_reg <= state_next; 369 | 370 | frame_ptr_reg <= frame_ptr_next; 371 | 372 | s_axis_tready_reg <= s_axis_tready_next; 373 | 374 | gmii_tx_en_reg <= gmii_tx_en_next; 375 | gmii_tx_er_reg <= gmii_tx_er_next; 376 | 377 | fcs_reg <= fcs_next; 378 | ifg_reg <= ifg_next; 379 | // datapath 380 | if (reset_crc) begin 381 | crc_state <= 32'hFFFFFFFF; 382 | end else if (update_crc) begin 383 | crc_state <= crc_next; 384 | end 385 | end 386 | 387 | mii_odd_reg <= mii_odd_next; 388 | mii_msn_reg <= mii_msn_next; 389 | 390 | s_tdata_reg <= s_tdata_next; 391 | 392 | gmii_txd_reg <= gmii_txd_next; 393 | end 394 | 395 | endmodule 396 | -------------------------------------------------------------------------------- /framing_top.sv: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | `default_nettype none 3 | 4 | module framing_top 5 | ( 6 | input wire msoc_clk, 7 | input wire [14:0] core_lsu_addr, 8 | input wire [63:0] core_lsu_wdata, 9 | input wire [7:0] core_lsu_be, 10 | input wire ce_d, 11 | input wire we_d, 12 | input wire framing_sel, 13 | output logic [63:0] framing_rdata, 14 | 15 | // Internal 125 MHz clock 16 | input wire clk_int, 17 | input wire rst_int, 18 | input wire clk90_int, 19 | input wire clk_200_int, 20 | 21 | /* 22 | * Ethernet: 1000BASE-T RGMII 23 | */ 24 | input wire phy_rx_clk, 25 | input wire [3:0] phy_rxd, 26 | input wire phy_rx_ctl, 27 | output wire phy_tx_clk, 28 | output wire [3:0] phy_txd, 29 | output wire phy_tx_ctl, 30 | output wire phy_reset_n, 31 | input wire phy_int_n, 32 | input wire phy_pme_n, 33 | 34 | input wire phy_mdio_i, 35 | output reg phy_mdio_o, 36 | output reg phy_mdio_oe, 37 | output wire phy_mdc, 38 | 39 | output reg eth_irq 40 | ); 41 | 42 | // obsolete signals to be removedphy_ 43 | // 44 | 45 | 46 | logic [14:0] core_lsu_addr_dly; 47 | 48 | logic tx_enable_i, mac_gmii_tx_en; 49 | logic [47:0] mac_address, rx_dest_mac; 50 | logic [10:0] tx_frame_addr, rx_length_axis[0:7], tx_packet_length; 51 | logic [12:0] axis_tx_frame_size; 52 | logic ce_d_dly, avail; 53 | logic [63:0] framing_rdata_pkt, framing_wdata_pkt; 54 | logic [3:0] tx_enable_dly, firstbuf, nextbuf, lastbuf; 55 | logic [2:0] last; 56 | 57 | reg byte_sync, sync, irq_en, tx_busy; 58 | 59 | wire [7:0] m_enb = (we_d ? core_lsu_be : 8'hFF); 60 | logic phy_mdclk, cooked, tx_enable_old, loopback, promiscuous; 61 | logic [3:0] spare; 62 | logic [10:0] rx_addr_axis; 63 | 64 | /* 65 | * AXI input 66 | */ 67 | reg tx_axis_tvalid; 68 | reg tx_axis_tvalid_dly; 69 | reg tx_axis_tlast; 70 | wire [7:0] tx_axis_tdata; 71 | wire tx_axis_tready; 72 | wire tx_axis_tuser = 1'b0; 73 | 74 | /* 75 | * AXI output 76 | */ 77 | wire [7:0] rx_axis_tdata; 78 | wire rx_axis_tvalid; 79 | wire rx_axis_tlast; 80 | wire rx_axis_tuser; 81 | 82 | /* 83 | * AXIS Status 84 | */ 85 | wire [31:0] tx_fcs_reg_rev, rx_fcs_reg_rev; 86 | 87 | always @(posedge clk_int) 88 | if (rst_int == 1'b1) 89 | begin 90 | byte_sync <= 1'b0; 91 | end 92 | else 93 | begin 94 | if (rx_axis_tvalid && (byte_sync == 0) && (nextbuf != (firstbuf+lastbuf)&15)) 95 | begin 96 | byte_sync <= 1'b1; 97 | end 98 | if (rx_axis_tlast && byte_sync) 99 | begin 100 | last <= 1'b1; 101 | end 102 | else if ((last > 0) && (last < 7)) 103 | begin 104 | byte_sync <= 1'b0; 105 | last <= last + 3'b1; 106 | end 107 | else 108 | begin 109 | last <= 3'b0; 110 | end 111 | end 112 | 113 | wire [1:0] rx_wr = rx_axis_tvalid << rx_addr_axis[2]; 114 | logic [15:0] douta; 115 | assign tx_axis_tdata = douta >> {tx_frame_addr[2],3'b000}; 116 | assign phy_mdc = phy_mdclk; 117 | 118 | dualmem_widen8 RAMB16_inst_rx ( 119 | .clka(clk_int), // Port A Clock 120 | .clkb(msoc_clk), // Port A Clock 121 | .douta(), // Port A 8-bit Data Output 122 | .addra({nextbuf[2:0],rx_addr_axis[10:3],rx_addr_axis[1:0]}), // Port A 11-bit Address Input 123 | .dina({rx_axis_tdata,rx_axis_tdata}), // Port A 8-bit Data Input 124 | .ena(rx_axis_tvalid), // Port A RAM Enable Input 125 | .wea(rx_wr), // Port A Write Enable Input 126 | .doutb(framing_rdata_pkt), // Port B 32-bit Data Output 127 | .addrb(core_lsu_addr[13:3]), // Port B 9-bit Address Input 128 | .dinb(core_lsu_wdata), // Port B 32-bit Data Input 129 | .enb(ce_d & framing_sel & core_lsu_addr[14]), 130 | // Port B RAM Enable Input 131 | .web(we_d ? {(|core_lsu_be[7:4]),(|core_lsu_be[3:0])} : 2'b0) // Port B Write Enable Input 132 | ); 133 | 134 | dualmem_widen RAMB16_inst_tx ( 135 | .clka(~clk_int), // Port A Clock 136 | .clkb(msoc_clk), // Port A Clock 137 | .douta(douta), // Port A 8-bit Data Output 138 | .addra({1'b0,tx_frame_addr[10:3],tx_frame_addr[1:0]}), // Port A 11-bit Address Input 139 | .dina(16'b0), // Port A 8-bit Data Input 140 | .ena(tx_axis_tvalid), // Port A RAM Enable Input 141 | .wea(2'b0), // Port A Write Enable Input 142 | .doutb(framing_wdata_pkt), // Port B 32-bit Data Output 143 | .addrb(core_lsu_addr[11:3]), // Port B 9-bit Address Input 144 | .dinb(core_lsu_wdata), // Port B 32-bit Data Input 145 | .enb(ce_d & framing_sel & (core_lsu_addr[14:12]==3'b001)), 146 | // Port B RAM Enable Input 147 | .web(we_d ? {(|core_lsu_be[7:4]),(|core_lsu_be[3:0])} : 2'b0) // Port B Write Enable Input 148 | ); 149 | 150 | always @(posedge msoc_clk) 151 | if (rst_int) 152 | begin 153 | core_lsu_addr_dly <= 0; 154 | mac_address <= 48'H230100890702; 155 | tx_packet_length <= 0; 156 | tx_enable_dly <= 0; 157 | cooked <= 1'b0; 158 | loopback <= 1'b0; 159 | spare <= 4'b0; 160 | promiscuous <= 1'b0; 161 | phy_mdio_oe <= 1'b0; 162 | phy_mdio_o <= 1'b0; 163 | phy_mdclk <= 1'b0; 164 | sync <= 1'b0; 165 | firstbuf <= 4'b0; 166 | lastbuf <= 4'b0; 167 | nextbuf <= 4'b0; 168 | eth_irq <= 1'b0; 169 | irq_en <= 1'b0; 170 | ce_d_dly <= 1'b0; 171 | tx_busy <= 1'b0; 172 | avail = 1'b0; 173 | end 174 | else 175 | begin 176 | core_lsu_addr_dly <= core_lsu_addr; 177 | ce_d_dly <= ce_d; 178 | avail = nextbuf != firstbuf; 179 | eth_irq <= avail & irq_en; // make eth_irq go away immediately if irq_en is low 180 | if (framing_sel&we_d&(&core_lsu_be[3:0])&(core_lsu_addr[14:11]==4'b0001)) 181 | case(core_lsu_addr[6:3]) 182 | 0: mac_address[31:0] <= core_lsu_wdata; 183 | 1: {irq_en,promiscuous,spare,loopback,cooked,mac_address[47:32]} <= core_lsu_wdata; 184 | 2: begin tx_enable_dly <= 10; tx_packet_length <= core_lsu_wdata; end /* tx payload size */ 185 | 3: begin tx_enable_dly <= 0; tx_packet_length <= 0; end 186 | 4: begin {phy_mdio_oe,phy_mdio_o,phy_mdclk} <= core_lsu_wdata; end 187 | 5: begin lastbuf <= core_lsu_wdata[3:0]; end 188 | 6: begin firstbuf <= core_lsu_wdata[3:0]; end 189 | default:; 190 | endcase 191 | if ((last > 0) && ~sync) 192 | begin 193 | // check broadcast/multicast address 194 | sync <= (rx_dest_mac[47:24]==24'h01005E) | (&rx_dest_mac) | (mac_address == rx_dest_mac) | promiscuous; 195 | end 196 | else if (!last) 197 | begin 198 | if (sync) nextbuf <= nextbuf + 1'b1; 199 | sync <= 1'b0; 200 | end 201 | if (mac_gmii_tx_en && tx_enable_i) 202 | begin 203 | tx_enable_dly <= 0; 204 | end 205 | else if (1'b1 == |tx_enable_dly) 206 | begin 207 | tx_busy <= 1'b1; 208 | tx_enable_dly <= tx_enable_dly + !(&tx_enable_dly); 209 | end 210 | else if (~mac_gmii_tx_en) 211 | tx_busy <= 1'b0; 212 | end 213 | 214 | always @(posedge clk_int) 215 | if (rst_int) 216 | begin 217 | tx_enable_i <= 1'b0; 218 | end 219 | else 220 | begin 221 | if (mac_gmii_tx_en && tx_axis_tlast) 222 | begin 223 | tx_enable_i <= 1'b0; 224 | end 225 | else if (1'b1 == &tx_enable_dly) 226 | tx_enable_i <= 1'b1; 227 | end 228 | 229 | always @* casez({ce_d_dly,core_lsu_addr_dly[14:3]}) 230 | 13'b10001????0000 : framing_rdata = mac_address[31:0]; 231 | 13'b10001????0001 : framing_rdata = {irq_en, promiscuous, spare, loopback, cooked, mac_address[47:32]}; 232 | 13'b1000?????0010 : framing_rdata = {tx_busy, 4'b0, tx_frame_addr, 5'b0, tx_packet_length}; 233 | 13'b10001????0011 : framing_rdata = tx_fcs_reg_rev; 234 | 13'b10001????0100 : framing_rdata = {phy_mdio_i,phy_mdio_oe,phy_mdio_o,phy_mdclk}; 235 | 13'b10001????0101 : framing_rdata = rx_fcs_reg_rev; 236 | 13'b10001????0110 : framing_rdata = {eth_irq, avail, lastbuf, nextbuf, firstbuf}; 237 | 13'b10001????1??? : framing_rdata = rx_length_axis[core_lsu_addr_dly[5:3]]; 238 | 13'b10010???????? : framing_rdata = framing_wdata_pkt; 239 | 13'b11??????????? : framing_rdata = framing_rdata_pkt; 240 | default: framing_rdata = 'h0; 241 | endcase 242 | 243 | parameter dly = 0; 244 | 245 | wire [31:0] tx_fcs_reg, rx_fcs_reg; 246 | assign tx_fcs_reg_rev = {tx_fcs_reg[0],tx_fcs_reg[1],tx_fcs_reg[2],tx_fcs_reg[3], 247 | tx_fcs_reg[4],tx_fcs_reg[5],tx_fcs_reg[6],tx_fcs_reg[7], 248 | tx_fcs_reg[8],tx_fcs_reg[9],tx_fcs_reg[10],tx_fcs_reg[11], 249 | tx_fcs_reg[12],tx_fcs_reg[13],tx_fcs_reg[14],tx_fcs_reg[15], 250 | tx_fcs_reg[16],tx_fcs_reg[17],tx_fcs_reg[18],tx_fcs_reg[19], 251 | tx_fcs_reg[20],tx_fcs_reg[21],tx_fcs_reg[22],tx_fcs_reg[23], 252 | tx_fcs_reg[24],tx_fcs_reg[25],tx_fcs_reg[26],tx_fcs_reg[27], 253 | tx_fcs_reg[28],tx_fcs_reg[29],tx_fcs_reg[30],tx_fcs_reg[31]}; 254 | assign rx_fcs_reg_rev = {rx_fcs_reg[0],rx_fcs_reg[1],rx_fcs_reg[2],rx_fcs_reg[3], 255 | rx_fcs_reg[4],rx_fcs_reg[5],rx_fcs_reg[6],rx_fcs_reg[7], 256 | rx_fcs_reg[8],rx_fcs_reg[9],rx_fcs_reg[10],rx_fcs_reg[11], 257 | rx_fcs_reg[12],rx_fcs_reg[13],rx_fcs_reg[14],rx_fcs_reg[15], 258 | rx_fcs_reg[16],rx_fcs_reg[17],rx_fcs_reg[18],rx_fcs_reg[19], 259 | rx_fcs_reg[20],rx_fcs_reg[21],rx_fcs_reg[22],rx_fcs_reg[23], 260 | rx_fcs_reg[24],rx_fcs_reg[25],rx_fcs_reg[26],rx_fcs_reg[27], 261 | rx_fcs_reg[28],rx_fcs_reg[29],rx_fcs_reg[30],rx_fcs_reg[31]}; 262 | 263 | always @(posedge clk_int) 264 | if (rst_int) 265 | begin 266 | tx_axis_tvalid <= 'b0; 267 | tx_axis_tvalid_dly <= 'b0; 268 | tx_frame_addr <= 'b0; 269 | tx_axis_tlast <= 'b0; 270 | end 271 | else 272 | begin 273 | tx_enable_old <= tx_enable_i; 274 | if (tx_enable_i & (tx_enable_old == 0)) 275 | begin 276 | tx_frame_addr <= 'b0; 277 | end 278 | if (tx_axis_tready) 279 | begin 280 | tx_frame_addr <= tx_frame_addr + 1; 281 | tx_axis_tlast <= (tx_frame_addr == tx_packet_length-2) & tx_axis_tvalid_dly; 282 | end 283 | tx_axis_tvalid <= tx_axis_tvalid_dly; 284 | if (tx_enable_old) 285 | tx_axis_tvalid_dly <= 1'b1; 286 | else if (~tx_axis_tlast) 287 | tx_axis_tvalid_dly <= 1'b0; 288 | end 289 | 290 | always @(posedge clk_int) 291 | if (rst_int) 292 | begin 293 | rx_addr_axis <= 'b0; 294 | rx_dest_mac <= 'b0; 295 | end 296 | else 297 | begin 298 | if (rx_axis_tvalid) 299 | begin 300 | rx_addr_axis <= rx_addr_axis + 1; 301 | if (rx_addr_axis < 6) 302 | rx_dest_mac <= {rx_dest_mac[39:0],rx_axis_tdata}; 303 | end 304 | if (rx_axis_tlast) 305 | begin 306 | rx_length_axis[nextbuf[2:0]] <= rx_addr_axis + 1; 307 | rx_addr_axis <= 'b0; 308 | end 309 | end 310 | 311 | rgmii_soc rgmii_soc1 312 | ( 313 | .rst_int(rst_int), 314 | .clk_int(clk_int), 315 | .clk90_int(clk90_int), 316 | .clk_200_int(clk_200_int), 317 | /* 318 | * Ethernet: 1000BASE-T RGMII 319 | */ 320 | .phy_rx_clk(phy_rx_clk), 321 | .phy_rxd(phy_rxd), 322 | .phy_rx_ctl(phy_rx_ctl), 323 | .phy_tx_clk(phy_tx_clk), 324 | .phy_txd(phy_txd), 325 | .phy_tx_ctl(phy_tx_ctl), 326 | .phy_reset_n(phy_reset_n), 327 | .phy_int_n(phy_int_n), 328 | .phy_pme_n(phy_pme_n), 329 | .mac_gmii_tx_en(mac_gmii_tx_en), 330 | .tx_axis_tdata(tx_axis_tdata), 331 | .tx_axis_tvalid(tx_axis_tvalid), 332 | .tx_axis_tready(tx_axis_tready), 333 | .tx_axis_tlast(tx_axis_tlast), 334 | .tx_axis_tuser(tx_axis_tuser), 335 | .rx_axis_tdata(rx_axis_tdata), 336 | .rx_axis_tvalid(rx_axis_tvalid), 337 | .rx_axis_tlast(rx_axis_tlast), 338 | .rx_axis_tuser(rx_axis_tuser), 339 | .rx_fcs_reg(rx_fcs_reg), 340 | .tx_fcs_reg(tx_fcs_reg) 341 | ); 342 | 343 | // `define XILINX_ILA_1 344 | // `define XILINX_ILA_2 345 | // `define XILINX_ILA_3 346 | 347 | `ifdef XILINX_ILA_1 348 | xlnx_ila_1 eth_ila_clk_rx ( 349 | .clk(clk_int), // input wire clk 350 | .probe0(rx_axis_tdata), // input wire [7:0] probe4 351 | .probe1(rx_axis_tvalid), // input wire [0:0] probe5 352 | .probe2(rx_axis_tlast), // input wire [0:0] probe6 353 | .probe3(rx_axis_tuser), // input wire [0:0] probe7 354 | .probe4(byte_sync), 355 | .probe5(last), 356 | .probe6(rx_addr_axis), 357 | .probe7(rx_dest_mac), 358 | .probe8(rx_length_axis[nextbuf[2:0]]), 359 | .probe9(rx_clk) 360 | ); 361 | `endif 362 | 363 | `ifdef XILINX_ILA_2 364 | xlnx_ila_2 eth_ila_clk_int ( 365 | .clk(clk_int), // input wire clk 366 | .probe0(tx_axis_tdata), // input wire [7:0] probe0 367 | .probe1(tx_axis_tvalid), // input wire [0:0] probe1 368 | .probe2(tx_axis_tready), // input wire [0:0] probe2 369 | .probe3(tx_axis_tlast), // input wire [0:0] probe3 370 | .probe4(tx_enable_i), 371 | .probe5(douta), 372 | .probe6(tx_axis_tvalid_dly), 373 | .probe7(tx_frame_addr), 374 | .probe8(mac_gmii_tx_en), 375 | .probe9(tx_enable_old) 376 | ); 377 | `endif 378 | 379 | `ifdef XILINX_ILA_3 380 | xlnx_ila_3 eth_ila_clk_msoc ( 381 | .clk(msoc_clk), // input wire clk 382 | .probe0(sync), 383 | .probe1(avail), 384 | .probe2(nextbuf), 385 | .probe3(tx_enable_dly), 386 | .probe4(tx_busy) 387 | ); 388 | `endif 389 | 390 | endmodule // framing_top 391 | `default_nettype wire 392 | -------------------------------------------------------------------------------- /axis_async_fifo.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2014-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | `timescale 1ns / 1ps 28 | 29 | /* 30 | * AXI4-Stream asynchronous FIFO 31 | */ 32 | module axis_async_fifo # 33 | ( 34 | parameter ADDR_WIDTH = 12, 35 | parameter DATA_WIDTH = 8, 36 | parameter KEEP_ENABLE = (DATA_WIDTH>8), 37 | parameter KEEP_WIDTH = (DATA_WIDTH/8), 38 | parameter LAST_ENABLE = 1, 39 | parameter ID_ENABLE = 0, 40 | parameter ID_WIDTH = 8, 41 | parameter DEST_ENABLE = 0, 42 | parameter DEST_WIDTH = 8, 43 | parameter USER_ENABLE = 1, 44 | parameter USER_WIDTH = 1, 45 | parameter FRAME_FIFO = 0, 46 | parameter USER_BAD_FRAME_VALUE = 1'b1, 47 | parameter USER_BAD_FRAME_MASK = 1'b1, 48 | parameter DROP_BAD_FRAME = 0, 49 | parameter DROP_WHEN_FULL = 0 50 | ) 51 | ( 52 | /* 53 | * Common asynchronous reset 54 | */ 55 | input wire async_rst, 56 | 57 | /* 58 | * AXI input 59 | */ 60 | input wire s_clk, 61 | input wire [DATA_WIDTH-1:0] s_axis_tdata, 62 | input wire [KEEP_WIDTH-1:0] s_axis_tkeep, 63 | input wire s_axis_tvalid, 64 | output wire s_axis_tready, 65 | input wire s_axis_tlast, 66 | input wire [ID_WIDTH-1:0] s_axis_tid, 67 | input wire [DEST_WIDTH-1:0] s_axis_tdest, 68 | input wire [USER_WIDTH-1:0] s_axis_tuser, 69 | 70 | /* 71 | * AXI output 72 | */ 73 | input wire m_clk, 74 | output wire [DATA_WIDTH-1:0] m_axis_tdata, 75 | output wire [KEEP_WIDTH-1:0] m_axis_tkeep, 76 | output wire m_axis_tvalid, 77 | input wire m_axis_tready, 78 | output wire m_axis_tlast, 79 | output wire [ID_WIDTH-1:0] m_axis_tid, 80 | output wire [DEST_WIDTH-1:0] m_axis_tdest, 81 | output wire [USER_WIDTH-1:0] m_axis_tuser, 82 | 83 | /* 84 | * Status 85 | */ 86 | output wire s_status_overflow, 87 | output wire s_status_bad_frame, 88 | output wire s_status_good_frame, 89 | output wire m_status_overflow, 90 | output wire m_status_bad_frame, 91 | output wire m_status_good_frame 92 | ); 93 | 94 | // check configuration 95 | initial begin 96 | if (FRAME_FIFO && !LAST_ENABLE) begin 97 | $error("Error: FRAME_FIFO set requires LAST_ENABLE set"); 98 | $finish; 99 | end 100 | 101 | if (DROP_BAD_FRAME && !FRAME_FIFO) begin 102 | $error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set"); 103 | $finish; 104 | end 105 | 106 | if (DROP_WHEN_FULL && !FRAME_FIFO) begin 107 | $error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set"); 108 | $finish; 109 | end 110 | 111 | if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin 112 | $error("Error: Invalid USER_BAD_FRAME_MASK value"); 113 | $finish; 114 | end 115 | end 116 | 117 | localparam KEEP_OFFSET = DATA_WIDTH; 118 | localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0); 119 | localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0); 120 | localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); 121 | localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); 122 | localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); 123 | 124 | reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next; 125 | reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next; 126 | reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next; 127 | reg [ADDR_WIDTH:0] wr_ptr_cur_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_gray_next; 128 | reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}}; 129 | reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next; 130 | reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next; 131 | reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}}; 132 | 133 | reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}}; 134 | reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}}; 135 | reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}}; 136 | reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}}; 137 | 138 | reg s_rst_sync1_reg = 1'b1; 139 | reg s_rst_sync2_reg = 1'b1; 140 | reg s_rst_sync3_reg = 1'b1; 141 | reg m_rst_sync1_reg = 1'b1; 142 | reg m_rst_sync2_reg = 1'b1; 143 | reg m_rst_sync3_reg = 1'b1; 144 | 145 | reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0]; 146 | reg [WIDTH-1:0] mem_read_data_reg; 147 | reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next; 148 | 149 | wire [WIDTH-1:0] s_axis; 150 | 151 | reg [WIDTH-1:0] m_axis_reg; 152 | reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next; 153 | 154 | // full when first TWO MSBs do NOT match, but rest matches 155 | // (gray code equivalent of first MSB different but rest same) 156 | wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) && 157 | (wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) && 158 | (wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0])); 159 | wire full_cur = ((wr_ptr_cur_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) && 160 | (wr_ptr_cur_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) && 161 | (wr_ptr_cur_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0])); 162 | // empty when pointers match exactly 163 | wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg; 164 | // overflow within packet 165 | wire full_wr = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) && 166 | (wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0])); 167 | 168 | // control signals 169 | reg write; 170 | reg read; 171 | reg store_output; 172 | 173 | reg drop_frame_reg = 1'b0, drop_frame_next; 174 | reg overflow_reg = 1'b0, overflow_next; 175 | reg bad_frame_reg = 1'b0, bad_frame_next; 176 | reg good_frame_reg = 1'b0, good_frame_next; 177 | 178 | reg overflow_sync1_reg = 1'b0; 179 | reg overflow_sync2_reg = 1'b0; 180 | reg overflow_sync3_reg = 1'b0; 181 | reg overflow_sync4_reg = 1'b0; 182 | reg bad_frame_sync1_reg = 1'b0; 183 | reg bad_frame_sync2_reg = 1'b0; 184 | reg bad_frame_sync3_reg = 1'b0; 185 | reg bad_frame_sync4_reg = 1'b0; 186 | reg good_frame_sync1_reg = 1'b0; 187 | reg good_frame_sync2_reg = 1'b0; 188 | reg good_frame_sync3_reg = 1'b0; 189 | reg good_frame_sync4_reg = 1'b0; 190 | 191 | assign s_axis_tready = (FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg; 192 | 193 | generate 194 | assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata; 195 | if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep; 196 | if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; 197 | if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid; 198 | if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest; 199 | if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser; 200 | endgenerate 201 | 202 | assign m_axis_tvalid = m_axis_tvalid_reg; 203 | 204 | assign m_axis_tdata = m_axis_reg[DATA_WIDTH-1:0]; 205 | assign m_axis_tkeep = KEEP_ENABLE ? m_axis_reg[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}}; 206 | assign m_axis_tlast = LAST_ENABLE ? m_axis_reg[LAST_OFFSET] : 1'b1; 207 | assign m_axis_tid = ID_ENABLE ? m_axis_reg[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}}; 208 | assign m_axis_tdest = DEST_ENABLE ? m_axis_reg[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}}; 209 | assign m_axis_tuser = USER_ENABLE ? m_axis_reg[USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}}; 210 | 211 | assign s_status_overflow = overflow_reg; 212 | assign s_status_bad_frame = bad_frame_reg; 213 | assign s_status_good_frame = good_frame_reg; 214 | 215 | assign m_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg; 216 | assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg; 217 | assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg; 218 | 219 | // reset synchronization 220 | always @(posedge s_clk or posedge async_rst) begin 221 | if (async_rst) begin 222 | s_rst_sync1_reg <= 1'b1; 223 | s_rst_sync2_reg <= 1'b1; 224 | s_rst_sync3_reg <= 1'b1; 225 | end else begin 226 | s_rst_sync1_reg <= 1'b0; 227 | s_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg; 228 | s_rst_sync3_reg <= s_rst_sync2_reg; 229 | end 230 | end 231 | 232 | always @(posedge m_clk or posedge async_rst) begin 233 | if (async_rst) begin 234 | m_rst_sync1_reg <= 1'b1; 235 | m_rst_sync2_reg <= 1'b1; 236 | m_rst_sync3_reg <= 1'b1; 237 | end else begin 238 | m_rst_sync1_reg <= 1'b0; 239 | m_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg; 240 | m_rst_sync3_reg <= m_rst_sync2_reg; 241 | end 242 | end 243 | 244 | // Write logic 245 | always @* begin 246 | write = 1'b0; 247 | 248 | drop_frame_next = 1'b0; 249 | overflow_next = 1'b0; 250 | bad_frame_next = 1'b0; 251 | good_frame_next = 1'b0; 252 | 253 | wr_ptr_next = wr_ptr_reg; 254 | wr_ptr_cur_next = wr_ptr_cur_reg; 255 | wr_ptr_gray_next = wr_ptr_gray_reg; 256 | wr_ptr_cur_gray_next = wr_ptr_cur_gray_reg; 257 | 258 | if (s_axis_tready && s_axis_tvalid) begin 259 | // transfer in 260 | if (!FRAME_FIFO) begin 261 | // normal FIFO mode 262 | write = 1'b1; 263 | wr_ptr_next = wr_ptr_reg + 1; 264 | wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1); 265 | end else if (full_cur || full_wr || drop_frame_reg) begin 266 | // full, packet overflow, or currently dropping frame 267 | // drop frame 268 | drop_frame_next = 1'b1; 269 | if (s_axis_tlast) begin 270 | // end of frame, reset write pointer 271 | wr_ptr_cur_next = wr_ptr_reg; 272 | wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1); 273 | drop_frame_next = 1'b0; 274 | overflow_next = 1'b1; 275 | end 276 | end else begin 277 | write = 1'b1; 278 | wr_ptr_cur_next = wr_ptr_cur_reg + 1; 279 | wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1); 280 | if (s_axis_tlast) begin 281 | // end of frame 282 | if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin 283 | // bad packet, reset write pointer 284 | wr_ptr_cur_next = wr_ptr_reg; 285 | wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1); 286 | bad_frame_next = 1'b1; 287 | end else begin 288 | // good packet, update write pointer 289 | wr_ptr_next = wr_ptr_cur_reg + 1; 290 | wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1); 291 | good_frame_next = 1'b1; 292 | end 293 | end 294 | end 295 | end 296 | end 297 | 298 | always @(posedge s_clk) begin 299 | if (s_rst_sync3_reg) begin 300 | wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; 301 | wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; 302 | wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}}; 303 | wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}}; 304 | 305 | drop_frame_reg <= 1'b0; 306 | overflow_reg <= 1'b0; 307 | bad_frame_reg <= 1'b0; 308 | good_frame_reg <= 1'b0; 309 | end else begin 310 | wr_ptr_reg <= wr_ptr_next; 311 | wr_ptr_cur_reg <= wr_ptr_cur_next; 312 | wr_ptr_gray_reg <= wr_ptr_gray_next; 313 | wr_ptr_cur_gray_reg <= wr_ptr_cur_gray_next; 314 | 315 | drop_frame_reg <= drop_frame_next; 316 | overflow_reg <= overflow_next; 317 | bad_frame_reg <= bad_frame_next; 318 | good_frame_reg <= good_frame_next; 319 | end 320 | 321 | if (FRAME_FIFO) begin 322 | wr_addr_reg <= wr_ptr_cur_next; 323 | end else begin 324 | wr_addr_reg <= wr_ptr_next; 325 | end 326 | 327 | if (write) begin 328 | mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= s_axis; 329 | end 330 | end 331 | 332 | // pointer synchronization 333 | always @(posedge s_clk) begin 334 | if (s_rst_sync3_reg) begin 335 | rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}}; 336 | rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}}; 337 | end else begin 338 | rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg; 339 | rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg; 340 | end 341 | end 342 | 343 | always @(posedge m_clk) begin 344 | if (m_rst_sync3_reg) begin 345 | wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}}; 346 | wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}}; 347 | end else begin 348 | wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg; 349 | wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg; 350 | end 351 | end 352 | 353 | // status synchronization 354 | always @(posedge s_clk) begin 355 | if (s_rst_sync3_reg) begin 356 | overflow_sync1_reg <= 1'b0; 357 | bad_frame_sync1_reg <= 1'b0; 358 | good_frame_sync1_reg <= 1'b0; 359 | end else begin 360 | overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg; 361 | bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg; 362 | good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg; 363 | end 364 | end 365 | 366 | always @(posedge m_clk) begin 367 | if (m_rst_sync3_reg) begin 368 | overflow_sync2_reg <= 1'b0; 369 | overflow_sync3_reg <= 1'b0; 370 | bad_frame_sync2_reg <= 1'b0; 371 | bad_frame_sync3_reg <= 1'b0; 372 | good_frame_sync2_reg <= 1'b0; 373 | good_frame_sync3_reg <= 1'b0; 374 | end else begin 375 | overflow_sync2_reg <= overflow_sync1_reg; 376 | overflow_sync3_reg <= overflow_sync2_reg; 377 | overflow_sync4_reg <= overflow_sync3_reg; 378 | bad_frame_sync2_reg <= bad_frame_sync1_reg; 379 | bad_frame_sync3_reg <= bad_frame_sync2_reg; 380 | bad_frame_sync4_reg <= bad_frame_sync3_reg; 381 | good_frame_sync2_reg <= good_frame_sync1_reg; 382 | good_frame_sync3_reg <= good_frame_sync2_reg; 383 | good_frame_sync4_reg <= good_frame_sync3_reg; 384 | end 385 | end 386 | 387 | // Read logic 388 | always @* begin 389 | read = 1'b0; 390 | 391 | rd_ptr_next = rd_ptr_reg; 392 | rd_ptr_gray_next = rd_ptr_gray_reg; 393 | 394 | mem_read_data_valid_next = mem_read_data_valid_reg; 395 | 396 | if (store_output || !mem_read_data_valid_reg) begin 397 | // output data not valid OR currently being transferred 398 | if (!empty) begin 399 | // not empty, perform read 400 | read = 1'b1; 401 | mem_read_data_valid_next = 1'b1; 402 | rd_ptr_next = rd_ptr_reg + 1; 403 | rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1); 404 | end else begin 405 | // empty, invalidate 406 | mem_read_data_valid_next = 1'b0; 407 | end 408 | end 409 | end 410 | 411 | always @(posedge m_clk) begin 412 | if (m_rst_sync3_reg) begin 413 | rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; 414 | rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}}; 415 | mem_read_data_valid_reg <= 1'b0; 416 | end else begin 417 | rd_ptr_reg <= rd_ptr_next; 418 | rd_ptr_gray_reg <= rd_ptr_gray_next; 419 | mem_read_data_valid_reg <= mem_read_data_valid_next; 420 | end 421 | 422 | rd_addr_reg <= rd_ptr_next; 423 | 424 | if (read) begin 425 | mem_read_data_reg <= mem[rd_addr_reg[ADDR_WIDTH-1:0]]; 426 | end 427 | end 428 | 429 | // Output register 430 | always @* begin 431 | store_output = 1'b0; 432 | 433 | m_axis_tvalid_next = m_axis_tvalid_reg; 434 | 435 | if (m_axis_tready || !m_axis_tvalid) begin 436 | store_output = 1'b1; 437 | m_axis_tvalid_next = mem_read_data_valid_reg; 438 | end 439 | end 440 | 441 | always @(posedge m_clk) begin 442 | if (m_rst_sync3_reg) begin 443 | m_axis_tvalid_reg <= 1'b0; 444 | end else begin 445 | m_axis_tvalid_reg <= m_axis_tvalid_next; 446 | end 447 | 448 | if (store_output) begin 449 | m_axis_reg <= mem_read_data_reg; 450 | end 451 | end 452 | 453 | endmodule 454 | -------------------------------------------------------------------------------- /rgmii_lfsr.sv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2016-2018 Alex Forencich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | // Language: Verilog 2001 26 | 27 | /* 28 | * Parametrizable combinatorial parallel LFSR/CRC 29 | */ 30 | module rgmii_lfsr # 31 | ( 32 | // width of LFSR 33 | parameter LFSR_WIDTH = 31, 34 | // LFSR polynomial 35 | parameter LFSR_POLY = 31'h10000001, 36 | // LFSR configuration: "GALOIS", "FIBONACCI" 37 | parameter LFSR_CONFIG = "FIBONACCI", 38 | // LFSR feed forward enable 39 | parameter LFSR_FEED_FORWARD = 0, 40 | // bit-reverse input and output 41 | parameter REVERSE = 0, 42 | // width of data input 43 | parameter DATA_WIDTH = 8, 44 | // implementation style: "AUTO", "LOOP", "REDUCTION" 45 | parameter STYLE = "AUTO" 46 | ) 47 | ( 48 | input wire [DATA_WIDTH-1:0] data_in, 49 | input wire [LFSR_WIDTH-1:0] state_in, 50 | output wire [DATA_WIDTH-1:0] data_out, 51 | output wire [LFSR_WIDTH-1:0] state_out 52 | ); 53 | 54 | /* 55 | 56 | Fully parametrizable combinatorial parallel LFSR/CRC module. Implements an unrolled LFSR 57 | next state computation, shifting DATA_WIDTH bits per pass through the module. Input data 58 | is XORed with LFSR feedback path, tie data_in to zero if this is not required. 59 | 60 | Works in two parts: statically computes a set of bit masks, then uses these bit masks to 61 | select bits for XORing to compute the next state. 62 | 63 | Ports: 64 | 65 | data_in 66 | 67 | Data bits to be shifted through the LFSR (DATA_WIDTH bits) 68 | 69 | state_in 70 | 71 | LFSR/CRC current state input (LFSR_WIDTH bits) 72 | 73 | data_out 74 | 75 | Data bits shifted out of LFSR (DATA_WIDTH bits) 76 | 77 | state_out 78 | 79 | LFSR/CRC next state output (LFSR_WIDTH bits) 80 | 81 | Parameters: 82 | 83 | LFSR_WIDTH 84 | 85 | Specify width of LFSR/CRC register 86 | 87 | LFSR_POLY 88 | 89 | Specify the LFSR/CRC polynomial in hex format. For example, the polynomial 90 | 91 | x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 92 | 93 | would be represented as 94 | 95 | 32'h04c11db7 96 | 97 | Note that the largest term (x^32) is suppressed. This term is generated automatically based 98 | on LFSR_WIDTH. 99 | 100 | LFSR_CONFIG 101 | 102 | Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used 103 | for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators, 104 | scramblers, and descrambers, while Galois is generally used for cyclic redundancy check 105 | generators and checkers. 106 | 107 | Fibonacci style (example for 64b66b scrambler, 0x8000000001) 108 | 109 | DIN (LSB first) 110 | | 111 | V 112 | (+)<---------------------------(+)<-----------------------------. 113 | | ^ | 114 | | .----. .----. .----. | .----. .----. .----. | 115 | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--' 116 | | '----' '----' '----' '----' '----' '----' 117 | V 118 | DOUT 119 | 120 | Galois style (example for CRC16, 0x8005) 121 | 122 | ,-------------------+-------------------------+----------(+)<-- DIN (MSB first) 123 | | | | ^ 124 | | .----. .----. V .----. .----. V .----. | 125 | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT 126 | '----' '----' '----' '----' '----' 127 | 128 | LFSR_FEED_FORWARD 129 | 130 | Generate feed forward instead of feed back LFSR. Enable this for PRBS checking and self- 131 | synchronous descrambling. 132 | 133 | Fibonacci feed-forward style (example for 64b66b descrambler, 0x8000000001) 134 | 135 | DIN (LSB first) 136 | | 137 | | .----. .----. .----. .----. .----. .----. 138 | +->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--. 139 | | '----' '----' '----' | '----' '----' '----' | 140 | | V | 141 | (+)<---------------------------(+)------------------------------' 142 | | 143 | V 144 | DOUT 145 | 146 | Galois feed-forward style 147 | 148 | ,-------------------+-------------------------+------------+--- DIN (MSB first) 149 | | | | | 150 | | .----. .----. V .----. .----. V .----. V 151 | `->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |->(+)-> DOUT 152 | '----' '----' '----' '----' '----' 153 | 154 | REVERSE 155 | 156 | Bit-reverse LFSR input and output. Shifts MSB first by default, set REVERSE for LSB first. 157 | 158 | DATA_WIDTH 159 | 160 | Specify width of input and output data bus. The module will perform one shift per input 161 | data bit, so if the input data bus is not required tie data_in to zero and set DATA_WIDTH 162 | to the required number of shifts per clock cycle. 163 | 164 | STYLE 165 | 166 | Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO" 167 | is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate 168 | directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate 169 | and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog 170 | reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction 171 | operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in 172 | Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing 173 | problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO" 174 | will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey 175 | synthesis translate directives. 176 | 177 | Settings for common LFSR/CRC implementations: 178 | 179 | Name Configuration Length Polynomial Initial value Notes 180 | CRC16-IBM Galois, bit-reverse 16 16'h8005 16'hffff 181 | CRC16-CCITT Galois 16 16'h1021 16'h1d0f 182 | CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output 183 | PRBS6 Fibonacci 6 6'h21 any 184 | PRBS7 Fibonacci 7 7'h41 any 185 | PRBS9 Fibonacci 9 9'h021 any ITU V.52 186 | PRBS10 Fibonacci 10 10'h081 any ITU 187 | PRBS11 Fibonacci 11 11'h201 any ITU O.152 188 | PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152 189 | PRBS17 Fibonacci 17 17'h04001 any 190 | PRBS20 Fibonacci 20 20'h00009 any ITU V.57 191 | PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151 192 | PRBS29 Fibonacci, inverted 29 29'h08000001 any 193 | PRBS31 Fibonacci, inverted 31 31'h10000001 any 194 | 64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet 195 | 128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3 196 | 197 | */ 198 | 199 | reg [LFSR_WIDTH-1:0] lfsr_mask_state[LFSR_WIDTH-1:0]; 200 | reg [DATA_WIDTH-1:0] lfsr_mask_data[LFSR_WIDTH-1:0]; 201 | reg [LFSR_WIDTH-1:0] output_mask_state[DATA_WIDTH-1:0]; 202 | reg [DATA_WIDTH-1:0] output_mask_data[DATA_WIDTH-1:0]; 203 | 204 | reg [LFSR_WIDTH-1:0] state_val; 205 | reg [DATA_WIDTH-1:0] data_val; 206 | 207 | integer i, j, k; 208 | 209 | initial begin 210 | // init bit masks 211 | for (i = 0; i < LFSR_WIDTH; i = i + 1) begin 212 | lfsr_mask_state[i] = {LFSR_WIDTH{1'b0}}; 213 | lfsr_mask_state[i][i] = 1'b1; 214 | lfsr_mask_data[i] = {DATA_WIDTH{1'b0}}; 215 | end 216 | for (i = 0; i < DATA_WIDTH; i = i + 1) begin 217 | output_mask_state[i] = {LFSR_WIDTH{1'b0}}; 218 | if (i < LFSR_WIDTH) begin 219 | output_mask_state[i][i] = 1'b1; 220 | end 221 | output_mask_data[i] = {DATA_WIDTH{1'b0}}; 222 | end 223 | 224 | // simulate shift register 225 | if (LFSR_CONFIG == "FIBONACCI") begin 226 | // Fibonacci configuration 227 | for (i = DATA_WIDTH-1; i >= 0; i = i - 1) begin 228 | // determine shift in value 229 | // current value in last FF, XOR with input data bit (MSB first) 230 | state_val = lfsr_mask_state[LFSR_WIDTH-1]; 231 | data_val = lfsr_mask_data[LFSR_WIDTH-1]; 232 | data_val = data_val ^ (1 << i); 233 | 234 | // add XOR inputs from correct indicies 235 | for (j = 1; j < LFSR_WIDTH; j = j + 1) begin 236 | if (LFSR_POLY & (1 << j)) begin 237 | state_val = lfsr_mask_state[j-1] ^ state_val; 238 | data_val = lfsr_mask_data[j-1] ^ data_val; 239 | end 240 | end 241 | 242 | // shift 243 | for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin 244 | lfsr_mask_state[j] = lfsr_mask_state[j-1]; 245 | lfsr_mask_data[j] = lfsr_mask_data[j-1]; 246 | end 247 | for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin 248 | output_mask_state[j] = output_mask_state[j-1]; 249 | output_mask_data[j] = output_mask_data[j-1]; 250 | end 251 | output_mask_state[0] = state_val; 252 | output_mask_data[0] = data_val; 253 | if (LFSR_FEED_FORWARD) begin 254 | // only shift in new input data 255 | state_val = {LFSR_WIDTH{1'b0}}; 256 | data_val = 1 << i; 257 | end 258 | lfsr_mask_state[0] = state_val; 259 | lfsr_mask_data[0] = data_val; 260 | end 261 | end else if (LFSR_CONFIG == "GALOIS") begin 262 | // Galois configuration 263 | for (i = DATA_WIDTH-1; i >= 0; i = i - 1) begin 264 | // determine shift in value 265 | // current value in last FF, XOR with input data bit (MSB first) 266 | state_val = lfsr_mask_state[LFSR_WIDTH-1]; 267 | data_val = lfsr_mask_data[LFSR_WIDTH-1]; 268 | data_val = data_val ^ (1 << i); 269 | 270 | // shift 271 | for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin 272 | lfsr_mask_state[j] = lfsr_mask_state[j-1]; 273 | lfsr_mask_data[j] = lfsr_mask_data[j-1]; 274 | end 275 | for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin 276 | output_mask_state[j] = output_mask_state[j-1]; 277 | output_mask_data[j] = output_mask_data[j-1]; 278 | end 279 | output_mask_state[0] = state_val; 280 | output_mask_data[0] = data_val; 281 | if (LFSR_FEED_FORWARD) begin 282 | // only shift in new input data 283 | state_val = {LFSR_WIDTH{1'b0}}; 284 | data_val = 1 << i; 285 | end 286 | lfsr_mask_state[0] = state_val; 287 | lfsr_mask_data[0] = data_val; 288 | 289 | // add XOR inputs at correct indicies 290 | for (j = 1; j < LFSR_WIDTH; j = j + 1) begin 291 | if (LFSR_POLY & (1 << j)) begin 292 | lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val; 293 | lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val; 294 | end 295 | end 296 | end 297 | end else begin 298 | $error("Error: unknown configuration setting!"); 299 | $finish; 300 | end 301 | 302 | // reverse bits if selected 303 | if (REVERSE) begin 304 | // reverse order 305 | for (i = 0; i < LFSR_WIDTH/2; i = i + 1) begin 306 | state_val = lfsr_mask_state[i]; 307 | data_val = lfsr_mask_data[i]; 308 | lfsr_mask_state[i] = lfsr_mask_state[LFSR_WIDTH-i-1]; 309 | lfsr_mask_data[i] = lfsr_mask_data[LFSR_WIDTH-i-1]; 310 | lfsr_mask_state[LFSR_WIDTH-i-1] = state_val; 311 | lfsr_mask_data[LFSR_WIDTH-i-1] = data_val; 312 | end 313 | for (i = 0; i < DATA_WIDTH/2; i = i + 1) begin 314 | state_val = output_mask_state[i]; 315 | data_val = output_mask_data[i]; 316 | output_mask_state[i] = output_mask_state[DATA_WIDTH-i-1]; 317 | output_mask_data[i] = output_mask_data[DATA_WIDTH-i-1]; 318 | output_mask_state[DATA_WIDTH-i-1] = state_val; 319 | output_mask_data[DATA_WIDTH-i-1] = data_val; 320 | end 321 | // reverse bits 322 | for (i = 0; i < LFSR_WIDTH; i = i + 1) begin 323 | state_val = 0; 324 | for (j = 0; j < LFSR_WIDTH; j = j + 1) begin 325 | state_val[j] = lfsr_mask_state[i][LFSR_WIDTH-j-1]; 326 | end 327 | lfsr_mask_state[i] = state_val; 328 | 329 | data_val = 0; 330 | for (j = 0; j < DATA_WIDTH; j = j + 1) begin 331 | data_val[j] = lfsr_mask_data[i][DATA_WIDTH-j-1]; 332 | end 333 | lfsr_mask_data[i] = data_val; 334 | end 335 | for (i = 0; i < DATA_WIDTH; i = i + 1) begin 336 | state_val = 0; 337 | for (j = 0; j < LFSR_WIDTH; j = j + 1) begin 338 | state_val[j] = output_mask_state[i][LFSR_WIDTH-j-1]; 339 | end 340 | output_mask_state[i] = state_val; 341 | 342 | data_val = 0; 343 | for (j = 0; j < DATA_WIDTH; j = j + 1) begin 344 | data_val[j] = output_mask_data[i][DATA_WIDTH-j-1]; 345 | end 346 | output_mask_data[i] = data_val; 347 | end 348 | end 349 | 350 | // for (i = 0; i < LFSR_WIDTH; i = i + 1) begin 351 | // $display("%b %b", lfsr_mask_state[i], lfsr_mask_data[i]); 352 | // end 353 | end 354 | 355 | // synthesis translate_off 356 | `define SIMULATION 357 | // synthesis translate_on 358 | 359 | `ifdef SIMULATION 360 | // "AUTO" style is "REDUCTION" for faster simulation 361 | parameter STYLE_INT = (STYLE == "AUTO") ? "REDUCTION" : STYLE; 362 | `else 363 | // "AUTO" style is "LOOP" for better synthesis result 364 | parameter STYLE_INT = (STYLE == "AUTO") ? "LOOP" : STYLE; 365 | `endif 366 | 367 | genvar n; 368 | 369 | generate 370 | 371 | if (STYLE_INT == "REDUCTION") begin 372 | 373 | // use Verilog reduction operator 374 | // fast in iverilog 375 | // significantly larger than generated code with ISE (inferred wide XORs may be tripping up optimizer) 376 | // slightly smaller than generated code with Quartus 377 | // --> better for simulation 378 | 379 | for (n = 0; n < LFSR_WIDTH; n = n + 1) begin : loop1 380 | assign state_out[n] = ^{(state_in & lfsr_mask_state[n]), (data_in & lfsr_mask_data[n])}; 381 | end 382 | for (n = 0; n < DATA_WIDTH; n = n + 1) begin : loop2 383 | assign data_out[n] = ^{(state_in & output_mask_state[n]), (data_in & output_mask_data[n])}; 384 | end 385 | 386 | end else if (STYLE_INT == "LOOP") begin 387 | 388 | // use nested loops 389 | // very slow in iverilog 390 | // slightly smaller than generated code with ISE 391 | // same size as generated code with Quartus 392 | // --> better for synthesis 393 | 394 | reg [LFSR_WIDTH-1:0] state_out_reg = 0; 395 | reg [DATA_WIDTH-1:0] data_out_reg = 0; 396 | 397 | assign state_out = state_out_reg; 398 | assign data_out = data_out_reg; 399 | 400 | always @* begin 401 | for (i = 0; i < LFSR_WIDTH; i = i + 1) begin 402 | state_out_reg[i] = 0; 403 | for (j = 0; j < LFSR_WIDTH; j = j + 1) begin 404 | if (lfsr_mask_state[i][j]) begin 405 | state_out_reg[i] = state_out_reg[i] ^ state_in[j]; 406 | end 407 | end 408 | for (j = 0; j < DATA_WIDTH; j = j + 1) begin 409 | if (lfsr_mask_data[i][j]) begin 410 | state_out_reg[i] = state_out_reg[i] ^ data_in[j]; 411 | end 412 | end 413 | end 414 | for (i = 0; i < DATA_WIDTH; i = i + 1) begin 415 | data_out_reg[i] = 0; 416 | for (j = 0; j < LFSR_WIDTH; j = j + 1) begin 417 | if (output_mask_state[i][j]) begin 418 | data_out_reg[i] = data_out_reg[i] ^ state_in[j]; 419 | end 420 | end 421 | for (j = 0; j < DATA_WIDTH; j = j + 1) begin 422 | if (output_mask_data[i][j]) begin 423 | data_out_reg[i] = data_out_reg[i] ^ data_in[j]; 424 | end 425 | end 426 | end 427 | end 428 | 429 | end else begin 430 | 431 | initial begin 432 | $error("Error: unknown style setting!"); 433 | $finish; 434 | end 435 | 436 | end 437 | 438 | endgenerate 439 | 440 | endmodule 441 | --------------------------------------------------------------------------------