├── LICENSE ├── README.md ├── rtl ├── comp │ ├── base │ │ ├── asfifo.vhd │ │ ├── fifo.vhd │ │ ├── fifo_mark.vhd │ │ ├── pll.vhd │ │ ├── rst_sync.vhd │ │ ├── sdp_ram.vhd │ │ └── sys_module.vhd │ ├── firewall │ │ ├── eraser.vhd │ │ ├── firewall.vhd │ │ ├── match_unit.vhd │ │ ├── match_unit_wb.vhd │ │ └── parser.vhd │ ├── rmii_mac │ │ ├── rmii_mac.vhd │ │ ├── rx_rmii_mac.vhd │ │ └── tx_rmii_mac.vhd │ ├── uart2wbm │ │ ├── uart.vhd │ │ ├── uart2wbm.vhd │ │ ├── uart_debouncer.vhd │ │ ├── uart_parity.vhd │ │ ├── uart_rx.vhd │ │ └── uart_tx.vhd │ └── wb_splitter │ │ └── wb_splitter.vhd ├── fpga.vhd └── synth │ ├── fpga.qpf │ ├── fpga.qsf │ └── fpga.sdc └── sw ├── configure_match.py ├── firewall.py ├── match_unit.py ├── print_summary.py ├── rmii_mac.py ├── sys_module.py └── wishbone.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jakub Cabal 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RMII Firewall FPGA 2 | The project "RMII Firewall FPGA" is VHDL implementation of 100 Mbps (RMII) firewall for FPGA. The RMII Firewall FPGA allows to filter Ethernet packets according to MAC or IP addresses. The Wishbone bus is used to control the entire design. The Wishbone requests can be transmitted from a PC via the UART interface. The target device is FPGA board CYC1000 by Trenz Electronic. As Ethernet PHY are used two LAN8720 boards connected to FPGA via RMII interfaces. 3 | 4 | ## Current status 5 | In development, it may not work properly! 6 | 7 | ## Top level diagram 8 | ``` 9 | +---------+ +-------------+ +---------+ 10 | ETH0 <===| RMII |<===| FIREWALL in |<===| RMII |<=== ETH1 11 | PORT ===>| MAC |===>| both ways |===>| MAC |===> PORT 12 | +----+----+ +------+------+ +----+----+ 13 | ↕ ↕ ↕ 14 | +================+================+ WISHBONE BUS 15 | ↕ ↕ 16 | +----+----+ +----+----+ 17 | UART <---| UART2WB | | SYSTEM | 18 | PORT --->| MASTER | | MODULE | 19 | +---------+ +---------+ 20 | ``` 21 | ## Main modules description 22 | 23 | * RMII MAC - Receiving and transmitting Ethernet packets on the RMII interface (limitations: only 100 Mbps full duplex mode, no CRC checking). 24 | * FIREWALL - Parses (extraction of MAC and IP addresses) and filters incoming packets by MAC or IP address. 25 | * UART2WB MASTER - Transmits the Wishbone requests and responses via UART interface (Wishbone bus master module). 26 | * SYSTEM MODULE - Basic system control and status registers (version, debug space etc.) accessible via Wishbone bus. 27 | 28 | ## Resource usage summary: 29 | 30 | Module | LE (LUT+FF) | LUT | FF | BRAM (M9k) | Fmax 31 | :---:|:---:|:---:|:---:|:---:|:---: 32 | FPGA (whole design) | 11471 | 6671‬ | 10147 | 52 | 70.2 MHz 33 | **Some submodules:** | === | === | === | === | === 34 | UART2WBM | 192 | 103 | 156 | 0 | 303.9 MHz 35 | RX_RMII_MAC | 1061 | 848 | 894 | 4 | 149.0 MHz 36 | TX_RMII_MAC | 370 | 232 | 318 | 3 | 165.7 MHz 37 | Firewall | 4121 | 2116 | 3746 | 19 | 153.6 MHz 38 | 39 | *Implementation was performed using Quartus Prime Lite Edition 18.1.0 for FPGA Intel Cyclone 10 LP 10CL025YU256C8G.* 40 | 41 | ## Address space 42 | ``` 43 | 0xOOOO - 0x3FFF -- System module 44 | 0x4000 - 0x40FF -- ETH PORT0 - RX RMII MAC module 45 | 0x4100 - 0x41FF -- ETH PORT0 - TX RMII MAC module 46 | 0x4200 - 0x5FFF -- Reserved 47 | 0x6000 - 0x60FF -- ETH PORT1 - RX RMII MAC module 48 | 0x6100 - 0x61FF -- ETH PORT1 - TX RMII MAC module 49 | 0x6200 - 0x7FFF -- Reserved 50 | 0x8000 - 0x83FF -- Firewall module (ETH PORT0 to PORT1) 51 | 0x8400 - 0x87FF -- MatchUnit MAC_DST (ETH PORT0 to PORT1) 52 | 0x8800 - 0x8BFF -- MatchUnit MAC_SRC (ETH PORT0 to PORT1) 53 | 0x8C00 - 0x8FFF -- MatchUnit IPV4_DST (ETH PORT0 to PORT1) 54 | 0x9000 - 0x93FF -- MatchUnit IPV4_SRC (ETH PORT0 to PORT1) 55 | 0x9400 - 0x97FF -- MatchUnit IPV6_DST (ETH PORT0 to PORT1) 56 | 0x9800 - 0x9BFF -- MatchUnit IPV6_SRC (ETH PORT0 to PORT1) 57 | 0x9C00 - 0x9FFF -- Reserved 58 | 0xA000 - 0xA3FF -- Firewall module (ETH PORT1 to PORT0) 59 | 0xA400 - 0xA7FF -- MatchUnit MAC_DST (ETH PORT1 to PORT0) 60 | 0xA800 - 0xABFF -- MatchUnit MAC_SRC (ETH PORT1 to PORT0) 61 | 0xAC00 - 0xAFFF -- MatchUnit IPV4_DST (ETH PORT1 to PORT0) 62 | 0xB000 - 0xB3FF -- MatchUnit IPV4_SRC (ETH PORT1 to PORT0) 63 | 0xB400 - 0xB7FF -- MatchUnit IPV6_DST (ETH PORT1 to PORT0) 64 | 0xB800 - 0xBBFF -- MatchUnit IPV6_SRC (ETH PORT1 to PORT0) 65 | 0xBC00 - 0xFFFF -- Reserved 66 | ``` 67 | ## License 68 | The RMII Firewall FPGA is available under the MIT license (MIT). Please read [LICENSE file](LICENSE). -------------------------------------------------------------------------------- /rtl/comp/base/asfifo.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | LIBRARY altera_mf; 13 | USE altera_mf.all; 14 | 15 | entity ASFIFO is 16 | Generic ( 17 | DATA_WIDTH : integer := 8; 18 | ADDR_WIDTH : integer := 4 19 | ); 20 | Port ( 21 | -- FIFO WRITE INTERFACE 22 | WR_CLK : in std_logic; 23 | WR_RST : in std_logic; 24 | WR_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 25 | WR_REQ : in std_logic; 26 | WR_FULL : out std_logic; 27 | -- FIFO READ INTERFACE 28 | RD_CLK : in std_logic; 29 | RD_RST : in std_logic; 30 | RD_DATA : out std_logic_vector(DATA_WIDTH-1 downto 0); 31 | RD_DATA_VLD : out std_logic; 32 | RD_REQ : in std_logic 33 | ); 34 | end entity; 35 | 36 | architecture RTL of ASFIFO is 37 | 38 | component dcfifo 39 | generic ( 40 | intended_device_family : string; 41 | lpm_numwords : natural; 42 | lpm_showahead : string; 43 | lpm_type : string; 44 | lpm_width : natural; 45 | lpm_widthu : natural; 46 | overflow_checking : string; 47 | rdsync_delaypipe : natural; 48 | read_aclr_synch : string; 49 | underflow_checking : string; 50 | use_eab : string; 51 | write_aclr_synch : string; 52 | wrsync_delaypipe : natural 53 | ); 54 | port ( 55 | aclr : in std_logic; 56 | data : in std_logic_vector(DATA_WIDTH-1 downto 0); 57 | rdclk : in std_logic; 58 | rdreq : in std_logic; 59 | wrclk : in std_logic; 60 | wrreq : in std_logic; 61 | q : out std_logic_vector(DATA_WIDTH-1 downto 0); 62 | rdempty : out std_logic; 63 | wrfull : out std_logic 64 | ); 65 | end component; 66 | 67 | attribute ALTERA_ATTRIBUTE : string; 68 | 69 | signal fifo_aclr : std_logic; 70 | signal rd_data_vld_n : std_logic; 71 | 72 | attribute ALTERA_ATTRIBUTE of RTL : architecture is "-name SDC_STATEMENT ""set_false_path -through [get_nets *fifo_aclr]"""; 73 | 74 | begin 75 | 76 | fifo_aclr <= WR_RST or RD_RST; 77 | 78 | dcfifo_i : dcfifo 79 | GENERIC MAP ( 80 | intended_device_family => "Cyclone 10 LP", 81 | lpm_numwords => 2**ADDR_WIDTH, 82 | lpm_showahead => "ON", 83 | lpm_type => "dcfifo", 84 | lpm_width => DATA_WIDTH, 85 | lpm_widthu => ADDR_WIDTH, 86 | overflow_checking => "ON", 87 | rdsync_delaypipe => 4, 88 | read_aclr_synch => "ON", 89 | underflow_checking => "ON", 90 | use_eab => "ON", 91 | write_aclr_synch => "ON", 92 | wrsync_delaypipe => 4 93 | ) 94 | PORT MAP ( 95 | aclr => fifo_aclr, 96 | data => WR_DATA, 97 | rdclk => RD_CLK, 98 | rdreq => RD_REQ, 99 | wrclk => WR_CLK, 100 | wrreq => WR_REQ, 101 | q => RD_DATA, 102 | rdempty => rd_data_vld_n, 103 | wrfull => WR_FULL 104 | ); 105 | 106 | RD_DATA_VLD <= not rd_data_vld_n; 107 | 108 | end architecture; 109 | -------------------------------------------------------------------------------- /rtl/comp/base/fifo.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity FIFO is 13 | Generic ( 14 | DATA_WIDTH : integer := 8; 15 | ADDR_WIDTH : integer := 4 16 | ); 17 | Port ( 18 | CLK : in std_logic; 19 | RST : in std_logic; 20 | -- FIFO WRITE INTERFACE 21 | WR_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 22 | WR_REQ : in std_logic; 23 | WR_FULL : out std_logic; 24 | -- FIFO READ INTERFACE 25 | RD_DATA : out std_logic_vector(DATA_WIDTH-1 downto 0); 26 | RD_DATA_VLD : out std_logic; 27 | RD_REQ : in std_logic; 28 | -- FIFO STATUS SIGNAL 29 | STATUS : out std_logic_vector(ADDR_WIDTH-1 downto 0) 30 | ); 31 | end entity; 32 | 33 | architecture RTL of FIFO is 34 | 35 | begin 36 | 37 | fifo_mark_i : entity work.FIFO_MARK 38 | generic map ( 39 | DATA_WIDTH => DATA_WIDTH, 40 | ADDR_WIDTH => ADDR_WIDTH 41 | ) 42 | port map ( 43 | CLK => CLK, 44 | RST => RST, 45 | -- FIFO WRITE INTERFACE 46 | WR_DATA => WR_DATA, 47 | WR_REQ => WR_REQ, 48 | WR_FULL => WR_FULL, 49 | -- FIFO READ INTERFACE 50 | RD_DATA => RD_DATA, 51 | RD_DATA_VLD => RD_DATA_VLD, 52 | RD_REQ => RD_REQ, 53 | -- FIFO OTHERS SIGNALS 54 | MARK => '1', 55 | DISCARD => '0', 56 | STATUS => STATUS 57 | ); 58 | 59 | end architecture; 60 | -------------------------------------------------------------------------------- /rtl/comp/base/fifo_mark.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity FIFO_MARK is 13 | Generic ( 14 | DATA_WIDTH : integer := 8; 15 | ADDR_WIDTH : integer := 4 16 | ); 17 | Port ( 18 | CLK : in std_logic; 19 | RST : in std_logic; 20 | -- FIFO WRITE INTERFACE 21 | WR_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 22 | WR_REQ : in std_logic; 23 | WR_FULL : out std_logic; 24 | -- FIFO READ INTERFACE 25 | RD_DATA : out std_logic_vector(DATA_WIDTH-1 downto 0); 26 | RD_DATA_VLD : out std_logic; 27 | RD_REQ : in std_logic; 28 | -- FIFO OTHERS SIGNALS 29 | MARK : in std_logic; 30 | DISCARD : in std_logic; 31 | STATUS : out std_logic_vector(ADDR_WIDTH-1 downto 0) 32 | ); 33 | end entity; 34 | 35 | architecture RTL of FIFO_MARK is 36 | 37 | signal wr_addr : unsigned(ADDR_WIDTH-1 downto 0); 38 | signal wr_addr_mark : unsigned(ADDR_WIDTH-1 downto 0); 39 | signal wr_allowed : std_logic; 40 | signal rd_addr : unsigned(ADDR_WIDTH-1 downto 0); 41 | signal rd_allowed : std_logic; 42 | signal cmp_full : std_logic; 43 | signal cmp_afull : std_logic; 44 | signal full_next : std_logic; 45 | signal full_reg : std_logic; 46 | signal cmp_empty : std_logic; 47 | 48 | type bram_type is array(2**ADDR_WIDTH-1 downto 0) of std_logic_vector(DATA_WIDTH-1 downto 0); 49 | signal bram : bram_type := (others => (others => '0')); 50 | 51 | begin 52 | 53 | wr_allowed <= WR_REQ and not full_reg; 54 | rd_allowed <= RD_REQ and not cmp_empty; 55 | 56 | -- ------------------------------------------------------------------------- 57 | -- BRAM AND READ DATA VALID 58 | -- ------------------------------------------------------------------------- 59 | 60 | bram_p : process (CLK) 61 | begin 62 | if (rising_edge(CLK)) then 63 | if (wr_allowed = '1') then 64 | bram(to_integer(wr_addr)) <= WR_DATA; 65 | end if; 66 | if (RD_REQ = '1') then 67 | RD_DATA <= bram(to_integer(rd_addr)); 68 | end if; 69 | end if; 70 | end process; 71 | 72 | rd_data_vld_p : process (CLK) 73 | begin 74 | if (rising_edge(CLK)) then 75 | if (RD_REQ = '1') then 76 | RD_DATA_VLD <= not cmp_empty; 77 | end if; 78 | end if; 79 | end process; 80 | 81 | -- ------------------------------------------------------------------------- 82 | -- WRITE ADDRESS COUNTER 83 | -- ------------------------------------------------------------------------- 84 | 85 | wr_addr_cnt_p : process (CLK) 86 | begin 87 | if (rising_edge(CLK)) then 88 | if (RST = '1') then 89 | wr_addr <= (others => '0'); 90 | elsif (DISCARD = '1') then 91 | wr_addr <= wr_addr_mark; 92 | elsif (wr_allowed = '1') then 93 | wr_addr <= wr_addr + 1; 94 | end if; 95 | end if; 96 | end process; 97 | 98 | wr_addr_mark_p : process (CLK) 99 | begin 100 | if (rising_edge(CLK)) then 101 | if (RST = '1') then 102 | wr_addr_mark <= (others => '0'); 103 | elsif (MARK = '1') then 104 | wr_addr_mark <= wr_addr; 105 | end if; 106 | end if; 107 | end process; 108 | 109 | -- ------------------------------------------------------------------------- 110 | -- READ ADDRESS COUNTER 111 | -- ------------------------------------------------------------------------- 112 | 113 | rd_addr_cnt_p : process (CLK) 114 | begin 115 | if (rising_edge(CLK)) then 116 | if (RST = '1') then 117 | rd_addr <= (others => '0'); 118 | elsif (rd_allowed = '1') then 119 | rd_addr <= rd_addr + 1; 120 | end if; 121 | end if; 122 | end process; 123 | 124 | -- ------------------------------------------------------------------------- 125 | -- WR_FULL FLAG REGISTER 126 | -- ------------------------------------------------------------------------- 127 | 128 | cmp_full <= '1' when (rd_addr = (wr_addr+1)) else '0'; 129 | cmp_afull <= '1' when (rd_addr = (wr_addr+2)) else '0'; 130 | full_next <= cmp_full or (cmp_afull and WR_REQ and not RD_REQ); 131 | 132 | full_reg_p : process (CLK) 133 | begin 134 | if (rising_edge(CLK)) then 135 | if (RST = '1') then 136 | full_reg <= '0'; 137 | else 138 | full_reg <= full_next; 139 | end if; 140 | end if; 141 | end process; 142 | 143 | WR_FULL <= full_reg; 144 | 145 | -- ------------------------------------------------------------------------- 146 | -- EMPTY FLAG AND FIFO STATUS 147 | -- ------------------------------------------------------------------------- 148 | 149 | cmp_empty <= '1' when (rd_addr = wr_addr_mark) else '0'; 150 | STATUS <= std_logic_vector(wr_addr - rd_addr); 151 | 152 | end architecture; 153 | -------------------------------------------------------------------------------- /rtl/comp/base/pll.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | LIBRARY altera_mf; 13 | USE altera_mf.all; 14 | 15 | entity PLL is 16 | Port ( 17 | IN_CLK_12M : in std_logic; 18 | IN_RST_BTN : in std_logic; 19 | OUT_PLL_LOCKED : out std_logic; 20 | OUT_CLK_25M : out std_logic; 21 | OUT_CLK_50M : out std_logic 22 | ); 23 | end entity; 24 | 25 | architecture RTL of PLL is 26 | 27 | component altpll 28 | generic ( 29 | bandwidth_type : string; 30 | clk0_divide_by : natural; 31 | clk0_duty_cycle : natural; 32 | clk0_multiply_by : natural; 33 | clk0_phase_shift : string; 34 | clk1_divide_by : natural; 35 | clk1_duty_cycle : natural; 36 | clk1_multiply_by : natural; 37 | clk1_phase_shift : string; 38 | compensate_clock : string; 39 | inclk0_input_frequency : natural; 40 | intended_device_family : string; 41 | lpm_hint : string; 42 | lpm_type : string; 43 | operation_mode : string; 44 | pll_type : string; 45 | port_activeclock : string; 46 | port_areset : string; 47 | port_clkbad0 : string; 48 | port_clkbad1 : string; 49 | port_clkloss : string; 50 | port_clkswitch : string; 51 | port_configupdate : string; 52 | port_fbin : string; 53 | port_inclk0 : string; 54 | port_inclk1 : string; 55 | port_locked : string; 56 | port_pfdena : string; 57 | port_phasecounterselect : string; 58 | port_phasedone : string; 59 | port_phasestep : string; 60 | port_phaseupdown : string; 61 | port_pllena : string; 62 | port_scanaclr : string; 63 | port_scanclk : string; 64 | port_scanclkena : string; 65 | port_scandata : string; 66 | port_scandataout : string; 67 | port_scandone : string; 68 | port_scanread : string; 69 | port_scanwrite : string; 70 | port_clk0 : string; 71 | port_clk1 : string; 72 | port_clk2 : string; 73 | port_clk3 : string; 74 | port_clk4 : string; 75 | port_clk5 : string; 76 | port_clkena0 : string; 77 | port_clkena1 : string; 78 | port_clkena2 : string; 79 | port_clkena3 : string; 80 | port_clkena4 : string; 81 | port_clkena5 : string; 82 | port_extclk0 : string; 83 | port_extclk1 : string; 84 | port_extclk2 : string; 85 | port_extclk3 : string; 86 | self_reset_on_loss_lock : string; 87 | width_clock : natural 88 | ); 89 | port ( 90 | areset : in std_logic; 91 | inclk : in std_logic_vector(1 downto 0); 92 | clk : out std_logic_vector(4 downto 0); 93 | locked : out std_logic 94 | ); 95 | end component; 96 | 97 | signal pll_in_clk : std_logic_vector(1 downto 0); 98 | signal pll_out_clk : std_logic_vector(4 downto 0); 99 | 100 | begin 101 | 102 | pll_in_clk <= '0' & IN_CLK_12M; 103 | 104 | altpll_i : altpll 105 | generic map ( 106 | bandwidth_type => "AUTO", 107 | clk0_divide_by => 12, 108 | clk0_duty_cycle => 50, 109 | clk0_multiply_by => 25, 110 | clk0_phase_shift => "0", 111 | clk1_divide_by => 6, 112 | clk1_duty_cycle => 50, 113 | clk1_multiply_by => 25, 114 | clk1_phase_shift => "0", 115 | compensate_clock => "CLK0", 116 | inclk0_input_frequency => 83333, 117 | intended_device_family => "Cyclone 10 LP", 118 | lpm_hint => "CBX_MODULE_PREFIX=pll", 119 | lpm_type => "altpll", 120 | operation_mode => "NORMAL", 121 | pll_type => "AUTO", 122 | port_activeclock => "PORT_UNUSED", 123 | port_areset => "PORT_USED", 124 | port_clkbad0 => "PORT_UNUSED", 125 | port_clkbad1 => "PORT_UNUSED", 126 | port_clkloss => "PORT_UNUSED", 127 | port_clkswitch => "PORT_UNUSED", 128 | port_configupdate => "PORT_UNUSED", 129 | port_fbin => "PORT_UNUSED", 130 | port_inclk0 => "PORT_USED", 131 | port_inclk1 => "PORT_UNUSED", 132 | port_locked => "PORT_USED", 133 | port_pfdena => "PORT_UNUSED", 134 | port_phasecounterselect => "PORT_UNUSED", 135 | port_phasedone => "PORT_UNUSED", 136 | port_phasestep => "PORT_UNUSED", 137 | port_phaseupdown => "PORT_UNUSED", 138 | port_pllena => "PORT_UNUSED", 139 | port_scanaclr => "PORT_UNUSED", 140 | port_scanclk => "PORT_UNUSED", 141 | port_scanclkena => "PORT_UNUSED", 142 | port_scandata => "PORT_UNUSED", 143 | port_scandataout => "PORT_UNUSED", 144 | port_scandone => "PORT_UNUSED", 145 | port_scanread => "PORT_UNUSED", 146 | port_scanwrite => "PORT_UNUSED", 147 | port_clk0 => "PORT_USED", 148 | port_clk1 => "PORT_USED", 149 | port_clk2 => "PORT_UNUSED", 150 | port_clk3 => "PORT_UNUSED", 151 | port_clk4 => "PORT_UNUSED", 152 | port_clk5 => "PORT_UNUSED", 153 | port_clkena0 => "PORT_UNUSED", 154 | port_clkena1 => "PORT_UNUSED", 155 | port_clkena2 => "PORT_UNUSED", 156 | port_clkena3 => "PORT_UNUSED", 157 | port_clkena4 => "PORT_UNUSED", 158 | port_clkena5 => "PORT_UNUSED", 159 | port_extclk0 => "PORT_UNUSED", 160 | port_extclk1 => "PORT_UNUSED", 161 | port_extclk2 => "PORT_UNUSED", 162 | port_extclk3 => "PORT_UNUSED", 163 | self_reset_on_loss_lock => "OFF", 164 | width_clock => 5 165 | ) 166 | port map ( 167 | areset => IN_RST_BTN, 168 | inclk => pll_in_clk, 169 | clk => pll_out_clk, 170 | locked => OUT_PLL_LOCKED 171 | ); 172 | 173 | OUT_CLK_25M <= pll_out_clk(0); 174 | OUT_CLK_50M <= pll_out_clk(1); 175 | 176 | end architecture; 177 | -------------------------------------------------------------------------------- /rtl/comp/base/rst_sync.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity RST_SYNC is 13 | Port ( 14 | CLK : in std_logic; 15 | ASYNC_RST : in std_logic; 16 | SYNCED_RST : out std_logic 17 | ); 18 | end entity; 19 | 20 | architecture RTL of RST_SYNC is 21 | 22 | attribute ALTERA_ATTRIBUTE : string; 23 | attribute PRESERVE : boolean; 24 | 25 | signal meta_reg : std_logic; 26 | signal reset_reg : std_logic; 27 | 28 | attribute ALTERA_ATTRIBUTE of RTL : architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers {*RST_SYNC:*|meta_reg}] """; 29 | attribute ALTERA_ATTRIBUTE of meta_reg : signal is "-name SYNCHRONIZER_IDENTIFICATION ""FORCED IF ASYNCHRONOUS"""; 30 | attribute ALTERA_ATTRIBUTE of reset_reg : signal is "-name SYNCHRONIZER_IDENTIFICATION ""FORCED IF ASYNCHRONOUS"""; 31 | attribute PRESERVE of meta_reg : signal is TRUE; 32 | attribute PRESERVE of reset_reg : signal is TRUE; 33 | 34 | begin 35 | 36 | process (CLK, ASYNC_RST) 37 | begin 38 | if (ASYNC_RST = '1') then 39 | meta_reg <= '1'; 40 | reset_reg <= '1'; 41 | elsif (rising_edge(CLK)) then 42 | meta_reg <= '0'; 43 | reset_reg <= meta_reg; 44 | end if; 45 | end process; 46 | 47 | SYNCED_RST <= reset_reg; 48 | 49 | end architecture; 50 | -------------------------------------------------------------------------------- /rtl/comp/base/sdp_ram.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity SDP_RAM is 13 | Generic ( 14 | DATA_WIDTH : integer := 8; 15 | ADDR_WIDTH : integer := 4 16 | ); 17 | Port ( 18 | CLK : in std_logic; 19 | RST : in std_logic; 20 | -- WRITE INTERFACE 21 | WR_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 22 | WR_ADDR : in std_logic_vector(ADDR_WIDTH-1 downto 0); 23 | WR_REQ : in std_logic; 24 | -- READ INTERFACE 25 | RD_ADDR : in std_logic_vector(ADDR_WIDTH-1 downto 0); 26 | RD_REQ : in std_logic; 27 | RD_DATA : out std_logic_vector(DATA_WIDTH-1 downto 0); 28 | RD_DATA_VLD : out std_logic 29 | ); 30 | end entity; 31 | 32 | architecture RTL of SDP_RAM is 33 | 34 | type bram_type is array(2**ADDR_WIDTH-1 downto 0) of std_logic_vector(DATA_WIDTH-1 downto 0); 35 | signal bram : bram_type := (others => (others => '0')); 36 | 37 | begin 38 | 39 | bram_wr_p : process (CLK) 40 | begin 41 | if (rising_edge(CLK)) then 42 | if (WR_REQ = '1') then 43 | bram(to_integer(unsigned(WR_ADDR))) <= WR_DATA; 44 | end if; 45 | end if; 46 | end process; 47 | 48 | bram_rd_p : process (CLK) 49 | begin 50 | if (rising_edge(CLK)) then 51 | if (RD_REQ = '1') then 52 | RD_DATA <= bram(to_integer(unsigned(RD_ADDR))); 53 | end if; 54 | end if; 55 | end process; 56 | 57 | rd_data_vld_p : process (CLK) 58 | begin 59 | if (rising_edge(CLK)) then 60 | RD_DATA_VLD <= RD_REQ; 61 | end if; 62 | end process; 63 | 64 | end architecture; 65 | -------------------------------------------------------------------------------- /rtl/comp/base/sys_module.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity SYS_MODULE is 13 | Port ( 14 | -- CLOCK AND RESET 15 | CLK : in std_logic; 16 | RST : in std_logic; 17 | 18 | -- WISHBONE SLAVE INTERFACE 19 | WB_CYC : in std_logic; 20 | WB_STB : in std_logic; 21 | WB_WE : in std_logic; 22 | WB_ADDR : in std_logic_vector(15 downto 0); 23 | WB_DIN : in std_logic_vector(31 downto 0); 24 | WB_STALL : out std_logic; 25 | WB_ACK : out std_logic; 26 | WB_DOUT : out std_logic_vector(31 downto 0) 27 | ); 28 | end entity; 29 | 30 | architecture RTL of SYS_MODULE is 31 | 32 | signal debug_reg_sel : std_logic; 33 | signal debug_reg_we : std_logic; 34 | signal debug_reg : std_logic_vector(31 downto 0); 35 | 36 | begin 37 | 38 | debug_reg_sel <= '1' when (WB_ADDR = X"0004") else '0'; 39 | debug_reg_we <= WB_STB and WB_WE and debug_reg_sel; 40 | 41 | debug_reg_p : process (CLK) 42 | begin 43 | if (rising_edge(CLK)) then 44 | if (debug_reg_we = '1') then 45 | debug_reg <= WB_DIN; 46 | end if; 47 | end if; 48 | end process; 49 | 50 | WB_STALL <= '0'; 51 | 52 | wb_ack_reg_p : process (CLK) 53 | begin 54 | if (rising_edge(CLK)) then 55 | WB_ACK <= WB_CYC and WB_STB; 56 | end if; 57 | end process; 58 | 59 | wb_dout_reg_p : process (CLK) 60 | begin 61 | if (rising_edge(CLK)) then 62 | case WB_ADDR is 63 | when X"0000" => 64 | WB_DOUT <= X"20191023"; 65 | when X"0004" => 66 | WB_DOUT <= debug_reg; 67 | when others => 68 | WB_DOUT <= X"DEADCAFE"; 69 | end case; 70 | end if; 71 | end process; 72 | 73 | end architecture; 74 | -------------------------------------------------------------------------------- /rtl/comp/firewall/eraser.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity ERASER is 13 | Port ( 14 | -- CLOCK AND RESET 15 | CLK : in std_logic; 16 | RST : in std_logic; 17 | 18 | -- INPUT META INTERFACE (PER EACH PACKET) 19 | RX_META_DISCARD : in std_logic; 20 | RX_META_VLD : in std_logic; 21 | 22 | -- INPUT STREAM INTERFACE 23 | RX_DATA : in std_logic_vector(7 downto 0); 24 | RX_SOP : in std_logic; 25 | RX_EOP : in std_logic; 26 | RX_VLD : in std_logic; 27 | RX_RDY : out std_logic; 28 | 29 | -- OUTPUT STREAM INTERFACE 30 | TX_DATA : out std_logic_vector(7 downto 0); 31 | TX_SOP : out std_logic; 32 | TX_EOP : out std_logic; 33 | TX_VLD : out std_logic; 34 | TX_RDY : in std_logic 35 | ); 36 | end entity; 37 | 38 | architecture RTL of ERASER is 39 | 40 | type fsm_state is (idle, paket_ok, paket_ko); 41 | signal fsm_pstate : fsm_state; 42 | signal fsm_nstate : fsm_state; 43 | 44 | begin 45 | 46 | TX_DATA <= RX_DATA; 47 | TX_SOP <= RX_SOP; 48 | TX_EOP <= RX_EOP; 49 | 50 | -- ------------------------------------------------------------------------- 51 | -- FSM 52 | -- ------------------------------------------------------------------------- 53 | 54 | process (CLK) 55 | begin 56 | if (rising_edge(CLK)) then 57 | if (RST = '1') then 58 | fsm_pstate <= idle; 59 | else 60 | fsm_pstate <= fsm_nstate; 61 | end if; 62 | end if; 63 | end process; 64 | 65 | process (fsm_pstate, RX_META_VLD, RX_META_DISCARD, TX_RDY, RX_VLD, RX_EOP) 66 | begin 67 | fsm_nstate <= idle; 68 | RX_RDY <= '0'; 69 | TX_VLD <= '0'; 70 | 71 | case fsm_pstate is 72 | when idle => 73 | RX_RDY <= '0'; 74 | TX_VLD <= '0'; 75 | if (RX_META_VLD = '1') then 76 | if (RX_META_DISCARD = '1') then 77 | fsm_nstate <= paket_ko; 78 | else 79 | fsm_nstate <= paket_ok; 80 | end if; 81 | else 82 | fsm_nstate <= idle; 83 | end if; 84 | 85 | when paket_ok => 86 | RX_RDY <= TX_RDY; 87 | TX_VLD <= RX_VLD; 88 | if (RX_EOP = '1' and RX_VLD = '1' and TX_RDY = '1') then 89 | fsm_nstate <= idle; 90 | else 91 | fsm_nstate <= paket_ok; 92 | end if; 93 | 94 | when paket_ko => 95 | RX_RDY <= '1'; 96 | TX_VLD <= '0'; 97 | if (RX_EOP = '1' and RX_VLD = '1') then 98 | fsm_nstate <= idle; 99 | else 100 | fsm_nstate <= paket_ko; 101 | end if; 102 | end case; 103 | end process; 104 | 105 | end architecture; 106 | -------------------------------------------------------------------------------- /rtl/comp/firewall/firewall.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity FIREWALL is 13 | Port ( 14 | -- CLOCK AND RESET 15 | CLK : in std_logic; 16 | RST : in std_logic; 17 | 18 | -- INPUT STREAM INTERFACE 19 | RX_DATA : in std_logic_vector(7 downto 0); 20 | RX_SOP : in std_logic; 21 | RX_EOP : in std_logic; 22 | RX_VLD : in std_logic; 23 | RX_RDY : out std_logic; 24 | 25 | -- OUTPUT STREAM INTERFACE 26 | TX_DATA : out std_logic_vector(7 downto 0); 27 | TX_SOP : out std_logic; 28 | TX_EOP : out std_logic; 29 | TX_VLD : out std_logic; 30 | TX_RDY : in std_logic; 31 | 32 | -- WISHBONE SLAVE INTERFACE 33 | WB_CYC : in std_logic; 34 | WB_STB : in std_logic; 35 | WB_WE : in std_logic; 36 | WB_ADDR : in std_logic_vector(15 downto 0); 37 | WB_DIN : in std_logic_vector(31 downto 0); 38 | WB_STALL : out std_logic; 39 | WB_ACK : out std_logic; 40 | WB_DOUT : out std_logic_vector(31 downto 0) 41 | ); 42 | end entity; 43 | 44 | architecture RTL of FIREWALL is 45 | 46 | constant WB_PORTS : natural := 8; 47 | constant WB_OFFSET : natural := 10; 48 | constant FIFO_DATA_WIDTH : natural := 8+1+1; -- data + sop + eop 49 | constant FIFO_ADDR_WIDTH : natural := 12; -- fifo depth = 4096 - 1 words 50 | 51 | signal wb_mfs_cyc : std_logic_vector(WB_PORTS-1 downto 0); 52 | signal wb_mfs_stb : std_logic_vector(WB_PORTS-1 downto 0); 53 | signal wb_mfs_we : std_logic_vector(WB_PORTS-1 downto 0); 54 | signal wb_mfs_addr : std_logic_vector(WB_PORTS*16-1 downto 0); 55 | signal wb_mfs_din : std_logic_vector(WB_PORTS*32-1 downto 0) := (others => '0'); 56 | signal wb_mfs_stall : std_logic_vector(WB_PORTS-1 downto 0) := (others => '0'); 57 | signal wb_mfs_ack : std_logic_vector(WB_PORTS-1 downto 0) := (others => '0'); 58 | signal wb_mfs_dout : std_logic_vector(WB_PORTS*32-1 downto 0); 59 | 60 | signal parser_data : std_logic_vector(7 downto 0); 61 | signal parser_sop : std_logic; 62 | signal parser_eop : std_logic; 63 | signal parser_vld : std_logic; 64 | signal parser_rdy : std_logic; 65 | signal parser_eop_vld : std_logic; 66 | signal parser_ipv4_vld : std_logic; 67 | signal parser_ipv6_vld : std_logic; 68 | 69 | signal ex_mac_dst : std_logic_vector(47 downto 0); 70 | signal ex_mac_src : std_logic_vector(47 downto 0); 71 | signal ex_ipv4_dst : std_logic_vector(31 downto 0); 72 | signal ex_ipv4_src : std_logic_vector(31 downto 0); 73 | signal ex_ipv4_vld : std_logic; 74 | signal ex_ipv6_dst : std_logic_vector(127 downto 0); 75 | signal ex_ipv6_src : std_logic_vector(127 downto 0); 76 | signal ex_ipv6_vld : std_logic; 77 | 78 | signal fifo_din : std_logic_vector(FIFO_DATA_WIDTH-1 downto 0); 79 | signal fifo_wr : std_logic; 80 | signal fifo_full : std_logic; 81 | signal fifo_dout : std_logic_vector(FIFO_DATA_WIDTH-1 downto 0); 82 | signal fifo_dout_vld : std_logic; 83 | signal fifo_rd : std_logic; 84 | 85 | signal stfi_data : std_logic_vector(7 downto 0); 86 | signal stfi_sop : std_logic; 87 | signal stfi_eop : std_logic; 88 | signal stfi_vld : std_logic; 89 | signal stfi_rdy : std_logic; 90 | 91 | signal eraser_data : std_logic_vector(7 downto 0); 92 | signal eraser_sop : std_logic; 93 | signal eraser_eop : std_logic; 94 | signal eraser_vld : std_logic; 95 | signal eraser_rdy : std_logic; 96 | 97 | signal match_mac_dst_hit : std_logic; 98 | signal match_mac_dst_vld : std_logic; 99 | signal match_mac_src_hit : std_logic; 100 | signal match_mac_src_vld : std_logic; 101 | 102 | signal match_ipv4_dst_hit : std_logic; 103 | signal match_ipv4_dst_vld : std_logic; 104 | signal match_ipv4_src_hit : std_logic; 105 | signal match_ipv4_src_vld : std_logic; 106 | 107 | signal match_ipv6_dst_hit : std_logic; 108 | signal match_ipv6_dst_vld : std_logic; 109 | signal match_ipv6_src_hit : std_logic; 110 | signal match_ipv6_src_vld : std_logic; 111 | 112 | signal match_hit : std_logic; 113 | signal match_vld : std_logic; 114 | 115 | signal cnt_pkt : unsigned(31 downto 0); 116 | signal cnt_ipv4 : unsigned(31 downto 0); 117 | signal cnt_ipv6 : unsigned(31 downto 0); 118 | signal cnt_mac_dst_hit : unsigned(31 downto 0); 119 | signal cnt_mac_src_hit : unsigned(31 downto 0); 120 | signal cnt_ipv4_dst_hit : unsigned(31 downto 0); 121 | signal cnt_ipv4_src_hit : unsigned(31 downto 0); 122 | signal cnt_ipv6_dst_hit : unsigned(31 downto 0); 123 | signal cnt_ipv6_src_hit : unsigned(31 downto 0); 124 | 125 | signal cnt_mac_dst_hit_en : std_logic; 126 | signal cnt_mac_src_hit_en : std_logic; 127 | signal cnt_ipv4_dst_hit_en : std_logic; 128 | signal cnt_ipv4_src_hit_en : std_logic; 129 | signal cnt_ipv6_dst_hit_en : std_logic; 130 | signal cnt_ipv6_src_hit_en : std_logic; 131 | 132 | signal cnt_pkt_reg : std_logic_vector(31 downto 0); 133 | signal cnt_ipv4_reg : std_logic_vector(31 downto 0); 134 | signal cnt_ipv6_reg : std_logic_vector(31 downto 0); 135 | signal cnt_mac_dst_hit_reg : std_logic_vector(31 downto 0); 136 | signal cnt_mac_src_hit_reg : std_logic_vector(31 downto 0); 137 | signal cnt_ipv4_dst_hit_reg : std_logic_vector(31 downto 0); 138 | signal cnt_ipv4_src_hit_reg : std_logic_vector(31 downto 0); 139 | signal cnt_ipv6_dst_hit_reg : std_logic_vector(31 downto 0); 140 | signal cnt_ipv6_src_hit_reg : std_logic_vector(31 downto 0); 141 | 142 | signal cmd_sel : std_logic; 143 | signal cmd_we : std_logic; 144 | signal cmd_enable : std_logic; 145 | signal cmd_disable : std_logic; 146 | signal cmd_cnt_clear : std_logic; 147 | signal cmd_cnt_sample : std_logic; 148 | 149 | signal disable_reg : std_logic; 150 | signal status_reg : std_logic_vector(31 downto 0); 151 | 152 | begin 153 | 154 | -- ------------------------------------------------------------------------- 155 | -- WISHBONE SPLITTER 156 | -- ------------------------------------------------------------------------- 157 | 158 | wb_splitter_i : entity work.WB_SPLITTER 159 | generic map ( 160 | MASTER_PORTS => WB_PORTS, 161 | ADDR_OFFSET => WB_OFFSET 162 | ) 163 | port map ( 164 | CLK => CLK, 165 | RST => RST, 166 | 167 | WB_S_CYC => WB_CYC, 168 | WB_S_STB => WB_STB, 169 | WB_S_WE => WB_WE, 170 | WB_S_ADDR => WB_ADDR, 171 | WB_S_DIN => WB_DIN, 172 | WB_S_STALL => WB_STALL, 173 | WB_S_ACK => WB_ACK, 174 | WB_S_DOUT => WB_DOUT, 175 | 176 | WB_M_CYC => wb_mfs_cyc, 177 | WB_M_STB => wb_mfs_stb, 178 | WB_M_WE => wb_mfs_we, 179 | WB_M_ADDR => wb_mfs_addr, 180 | WB_M_DOUT => wb_mfs_dout, 181 | WB_M_STALL => wb_mfs_stall, 182 | WB_M_ACK => wb_mfs_ack, 183 | WB_M_DIN => wb_mfs_din 184 | ); 185 | 186 | -- ------------------------------------------------------------------------- 187 | -- PACKET PARSER 188 | -- ------------------------------------------------------------------------- 189 | 190 | parser_i : entity work.PARSER 191 | port map ( 192 | CLK => CLK, 193 | RST => RST, 194 | 195 | RX_DATA => RX_DATA, 196 | RX_SOP => RX_SOP, 197 | RX_EOP => RX_EOP, 198 | RX_VLD => RX_VLD, 199 | RX_RDY => RX_RDY, 200 | 201 | TX_DATA => parser_data, 202 | TX_SOP => parser_sop, 203 | TX_EOP => parser_eop, 204 | TX_VLD => parser_vld, 205 | TX_RDY => parser_rdy, 206 | 207 | EX_MAC_DST => ex_mac_dst, 208 | EX_MAC_SRC => ex_mac_src, 209 | EX_IPV4_VLD => ex_ipv4_vld, 210 | EX_IPV4_DST => ex_ipv4_dst, 211 | EX_IPV4_SRC => ex_ipv4_src, 212 | EX_IPV6_VLD => ex_ipv6_vld, 213 | EX_IPV6_DST => ex_ipv6_dst, 214 | EX_IPV6_SRC => ex_ipv6_src 215 | ); 216 | 217 | parser_eop_vld <= parser_vld and parser_rdy and parser_eop; 218 | parser_ipv4_vld <= parser_eop_vld and ex_ipv4_vld; 219 | parser_ipv6_vld <= parser_eop_vld and ex_ipv6_vld; 220 | 221 | -- ------------------------------------------------------------------------- 222 | -- STREAM FIFO 223 | -- ------------------------------------------------------------------------- 224 | 225 | fifo_din <= parser_data & parser_sop & parser_eop; 226 | fifo_wr <= parser_vld; 227 | parser_rdy <= not fifo_full; 228 | 229 | fifo_i : entity work.FIFO 230 | generic map ( 231 | DATA_WIDTH => FIFO_DATA_WIDTH, 232 | ADDR_WIDTH => FIFO_ADDR_WIDTH 233 | ) 234 | port map ( 235 | CLK => CLK, 236 | RST => RST, 237 | -- FIFO WRITE INTERFACE 238 | WR_DATA => fifo_din, 239 | WR_REQ => fifo_wr, 240 | WR_FULL => fifo_full, 241 | -- FIFO READ INTERFACE 242 | RD_DATA => fifo_dout, 243 | RD_DATA_VLD => fifo_dout_vld, 244 | RD_REQ => fifo_rd, 245 | -- FIFO OTHERS SIGNALS 246 | STATUS => open 247 | ); 248 | 249 | fifo_rd <= stfi_rdy; 250 | stfi_data <= fifo_dout(8+2-1 downto 2); 251 | stfi_sop <= fifo_dout(1); 252 | stfi_eop <= fifo_dout(0); 253 | stfi_vld <= fifo_dout_vld; 254 | 255 | -- ------------------------------------------------------------------------- 256 | -- MATCH UNITS 257 | -- ------------------------------------------------------------------------- 258 | 259 | match_mac_dst_i : entity work.MATCH_UNIT_WB 260 | generic map ( 261 | DATA_WIDTH => 48, 262 | ADDR_WIDTH => 5 263 | ) 264 | port map ( 265 | CLK => CLK, 266 | RST => RST, 267 | 268 | MATCH_DATA => ex_mac_dst, 269 | MATCH_ENA => '1', 270 | MATCH_REQ => parser_eop_vld, 271 | MATCH_BUSY => open, 272 | MATCH_ADDR => open, 273 | MATCH_HIT => match_mac_dst_hit, 274 | MATCH_VLD => match_mac_dst_vld, 275 | 276 | WB_CYC => wb_mfs_cyc(1), 277 | WB_STB => wb_mfs_stb(1), 278 | WB_WE => wb_mfs_we(1), 279 | WB_ADDR => wb_mfs_addr((1+1)*16-1 downto 1*16), 280 | WB_DIN => wb_mfs_dout((1+1)*32-1 downto 1*32), 281 | WB_STALL => wb_mfs_stall(1), 282 | WB_ACK => wb_mfs_ack(1), 283 | WB_DOUT => wb_mfs_din((1+1)*32-1 downto 1*32) 284 | ); 285 | 286 | match_mac_src_i : entity work.MATCH_UNIT_WB 287 | generic map ( 288 | DATA_WIDTH => 48, 289 | ADDR_WIDTH => 5 290 | ) 291 | port map ( 292 | CLK => CLK, 293 | RST => RST, 294 | 295 | MATCH_DATA => ex_mac_src, 296 | MATCH_ENA => '1', 297 | MATCH_REQ => parser_eop_vld, 298 | MATCH_BUSY => open, 299 | MATCH_ADDR => open, 300 | MATCH_HIT => match_mac_src_hit, 301 | MATCH_VLD => match_mac_src_vld, 302 | 303 | WB_CYC => wb_mfs_cyc(2), 304 | WB_STB => wb_mfs_stb(2), 305 | WB_WE => wb_mfs_we(2), 306 | WB_ADDR => wb_mfs_addr((2+1)*16-1 downto 2*16), 307 | WB_DIN => wb_mfs_dout((2+1)*32-1 downto 2*32), 308 | WB_STALL => wb_mfs_stall(2), 309 | WB_ACK => wb_mfs_ack(2), 310 | WB_DOUT => wb_mfs_din((2+1)*32-1 downto 2*32) 311 | ); 312 | 313 | match_ipv4_dst_i : entity work.MATCH_UNIT_WB 314 | generic map ( 315 | DATA_WIDTH => 32, 316 | ADDR_WIDTH => 5 317 | ) 318 | port map ( 319 | CLK => CLK, 320 | RST => RST, 321 | 322 | MATCH_DATA => ex_ipv4_dst, 323 | MATCH_ENA => ex_ipv4_vld, 324 | MATCH_REQ => parser_eop_vld, 325 | MATCH_BUSY => open, 326 | MATCH_ADDR => open, 327 | MATCH_HIT => match_ipv4_dst_hit, 328 | MATCH_VLD => match_ipv4_dst_vld, 329 | 330 | WB_CYC => wb_mfs_cyc(3), 331 | WB_STB => wb_mfs_stb(3), 332 | WB_WE => wb_mfs_we(3), 333 | WB_ADDR => wb_mfs_addr((3+1)*16-1 downto 3*16), 334 | WB_DIN => wb_mfs_dout((3+1)*32-1 downto 3*32), 335 | WB_STALL => wb_mfs_stall(3), 336 | WB_ACK => wb_mfs_ack(3), 337 | WB_DOUT => wb_mfs_din((3+1)*32-1 downto 3*32) 338 | ); 339 | 340 | match_ipv4_src_i : entity work.MATCH_UNIT_WB 341 | generic map ( 342 | DATA_WIDTH => 32, 343 | ADDR_WIDTH => 5 344 | ) 345 | port map ( 346 | CLK => CLK, 347 | RST => RST, 348 | 349 | MATCH_DATA => ex_ipv4_src, 350 | MATCH_ENA => ex_ipv4_vld, 351 | MATCH_REQ => parser_eop_vld, 352 | MATCH_BUSY => open, 353 | MATCH_ADDR => open, 354 | MATCH_HIT => match_ipv4_src_hit, 355 | MATCH_VLD => match_ipv4_src_vld, 356 | 357 | WB_CYC => wb_mfs_cyc(4), 358 | WB_STB => wb_mfs_stb(4), 359 | WB_WE => wb_mfs_we(4), 360 | WB_ADDR => wb_mfs_addr((4+1)*16-1 downto 4*16), 361 | WB_DIN => wb_mfs_dout((4+1)*32-1 downto 4*32), 362 | WB_STALL => wb_mfs_stall(4), 363 | WB_ACK => wb_mfs_ack(4), 364 | WB_DOUT => wb_mfs_din((4+1)*32-1 downto 4*32) 365 | ); 366 | 367 | match_ipv6_dst_i : entity work.MATCH_UNIT_WB 368 | generic map ( 369 | DATA_WIDTH => 128, 370 | ADDR_WIDTH => 5 371 | ) 372 | port map ( 373 | CLK => CLK, 374 | RST => RST, 375 | 376 | MATCH_DATA => ex_ipv6_dst, 377 | MATCH_ENA => ex_ipv6_vld, 378 | MATCH_REQ => parser_eop_vld, 379 | MATCH_BUSY => open, 380 | MATCH_ADDR => open, 381 | MATCH_HIT => match_ipv6_dst_hit, 382 | MATCH_VLD => match_ipv6_dst_vld, 383 | 384 | WB_CYC => wb_mfs_cyc(5), 385 | WB_STB => wb_mfs_stb(5), 386 | WB_WE => wb_mfs_we(5), 387 | WB_ADDR => wb_mfs_addr((5+1)*16-1 downto 5*16), 388 | WB_DIN => wb_mfs_dout((5+1)*32-1 downto 5*32), 389 | WB_STALL => wb_mfs_stall(5), 390 | WB_ACK => wb_mfs_ack(5), 391 | WB_DOUT => wb_mfs_din((5+1)*32-1 downto 5*32) 392 | ); 393 | 394 | match_ipv6_src_i : entity work.MATCH_UNIT_WB 395 | generic map ( 396 | DATA_WIDTH => 128, 397 | ADDR_WIDTH => 5 398 | ) 399 | port map ( 400 | CLK => CLK, 401 | RST => RST, 402 | 403 | MATCH_DATA => ex_ipv6_src, 404 | MATCH_ENA => ex_ipv6_vld, 405 | MATCH_REQ => parser_eop_vld, 406 | MATCH_BUSY => open, 407 | MATCH_ADDR => open, 408 | MATCH_HIT => match_ipv6_src_hit, 409 | MATCH_VLD => match_ipv6_src_vld, 410 | 411 | WB_CYC => wb_mfs_cyc(6), 412 | WB_STB => wb_mfs_stb(6), 413 | WB_WE => wb_mfs_we(6), 414 | WB_ADDR => wb_mfs_addr((6+1)*16-1 downto 6*16), 415 | WB_DIN => wb_mfs_dout((6+1)*32-1 downto 6*32), 416 | WB_STALL => wb_mfs_stall(6), 417 | WB_ACK => wb_mfs_ack(6), 418 | WB_DOUT => wb_mfs_din((6+1)*32-1 downto 6*32) 419 | ); 420 | 421 | match_hit <= match_mac_dst_hit or match_mac_src_hit or 422 | match_ipv4_dst_hit or match_ipv4_src_hit or 423 | match_ipv6_dst_hit or match_ipv6_src_hit; 424 | match_vld <= match_ipv4_dst_vld; 425 | 426 | -- ------------------------------------------------------------------------- 427 | -- ERASER MODULE 428 | -- ------------------------------------------------------------------------- 429 | 430 | eraser_i : entity work.ERASER 431 | port map ( 432 | CLK => CLK, 433 | RST => RST, 434 | 435 | RX_META_DISCARD => match_hit, 436 | RX_META_VLD => match_vld, 437 | 438 | RX_DATA => stfi_data, 439 | RX_SOP => stfi_sop, 440 | RX_EOP => stfi_eop, 441 | RX_VLD => stfi_vld, 442 | RX_RDY => stfi_rdy, 443 | 444 | TX_DATA => eraser_data, 445 | TX_SOP => eraser_sop, 446 | TX_EOP => eraser_eop, 447 | TX_VLD => eraser_vld, 448 | TX_RDY => eraser_rdy 449 | ); 450 | 451 | TX_DATA <= eraser_data; 452 | TX_SOP <= eraser_sop; 453 | TX_EOP <= eraser_eop; 454 | TX_VLD <= eraser_vld; 455 | eraser_rdy <= TX_RDY; 456 | 457 | -- ------------------------------------------------------------------------- 458 | -- STATISTICS COUNTERS 459 | -- ------------------------------------------------------------------------- 460 | 461 | cnt_mac_dst_hit_en <= match_mac_dst_vld and match_mac_dst_hit; 462 | cnt_mac_src_hit_en <= match_mac_src_vld and match_mac_src_hit; 463 | cnt_ipv4_dst_hit_en <= match_ipv4_dst_vld and match_ipv4_dst_hit; 464 | cnt_ipv4_src_hit_en <= match_ipv4_src_vld and match_ipv4_src_hit; 465 | cnt_ipv6_dst_hit_en <= match_ipv6_dst_vld and match_ipv6_dst_hit; 466 | cnt_ipv6_src_hit_en <= match_ipv6_src_vld and match_ipv6_src_hit; 467 | 468 | process (CLK) 469 | begin 470 | if (rising_edge(CLK)) then 471 | if (RST = '1' or cmd_cnt_clear = '1') then 472 | cnt_pkt <= (others => '0'); 473 | elsif (parser_eop_vld = '1') then 474 | cnt_pkt <= cnt_pkt + 1; 475 | end if; 476 | end if; 477 | end process; 478 | 479 | process (CLK) 480 | begin 481 | if (rising_edge(CLK)) then 482 | if (RST = '1' or cmd_cnt_clear = '1') then 483 | cnt_ipv4 <= (others => '0'); 484 | elsif (parser_ipv4_vld = '1') then 485 | cnt_ipv4 <= cnt_ipv4 + 1; 486 | end if; 487 | end if; 488 | end process; 489 | 490 | process (CLK) 491 | begin 492 | if (rising_edge(CLK)) then 493 | if (RST = '1' or cmd_cnt_clear = '1') then 494 | cnt_ipv6 <= (others => '0'); 495 | elsif (parser_eop_vld = '1' and ex_ipv6_vld = '1') then 496 | cnt_ipv6 <= cnt_ipv6 + 1; 497 | end if; 498 | end if; 499 | end process; 500 | 501 | process (CLK) 502 | begin 503 | if (rising_edge(CLK)) then 504 | if (RST = '1' or cmd_cnt_clear = '1') then 505 | cnt_mac_dst_hit <= (others => '0'); 506 | elsif (cnt_mac_dst_hit_en = '1') then 507 | cnt_mac_dst_hit <= cnt_mac_dst_hit + 1; 508 | end if; 509 | end if; 510 | end process; 511 | 512 | process (CLK) 513 | begin 514 | if (rising_edge(CLK)) then 515 | if (RST = '1' or cmd_cnt_clear = '1') then 516 | cnt_mac_src_hit <= (others => '0'); 517 | elsif (cnt_mac_src_hit_en = '1') then 518 | cnt_mac_src_hit <= cnt_mac_src_hit + 1; 519 | end if; 520 | end if; 521 | end process; 522 | 523 | process (CLK) 524 | begin 525 | if (rising_edge(CLK)) then 526 | if (RST = '1' or cmd_cnt_clear = '1') then 527 | cnt_ipv4_dst_hit <= (others => '0'); 528 | elsif (cnt_ipv4_dst_hit_en = '1') then 529 | cnt_ipv4_dst_hit <= cnt_ipv4_dst_hit + 1; 530 | end if; 531 | end if; 532 | end process; 533 | 534 | process (CLK) 535 | begin 536 | if (rising_edge(CLK)) then 537 | if (RST = '1' or cmd_cnt_clear = '1') then 538 | cnt_ipv4_src_hit <= (others => '0'); 539 | elsif (cnt_ipv4_src_hit_en = '1') then 540 | cnt_ipv4_src_hit <= cnt_ipv4_src_hit + 1; 541 | end if; 542 | end if; 543 | end process; 544 | 545 | process (CLK) 546 | begin 547 | if (rising_edge(CLK)) then 548 | if (RST = '1' or cmd_cnt_clear = '1') then 549 | cnt_ipv6_dst_hit <= (others => '0'); 550 | elsif (cnt_ipv6_dst_hit_en = '1') then 551 | cnt_ipv6_dst_hit <= cnt_ipv6_dst_hit + 1; 552 | end if; 553 | end if; 554 | end process; 555 | 556 | process (CLK) 557 | begin 558 | if (rising_edge(CLK)) then 559 | if (RST = '1' or cmd_cnt_clear = '1') then 560 | cnt_ipv6_src_hit <= (others => '0'); 561 | elsif (cnt_ipv6_src_hit_en = '1') then 562 | cnt_ipv6_src_hit <= cnt_ipv6_src_hit + 1; 563 | end if; 564 | end if; 565 | end process; 566 | 567 | -- ------------------------------------------------------------------------- 568 | -- WISHBONE SLAVE LOGIC 569 | -- ------------------------------------------------------------------------- 570 | 571 | cmd_sel <= '1' when (wb_mfs_addr(7 downto 0) = X"00") else '0'; 572 | cmd_we <= wb_mfs_stb(0) and wb_mfs_we(0) and cmd_sel; 573 | 574 | cmd_reg_p : process (CLK) 575 | begin 576 | if (rising_edge(CLK)) then 577 | cmd_enable <= '0'; 578 | cmd_disable <= '0'; 579 | cmd_cnt_clear <= '0'; 580 | cmd_cnt_sample <= '0'; 581 | if (cmd_we = '1' and wb_mfs_dout(7 downto 0) = X"00") then 582 | cmd_enable <= '1'; 583 | end if; 584 | if (cmd_we = '1' and wb_mfs_dout(7 downto 0) = X"01") then 585 | cmd_disable <= '1'; 586 | end if; 587 | if (cmd_we = '1' and wb_mfs_dout(7 downto 0) = X"02") then 588 | cmd_cnt_clear <= '1'; 589 | end if; 590 | if (cmd_we = '1' and wb_mfs_dout(7 downto 0) = X"03") then 591 | cmd_cnt_sample <= '1'; 592 | end if; 593 | end if; 594 | end process; 595 | 596 | disable_reg_p : process (CLK) 597 | begin 598 | if (rising_edge(CLK)) then 599 | if (RST = '1' or cmd_disable = '1') then 600 | disable_reg <= '0'; 601 | elsif (cmd_enable = '1') then 602 | disable_reg <= '1'; 603 | end if; 604 | end if; 605 | end process; 606 | 607 | cnt_sampled_reg_p : process (CLK) 608 | begin 609 | if (rising_edge(CLK)) then 610 | if (cmd_cnt_sample = '1') then 611 | cnt_pkt_reg <= std_logic_vector(cnt_pkt); 612 | cnt_ipv4_reg <= std_logic_vector(cnt_ipv4); 613 | cnt_ipv6_reg <= std_logic_vector(cnt_ipv6); 614 | cnt_mac_dst_hit_reg <= std_logic_vector(cnt_mac_dst_hit); 615 | cnt_mac_src_hit_reg <= std_logic_vector(cnt_mac_src_hit); 616 | cnt_ipv4_dst_hit_reg <= std_logic_vector(cnt_ipv4_dst_hit); 617 | cnt_ipv4_src_hit_reg <= std_logic_vector(cnt_ipv4_src_hit); 618 | cnt_ipv6_dst_hit_reg <= std_logic_vector(cnt_ipv6_dst_hit); 619 | cnt_ipv6_src_hit_reg <= std_logic_vector(cnt_ipv6_src_hit); 620 | end if; 621 | end if; 622 | end process; 623 | 624 | status_reg <= (others => '0'); 625 | 626 | wb_mfs_stall(0) <= '0'; 627 | 628 | wb_ack_reg_p : process (CLK) 629 | begin 630 | if (rising_edge(CLK)) then 631 | wb_mfs_ack(0) <= wb_mfs_cyc(0) and wb_mfs_stb(0); 632 | end if; 633 | end process; 634 | 635 | wb_dout_reg_p : process (CLK) 636 | begin 637 | if (rising_edge(CLK)) then 638 | case wb_mfs_addr(7 downto 0) is 639 | when X"00" => 640 | wb_mfs_din(31 downto 0) <= X"20191130"; -- version 641 | when X"04" => 642 | wb_mfs_din(31 downto 0) <= status_reg; 643 | when X"10" => 644 | wb_mfs_din(31 downto 0) <= cnt_pkt_reg; 645 | when X"14" => 646 | wb_mfs_din(31 downto 0) <= cnt_ipv4_reg; 647 | when X"18" => 648 | wb_mfs_din(31 downto 0) <= cnt_ipv6_reg; 649 | when X"20" => 650 | wb_mfs_din(31 downto 0) <= cnt_mac_dst_hit_reg; 651 | when X"24" => 652 | wb_mfs_din(31 downto 0) <= cnt_mac_src_hit_reg; 653 | when X"28" => 654 | wb_mfs_din(31 downto 0) <= cnt_ipv4_dst_hit_reg; 655 | when X"2C" => 656 | wb_mfs_din(31 downto 0) <= cnt_ipv4_src_hit_reg; 657 | when X"30" => 658 | wb_mfs_din(31 downto 0) <= cnt_ipv6_dst_hit_reg; 659 | when X"34" => 660 | wb_mfs_din(31 downto 0) <= cnt_ipv6_src_hit_reg; 661 | when others => 662 | wb_mfs_din(31 downto 0) <= X"DEADCAFE"; 663 | end case; 664 | end if; 665 | end process; 666 | 667 | end architecture; 668 | -------------------------------------------------------------------------------- /rtl/comp/firewall/match_unit.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity MATCH_UNIT is 13 | Generic ( 14 | DATA_WIDTH : integer := 8; 15 | ADDR_WIDTH : integer := 4 16 | ); 17 | Port ( 18 | -- CLOCK AND RESET 19 | CLK : in std_logic; 20 | RST : in std_logic; 21 | 22 | -- MATCH INTERFACE 23 | MATCH_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 24 | MATCH_ENA : in std_logic; 25 | MATCH_REQ : in std_logic; 26 | MATCH_BUSY : out std_logic; 27 | MATCH_ADDR : out std_logic_vector(ADDR_WIDTH-1 downto 0); 28 | MATCH_HIT : out std_logic; 29 | MATCH_VLD : out std_logic; 30 | 31 | -- WRITE INTERFACE 32 | WRITE_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 33 | WRITE_ENA : in std_logic; 34 | WRITE_ADDR : in std_logic_vector(ADDR_WIDTH-1 downto 0); 35 | WRITE_REQ : in std_logic 36 | ); 37 | end entity; 38 | 39 | architecture RTL of MATCH_UNIT is 40 | 41 | constant RAM_DATA_WIDTH : natural := DATA_WIDTH+1; 42 | 43 | signal ram_wr_data : std_logic_vector(RAM_DATA_WIDTH-1 downto 0); 44 | signal ram_rd_addr : std_logic_vector(ADDR_WIDTH-1 downto 0); 45 | signal ram_rd_data : std_logic_vector(RAM_DATA_WIDTH-1 downto 0); 46 | signal ram_rd_data_vld : std_logic; 47 | 48 | signal match_addr_cnt : unsigned(ADDR_WIDTH+1-1 downto 0); 49 | signal match_addr_cnt_max : std_logic; 50 | signal match_data_reg : std_logic_vector(DATA_WIDTH-1 downto 0); 51 | signal match_ena_reg : std_logic; 52 | signal match_run : std_logic; 53 | 54 | signal ram_match_hit : std_logic; 55 | signal ram_match_vld : std_logic; 56 | 57 | type fsm_state is (idle, match_running, done); 58 | signal fsm_pstate : fsm_state; 59 | signal fsm_nstate : fsm_state; 60 | 61 | begin 62 | 63 | ram_wr_data <= WRITE_DATA & WRITE_ENA; 64 | 65 | sdp_ram_i : entity work.SDP_RAM 66 | generic map ( 67 | DATA_WIDTH => RAM_DATA_WIDTH, 68 | ADDR_WIDTH => ADDR_WIDTH 69 | ) 70 | port map ( 71 | CLK => CLK, 72 | RST => RST, 73 | 74 | WR_DATA => ram_wr_data, 75 | WR_ADDR => WRITE_ADDR, 76 | WR_REQ => WRITE_REQ, 77 | 78 | RD_ADDR => ram_rd_addr, 79 | RD_REQ => match_run, 80 | RD_DATA => ram_rd_data, 81 | RD_DATA_VLD => ram_rd_data_vld 82 | ); 83 | 84 | process (CLK) 85 | begin 86 | if (rising_edge(CLK)) then 87 | if (match_run = '1') then 88 | match_addr_cnt <= match_addr_cnt + 1; 89 | else 90 | match_addr_cnt <= (others => '0'); 91 | end if; 92 | end if; 93 | end process; 94 | 95 | match_addr_cnt_max <= match_addr_cnt(ADDR_WIDTH); 96 | ram_rd_addr <= std_logic_vector(match_addr_cnt(ADDR_WIDTH-1 downto 0)); 97 | 98 | process (CLK) 99 | begin 100 | if (rising_edge(CLK)) then 101 | if (MATCH_REQ = '1' and match_run = '0') then 102 | match_data_reg <= MATCH_DATA; 103 | match_ena_reg <= MATCH_ENA; 104 | end if; 105 | end if; 106 | end process; 107 | 108 | ram_match_hit <= '1' when (ram_rd_data(DATA_WIDTH+1-1 downto 1) = match_data_reg) else '0'; 109 | ram_match_vld <= ram_match_hit and ram_rd_data(0) and ram_rd_data_vld and match_ena_reg; 110 | 111 | process (CLK) 112 | begin 113 | if (rising_edge(CLK)) then 114 | if (match_run = '0') then 115 | MATCH_ADDR <= (others => '0'); 116 | MATCH_HIT <= '0'; 117 | elsif (ram_match_vld = '1') then 118 | MATCH_ADDR <= ram_rd_addr; 119 | MATCH_HIT <= '1'; 120 | end if; 121 | end if; 122 | end process; 123 | 124 | -- ------------------------------------------------------------------------- 125 | -- FSM 126 | -- ------------------------------------------------------------------------- 127 | 128 | process (CLK) 129 | begin 130 | if (rising_edge(CLK)) then 131 | if (RST = '1') then 132 | fsm_pstate <= idle; 133 | else 134 | fsm_pstate <= fsm_nstate; 135 | end if; 136 | end if; 137 | end process; 138 | 139 | process (fsm_pstate, MATCH_REQ, match_addr_cnt_max) 140 | begin 141 | fsm_nstate <= idle; 142 | match_run <= '0'; 143 | MATCH_VLD <= '0'; 144 | 145 | case fsm_pstate is 146 | when idle => 147 | if (MATCH_REQ = '1') then 148 | fsm_nstate <= match_running; 149 | else 150 | fsm_nstate <= idle; 151 | end if; 152 | 153 | when match_running => 154 | match_run <= '1'; 155 | if (match_addr_cnt_max = '1') then 156 | fsm_nstate <= done; 157 | else 158 | fsm_nstate <= match_running; 159 | end if; 160 | 161 | when done => 162 | match_run <= '1'; 163 | MATCH_VLD <= '1'; 164 | fsm_nstate <= idle; 165 | 166 | end case; 167 | end process; 168 | 169 | MATCH_BUSY <= match_run; 170 | 171 | end architecture; 172 | -------------------------------------------------------------------------------- /rtl/comp/firewall/match_unit_wb.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity MATCH_UNIT_WB is 13 | Generic ( 14 | DATA_WIDTH : integer := 8; 15 | ADDR_WIDTH : integer := 4 16 | ); 17 | Port ( 18 | -- CLOCK AND RESET 19 | CLK : in std_logic; 20 | RST : in std_logic; 21 | 22 | -- MATCH INTERFACE 23 | MATCH_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0); 24 | MATCH_ENA : in std_logic; 25 | MATCH_REQ : in std_logic; 26 | MATCH_BUSY : out std_logic; 27 | MATCH_ADDR : out std_logic_vector(ADDR_WIDTH-1 downto 0); 28 | MATCH_HIT : out std_logic; 29 | MATCH_VLD : out std_logic; 30 | 31 | -- WISHBONE SLAVE INTERFACE 32 | WB_CYC : in std_logic; 33 | WB_STB : in std_logic; 34 | WB_WE : in std_logic; 35 | WB_ADDR : in std_logic_vector(15 downto 0); 36 | WB_DIN : in std_logic_vector(31 downto 0); 37 | WB_STALL : out std_logic; 38 | WB_ACK : out std_logic; 39 | WB_DOUT : out std_logic_vector(31 downto 0) 40 | ); 41 | end entity; 42 | 43 | architecture RTL of MATCH_UNIT_WB is 44 | 45 | constant WB_WORDS : integer := integer(real(DATA_WIDTH)/real(32)); 46 | 47 | signal match_hit_sig : std_logic; 48 | signal match_vld_sig : std_logic; 49 | 50 | signal wr_enable : std_logic; 51 | signal wr_request : std_logic; 52 | signal wr_data_reg : std_logic_vector(WB_WORDS*32-1 downto 0); 53 | signal wr_addr_reg : std_logic_vector(31 downto 0); 54 | 55 | signal index_reg : integer range 0 to WB_WORDS-1; 56 | 57 | signal cmd_sel : std_logic; 58 | signal cmd_we : std_logic; 59 | signal cmd_set_rule : std_logic; 60 | signal cmd_rst_rule : std_logic; 61 | 62 | signal addr_sel : std_logic; 63 | signal addr_we : std_logic; 64 | 65 | signal data_sel : std_logic; 66 | signal data_we : std_logic; 67 | 68 | signal status_reg : std_logic_vector(31 downto 0); 69 | 70 | begin 71 | 72 | -- ------------------------------------------------------------------------- 73 | -- MATCH UNIT 74 | -- ------------------------------------------------------------------------- 75 | 76 | match_unit_i : entity work.MATCH_UNIT 77 | generic map ( 78 | DATA_WIDTH => DATA_WIDTH, 79 | ADDR_WIDTH => ADDR_WIDTH 80 | ) 81 | port map ( 82 | CLK => CLK, 83 | RST => RST, 84 | 85 | MATCH_DATA => MATCH_DATA, 86 | MATCH_ENA => MATCH_ENA, 87 | MATCH_REQ => MATCH_REQ, 88 | MATCH_BUSY => MATCH_BUSY, 89 | MATCH_ADDR => MATCH_ADDR, 90 | MATCH_HIT => match_hit_sig, 91 | MATCH_VLD => match_vld_sig, 92 | 93 | WRITE_DATA => wr_data_reg(DATA_WIDTH-1 downto 0), 94 | WRITE_ENA => wr_enable, 95 | WRITE_ADDR => wr_addr_reg(ADDR_WIDTH-1 downto 0), 96 | WRITE_REQ => wr_request 97 | ); 98 | 99 | MATCH_HIT <= match_hit_sig; 100 | MATCH_VLD <= match_vld_sig; 101 | 102 | wr_enable <= cmd_set_rule; 103 | wr_request <= cmd_set_rule or cmd_rst_rule; 104 | 105 | wr_addr_reg_p : process (CLK) 106 | begin 107 | if (rising_edge(CLK)) then 108 | if (addr_we = '1') then 109 | wr_addr_reg <= WB_DIN; 110 | end if; 111 | end if; 112 | end process; 113 | 114 | index_reg_p : process (CLK) 115 | begin 116 | if (rising_edge(CLK)) then 117 | if (RST = '1' or wr_request = '1') then 118 | index_reg <= 0; 119 | elsif (data_we = '1') then 120 | index_reg <= index_reg + 1; 121 | end if; 122 | end if; 123 | end process; 124 | 125 | wr_data_reg_p : process (CLK) 126 | begin 127 | if (rising_edge(CLK)) then 128 | if (data_we = '1') then 129 | wr_data_reg((index_reg+1)*32-1 downto index_reg*32) <= WB_DIN; 130 | end if; 131 | end if; 132 | end process; 133 | 134 | -- ------------------------------------------------------------------------- 135 | -- WISHBONE SLAVE LOGIC 136 | -- ------------------------------------------------------------------------- 137 | 138 | cmd_sel <= '1' when (WB_ADDR(7 downto 0) = X"00") else '0'; 139 | cmd_we <= WB_STB and WB_WE and cmd_sel; 140 | 141 | addr_sel <= '1' when (WB_ADDR(7 downto 0) = X"08") else '0'; 142 | addr_we <= WB_STB and WB_WE and addr_sel; 143 | 144 | data_sel <= '1' when (WB_ADDR(7 downto 0) = X"0C") else '0'; 145 | data_we <= WB_STB and WB_WE and data_sel; 146 | 147 | cmd_reg_p : process (CLK) 148 | begin 149 | if (rising_edge(CLK)) then 150 | cmd_set_rule <= '0'; 151 | cmd_rst_rule <= '0'; 152 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"00") then 153 | cmd_set_rule <= '1'; 154 | end if; 155 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"01") then 156 | cmd_rst_rule <= '1'; 157 | end if; 158 | end if; 159 | end process; 160 | 161 | status_reg <= std_logic_vector(to_unsigned(WB_WORDS,32)); 162 | 163 | WB_STALL <= '0'; 164 | 165 | wb_ack_reg_p : process (CLK) 166 | begin 167 | if (rising_edge(CLK)) then 168 | WB_ACK <= WB_CYC and WB_STB; 169 | end if; 170 | end process; 171 | 172 | wb_dout_reg_p : process (CLK) 173 | begin 174 | if (rising_edge(CLK)) then 175 | case WB_ADDR(7 downto 0) is 176 | when X"00" => 177 | WB_DOUT <= X"20191121"; -- version 178 | when X"04" => 179 | WB_DOUT <= status_reg; 180 | when X"08" => 181 | WB_DOUT <= wr_addr_reg; 182 | when others => 183 | WB_DOUT <= X"DEADCAFE"; 184 | end case; 185 | end if; 186 | end process; 187 | 188 | end architecture; 189 | -------------------------------------------------------------------------------- /rtl/comp/firewall/parser.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity PARSER is 13 | Port ( 14 | -- CLOCK AND RESET 15 | CLK : in std_logic; 16 | RST : in std_logic; 17 | 18 | -- INPUT STREAM INTERFACE 19 | RX_DATA : in std_logic_vector(7 downto 0); 20 | RX_SOP : in std_logic; 21 | RX_EOP : in std_logic; 22 | RX_VLD : in std_logic; 23 | RX_RDY : out std_logic; 24 | 25 | -- OUTPUT STREAM INTERFACE 26 | TX_DATA : out std_logic_vector(7 downto 0); 27 | TX_SOP : out std_logic; 28 | TX_EOP : out std_logic; 29 | TX_VLD : out std_logic; 30 | TX_RDY : in std_logic; 31 | 32 | -- OUTPUT EXTRACT INTERFACE (valid with TX_EOP) 33 | EX_MAC_DST : out std_logic_vector(47 downto 0); 34 | EX_MAC_SRC : out std_logic_vector(47 downto 0); 35 | EX_IPV4_VLD : out std_logic; 36 | EX_IPV4_DST : out std_logic_vector(31 downto 0); 37 | EX_IPV4_SRC : out std_logic_vector(31 downto 0); 38 | EX_IPV6_VLD : out std_logic; 39 | EX_IPV6_DST : out std_logic_vector(127 downto 0); 40 | EX_IPV6_SRC : out std_logic_vector(127 downto 0) 41 | ); 42 | end entity; 43 | 44 | architecture RTL of PARSER is 45 | 46 | signal rx_eop_vld : std_logic; 47 | signal rx_word_vld : std_logic; 48 | signal rx_data_reg : std_logic_vector(8-1 downto 0); 49 | signal offset : unsigned(14-1 downto 0); 50 | 51 | type fsm_state is (idle, mac_dst, mac_src, ethertype, ipv4_src, ipv4_dst, 52 | ipv6_src, ipv6_dst, done); 53 | signal fsm_pstate : fsm_state; 54 | signal fsm_nstate : fsm_state; 55 | 56 | signal mac_dst_shreg_en : std_logic; 57 | signal mac_src_shreg_en : std_logic; 58 | signal ipv4_vld_reg_next : std_logic; 59 | signal ipv4_src_shreg_en : std_logic; 60 | signal ipv4_dst_shreg_en : std_logic; 61 | signal ipv6_vld_reg_next : std_logic; 62 | signal ipv6_src_shreg_en : std_logic; 63 | signal ipv6_dst_shreg_en : std_logic; 64 | 65 | signal mac_dst_shreg : std_logic_vector(48-1 downto 0); 66 | signal mac_src_shreg : std_logic_vector(48-1 downto 0); 67 | signal ipv4_vld_reg : std_logic; 68 | signal ipv4_dst_shreg : std_logic_vector(32-1 downto 0); 69 | signal ipv4_src_shreg : std_logic_vector(32-1 downto 0); 70 | signal ipv6_vld_reg : std_logic; 71 | signal ipv6_dst_shreg : std_logic_vector(128-1 downto 0); 72 | signal ipv6_src_shreg : std_logic_vector(128-1 downto 0); 73 | 74 | begin 75 | 76 | rx_eop_vld <= RX_EOP and RX_VLD and TX_RDY; 77 | rx_word_vld <= RX_VLD and TX_RDY; 78 | 79 | process (CLK) 80 | begin 81 | if (rising_edge(CLK)) then 82 | if (rx_word_vld = '1') then 83 | rx_data_reg <= RX_DATA; 84 | end if; 85 | end if; 86 | end process; 87 | 88 | process (CLK) 89 | begin 90 | if (rising_edge(CLK)) then 91 | if (RST = '1' or rx_eop_vld = '1') then 92 | offset <= (others => '0'); 93 | elsif (rx_word_vld = '1') then 94 | offset <= offset + 1; 95 | end if; 96 | end if; 97 | end process; 98 | 99 | -- ------------------------------------------------------------------------- 100 | -- FSM - PACKET PARSING 101 | -- ------------------------------------------------------------------------- 102 | 103 | process (CLK) 104 | begin 105 | if (rising_edge(CLK)) then 106 | if (RST = '1') then 107 | fsm_pstate <= idle; 108 | elsif (TX_RDY = '1') then 109 | fsm_pstate <= fsm_nstate; 110 | end if; 111 | end if; 112 | end process; 113 | 114 | process (fsm_pstate, RX_DATA, RX_SOP, RX_EOP, RX_VLD, rx_data_reg, offset, 115 | ipv4_vld_reg, ipv6_vld_reg) 116 | begin 117 | fsm_nstate <= idle; 118 | mac_dst_shreg_en <= '0'; 119 | mac_src_shreg_en <= '0'; 120 | ipv4_vld_reg_next <= ipv4_vld_reg; 121 | ipv4_src_shreg_en <= '0'; 122 | ipv4_dst_shreg_en <= '0'; 123 | ipv6_vld_reg_next <= ipv6_vld_reg; 124 | ipv6_src_shreg_en <= '0'; 125 | ipv6_dst_shreg_en <= '0'; 126 | 127 | case fsm_pstate is 128 | when idle => 129 | ipv4_vld_reg_next <= '0'; 130 | ipv6_vld_reg_next <= '0'; 131 | mac_dst_shreg_en <= '1'; 132 | if (RX_VLD = '1' and RX_SOP = '1') then 133 | fsm_nstate <= mac_dst; 134 | else 135 | fsm_nstate <= idle; 136 | end if; 137 | 138 | when mac_dst => 139 | mac_dst_shreg_en <= '1'; 140 | if (RX_VLD = '1' and offset = 5) then 141 | fsm_nstate <= mac_src; 142 | else 143 | fsm_nstate <= mac_dst; 144 | end if; 145 | 146 | when mac_src => 147 | mac_src_shreg_en <= '1'; 148 | if (RX_VLD = '1' and offset = 11) then 149 | fsm_nstate <= ethertype; 150 | else 151 | fsm_nstate <= mac_src; 152 | end if; 153 | 154 | when ethertype => 155 | if (RX_VLD = '1' and offset = 13) then 156 | if (rx_data_reg = X"08" and RX_DATA = X"00") then 157 | fsm_nstate <= ipv4_src; 158 | elsif (rx_data_reg = X"86" and RX_DATA = X"DD") then 159 | fsm_nstate <= ipv6_src; 160 | else 161 | fsm_nstate <= done; 162 | end if; 163 | else 164 | fsm_nstate <= ethertype; 165 | end if; 166 | 167 | when ipv4_src => 168 | ipv4_vld_reg_next <= '1'; 169 | ipv4_src_shreg_en <= '1'; 170 | if (RX_VLD = '1' and offset = 29) then 171 | fsm_nstate <= ipv4_dst; 172 | else 173 | fsm_nstate <= ipv4_src; 174 | end if; 175 | 176 | when ipv4_dst => 177 | ipv4_vld_reg_next <= '1'; 178 | ipv4_dst_shreg_en <= '1'; 179 | if (RX_VLD = '1' and offset = 33) then 180 | fsm_nstate <= done; 181 | else 182 | fsm_nstate <= ipv4_dst; 183 | end if; 184 | 185 | when ipv6_src => 186 | ipv6_vld_reg_next <= '1'; 187 | ipv6_src_shreg_en <= '1'; 188 | if (RX_VLD = '1' and offset = 37) then 189 | fsm_nstate <= ipv6_dst; 190 | else 191 | fsm_nstate <= ipv6_src; 192 | end if; 193 | 194 | when ipv6_dst => 195 | ipv6_vld_reg_next <= '1'; 196 | ipv6_dst_shreg_en <= '1'; 197 | if (RX_VLD = '1' and offset = 53) then 198 | fsm_nstate <= done; 199 | else 200 | fsm_nstate <= ipv6_dst; 201 | end if; 202 | 203 | when done => 204 | if (RX_VLD = '1' and RX_EOP = '1') then 205 | fsm_nstate <= idle; 206 | else 207 | fsm_nstate <= done; 208 | end if; 209 | 210 | end case; 211 | end process; 212 | 213 | -- ------------------------------------------------------------------------- 214 | -- HELPER SHIFT REGSTERS AND STATE REGISTERS 215 | -- ------------------------------------------------------------------------- 216 | 217 | process (CLK) 218 | begin 219 | if (rising_edge(CLK)) then 220 | if (mac_dst_shreg_en = '1') then 221 | mac_dst_shreg <= mac_dst_shreg(47-8 downto 0) & RX_DATA; 222 | end if; 223 | end if; 224 | end process; 225 | 226 | process (CLK) 227 | begin 228 | if (rising_edge(CLK)) then 229 | if (mac_src_shreg_en = '1') then 230 | mac_src_shreg <= mac_src_shreg(47-8 downto 0) & RX_DATA; 231 | end if; 232 | end if; 233 | end process; 234 | 235 | process (CLK) 236 | begin 237 | if (rising_edge(CLK)) then 238 | if (ipv4_dst_shreg_en = '1') then 239 | ipv4_dst_shreg <= ipv4_dst_shreg(31-8 downto 0) & RX_DATA; 240 | end if; 241 | end if; 242 | end process; 243 | 244 | process (CLK) 245 | begin 246 | if (rising_edge(CLK)) then 247 | if (ipv4_src_shreg_en = '1') then 248 | ipv4_src_shreg <= ipv4_src_shreg(31-8 downto 0) & RX_DATA; 249 | end if; 250 | end if; 251 | end process; 252 | 253 | process (CLK) 254 | begin 255 | if (rising_edge(CLK)) then 256 | if (ipv6_dst_shreg_en = '1') then 257 | ipv6_dst_shreg <= ipv6_dst_shreg(127-8 downto 0) & RX_DATA; 258 | end if; 259 | end if; 260 | end process; 261 | 262 | process (CLK) 263 | begin 264 | if (rising_edge(CLK)) then 265 | if (ipv6_src_shreg_en = '1') then 266 | ipv6_src_shreg <= ipv6_src_shreg(127-8 downto 0) & RX_DATA; 267 | end if; 268 | end if; 269 | end process; 270 | 271 | process (CLK) 272 | begin 273 | if (rising_edge(CLK)) then 274 | ipv4_vld_reg <= ipv4_vld_reg_next; 275 | ipv6_vld_reg <= ipv6_vld_reg_next; 276 | end if; 277 | end process; 278 | 279 | -- ------------------------------------------------------------------------- 280 | -- OUTPUT ASSIGMENTS 281 | -- ------------------------------------------------------------------------- 282 | 283 | TX_DATA <= RX_DATA; 284 | TX_SOP <= RX_SOP; 285 | TX_EOP <= RX_EOP; 286 | TX_VLD <= RX_VLD; 287 | RX_RDY <= TX_RDY; 288 | 289 | EX_MAC_DST <= mac_dst_shreg; 290 | EX_MAC_SRC <= mac_src_shreg; 291 | EX_IPV4_VLD <= ipv4_vld_reg; 292 | EX_IPV4_DST <= ipv4_dst_shreg; 293 | EX_IPV4_SRC <= ipv4_src_shreg; 294 | EX_IPV6_VLD <= ipv6_vld_reg; 295 | EX_IPV6_DST <= ipv6_dst_shreg; 296 | EX_IPV6_SRC <= ipv6_src_shreg; 297 | 298 | end architecture; 299 | -------------------------------------------------------------------------------- /rtl/comp/rmii_mac/rmii_mac.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | -- Only 100 Mbps full duplex mode is supported now. 13 | 14 | entity RMII_MAC is 15 | Port ( 16 | -- CLOCKS AND RESETS 17 | RMII_CLK : in std_logic; 18 | RMII_RST : in std_logic; 19 | USER_CLK : in std_logic; 20 | USER_RST : in std_logic; 21 | 22 | -- RMII INTERFACE (RMII_CLK) 23 | RMII_RXD : in std_logic_vector(1 downto 0); 24 | RMII_CSR_DV : in std_logic; 25 | RMII_TXD : out std_logic_vector(1 downto 0); 26 | RMII_TX_EN : out std_logic; 27 | 28 | -- USER OUTPUT STREAM INTERFACE (USER_CLK) 29 | TX_DATA : out std_logic_vector(7 downto 0); 30 | TX_SOP : out std_logic; 31 | TX_EOP : out std_logic; 32 | TX_VLD : out std_logic; 33 | TX_RDY : in std_logic; 34 | 35 | -- USER INPUT STREAM INTERFACE (USER_CLK) 36 | RX_DATA : in std_logic_vector(7 downto 0); 37 | RX_SOP : in std_logic; 38 | RX_EOP : in std_logic; 39 | RX_VLD : in std_logic; 40 | RX_RDY : out std_logic; 41 | 42 | -- WISHBONE SLAVE INTERFACE (USER_CLK) 43 | WB_CYC : in std_logic; 44 | WB_STB : in std_logic; 45 | WB_WE : in std_logic; 46 | WB_ADDR : in std_logic_vector(15 downto 0); 47 | WB_DIN : in std_logic_vector(31 downto 0); 48 | WB_STALL : out std_logic; 49 | WB_ACK : out std_logic; 50 | WB_DOUT : out std_logic_vector(31 downto 0) 51 | ); 52 | end entity; 53 | 54 | architecture RTL of RMII_MAC is 55 | 56 | constant WB_PORTS : natural := 2; 57 | 58 | signal split_wb_cyc : std_logic_vector(WB_PORTS-1 downto 0); 59 | signal split_wb_stb : std_logic_vector(WB_PORTS-1 downto 0); 60 | signal split_wb_we : std_logic_vector(WB_PORTS-1 downto 0); 61 | signal split_wb_addr : std_logic_vector(WB_PORTS*16-1 downto 0); 62 | signal split_wb_din : std_logic_vector(WB_PORTS*32-1 downto 0); 63 | signal split_wb_stall : std_logic_vector(WB_PORTS-1 downto 0); 64 | signal split_wb_ack : std_logic_vector(WB_PORTS-1 downto 0); 65 | signal split_wb_dout : std_logic_vector(WB_PORTS*32-1 downto 0); 66 | 67 | begin 68 | 69 | rx_i : entity work.RX_RMII_MAC 70 | port map ( 71 | RMII_CLK => RMII_CLK, 72 | RMII_RST => RMII_RST, 73 | USER_CLK => USER_CLK, 74 | USER_RST => USER_RST, 75 | 76 | RMII_RXD => RMII_RXD, 77 | RMII_CSR_DV => RMII_CSR_DV, 78 | 79 | TX_DATA => TX_DATA, 80 | TX_SOP => TX_SOP, 81 | TX_EOP => TX_EOP, 82 | TX_VLD => TX_VLD, 83 | TX_RDY => TX_RDY, 84 | 85 | WB_CYC => split_wb_cyc(0), 86 | WB_STB => split_wb_stb(0), 87 | WB_WE => split_wb_we(0), 88 | WB_ADDR => split_wb_addr(16-1 downto 0), 89 | WB_DIN => split_wb_din(32-1 downto 0), 90 | WB_STALL => split_wb_stall(0), 91 | WB_ACK => split_wb_ack(0), 92 | WB_DOUT => split_wb_dout(32-1 downto 0) 93 | ); 94 | 95 | tx_i : entity work.TX_RMII_MAC 96 | port map ( 97 | RMII_CLK => RMII_CLK, 98 | RMII_RST => RMII_RST, 99 | USER_CLK => USER_CLK, 100 | USER_RST => USER_RST, 101 | 102 | RMII_TXD => RMII_TXD, 103 | RMII_TX_EN => RMII_TX_EN, 104 | 105 | RX_DATA => RX_DATA, 106 | RX_SOP => RX_SOP, 107 | RX_EOP => RX_EOP, 108 | RX_VLD => RX_VLD, 109 | RX_RDY => RX_RDY, 110 | 111 | WB_CYC => split_wb_cyc(1), 112 | WB_STB => split_wb_stb(1), 113 | WB_WE => split_wb_we(1), 114 | WB_ADDR => split_wb_addr(32-1 downto 16), 115 | WB_DIN => split_wb_din(64-1 downto 32), 116 | WB_STALL => split_wb_stall(1), 117 | WB_ACK => split_wb_ack(1), 118 | WB_DOUT => split_wb_dout(64-1 downto 32) 119 | ); 120 | 121 | wb_splitter_i : entity work.WB_SPLITTER 122 | generic map ( 123 | MASTER_PORTS => WB_PORTS, 124 | ADDR_OFFSET => 8 125 | ) 126 | port map ( 127 | CLK => USER_CLK, 128 | RST => USER_RST, 129 | 130 | WB_S_CYC => WB_CYC, 131 | WB_S_STB => WB_STB, 132 | WB_S_WE => WB_WE, 133 | WB_S_ADDR => WB_ADDR, 134 | WB_S_DIN => WB_DIN, 135 | WB_S_STALL => WB_STALL, 136 | WB_S_ACK => WB_ACK, 137 | WB_S_DOUT => WB_DOUT, 138 | 139 | WB_M_CYC => split_wb_cyc, 140 | WB_M_STB => split_wb_stb, 141 | WB_M_WE => split_wb_we, 142 | WB_M_ADDR => split_wb_addr, 143 | WB_M_DOUT => split_wb_din, 144 | WB_M_STALL => split_wb_stall, 145 | WB_M_ACK => split_wb_ack, 146 | WB_M_DIN => split_wb_dout 147 | ); 148 | 149 | end architecture; 150 | -------------------------------------------------------------------------------- /rtl/comp/rmii_mac/rx_rmii_mac.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | -- Only 100 Mbps full duplex mode is supported now. 13 | 14 | entity RX_RMII_MAC is 15 | Port ( 16 | -- CLOCKS AND RESETS 17 | RMII_CLK : in std_logic; 18 | RMII_RST : in std_logic; 19 | USER_CLK : in std_logic; 20 | USER_RST : in std_logic; 21 | 22 | -- RMII INPUT INTERFACE (RMII_CLK) 23 | RMII_RXD : in std_logic_vector(1 downto 0); 24 | RMII_CSR_DV : in std_logic; 25 | 26 | -- USER OUTPUT STREAM INTERFACE (USER_CLK) 27 | TX_DATA : out std_logic_vector(7 downto 0); 28 | TX_SOP : out std_logic; 29 | TX_EOP : out std_logic; 30 | TX_VLD : out std_logic; 31 | TX_RDY : in std_logic; 32 | 33 | -- WISHBONE SLAVE INTERFACE (USER_CLK) 34 | WB_CYC : in std_logic; 35 | WB_STB : in std_logic; 36 | WB_WE : in std_logic; 37 | WB_ADDR : in std_logic_vector(15 downto 0); 38 | WB_DIN : in std_logic_vector(31 downto 0); 39 | WB_STALL : out std_logic; 40 | WB_ACK : out std_logic; 41 | WB_DOUT : out std_logic_vector(31 downto 0) 42 | ); 43 | end entity; 44 | 45 | architecture RTL of RX_RMII_MAC is 46 | 47 | constant ASFIFO_DATA_WIDTH : natural := 8+1; -- data + last 48 | constant ASFIFO_ADDR_WIDTH : natural := 6; 49 | constant FIFO_DATA_WIDTH : natural := 8+1+1; -- data + sop + eop 50 | constant FIFO_ADDR_WIDTH : natural := 11; -- fifo depth = 2048 - 1 words 51 | 52 | signal rmii_rxd_meta : std_logic_vector(1 downto 0); 53 | signal rmii_rxd_sync : std_logic_vector(1 downto 0); 54 | signal rmii_csr_dv_meta : std_logic; 55 | signal rmii_csr_dv_sync : std_logic; 56 | 57 | signal rmii_rxd_reg : std_logic_vector(1 downto 0); 58 | signal rmii_csr_dv_reg : std_logic; 59 | signal rx_cnt : unsigned(1 downto 0); 60 | signal rx_cnt_max : std_logic; 61 | signal rx_cnt_rst : std_logic; 62 | 63 | signal rx_byte : std_logic_vector(7 downto 0); 64 | signal rx_byte_last : std_logic; 65 | signal rx_byte_vld : std_logic; 66 | 67 | signal asfifo_din : std_logic_vector(ASFIFO_DATA_WIDTH-1 downto 0); 68 | signal asfifo_dout : std_logic_vector(ASFIFO_DATA_WIDTH-1 downto 0); 69 | 70 | signal rx_byte_synced : std_logic_vector(7 downto 0); 71 | signal rx_byte_last_synced : std_logic; 72 | signal rx_byte_vld_synced : std_logic; 73 | 74 | type fsm_dec_state is (idle, preamble, sop, wait4eop); 75 | signal fsm_dec_pstate : fsm_dec_state; 76 | signal fsm_dec_nstate : fsm_dec_state; 77 | signal fsm_dec_dbg_st : std_logic_vector(1 downto 0); 78 | 79 | signal vld_flag : std_logic; 80 | signal sop_flag : std_logic; 81 | signal eop_flag : std_logic; 82 | 83 | signal sb0_data : std_logic_vector(7 downto 0); 84 | signal sb0_sop : std_logic; 85 | signal sb0_eop : std_logic; 86 | signal sb0_vld : std_logic; 87 | 88 | signal sb1_data : std_logic_vector(7 downto 0); 89 | signal sb1_sop : std_logic; 90 | signal sb1_eop : std_logic; 91 | signal sb1_vld : std_logic; 92 | 93 | signal pkt_in_progress : std_logic; 94 | signal pkt_in_progress_reg : std_logic; 95 | 96 | signal cnt_rx_pkt : unsigned(31 downto 0); 97 | signal cnt_rx_pkt_reg : std_logic_vector(31 downto 0); 98 | signal cnt_tx_pkt : unsigned(31 downto 0); 99 | signal cnt_tx_pkt_reg : std_logic_vector(31 downto 0); 100 | 101 | signal cnt_bytes : unsigned(13 downto 0); 102 | signal cnt_bytes_next : unsigned(13 downto 0); 103 | 104 | signal rx_pkt_undersize : std_logic; 105 | signal rx_pkt_64_to_127 : std_logic; 106 | signal rx_pkt_128_to_255 : std_logic; 107 | signal rx_pkt_256_to_511 : std_logic; 108 | signal rx_pkt_512_to_767 : std_logic; 109 | signal rx_pkt_768_to_1023 : std_logic; 110 | signal rx_pkt_1024_to_1522 : std_logic; 111 | signal rx_pkt_oversize : std_logic; 112 | 113 | signal cnt_rx_pkt_undersize : unsigned(31 downto 0); 114 | signal cnt_rx_pkt_64_to_127 : unsigned(31 downto 0); 115 | signal cnt_rx_pkt_128_to_255 : unsigned(31 downto 0); 116 | signal cnt_rx_pkt_256_to_511 : unsigned(31 downto 0); 117 | signal cnt_rx_pkt_512_to_767 : unsigned(31 downto 0); 118 | signal cnt_rx_pkt_768_to_1023 : unsigned(31 downto 0); 119 | signal cnt_rx_pkt_1024_to_1522 : unsigned(31 downto 0); 120 | signal cnt_rx_pkt_oversize : unsigned(31 downto 0); 121 | 122 | signal cnt_rx_pkt_undersize_reg : std_logic_vector(31 downto 0); 123 | signal cnt_rx_pkt_64_to_127_reg : std_logic_vector(31 downto 0); 124 | signal cnt_rx_pkt_128_to_255_reg : std_logic_vector(31 downto 0); 125 | signal cnt_rx_pkt_256_to_511_reg : std_logic_vector(31 downto 0); 126 | signal cnt_rx_pkt_512_to_767_reg : std_logic_vector(31 downto 0); 127 | signal cnt_rx_pkt_768_to_1023_reg : std_logic_vector(31 downto 0); 128 | signal cnt_rx_pkt_1024_to_1522_reg : std_logic_vector(31 downto 0); 129 | signal cnt_rx_pkt_oversize_reg : std_logic_vector(31 downto 0); 130 | 131 | type fsm_fic_state is (idle, packet, discard); 132 | signal fsm_fic_pstate : fsm_fic_state; 133 | signal fsm_fic_nstate : fsm_fic_state; 134 | signal fsm_fic_dbg_st : std_logic_vector(1 downto 0); 135 | 136 | signal fifom_din : std_logic_vector(FIFO_DATA_WIDTH-1 downto 0); 137 | signal fifom_wr : std_logic; 138 | signal fifom_mark : std_logic; 139 | signal fifom_discard : std_logic; 140 | signal fifom_full : std_logic; 141 | signal fifom_dout : std_logic_vector(FIFO_DATA_WIDTH-1 downto 0); 142 | signal fifom_dout_vld : std_logic; 143 | signal fifom_rd : std_logic; 144 | signal fifom_status : std_logic_vector(FIFO_ADDR_WIDTH-1 downto 0); 145 | 146 | signal cmd_sel : std_logic; 147 | signal cmd_we : std_logic; 148 | signal cmd_enable : std_logic; 149 | signal cmd_disable : std_logic; 150 | signal cmd_cnt_clear : std_logic; 151 | signal cmd_cnt_sample : std_logic; 152 | 153 | signal disable_reg : std_logic; 154 | signal status_reg : std_logic_vector(31 downto 0); 155 | 156 | begin 157 | 158 | -- ------------------------------------------------------------------------- 159 | -- RMII TO BYTE STREAM 160 | -- ------------------------------------------------------------------------- 161 | 162 | -- two flipflops as prevent metastability 163 | process (RMII_CLK) 164 | begin 165 | if (rising_edge(RMII_CLK)) then 166 | rmii_rxd_meta <= RMII_RXD; 167 | rmii_rxd_sync <= rmii_rxd_meta; 168 | rmii_csr_dv_meta <= RMII_CSR_DV; 169 | rmii_csr_dv_sync <= rmii_csr_dv_meta; 170 | end if; 171 | end process; 172 | 173 | process (RMII_CLK) 174 | begin 175 | if (rising_edge(RMII_CLK)) then 176 | rmii_rxd_reg <= rmii_rxd_sync; 177 | rmii_csr_dv_reg <= rmii_csr_dv_sync; 178 | end if; 179 | end process; 180 | 181 | process (RMII_CLK) 182 | begin 183 | if (rising_edge(RMII_CLK)) then 184 | if (RMII_RST = '1' or rmii_csr_dv_reg = '0') then 185 | rx_cnt_rst <= '1'; 186 | elsif (rmii_csr_dv_reg = '1' and rmii_rxd_reg = "01") then 187 | rx_cnt_rst <= '0'; 188 | end if; 189 | end if; 190 | end process; 191 | 192 | process (RMII_CLK) 193 | begin 194 | if (rising_edge(RMII_CLK)) then 195 | if (rx_cnt_rst = '1') then 196 | rx_cnt <= to_unsigned(1,2); 197 | else 198 | rx_cnt <= rx_cnt + 1; 199 | end if; 200 | end if; 201 | end process; 202 | 203 | rx_cnt_max <= '1' when (rx_cnt = 3) else '0'; 204 | 205 | process (RMII_CLK) 206 | begin 207 | if (rising_edge(RMII_CLK)) then 208 | rx_byte <= rmii_rxd_reg & rx_byte(7 downto 2); 209 | rx_byte_last <= rmii_csr_dv_reg and not rmii_csr_dv_sync; 210 | end if; 211 | end process; 212 | 213 | process (RMII_CLK) 214 | begin 215 | if (rising_edge(RMII_CLK)) then 216 | if (RMII_RST = '1') then 217 | rx_byte_vld <= '0'; 218 | else 219 | rx_byte_vld <= rx_cnt_max and rmii_csr_dv_reg; 220 | end if; 221 | end if; 222 | end process; 223 | 224 | -- ------------------------------------------------------------------------- 225 | -- CROSS DOMAIN CROSSING OF BYTE STREAM 226 | -- ------------------------------------------------------------------------- 227 | 228 | asfifo_din <= rx_byte & rx_byte_last; 229 | 230 | asfifo_i : entity work.ASFIFO 231 | generic map ( 232 | DATA_WIDTH => ASFIFO_DATA_WIDTH, 233 | ADDR_WIDTH => ASFIFO_ADDR_WIDTH 234 | ) 235 | port map ( 236 | -- FIFO WRITE INTERFACE 237 | WR_CLK => RMII_CLK, 238 | WR_RST => RMII_RST, 239 | WR_DATA => asfifo_din, 240 | WR_REQ => rx_byte_vld, 241 | WR_FULL => open, -- USER_CLK must be >= RMII_CLK/4 242 | -- FIFO READ INTERFACE 243 | RD_CLK => USER_CLK, 244 | RD_RST => USER_RST, 245 | RD_DATA => asfifo_dout, 246 | RD_DATA_VLD => rx_byte_vld_synced, 247 | RD_REQ => rx_byte_vld_synced 248 | ); 249 | 250 | rx_byte_synced <= asfifo_dout(8+1-1 downto 1); 251 | rx_byte_last_synced <= asfifo_dout(0); 252 | 253 | -- ------------------------------------------------------------------------- 254 | -- FSM - DECODING PACKET IN BYTE STREAM 255 | -- ------------------------------------------------------------------------- 256 | 257 | process (USER_CLK) 258 | begin 259 | if (rising_edge(USER_CLK)) then 260 | if (USER_RST = '1') then 261 | fsm_dec_pstate <= idle; 262 | else 263 | fsm_dec_pstate <= fsm_dec_nstate; 264 | end if; 265 | end if; 266 | end process; 267 | 268 | process (fsm_dec_pstate, rx_byte_vld_synced, rx_byte_synced, rx_byte_last_synced) 269 | begin 270 | fsm_dec_nstate <= idle; 271 | fsm_dec_dbg_st <= "00"; 272 | vld_flag <= '0'; 273 | sop_flag <= '0'; 274 | eop_flag <= '0'; 275 | 276 | case fsm_dec_pstate is 277 | when idle => 278 | fsm_dec_dbg_st <= "00"; 279 | if (rx_byte_vld_synced = '1' and rx_byte_synced = X"55") then 280 | fsm_dec_nstate <= preamble; 281 | else 282 | fsm_dec_nstate <= idle; 283 | end if; 284 | 285 | when preamble => -- todo check number of preamble bytes 286 | fsm_dec_dbg_st <= "01"; 287 | if (rx_byte_vld_synced = '1') then 288 | if (rx_byte_synced = X"D5") then 289 | fsm_dec_nstate <= sop; 290 | elsif (rx_byte_synced = X"55") then 291 | fsm_dec_nstate <= preamble; 292 | else 293 | fsm_dec_nstate <= idle; 294 | end if; 295 | else 296 | fsm_dec_nstate <= preamble; 297 | end if; 298 | 299 | when sop => -- start of packet (first byte) 300 | fsm_dec_dbg_st <= "10"; 301 | vld_flag <= '1'; 302 | sop_flag <= '1'; 303 | if (rx_byte_vld_synced = '1') then 304 | fsm_dec_nstate <= wait4eop; 305 | else 306 | fsm_dec_nstate <= sop; 307 | end if; 308 | 309 | when wait4eop => -- wait for end of packet (last byte) 310 | fsm_dec_dbg_st <= "11"; 311 | vld_flag <= '1'; 312 | if (rx_byte_vld_synced = '1' and rx_byte_last_synced = '1') then 313 | eop_flag <= '1'; 314 | fsm_dec_nstate <= idle; 315 | else 316 | fsm_dec_nstate <= wait4eop; 317 | end if; 318 | 319 | end case; 320 | end process; 321 | 322 | process (USER_CLK) 323 | begin 324 | if (rising_edge(USER_CLK)) then 325 | sb0_data <= rx_byte_synced; 326 | sb0_sop <= sop_flag; 327 | sb0_eop <= eop_flag; 328 | end if; 329 | end process; 330 | 331 | process (USER_CLK) 332 | begin 333 | if (rising_edge(USER_CLK)) then 334 | if (USER_RST = '1') then 335 | sb0_vld <= '0'; 336 | else 337 | sb0_vld <= rx_byte_vld_synced and vld_flag; 338 | end if; 339 | end if; 340 | end process; 341 | 342 | -- ------------------------------------------------------------------------- 343 | -- FRAME CHECK (TODO) 344 | -- ------------------------------------------------------------------------- 345 | 346 | sb1_data <= sb0_data; 347 | sb1_sop <= sb0_sop; 348 | sb1_eop <= sb0_eop; 349 | sb1_vld <= sb0_vld; 350 | 351 | -- ------------------------------------------------------------------------- 352 | -- FRAME STATISTICS 353 | -- ------------------------------------------------------------------------- 354 | 355 | process (USER_CLK) 356 | begin 357 | if (rising_edge(USER_CLK)) then 358 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 359 | cnt_rx_pkt <= (others => '0'); 360 | elsif (sb1_eop = '1' and sb1_vld = '1') then 361 | cnt_rx_pkt <= cnt_rx_pkt + 1; 362 | end if; 363 | end if; 364 | end process; 365 | 366 | process (USER_CLK) 367 | begin 368 | if (rising_edge(USER_CLK)) then 369 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 370 | cnt_tx_pkt <= (others => '0'); 371 | elsif (fifom_discard = '0' and sb1_eop = '1' and sb1_vld = '1') then 372 | cnt_tx_pkt <= cnt_tx_pkt + 1; 373 | end if; 374 | end if; 375 | end process; 376 | 377 | process (USER_CLK) 378 | begin 379 | if (rising_edge(USER_CLK)) then 380 | if (USER_RST = '1' or (sb1_eop = '1' and sb1_vld = '1')) then 381 | cnt_bytes <= (others => '0'); 382 | elsif (sb1_vld = '1') then 383 | cnt_bytes <= cnt_bytes_next; 384 | end if; 385 | end if; 386 | end process; 387 | 388 | cnt_bytes_next <= cnt_bytes + 1; 389 | 390 | rx_pkt_undersize <= '1' when (cnt_bytes_next < 64) else '0'; 391 | rx_pkt_64_to_127 <= '1' when (cnt_bytes_next >= 64 and cnt_bytes_next < 128) else '0'; 392 | rx_pkt_128_to_255 <= '1' when (cnt_bytes_next >= 128 and cnt_bytes_next < 256) else '0'; 393 | rx_pkt_256_to_511 <= '1' when (cnt_bytes_next >= 256 and cnt_bytes_next < 512) else '0'; 394 | rx_pkt_512_to_767 <= '1' when (cnt_bytes_next >= 512 and cnt_bytes_next < 768) else '0'; 395 | rx_pkt_768_to_1023 <= '1' when (cnt_bytes_next >= 768 and cnt_bytes_next < 1024) else '0'; 396 | rx_pkt_1024_to_1522 <= '1' when (cnt_bytes_next >= 1024 and cnt_bytes_next < 1522) else '0'; 397 | rx_pkt_oversize <= '1' when (cnt_bytes_next > 1522) else '0'; 398 | 399 | process (USER_CLK) 400 | begin 401 | if (rising_edge(USER_CLK)) then 402 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 403 | cnt_rx_pkt_undersize <= (others => '0'); 404 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_undersize = '1') then 405 | cnt_rx_pkt_undersize <= cnt_rx_pkt_undersize + 1; 406 | end if; 407 | end if; 408 | end process; 409 | 410 | process (USER_CLK) 411 | begin 412 | if (rising_edge(USER_CLK)) then 413 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 414 | cnt_rx_pkt_64_to_127 <= (others => '0'); 415 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_64_to_127 = '1') then 416 | cnt_rx_pkt_64_to_127 <= cnt_rx_pkt_64_to_127 + 1; 417 | end if; 418 | end if; 419 | end process; 420 | 421 | process (USER_CLK) 422 | begin 423 | if (rising_edge(USER_CLK)) then 424 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 425 | cnt_rx_pkt_128_to_255 <= (others => '0'); 426 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_128_to_255 = '1') then 427 | cnt_rx_pkt_128_to_255 <= cnt_rx_pkt_128_to_255 + 1; 428 | end if; 429 | end if; 430 | end process; 431 | 432 | process (USER_CLK) 433 | begin 434 | if (rising_edge(USER_CLK)) then 435 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 436 | cnt_rx_pkt_256_to_511 <= (others => '0'); 437 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_256_to_511 = '1') then 438 | cnt_rx_pkt_256_to_511 <= cnt_rx_pkt_256_to_511 + 1; 439 | end if; 440 | end if; 441 | end process; 442 | 443 | process (USER_CLK) 444 | begin 445 | if (rising_edge(USER_CLK)) then 446 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 447 | cnt_rx_pkt_512_to_767 <= (others => '0'); 448 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_512_to_767 = '1') then 449 | cnt_rx_pkt_512_to_767 <= cnt_rx_pkt_512_to_767 + 1; 450 | end if; 451 | end if; 452 | end process; 453 | 454 | process (USER_CLK) 455 | begin 456 | if (rising_edge(USER_CLK)) then 457 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 458 | cnt_rx_pkt_768_to_1023 <= (others => '0'); 459 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_768_to_1023 = '1') then 460 | cnt_rx_pkt_768_to_1023 <= cnt_rx_pkt_768_to_1023 + 1; 461 | end if; 462 | end if; 463 | end process; 464 | 465 | process (USER_CLK) 466 | begin 467 | if (rising_edge(USER_CLK)) then 468 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 469 | cnt_rx_pkt_1024_to_1522 <= (others => '0'); 470 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_1024_to_1522 = '1') then 471 | cnt_rx_pkt_1024_to_1522 <= cnt_rx_pkt_1024_to_1522 + 1; 472 | end if; 473 | end if; 474 | end process; 475 | 476 | process (USER_CLK) 477 | begin 478 | if (rising_edge(USER_CLK)) then 479 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 480 | cnt_rx_pkt_oversize <= (others => '0'); 481 | elsif (sb1_eop = '1' and sb1_vld = '1' and rx_pkt_oversize = '1') then 482 | cnt_rx_pkt_oversize <= cnt_rx_pkt_oversize + 1; 483 | end if; 484 | end if; 485 | end process; 486 | 487 | -- ------------------------------------------------------------------------- 488 | -- STORE AND FORWARD/DISCARD FIFO 489 | -- ------------------------------------------------------------------------- 490 | 491 | process (USER_CLK) 492 | begin 493 | if (rising_edge(USER_CLK)) then 494 | if (USER_RST = '1' or (sb1_eop = '1' and sb1_vld = '1')) then 495 | pkt_in_progress_reg <= '0'; 496 | elsif (sb1_sop = '1' and sb1_vld = '1') then 497 | pkt_in_progress_reg <= '1'; 498 | end if; 499 | end if; 500 | end process; 501 | 502 | pkt_in_progress <= pkt_in_progress_reg or (sb1_sop and sb1_vld); 503 | 504 | process (USER_CLK) 505 | begin 506 | if (rising_edge(USER_CLK)) then 507 | if (USER_RST = '1') then 508 | fsm_fic_pstate <= idle; 509 | else 510 | fsm_fic_pstate <= fsm_fic_nstate; 511 | end if; 512 | end if; 513 | end process; 514 | 515 | process (fsm_fic_pstate, fifom_full, sb1_vld, sb1_sop, sb1_eop, pkt_in_progress) 516 | begin 517 | fsm_fic_nstate <= idle; 518 | fsm_fic_dbg_st <= "00"; 519 | fifom_mark <= '0'; 520 | fifom_discard <= '0'; 521 | 522 | case fsm_fic_pstate is 523 | when idle => 524 | fsm_fic_dbg_st <= "00"; 525 | fifom_mark <= '1'; 526 | if (fifom_full = '1') then 527 | fifom_discard <= '1'; 528 | fsm_fic_nstate <= discard; 529 | elsif (sb1_vld = '1' and sb1_sop = '1') then 530 | fsm_fic_nstate <= packet; 531 | else 532 | fsm_fic_nstate <= idle; 533 | end if; 534 | 535 | when packet => 536 | fsm_fic_dbg_st <= "01"; 537 | if (fifom_full = '1') then 538 | fifom_discard <= '1'; 539 | fsm_fic_nstate <= discard; 540 | elsif (sb1_vld = '1' and sb1_eop = '1') then 541 | fsm_fic_nstate <= idle; 542 | else 543 | fsm_fic_nstate <= packet; 544 | end if; 545 | 546 | when discard => 547 | fsm_fic_dbg_st <= "10"; 548 | fifom_discard <= '1'; 549 | if (pkt_in_progress = '0' and fifom_full = '0') then 550 | fsm_fic_nstate <= idle; 551 | else 552 | fsm_fic_nstate <= discard; 553 | end if; 554 | 555 | end case; 556 | end process; 557 | 558 | fifom_din <= sb1_data & sb1_sop & sb1_eop; 559 | fifom_wr <= sb1_vld; 560 | 561 | fifo_mark_i : entity work.FIFO_MARK 562 | generic map ( 563 | DATA_WIDTH => FIFO_DATA_WIDTH, 564 | ADDR_WIDTH => FIFO_ADDR_WIDTH 565 | ) 566 | port map ( 567 | CLK => USER_CLK, 568 | RST => USER_RST, 569 | -- FIFO WRITE INTERFACE 570 | WR_DATA => fifom_din, 571 | WR_REQ => fifom_wr, 572 | WR_FULL => fifom_full, 573 | -- FIFO READ INTERFACE 574 | RD_DATA => fifom_dout, 575 | RD_DATA_VLD => fifom_dout_vld, 576 | RD_REQ => fifom_rd, 577 | -- FIFO OTHERS SIGNALS 578 | MARK => fifom_mark, 579 | DISCARD => fifom_discard, 580 | STATUS => fifom_status 581 | ); 582 | 583 | fifom_rd <= TX_RDY and not disable_reg; 584 | 585 | TX_DATA <= fifom_dout(8+2-1 downto 2); 586 | TX_SOP <= fifom_dout(1); 587 | TX_EOP <= fifom_dout(0); 588 | TX_VLD <= fifom_dout_vld and not disable_reg; 589 | 590 | -- ------------------------------------------------------------------------- 591 | -- WISHBONE SLAVE LOGIC 592 | -- ------------------------------------------------------------------------- 593 | 594 | cmd_sel <= '1' when (WB_ADDR(7 downto 0) = X"00") else '0'; 595 | cmd_we <= wb_stb and wb_we and cmd_sel; 596 | 597 | cmd_reg_p : process (USER_CLK) 598 | begin 599 | if (rising_edge(USER_CLK)) then 600 | cmd_enable <= '0'; 601 | cmd_disable <= '0'; 602 | cmd_cnt_clear <= '0'; 603 | cmd_cnt_sample <= '0'; 604 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"00") then 605 | cmd_enable <= '1'; 606 | end if; 607 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"01") then 608 | cmd_disable <= '1'; 609 | end if; 610 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"02") then 611 | cmd_cnt_clear <= '1'; 612 | end if; 613 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"03") then 614 | cmd_cnt_sample <= '1'; 615 | end if; 616 | end if; 617 | end process; 618 | 619 | disable_reg_p : process (USER_CLK) 620 | begin 621 | if (rising_edge(USER_CLK)) then 622 | if (USER_RST = '1' or cmd_disable = '1') then 623 | disable_reg <= '0'; 624 | elsif (cmd_enable = '1') then 625 | disable_reg <= '1'; 626 | end if; 627 | end if; 628 | end process; 629 | 630 | cnt_sampled_reg_p : process (USER_CLK) 631 | begin 632 | if (rising_edge(USER_CLK)) then 633 | if (cmd_cnt_sample = '1') then 634 | cnt_rx_pkt_reg <= std_logic_vector(cnt_rx_pkt); 635 | cnt_tx_pkt_reg <= std_logic_vector(cnt_tx_pkt); 636 | cnt_rx_pkt_undersize_reg <= std_logic_vector(cnt_rx_pkt_undersize); 637 | cnt_rx_pkt_64_to_127_reg <= std_logic_vector(cnt_rx_pkt_64_to_127); 638 | cnt_rx_pkt_128_to_255_reg <= std_logic_vector(cnt_rx_pkt_128_to_255); 639 | cnt_rx_pkt_256_to_511_reg <= std_logic_vector(cnt_rx_pkt_256_to_511); 640 | cnt_rx_pkt_512_to_767_reg <= std_logic_vector(cnt_rx_pkt_512_to_767); 641 | cnt_rx_pkt_768_to_1023_reg <= std_logic_vector(cnt_rx_pkt_768_to_1023); 642 | cnt_rx_pkt_1024_to_1522_reg <= std_logic_vector(cnt_rx_pkt_1024_to_1522); 643 | cnt_rx_pkt_oversize_reg <= std_logic_vector(cnt_rx_pkt_oversize); 644 | end if; 645 | end if; 646 | end process; 647 | 648 | status_reg <= (31 downto 27 => '0') & 649 | fifom_status & 650 | "00" & fsm_fic_dbg_st & 651 | "00" & fsm_dec_dbg_st & 652 | (not fifom_full) & fifom_wr & TX_RDY & fifom_dout_vld & 653 | "000" & disable_reg; 654 | 655 | WB_STALL <= '0'; 656 | 657 | wb_ack_reg_p : process (USER_CLK) 658 | begin 659 | if (rising_edge(USER_CLK)) then 660 | WB_ACK <= WB_CYC and WB_STB; 661 | end if; 662 | end process; 663 | 664 | wb_dout_reg_p : process (USER_CLK) 665 | begin 666 | if (rising_edge(USER_CLK)) then 667 | case WB_ADDR(7 downto 0) is 668 | when X"00" => 669 | WB_DOUT <= X"20191102"; -- version 670 | when X"04" => 671 | WB_DOUT <= status_reg; 672 | when X"10" => 673 | WB_DOUT <= cnt_rx_pkt_reg; 674 | when X"14" => 675 | WB_DOUT <= cnt_tx_pkt_reg; 676 | when X"20" => 677 | WB_DOUT <= cnt_rx_pkt_undersize_reg; 678 | when X"24" => 679 | WB_DOUT <= cnt_rx_pkt_64_to_127_reg; 680 | when X"28" => 681 | WB_DOUT <= cnt_rx_pkt_128_to_255_reg; 682 | when X"2C" => 683 | WB_DOUT <= cnt_rx_pkt_256_to_511_reg; 684 | when X"30" => 685 | WB_DOUT <= cnt_rx_pkt_512_to_767_reg; 686 | when X"34" => 687 | WB_DOUT <= cnt_rx_pkt_768_to_1023_reg; 688 | when X"38" => 689 | WB_DOUT <= cnt_rx_pkt_1024_to_1522_reg; 690 | when X"3C" => 691 | WB_DOUT <= cnt_rx_pkt_oversize_reg; 692 | when others => 693 | WB_DOUT <= X"DEADCAFE"; 694 | end case; 695 | end if; 696 | end process; 697 | 698 | end architecture; 699 | -------------------------------------------------------------------------------- /rtl/comp/rmii_mac/tx_rmii_mac.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | -- Only 100 Mbps full duplex mode is supported now. 13 | 14 | entity TX_RMII_MAC is 15 | Port ( 16 | -- CLOCKS AND RESETS 17 | RMII_CLK : in std_logic; 18 | RMII_RST : in std_logic; 19 | USER_CLK : in std_logic; 20 | USER_RST : in std_logic; 21 | 22 | -- RMII OUTPUT INTERFACE (RMII_CLK) 23 | RMII_TXD : out std_logic_vector(1 downto 0); 24 | RMII_TX_EN : out std_logic; 25 | 26 | -- USER INPUT STREAM INTERFACE (USER_CLK) 27 | RX_DATA : in std_logic_vector(7 downto 0); 28 | RX_SOP : in std_logic; 29 | RX_EOP : in std_logic; 30 | RX_VLD : in std_logic; 31 | RX_RDY : out std_logic; 32 | 33 | -- WISHBONE SLAVE INTERFACE (USER_CLK) 34 | WB_CYC : in std_logic; 35 | WB_STB : in std_logic; 36 | WB_WE : in std_logic; 37 | WB_ADDR : in std_logic_vector(15 downto 0); 38 | WB_DIN : in std_logic_vector(31 downto 0); 39 | WB_STALL : out std_logic; 40 | WB_ACK : out std_logic; 41 | WB_DOUT : out std_logic_vector(31 downto 0) 42 | ); 43 | end entity; 44 | 45 | architecture RTL of TX_RMII_MAC is 46 | 47 | constant ASFIFO_DATA_WIDTH : natural := 8+1+1; -- data + sop + eop 48 | constant ASFIFO_ADDR_WIDTH : natural := 11; -- fifo depth 49 | 50 | signal rx_rdy_en : std_logic; 51 | signal rx_vld_en : std_logic; 52 | 53 | signal asfifo_din : std_logic_vector(ASFIFO_DATA_WIDTH-1 downto 0); 54 | signal asfifo_dout : std_logic_vector(ASFIFO_DATA_WIDTH-1 downto 0); 55 | signal asfifo_full : std_logic; 56 | 57 | signal rx_data_synced : std_logic_vector(7 downto 0); 58 | signal rx_sop_synced : std_logic; 59 | signal rx_eop_synced : std_logic; 60 | signal rx_vld_synced : std_logic; 61 | signal rx_rdy_synced : std_logic; 62 | 63 | signal rx_eop_vld : std_logic; 64 | signal pkt_rdy : std_logic; 65 | signal pkt_rdy_next : std_logic; 66 | 67 | signal cnt_rx_pkt : unsigned(31 downto 0); 68 | signal cnt_rx_pkt_reg : std_logic_vector(31 downto 0); 69 | 70 | type fsm_tx_state is (idle, preamble, sfd, packet, ipg); 71 | signal fsm_tx_pstate : fsm_tx_state; 72 | signal fsm_tx_nstate : fsm_tx_state; 73 | signal fsm_tx_enable : std_logic; 74 | signal fsm_tx_dbg_st : std_logic_vector(2 downto 0); 75 | 76 | signal cnt_reg : unsigned(3 downto 0); 77 | signal cnt_reg_next : unsigned(3 downto 0); 78 | signal tx_byte : std_logic_vector(7 downto 0); 79 | signal tx_en : std_logic; 80 | 81 | signal tx_cnt : unsigned(1 downto 0); 82 | signal txd_reg : std_logic_vector(1 downto 0); 83 | signal tx_en_reg : std_logic; 84 | 85 | signal cmd_sel : std_logic; 86 | signal cmd_we : std_logic; 87 | signal cmd_disable : std_logic; 88 | signal cmd_enable : std_logic; 89 | signal cmd_cnt_clear : std_logic; 90 | signal cmd_cnt_sample : std_logic; 91 | 92 | signal disable_reg : std_logic; 93 | 94 | begin 95 | 96 | -- ------------------------------------------------------------------------- 97 | -- FRAME STATISTICS 98 | -- ------------------------------------------------------------------------- 99 | 100 | process (USER_CLK) 101 | begin 102 | if (rising_edge(USER_CLK)) then 103 | if (USER_RST = '1' or cmd_cnt_clear = '1') then 104 | cnt_rx_pkt <= (others => '0'); 105 | elsif (RX_EOP = '1' and rx_vld_en = '1' and rx_rdy_en = '1') then 106 | cnt_rx_pkt <= cnt_rx_pkt + 1; 107 | end if; 108 | end if; 109 | end process; 110 | 111 | -- ------------------------------------------------------------------------- 112 | -- RX DATA BUFFER 113 | -- ------------------------------------------------------------------------- 114 | 115 | rx_rdy_en <= not disable_reg and not asfifo_full; 116 | rx_vld_en <= RX_VLD and not disable_reg; 117 | 118 | RX_RDY <= rx_rdy_en; 119 | 120 | asfifo_din <= RX_DATA & RX_SOP & RX_EOP; 121 | 122 | data_asfifo_i : entity work.ASFIFO 123 | generic map ( 124 | DATA_WIDTH => ASFIFO_DATA_WIDTH, 125 | ADDR_WIDTH => ASFIFO_ADDR_WIDTH 126 | ) 127 | port map ( 128 | -- FIFO WRITE INTERFACE 129 | WR_CLK => USER_CLK, 130 | WR_RST => USER_RST, 131 | WR_DATA => asfifo_din, 132 | WR_REQ => rx_vld_en, 133 | WR_FULL => asfifo_full, 134 | -- FIFO READ INTERFACE 135 | RD_CLK => RMII_CLK, 136 | RD_RST => RMII_RST, 137 | RD_DATA => asfifo_dout, 138 | RD_DATA_VLD => rx_vld_synced, 139 | RD_REQ => rx_rdy_synced 140 | ); 141 | 142 | rx_data_synced <= asfifo_dout(8+2-1 downto 2); 143 | rx_sop_synced <= asfifo_dout(1); 144 | rx_eop_synced <= asfifo_dout(0); 145 | 146 | rx_eop_vld <= rx_vld_en and rx_rdy_en and RX_EOP; 147 | 148 | eop_asfifo_i : entity work.ASFIFO 149 | generic map ( 150 | DATA_WIDTH => 1, 151 | ADDR_WIDTH => ASFIFO_ADDR_WIDTH-4 152 | ) 153 | port map ( 154 | -- FIFO WRITE INTERFACE 155 | WR_CLK => USER_CLK, 156 | WR_RST => USER_RST, 157 | WR_DATA => (others => '1'), 158 | WR_REQ => rx_eop_vld, 159 | WR_FULL => open, 160 | -- FIFO READ INTERFACE 161 | RD_CLK => RMII_CLK, 162 | RD_RST => RMII_RST, 163 | RD_DATA => open, 164 | RD_DATA_VLD => pkt_rdy, 165 | RD_REQ => pkt_rdy_next 166 | ); 167 | 168 | -- ------------------------------------------------------------------------- 169 | -- RMII TX FSM 170 | -- ------------------------------------------------------------------------- 171 | 172 | process (RMII_CLK) 173 | begin 174 | if (rising_edge(RMII_CLK)) then 175 | if (RMII_RST = '1') then 176 | fsm_tx_pstate <= idle; 177 | cnt_reg <= (others => '0'); 178 | elsif (fsm_tx_enable = '1') then 179 | fsm_tx_pstate <= fsm_tx_nstate; 180 | cnt_reg <= cnt_reg_next; 181 | end if; 182 | end if; 183 | end process; 184 | 185 | process (fsm_tx_pstate, fsm_tx_enable, rx_data_synced, rx_vld_synced, 186 | rx_sop_synced, rx_eop_synced, pkt_rdy, cnt_reg) 187 | begin 188 | fsm_tx_nstate <= idle; 189 | fsm_tx_dbg_st <= "000"; 190 | rx_rdy_synced <= '0'; 191 | cnt_reg_next <= (others => '0'); 192 | pkt_rdy_next <= '0'; 193 | tx_byte <= X"00"; 194 | tx_en <= '0'; 195 | 196 | case fsm_tx_pstate is 197 | when idle => 198 | fsm_tx_dbg_st <= "000"; 199 | if (rx_sop_synced = '1' and rx_vld_synced = '1' and pkt_rdy = '1') then 200 | fsm_tx_nstate <= preamble; 201 | else 202 | fsm_tx_nstate <= idle; 203 | end if; 204 | 205 | when preamble => -- seven preamble bytes 206 | fsm_tx_dbg_st <= "001"; 207 | cnt_reg_next <= cnt_reg + 1; 208 | tx_byte <= X"55"; 209 | tx_en <= '1'; 210 | 211 | if (cnt_reg = 6) then 212 | fsm_tx_nstate <= sfd; 213 | else 214 | fsm_tx_nstate <= preamble; 215 | end if; 216 | 217 | when sfd => -- one SFD byte 218 | fsm_tx_dbg_st <= "010"; 219 | pkt_rdy_next <= fsm_tx_enable; 220 | tx_byte <= X"D5"; 221 | tx_en <= '1'; 222 | 223 | fsm_tx_nstate <= packet; 224 | 225 | when packet => 226 | fsm_tx_dbg_st <= "011"; 227 | rx_rdy_synced <= fsm_tx_enable; 228 | tx_byte <= rx_data_synced; 229 | tx_en <= '1'; 230 | 231 | if (rx_vld_synced = '1' and rx_eop_synced = '1') then 232 | fsm_tx_nstate <= ipg; 233 | else 234 | fsm_tx_nstate <= packet; 235 | end if; 236 | 237 | when ipg => -- inter packet gap = 12 bytes 238 | fsm_tx_dbg_st <= "100"; 239 | cnt_reg_next <= cnt_reg + 1; 240 | 241 | if (cnt_reg = 11) then 242 | fsm_tx_nstate <= idle; 243 | else 244 | fsm_tx_nstate <= ipg; 245 | end if; 246 | 247 | end case; 248 | end process; 249 | 250 | -- ------------------------------------------------------------------------- 251 | -- BYTE STREAM TO RMII 252 | -- ------------------------------------------------------------------------- 253 | 254 | process (RMII_CLK) 255 | begin 256 | if (rising_edge(RMII_CLK)) then 257 | if (RMII_RST = '1') then 258 | tx_cnt <= (others => '0'); 259 | else 260 | tx_cnt <= tx_cnt + 1; 261 | end if; 262 | end if; 263 | end process; 264 | 265 | fsm_tx_enable <= '1' when (tx_cnt = "11") else '0'; 266 | 267 | process (RMII_CLK) 268 | begin 269 | if (rising_edge(RMII_CLK)) then 270 | case tx_cnt is 271 | when "00" => 272 | txd_reg <= tx_byte(1 downto 0); 273 | when "01" => 274 | txd_reg <= tx_byte(3 downto 2); 275 | when "10" => 276 | txd_reg <= tx_byte(5 downto 4); 277 | when others => 278 | txd_reg <= tx_byte(7 downto 6); 279 | end case; 280 | end if; 281 | end process; 282 | 283 | process (RMII_CLK) 284 | begin 285 | if (rising_edge(RMII_CLK)) then 286 | if (RMII_RST = '1') then 287 | tx_en_reg <= '0'; 288 | else 289 | tx_en_reg <= tx_en; 290 | end if; 291 | end if; 292 | end process; 293 | 294 | RMII_TXD <= txd_reg; 295 | RMII_TX_EN <= tx_en_reg; 296 | 297 | -- ------------------------------------------------------------------------- 298 | -- WISHBONE SLAVE LOGIC 299 | -- ------------------------------------------------------------------------- 300 | 301 | cmd_sel <= '1' when (WB_ADDR(7 downto 0) = X"00") else '0'; 302 | cmd_we <= wb_stb and wb_we and cmd_sel; 303 | 304 | cmd_reg_p : process (USER_CLK) 305 | begin 306 | if (rising_edge(USER_CLK)) then 307 | cmd_disable <= '0'; 308 | cmd_enable <= '0'; 309 | cmd_cnt_clear <= '0'; 310 | cmd_cnt_sample <= '0'; 311 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"00") then 312 | cmd_disable <= '1'; 313 | end if; 314 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"01") then 315 | cmd_enable <= '1'; 316 | end if; 317 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"02") then 318 | cmd_cnt_clear <= '1'; 319 | end if; 320 | if (cmd_we = '1' and WB_DIN(7 downto 0) = X"03") then 321 | cmd_cnt_sample <= '1'; 322 | end if; 323 | end if; 324 | end process; 325 | 326 | disable_reg_p : process (USER_CLK) 327 | begin 328 | if (rising_edge(USER_CLK)) then 329 | if (USER_RST = '1' or cmd_enable = '1') then 330 | disable_reg <= '0'; 331 | elsif (cmd_disable = '1') then 332 | disable_reg <= '1'; 333 | end if; 334 | end if; 335 | end process; 336 | 337 | cnt_sampled_reg_p : process (USER_CLK) 338 | begin 339 | if (rising_edge(USER_CLK)) then 340 | if (cmd_cnt_sample = '1') then 341 | cnt_rx_pkt_reg <= std_logic_vector(cnt_rx_pkt); 342 | end if; 343 | end if; 344 | end process; 345 | 346 | WB_STALL <= '0'; 347 | 348 | wb_ack_reg_p : process (USER_CLK) 349 | begin 350 | if (rising_edge(USER_CLK)) then 351 | WB_ACK <= WB_CYC and WB_STB; 352 | end if; 353 | end process; 354 | 355 | wb_dout_reg_p : process (USER_CLK) 356 | begin 357 | if (rising_edge(USER_CLK)) then 358 | case WB_ADDR(7 downto 0) is 359 | when X"00" => 360 | WB_DOUT <= X"20191026"; -- version 361 | when X"04" => 362 | WB_DOUT <= (31 downto 8 => '0') & "00" & (not asfifo_full) & RX_VLD & "000" & disable_reg; 363 | when X"10" => 364 | WB_DOUT <= cnt_rx_pkt_reg; 365 | when others => 366 | WB_DOUT <= X"DEADCAFE"; 367 | end case; 368 | end if; 369 | end process; 370 | 371 | end architecture; 372 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: SIMPLE UART FOR FPGA 3 | -------------------------------------------------------------------------------- 4 | -- MODULE: UART TOP MODULE 5 | -- AUTHORS: Jakub Cabal 6 | -- LICENSE: The MIT License (MIT), please read LICENSE file 7 | -- WEBSITE: https://github.com/jakubcabal/uart-for-fpga 8 | -------------------------------------------------------------------------------- 9 | 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.NUMERIC_STD.ALL; 13 | use IEEE.MATH_REAL.ALL; 14 | 15 | -- SIMPLE UART FOR FPGA 16 | -- ==================== 17 | -- UART FOR FPGA REQUIRES: 1 START BIT, 8 DATA BITS, 1 STOP BIT!!! 18 | -- OTHER PARAMETERS CAN BE SET USING GENERICS. 19 | 20 | -- DESCRIPTION OF RELEASED VERSIONS: 21 | -- ================================= 22 | -- Version 1.0 - released on 27 May 2016 23 | -- Initial release. 24 | -- Version 1.1 - released on 20 December 2018 25 | -- Added better debouncer. 26 | -- Added simulation script and Quartus project file. 27 | -- Removed unnecessary resets. 28 | -- Signal BUSY replaced by DIN_RDY. 29 | -- Many other optimizations and changes. 30 | -- Version 1.2 - 31 | -- Added double FF for safe CDC. 32 | -- Fixed fake received transaction after FPGA boot without reset. 33 | 34 | entity UART is 35 | Generic ( 36 | CLK_FREQ : integer := 50e6; -- system clock frequency in Hz 37 | BAUD_RATE : integer := 115200; -- baud rate value 38 | PARITY_BIT : string := "none"; -- type of parity: "none", "even", "odd", "mark", "space" 39 | USE_DEBOUNCER : boolean := True -- enable/disable debouncer 40 | ); 41 | Port ( 42 | -- CLOCK AND RESET 43 | CLK : in std_logic; -- system clock 44 | RST : in std_logic; -- high active synchronous reset 45 | -- UART INTERFACE 46 | UART_TXD : out std_logic; -- serial transmit data 47 | UART_RXD : in std_logic; -- serial receive data 48 | -- USER DATA INPUT INTERFACE 49 | DIN : in std_logic_vector(7 downto 0); -- input data to be transmitted over UART 50 | DIN_VLD : in std_logic; -- when DIN_VLD = 1, input data (DIN) are valid 51 | DIN_RDY : out std_logic; -- when DIN_RDY = 1, transmitter is ready and valid input data will be accepted for transmiting 52 | -- USER DATA OUTPUT INTERFACE 53 | DOUT : out std_logic_vector(7 downto 0); -- output data received via UART 54 | DOUT_VLD : out std_logic; -- when DOUT_VLD = 1, output data (DOUT) are valid (is assert only for one clock cycle) 55 | FRAME_ERROR : out std_logic -- when FRAME_ERROR = 1, stop bit was invalid (is assert only for one clock cycle) 56 | ); 57 | end entity; 58 | 59 | architecture RTL of UART is 60 | 61 | constant DIVIDER_VALUE : integer := CLK_FREQ/(16*BAUD_RATE); 62 | constant CLK_CNT_WIDTH : integer := integer(ceil(log2(real(DIVIDER_VALUE)))); 63 | constant CLK_CNT_MAX : unsigned := to_unsigned(DIVIDER_VALUE-1, CLK_CNT_WIDTH); 64 | 65 | signal oversampling_clk_cnt : unsigned(CLK_CNT_WIDTH-1 downto 0); 66 | signal oversampling_clk_en : std_logic; 67 | signal uart_rxd_meta_n : std_logic; 68 | signal uart_rxd_synced_n : std_logic; 69 | signal uart_rxd_debounced_n : std_logic; 70 | signal uart_rxd_debounced : std_logic; 71 | 72 | begin 73 | 74 | -- ------------------------------------------------------------------------- 75 | -- UART OVERSAMPLING (16X) CLOCK COUNTER AND CLOCK ENABLE FLAG 76 | -- ------------------------------------------------------------------------- 77 | 78 | oversampling_clk_cnt_p : process (CLK) 79 | begin 80 | if (rising_edge(CLK)) then 81 | if (RST = '1') then 82 | oversampling_clk_cnt <= (others => '0'); 83 | else 84 | if (oversampling_clk_en = '1') then 85 | oversampling_clk_cnt <= (others => '0'); 86 | else 87 | oversampling_clk_cnt <= oversampling_clk_cnt + 1; 88 | end if; 89 | end if; 90 | end if; 91 | end process; 92 | 93 | oversampling_clk_en <= '1' when (oversampling_clk_cnt = CLK_CNT_MAX) else '0'; 94 | 95 | -- ------------------------------------------------------------------------- 96 | -- UART RXD CROSS DOMAIN CROSSING 97 | -- ------------------------------------------------------------------------- 98 | 99 | uart_rxd_cdc_reg_p : process (CLK) 100 | begin 101 | if (rising_edge(CLK)) then 102 | uart_rxd_meta_n <= not UART_RXD; 103 | uart_rxd_synced_n <= uart_rxd_meta_n; 104 | end if; 105 | end process; 106 | 107 | -- ------------------------------------------------------------------------- 108 | -- UART RXD DEBAUNCER 109 | -- ------------------------------------------------------------------------- 110 | 111 | use_debouncer_g : if (USE_DEBOUNCER = True) generate 112 | debouncer_i : entity work.UART_DEBOUNCER 113 | generic map( 114 | LATENCY => 4 115 | ) 116 | port map ( 117 | CLK => CLK, 118 | DEB_IN => uart_rxd_synced_n, 119 | DEB_OUT => uart_rxd_debounced_n 120 | ); 121 | end generate; 122 | 123 | not_use_debouncer_g : if (USE_DEBOUNCER = False) generate 124 | uart_rxd_debounced_n <= uart_rxd_synced_n; 125 | end generate; 126 | 127 | uart_rxd_debounced <= not uart_rxd_debounced_n; 128 | 129 | -- ------------------------------------------------------------------------- 130 | -- UART RECEIVER 131 | -- ------------------------------------------------------------------------- 132 | 133 | uart_rx_i: entity work.UART_RX 134 | generic map ( 135 | PARITY_BIT => PARITY_BIT 136 | ) 137 | port map ( 138 | CLK => CLK, 139 | RST => RST, 140 | -- UART INTERFACE 141 | UART_CLK_EN => oversampling_clk_en, 142 | UART_RXD => uart_rxd_debounced, 143 | -- USER DATA OUTPUT INTERFACE 144 | DOUT => DOUT, 145 | DOUT_VLD => DOUT_VLD, 146 | FRAME_ERROR => FRAME_ERROR, 147 | PARITY_ERROR => open 148 | ); 149 | 150 | -- ------------------------------------------------------------------------- 151 | -- UART TRANSMITTER 152 | -- ------------------------------------------------------------------------- 153 | 154 | uart_tx_i: entity work.UART_TX 155 | generic map ( 156 | PARITY_BIT => PARITY_BIT 157 | ) 158 | port map ( 159 | CLK => CLK, 160 | RST => RST, 161 | -- UART INTERFACE 162 | UART_CLK_EN => oversampling_clk_en, 163 | UART_TXD => UART_TXD, 164 | -- USER DATA INPUT INTERFACE 165 | DIN => DIN, 166 | DIN_VLD => DIN_VLD, 167 | DIN_RDY => DIN_RDY 168 | ); 169 | 170 | end architecture; 171 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart2wbm.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity UART2WBM is 13 | Generic ( 14 | CLK_FREQ : integer := 50e6; -- system clock frequency in Hz 15 | BAUD_RATE : integer := 115200 -- baud rate value 16 | ); 17 | Port ( 18 | -- CLOCK AND RESET 19 | CLK : in std_logic; 20 | RST : in std_logic; 21 | -- UART INTERFACE 22 | UART_TXD : out std_logic; 23 | UART_RXD : in std_logic; 24 | -- WISHBONE MASTER INTERFACE 25 | WB_CYC : out std_logic; 26 | WB_STB : out std_logic; 27 | WB_WE : out std_logic; 28 | WB_ADDR : out std_logic_vector(15 downto 0); 29 | WB_DOUT : out std_logic_vector(31 downto 0); 30 | WB_STALL : in std_logic; 31 | WB_ACK : in std_logic; 32 | WB_DIN : in std_logic_vector(31 downto 0) 33 | ); 34 | end entity; 35 | 36 | architecture RTL of UART2WBM is 37 | 38 | type state is (cmd, addr_low, addr_high, dout0, dout1, dout2, dout3, 39 | request, wait4ack, response, din0, din1, din2, din3); 40 | signal fsm_pstate : state; 41 | signal fsm_nstate : state; 42 | 43 | signal cmd_reg : std_logic_vector(7 downto 0); 44 | signal cmd_next : std_logic_vector(7 downto 0); 45 | signal addr_reg : std_logic_vector(15 downto 0); 46 | signal addr_next : std_logic_vector(15 downto 0); 47 | signal dout_reg : std_logic_vector(31 downto 0); 48 | signal dout_next : std_logic_vector(31 downto 0); 49 | signal din_reg : std_logic_vector(31 downto 0); 50 | 51 | signal uart_dout : std_logic_vector(7 downto 0); 52 | signal uart_dout_vld : std_logic; 53 | signal uart_din : std_logic_vector(7 downto 0); 54 | signal uart_din_vld : std_logic; 55 | signal uart_din_rdy : std_logic; 56 | 57 | begin 58 | 59 | WB_CYC <= '1'; 60 | 61 | process (CLK) 62 | begin 63 | if (rising_edge(CLK)) then 64 | cmd_reg <= cmd_next; 65 | addr_reg <= addr_next; 66 | dout_reg <= dout_next; 67 | end if; 68 | end process; 69 | 70 | WB_WE <= cmd_reg(0); 71 | WB_ADDR <= addr_reg; 72 | WB_DOUT <= dout_reg; 73 | 74 | process (CLK) 75 | begin 76 | if (rising_edge(CLK)) then 77 | if (WB_ACK = '1') then 78 | din_reg <= WB_DIN; 79 | end if; 80 | end if; 81 | end process; 82 | 83 | -- ------------------------------------------------------------------------- 84 | -- FSM 85 | -- ------------------------------------------------------------------------- 86 | 87 | process (CLK) 88 | begin 89 | if (rising_edge(CLK)) then 90 | if (RST = '1') then 91 | fsm_pstate <= cmd; 92 | else 93 | fsm_pstate <= fsm_nstate; 94 | end if; 95 | end if; 96 | end process; 97 | 98 | process (fsm_pstate, uart_dout, uart_dout_vld, cmd_reg, addr_reg, dout_reg, 99 | WB_STALL, WB_ACK, uart_din_rdy, din_reg) 100 | begin 101 | fsm_nstate <= cmd; 102 | cmd_next <= cmd_reg; 103 | addr_next <= addr_reg; 104 | dout_next <= dout_reg; 105 | WB_STB <= '0'; 106 | uart_din <= cmd_reg; 107 | uart_din_vld <= '0'; 108 | 109 | case fsm_pstate is 110 | when cmd => 111 | cmd_next <= uart_dout; 112 | 113 | if (uart_dout_vld = '1') then 114 | fsm_nstate <= addr_low; 115 | else 116 | fsm_nstate <= cmd; 117 | end if; 118 | 119 | when addr_low => 120 | addr_next(7 downto 0) <= uart_dout; 121 | 122 | if (uart_dout_vld = '1') then 123 | fsm_nstate <= addr_high; 124 | else 125 | fsm_nstate <= addr_low; 126 | end if; 127 | 128 | when addr_high => 129 | addr_next(15 downto 8) <= uart_dout; 130 | 131 | if (uart_dout_vld = '1') then 132 | if (cmd_reg(0) = '1') then 133 | fsm_nstate <= dout0; 134 | else 135 | fsm_nstate <= request; -- read request 136 | end if; 137 | else 138 | fsm_nstate <= addr_high; 139 | end if; 140 | 141 | when dout0 => 142 | dout_next(7 downto 0) <= uart_dout; 143 | 144 | if (uart_dout_vld = '1') then 145 | fsm_nstate <= dout1; 146 | else 147 | fsm_nstate <= dout0; 148 | end if; 149 | 150 | when dout1 => 151 | dout_next(15 downto 8) <= uart_dout; 152 | 153 | if (uart_dout_vld = '1') then 154 | fsm_nstate <= dout2; 155 | else 156 | fsm_nstate <= dout1; 157 | end if; 158 | 159 | when dout2 => 160 | dout_next(23 downto 16) <= uart_dout; 161 | 162 | if (uart_dout_vld = '1') then 163 | fsm_nstate <= dout3; 164 | else 165 | fsm_nstate <= dout2; 166 | end if; 167 | 168 | when dout3 => 169 | dout_next(31 downto 24) <= uart_dout; 170 | 171 | if (uart_dout_vld = '1') then 172 | fsm_nstate <= request; -- write request 173 | else 174 | fsm_nstate <= dout3; 175 | end if; 176 | 177 | when request => 178 | WB_STB <= '1'; -- request is valid 179 | 180 | if (WB_STALL = '0') then 181 | fsm_nstate <= wait4ack; 182 | else 183 | fsm_nstate <= request; 184 | end if; 185 | 186 | when wait4ack => 187 | if (WB_ACK = '1') then 188 | fsm_nstate <= response; 189 | else 190 | fsm_nstate <= wait4ack; 191 | end if; 192 | 193 | when response => 194 | uart_din <= cmd_reg; 195 | uart_din_vld <= '1'; 196 | 197 | if (uart_din_rdy = '1') then 198 | if (cmd_reg(0) = '1') then 199 | fsm_nstate <= cmd; 200 | else 201 | fsm_nstate <= din0; 202 | end if; 203 | else 204 | fsm_nstate <= response; 205 | end if; 206 | 207 | when din0 => 208 | uart_din <= din_reg(7 downto 0); 209 | uart_din_vld <= '1'; 210 | 211 | if (uart_din_rdy = '1') then 212 | fsm_nstate <= din1; 213 | else 214 | fsm_nstate <= din0; 215 | end if; 216 | 217 | when din1 => 218 | uart_din <= din_reg(15 downto 8); 219 | uart_din_vld <= '1'; 220 | 221 | if (uart_din_rdy = '1') then 222 | fsm_nstate <= din2; 223 | else 224 | fsm_nstate <= din1; 225 | end if; 226 | 227 | when din2 => 228 | uart_din <= din_reg(23 downto 16); 229 | uart_din_vld <= '1'; 230 | 231 | if (uart_din_rdy = '1') then 232 | fsm_nstate <= din3; 233 | else 234 | fsm_nstate <= din2; 235 | end if; 236 | 237 | when din3 => 238 | uart_din <= din_reg(31 downto 24); 239 | uart_din_vld <= '1'; 240 | 241 | if (uart_din_rdy = '1') then 242 | fsm_nstate <= cmd; 243 | else 244 | fsm_nstate <= din3; 245 | end if; 246 | 247 | end case; 248 | end process; 249 | 250 | -- ------------------------------------------------------------------------- 251 | -- UART module 252 | -- ------------------------------------------------------------------------- 253 | 254 | uart_i : entity work.UART 255 | generic map ( 256 | CLK_FREQ => CLK_FREQ, 257 | BAUD_RATE => BAUD_RATE, 258 | PARITY_BIT => "none", 259 | USE_DEBOUNCER => True 260 | ) 261 | port map ( 262 | CLK => CLK, 263 | RST => RST, 264 | -- UART INTERFACE 265 | UART_TXD => UART_TXD, 266 | UART_RXD => UART_RXD, 267 | -- USER DATA OUTPUT INTERFACE 268 | DOUT => uart_dout, 269 | DOUT_VLD => uart_dout_vld, 270 | FRAME_ERROR => open, 271 | -- USER DATA INPUT INTERFACE 272 | DIN => uart_din, 273 | DIN_VLD => uart_din_vld, 274 | DIN_RDY => uart_din_rdy 275 | ); 276 | 277 | end architecture; 278 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart_debouncer.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: SIMPLE UART FOR FPGA 3 | -------------------------------------------------------------------------------- 4 | -- MODULE: UART DEBOUNCER 5 | -- AUTHORS: Jakub Cabal 6 | -- LICENSE: The MIT License (MIT), please read LICENSE file 7 | -- WEBSITE: https://github.com/jakubcabal/uart-for-fpga 8 | -------------------------------------------------------------------------------- 9 | 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.NUMERIC_STD.ALL; 13 | 14 | entity UART_DEBOUNCER is 15 | Generic ( 16 | -- latency of debouncer in clock cycles, minimum value is 2, 17 | -- value also corresponds to the number of bits compared 18 | LATENCY : natural := 4 19 | ); 20 | Port ( 21 | CLK : in std_logic; -- system clock 22 | DEB_IN : in std_logic; -- input of signal from outside FPGA 23 | DEB_OUT : out std_logic -- output of debounced (filtered) signal 24 | ); 25 | end UART_DEBOUNCER; 26 | 27 | architecture RTL of UART_DEBOUNCER is 28 | 29 | constant SHREG_DEPTH : natural := LATENCY-1; 30 | 31 | signal input_shreg : std_logic_vector(SHREG_DEPTH-1 downto 0); 32 | signal output_reg_rst : std_logic; 33 | signal output_reg_set : std_logic; 34 | 35 | begin 36 | 37 | -- parameterized input shift register 38 | input_shreg_p : process (CLK) 39 | begin 40 | if (rising_edge(CLK)) then 41 | input_shreg <= input_shreg(SHREG_DEPTH-2 downto 0) & DEB_IN; 42 | end if; 43 | end process; 44 | 45 | -- output register will be reset when all compared bits are low 46 | output_reg_rst_p : process (DEB_IN, input_shreg) 47 | variable or_var : std_logic; 48 | begin 49 | or_var := DEB_IN; 50 | all_bits_or_l : for i in 0 to SHREG_DEPTH-1 loop 51 | or_var := or_var or input_shreg(i); 52 | end loop; 53 | output_reg_rst <= not or_var; 54 | end process; 55 | 56 | -- output register will be set when all compared bits are high 57 | output_reg_set_p : process (DEB_IN, input_shreg) 58 | variable and_var : std_logic; 59 | begin 60 | and_var := DEB_IN; 61 | all_bits_and_l : for i in 0 to SHREG_DEPTH-1 loop 62 | and_var := and_var and input_shreg(i); 63 | end loop; 64 | output_reg_set <= and_var; 65 | end process; 66 | 67 | -- output register 68 | output_reg_p : process (CLK) 69 | begin 70 | if (rising_edge(CLK)) then 71 | if (output_reg_rst = '1') then 72 | DEB_OUT <= '0'; 73 | elsif (output_reg_set = '1') then 74 | DEB_OUT <= '1'; 75 | end if; 76 | end if; 77 | end process; 78 | 79 | end RTL; 80 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart_parity.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: SIMPLE UART FOR FPGA 3 | -------------------------------------------------------------------------------- 4 | -- MODULE: UART PARITY BIT GENERATOR 5 | -- AUTHORS: Jakub Cabal 6 | -- LICENSE: The MIT License (MIT), please read LICENSE file 7 | -- WEBSITE: https://github.com/jakubcabal/uart-for-fpga 8 | -------------------------------------------------------------------------------- 9 | 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.NUMERIC_STD.ALL; 13 | 14 | entity UART_PARITY is 15 | Generic ( 16 | DATA_WIDTH : integer := 8; 17 | PARITY_TYPE : string := "none" -- legal values: "none", "even", "odd", "mark", "space" 18 | ); 19 | Port ( 20 | DATA_IN : in std_logic_vector(DATA_WIDTH-1 downto 0); 21 | PARITY_OUT : out std_logic 22 | ); 23 | end UART_PARITY; 24 | 25 | architecture FULL of UART_PARITY is 26 | 27 | begin 28 | 29 | -- ------------------------------------------------------------------------- 30 | -- PARITY BIT GENERATOR 31 | -- ------------------------------------------------------------------------- 32 | 33 | even_parity_g : if (PARITY_TYPE = "even") generate 34 | 35 | process (DATA_IN) 36 | variable parity_temp : std_logic; 37 | begin 38 | parity_temp := '0'; 39 | for i in DATA_IN'range loop 40 | parity_temp := parity_temp XOR DATA_IN(i); 41 | end loop; 42 | PARITY_OUT <= parity_temp; 43 | end process; 44 | 45 | end generate; 46 | 47 | odd_parity_g : if (PARITY_TYPE = "odd") generate 48 | 49 | process (DATA_IN) 50 | variable parity_temp : std_logic; 51 | begin 52 | parity_temp := '1'; 53 | for i in DATA_IN'range loop 54 | parity_temp := parity_temp XOR DATA_IN(i); 55 | end loop; 56 | PARITY_OUT <= parity_temp; 57 | end process; 58 | 59 | end generate; 60 | 61 | mark_parity_g : if (PARITY_TYPE = "mark") generate 62 | 63 | PARITY_OUT <= '1'; 64 | 65 | end generate; 66 | 67 | space_parity_g : if (PARITY_TYPE = "space") generate 68 | 69 | PARITY_OUT <= '0'; 70 | 71 | end generate; 72 | 73 | end FULL; 74 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart_rx.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: SIMPLE UART FOR FPGA 3 | -------------------------------------------------------------------------------- 4 | -- MODULE: UART RECEIVER 5 | -- AUTHORS: Jakub Cabal 6 | -- LICENSE: The MIT License (MIT), please read LICENSE file 7 | -- WEBSITE: https://github.com/jakubcabal/uart-for-fpga 8 | -------------------------------------------------------------------------------- 9 | 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.NUMERIC_STD.ALL; 13 | 14 | entity UART_RX is 15 | Generic ( 16 | PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space" 17 | ); 18 | Port ( 19 | CLK : in std_logic; -- system clock 20 | RST : in std_logic; -- high active synchronous reset 21 | -- UART INTERFACE 22 | UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable 23 | UART_RXD : in std_logic; -- serial receive data 24 | -- USER DATA OUTPUT INTERFACE 25 | DOUT : out std_logic_vector(7 downto 0); -- output data received via UART 26 | DOUT_VLD : out std_logic; -- when DOUT_VLD = 1, output data (DOUT) are valid without errors (is assert only for one clock cycle) 27 | FRAME_ERROR : out std_logic; -- when FRAME_ERROR = 1, stop bit was invalid (is assert only for one clock cycle) 28 | PARITY_ERROR : out std_logic -- when PARITY_ERROR = 1, parity bit was invalid (is assert only for one clock cycle) 29 | ); 30 | end entity; 31 | 32 | architecture RTL of UART_RX is 33 | 34 | signal rx_clk_en : std_logic; 35 | signal rx_ticks : unsigned(3 downto 0); 36 | signal rx_data : std_logic_vector(7 downto 0); 37 | signal rx_bit_count : unsigned(2 downto 0); 38 | signal rx_parity_bit : std_logic; 39 | signal rx_parity_error : std_logic; 40 | signal rx_parity_check_en : std_logic; 41 | signal rx_done : std_logic; 42 | signal fsm_receiving : std_logic; 43 | signal fsm_databits : std_logic; 44 | signal fsm_stopbit : std_logic; 45 | 46 | type state is (idle, startbit, databits, paritybit, stopbit); 47 | signal fsm_pstate : state; 48 | signal fsm_nstate : state; 49 | 50 | begin 51 | 52 | -- ------------------------------------------------------------------------- 53 | -- UART RECEIVER CLOCK DIVIDER AND CLOCK ENABLE FLAG 54 | -- ------------------------------------------------------------------------- 55 | 56 | uart_rx_clk_divider_p : process (CLK) 57 | begin 58 | if (rising_edge(CLK)) then 59 | if (fsm_receiving = '1') then 60 | if (UART_CLK_EN = '1') then 61 | if (rx_ticks = "1111") then 62 | rx_ticks <= (others => '0'); 63 | else 64 | rx_ticks <= rx_ticks + 1; 65 | end if; 66 | else 67 | rx_ticks <= rx_ticks; 68 | end if; 69 | else 70 | rx_ticks <= (others => '0'); 71 | end if; 72 | end if; 73 | end process; 74 | 75 | uart_rx_clk_en_p : process (CLK) 76 | begin 77 | if (rising_edge(CLK)) then 78 | if (RST = '1') then 79 | rx_clk_en <= '0'; 80 | elsif (UART_CLK_EN = '1' AND rx_ticks = "0111") then 81 | rx_clk_en <= '1'; 82 | else 83 | rx_clk_en <= '0'; 84 | end if; 85 | end if; 86 | end process; 87 | 88 | -- ------------------------------------------------------------------------- 89 | -- UART RECEIVER BIT COUNTER 90 | -- ------------------------------------------------------------------------- 91 | 92 | uart_rx_bit_counter_p : process (CLK) 93 | begin 94 | if (rising_edge(CLK)) then 95 | if (RST = '1') then 96 | rx_bit_count <= (others => '0'); 97 | elsif (rx_clk_en = '1' AND fsm_databits = '1') then 98 | if (rx_bit_count = "111") then 99 | rx_bit_count <= (others => '0'); 100 | else 101 | rx_bit_count <= rx_bit_count + 1; 102 | end if; 103 | end if; 104 | end if; 105 | end process; 106 | 107 | -- ------------------------------------------------------------------------- 108 | -- UART RECEIVER DATA SHIFT REGISTER 109 | -- ------------------------------------------------------------------------- 110 | 111 | uart_rx_data_shift_reg_p : process (CLK) 112 | begin 113 | if (rising_edge(CLK)) then 114 | if (rx_clk_en = '1' AND fsm_databits = '1') then 115 | rx_data <= UART_RXD & rx_data(7 downto 1); 116 | end if; 117 | end if; 118 | end process; 119 | 120 | DOUT <= rx_data; 121 | 122 | -- ------------------------------------------------------------------------- 123 | -- UART RECEIVER PARITY GENERATOR AND CHECK 124 | -- ------------------------------------------------------------------------- 125 | 126 | uart_rx_parity_g : if (PARITY_BIT /= "none") generate 127 | uart_rx_parity_gen_i: entity work.UART_PARITY 128 | generic map ( 129 | DATA_WIDTH => 8, 130 | PARITY_TYPE => PARITY_BIT 131 | ) 132 | port map ( 133 | DATA_IN => rx_data, 134 | PARITY_OUT => rx_parity_bit 135 | ); 136 | 137 | uart_rx_parity_check_reg_p : process (CLK) 138 | begin 139 | if (rising_edge(CLK)) then 140 | if (rx_clk_en = '1') then 141 | rx_parity_error <= rx_parity_bit XOR UART_RXD; 142 | end if; 143 | end if; 144 | end process; 145 | end generate; 146 | 147 | uart_rx_noparity_g : if (PARITY_BIT = "none") generate 148 | rx_parity_error <= '0'; 149 | end generate; 150 | 151 | -- ------------------------------------------------------------------------- 152 | -- UART RECEIVER OUTPUT REGISTER 153 | -- ------------------------------------------------------------------------- 154 | 155 | rx_done <= rx_clk_en and fsm_stopbit; 156 | 157 | uart_rx_output_reg_p : process (CLK) 158 | begin 159 | if (rising_edge(CLK)) then 160 | if (RST = '1') then 161 | DOUT_VLD <= '0'; 162 | FRAME_ERROR <= '0'; 163 | PARITY_ERROR <= '0'; 164 | else 165 | DOUT_VLD <= rx_done and not rx_parity_error and UART_RXD; 166 | FRAME_ERROR <= rx_done and not UART_RXD; 167 | PARITY_ERROR <= rx_done and rx_parity_error; 168 | end if; 169 | end if; 170 | end process; 171 | 172 | -- ------------------------------------------------------------------------- 173 | -- UART RECEIVER FSM 174 | -- ------------------------------------------------------------------------- 175 | 176 | -- PRESENT STATE REGISTER 177 | process (CLK) 178 | begin 179 | if (rising_edge(CLK)) then 180 | if (RST = '1') then 181 | fsm_pstate <= idle; 182 | else 183 | fsm_pstate <= fsm_nstate; 184 | end if; 185 | end if; 186 | end process; 187 | 188 | -- NEXT STATE AND OUTPUTS LOGIC 189 | process (fsm_pstate, UART_RXD, rx_clk_en, rx_bit_count) 190 | begin 191 | case fsm_pstate is 192 | 193 | when idle => 194 | fsm_stopbit <= '0'; 195 | fsm_databits <= '0'; 196 | fsm_receiving <= '0'; 197 | 198 | if (UART_RXD = '0') then 199 | fsm_nstate <= startbit; 200 | else 201 | fsm_nstate <= idle; 202 | end if; 203 | 204 | when startbit => 205 | fsm_stopbit <= '0'; 206 | fsm_databits <= '0'; 207 | fsm_receiving <= '1'; 208 | 209 | if (rx_clk_en = '1') then 210 | fsm_nstate <= databits; 211 | else 212 | fsm_nstate <= startbit; 213 | end if; 214 | 215 | when databits => 216 | fsm_stopbit <= '0'; 217 | fsm_databits <= '1'; 218 | fsm_receiving <= '1'; 219 | 220 | if ((rx_clk_en = '1') AND (rx_bit_count = "111")) then 221 | if (PARITY_BIT = "none") then 222 | fsm_nstate <= stopbit; 223 | else 224 | fsm_nstate <= paritybit; 225 | end if ; 226 | else 227 | fsm_nstate <= databits; 228 | end if; 229 | 230 | when paritybit => 231 | fsm_stopbit <= '0'; 232 | fsm_databits <= '0'; 233 | fsm_receiving <= '1'; 234 | 235 | if (rx_clk_en = '1') then 236 | fsm_nstate <= stopbit; 237 | else 238 | fsm_nstate <= paritybit; 239 | end if; 240 | 241 | when stopbit => 242 | fsm_stopbit <= '1'; 243 | fsm_databits <= '0'; 244 | fsm_receiving <= '1'; 245 | 246 | if (rx_clk_en = '1') then 247 | fsm_nstate <= idle; 248 | else 249 | fsm_nstate <= stopbit; 250 | end if; 251 | 252 | when others => 253 | fsm_stopbit <= '0'; 254 | fsm_databits <= '0'; 255 | fsm_receiving <= '0'; 256 | fsm_nstate <= idle; 257 | 258 | end case; 259 | end process; 260 | 261 | end architecture; 262 | -------------------------------------------------------------------------------- /rtl/comp/uart2wbm/uart_tx.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: SIMPLE UART FOR FPGA 3 | -------------------------------------------------------------------------------- 4 | -- MODULE: UART TRANSMITTER 5 | -- AUTHORS: Jakub Cabal 6 | -- LICENSE: The MIT License (MIT), please read LICENSE file 7 | -- WEBSITE: https://github.com/jakubcabal/uart-for-fpga 8 | -------------------------------------------------------------------------------- 9 | 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | use IEEE.NUMERIC_STD.ALL; 13 | 14 | entity UART_TX is 15 | Generic ( 16 | PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space" 17 | ); 18 | Port ( 19 | CLK : in std_logic; -- system clock 20 | RST : in std_logic; -- high active synchronous reset 21 | -- UART INTERFACE 22 | UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable 23 | UART_TXD : out std_logic; -- serial transmit data 24 | -- USER DATA INPUT INTERFACE 25 | DIN : in std_logic_vector(7 downto 0); -- input data to be transmitted over UART 26 | DIN_VLD : in std_logic; -- when DIN_VLD = 1, input data (DIN) are valid 27 | DIN_RDY : out std_logic -- when DIN_RDY = 1, transmitter is ready and valid input data will be accepted for transmiting 28 | ); 29 | end UART_TX; 30 | 31 | architecture FULL of UART_TX is 32 | 33 | signal tx_clk_en : std_logic; 34 | signal tx_clk_divider_en : std_logic; 35 | signal tx_ticks : unsigned(3 downto 0); 36 | signal tx_data : std_logic_vector(7 downto 0); 37 | signal tx_bit_count : unsigned(2 downto 0); 38 | signal tx_bit_count_en : std_logic; 39 | signal tx_ready : std_logic; 40 | signal tx_parity_bit : std_logic; 41 | signal tx_data_out_sel : std_logic_vector(1 downto 0); 42 | 43 | type state is (idle, txsync, startbit, databits, paritybit, stopbit); 44 | signal tx_pstate : state; 45 | signal tx_nstate : state; 46 | 47 | begin 48 | 49 | DIN_RDY <= tx_ready; 50 | 51 | -- ------------------------------------------------------------------------- 52 | -- UART TRANSMITTER CLOCK DIVIDER 53 | -- ------------------------------------------------------------------------- 54 | 55 | uart_tx_clk_divider_p : process (CLK) 56 | begin 57 | if (rising_edge(CLK)) then 58 | if (tx_clk_divider_en = '1') then 59 | if (uart_clk_en = '1') then 60 | if (tx_ticks = "1111") then 61 | tx_ticks <= (others => '0'); 62 | else 63 | tx_ticks <= tx_ticks + 1; 64 | end if; 65 | else 66 | tx_ticks <= tx_ticks; 67 | end if; 68 | else 69 | tx_ticks <= (others => '0'); 70 | end if; 71 | end if; 72 | end process; 73 | 74 | uart_tx_clk_en_p : process (CLK) 75 | begin 76 | if (rising_edge(CLK)) then 77 | if (RST = '1') then 78 | tx_clk_en <= '0'; 79 | elsif (uart_clk_en = '1' AND tx_ticks = "0001") then 80 | tx_clk_en <= '1'; 81 | else 82 | tx_clk_en <= '0'; 83 | end if; 84 | end if; 85 | end process; 86 | 87 | -- ------------------------------------------------------------------------- 88 | -- UART TRANSMITTER INPUT DATA REGISTER 89 | -- ------------------------------------------------------------------------- 90 | 91 | uart_tx_input_data_reg_p : process (CLK) 92 | begin 93 | if (rising_edge(CLK)) then 94 | if (DIN_VLD = '1' AND tx_ready = '1') then 95 | tx_data <= DIN; 96 | end if; 97 | end if; 98 | end process; 99 | 100 | -- ------------------------------------------------------------------------- 101 | -- UART TRANSMITTER BIT COUNTER 102 | -- ------------------------------------------------------------------------- 103 | 104 | uart_tx_bit_counter_p : process (CLK) 105 | begin 106 | if (rising_edge(CLK)) then 107 | if (RST = '1') then 108 | tx_bit_count <= (others => '0'); 109 | elsif (tx_bit_count_en = '1' AND tx_clk_en = '1') then 110 | if (tx_bit_count = "111") then 111 | tx_bit_count <= (others => '0'); 112 | else 113 | tx_bit_count <= tx_bit_count + 1; 114 | end if; 115 | end if; 116 | end if; 117 | end process; 118 | 119 | -- ------------------------------------------------------------------------- 120 | -- UART TRANSMITTER PARITY GENERATOR 121 | -- ------------------------------------------------------------------------- 122 | 123 | uart_tx_parity_g : if (PARITY_BIT /= "none") generate 124 | uart_tx_parity_gen_i: entity work.UART_PARITY 125 | generic map ( 126 | DATA_WIDTH => 8, 127 | PARITY_TYPE => PARITY_BIT 128 | ) 129 | port map ( 130 | DATA_IN => tx_data, 131 | PARITY_OUT => tx_parity_bit 132 | ); 133 | end generate; 134 | 135 | uart_tx_noparity_g : if (PARITY_BIT = "none") generate 136 | tx_parity_bit <= '0'; 137 | end generate; 138 | 139 | -- ------------------------------------------------------------------------- 140 | -- UART TRANSMITTER OUTPUT DATA REGISTER 141 | -- ------------------------------------------------------------------------- 142 | 143 | uart_tx_output_data_reg_p : process (CLK) 144 | begin 145 | if (rising_edge(CLK)) then 146 | if (RST = '1') then 147 | UART_TXD <= '1'; 148 | else 149 | case tx_data_out_sel is 150 | when "01" => -- START BIT 151 | UART_TXD <= '0'; 152 | when "10" => -- DATA BITS 153 | UART_TXD <= tx_data(to_integer(tx_bit_count)); 154 | when "11" => -- PARITY BIT 155 | UART_TXD <= tx_parity_bit; 156 | when others => -- STOP BIT OR IDLE 157 | UART_TXD <= '1'; 158 | end case; 159 | end if; 160 | end if; 161 | end process; 162 | 163 | -- ------------------------------------------------------------------------- 164 | -- UART TRANSMITTER FSM 165 | -- ------------------------------------------------------------------------- 166 | 167 | -- PRESENT STATE REGISTER 168 | process (CLK) 169 | begin 170 | if (rising_edge(CLK)) then 171 | if (RST = '1') then 172 | tx_pstate <= idle; 173 | else 174 | tx_pstate <= tx_nstate; 175 | end if; 176 | end if; 177 | end process; 178 | 179 | -- NEXT STATE AND OUTPUTS LOGIC 180 | process (tx_pstate, DIN_VLD, tx_clk_en, tx_bit_count) 181 | begin 182 | 183 | case tx_pstate is 184 | 185 | when idle => 186 | tx_ready <= '1'; 187 | tx_data_out_sel <= "00"; 188 | tx_bit_count_en <= '0'; 189 | tx_clk_divider_en <= '0'; 190 | 191 | if (DIN_VLD = '1') then 192 | tx_nstate <= txsync; 193 | else 194 | tx_nstate <= idle; 195 | end if; 196 | 197 | when txsync => 198 | tx_ready <= '0'; 199 | tx_data_out_sel <= "00"; 200 | tx_bit_count_en <= '0'; 201 | tx_clk_divider_en <= '1'; 202 | 203 | if (tx_clk_en = '1') then 204 | tx_nstate <= startbit; 205 | else 206 | tx_nstate <= txsync; 207 | end if; 208 | 209 | when startbit => 210 | tx_ready <= '0'; 211 | tx_data_out_sel <= "01"; 212 | tx_bit_count_en <= '0'; 213 | tx_clk_divider_en <= '1'; 214 | 215 | if (tx_clk_en = '1') then 216 | tx_nstate <= databits; 217 | else 218 | tx_nstate <= startbit; 219 | end if; 220 | 221 | when databits => 222 | tx_ready <= '0'; 223 | tx_data_out_sel <= "10"; 224 | tx_bit_count_en <= '1'; 225 | tx_clk_divider_en <= '1'; 226 | 227 | if ((tx_clk_en = '1') AND (tx_bit_count = "111")) then 228 | if (PARITY_BIT = "none") then 229 | tx_nstate <= stopbit; 230 | else 231 | tx_nstate <= paritybit; 232 | end if ; 233 | else 234 | tx_nstate <= databits; 235 | end if; 236 | 237 | when paritybit => 238 | tx_ready <= '0'; 239 | tx_data_out_sel <= "11"; 240 | tx_bit_count_en <= '0'; 241 | tx_clk_divider_en <= '1'; 242 | 243 | if (tx_clk_en = '1') then 244 | tx_nstate <= stopbit; 245 | else 246 | tx_nstate <= paritybit; 247 | end if; 248 | 249 | when stopbit => 250 | tx_ready <= '1'; 251 | tx_data_out_sel <= "00"; 252 | tx_bit_count_en <= '0'; 253 | tx_clk_divider_en <= '1'; 254 | 255 | if (DIN_VLD = '1') then 256 | tx_nstate <= txsync; 257 | elsif (tx_clk_en = '1') then 258 | tx_nstate <= idle; 259 | else 260 | tx_nstate <= stopbit; 261 | end if; 262 | 263 | when others => 264 | tx_ready <= '0'; 265 | tx_data_out_sel <= "00"; 266 | tx_bit_count_en <= '0'; 267 | tx_clk_divider_en <= '0'; 268 | tx_nstate <= idle; 269 | 270 | end case; 271 | end process; 272 | 273 | end FULL; 274 | -------------------------------------------------------------------------------- /rtl/comp/wb_splitter/wb_splitter.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | use IEEE.MATH_REAL.ALL; 12 | 13 | entity WB_SPLITTER is 14 | Generic ( 15 | MASTER_PORTS : natural := 2; 16 | ADDR_OFFSET : natural := 8 17 | ); 18 | Port ( 19 | -- CLOCK AND RESET 20 | CLK : in std_logic; 21 | RST : in std_logic; 22 | 23 | -- WISHBONE SLAVE INTERFACE 24 | WB_S_CYC : in std_logic; 25 | WB_S_STB : in std_logic; 26 | WB_S_WE : in std_logic; 27 | WB_S_ADDR : in std_logic_vector(15 downto 0); 28 | WB_S_DIN : in std_logic_vector(31 downto 0); 29 | WB_S_STALL : out std_logic; 30 | WB_S_ACK : out std_logic; 31 | WB_S_DOUT : out std_logic_vector(31 downto 0); 32 | 33 | -- WISHBONE MASTER INTERFACES 34 | WB_M_CYC : out std_logic_vector(MASTER_PORTS-1 downto 0); 35 | WB_M_STB : out std_logic_vector(MASTER_PORTS-1 downto 0); 36 | WB_M_WE : out std_logic_vector(MASTER_PORTS-1 downto 0); 37 | WB_M_ADDR : out std_logic_vector(MASTER_PORTS*16-1 downto 0); 38 | WB_M_DOUT : out std_logic_vector(MASTER_PORTS*32-1 downto 0); 39 | WB_M_STALL : in std_logic_vector(MASTER_PORTS-1 downto 0); 40 | WB_M_ACK : in std_logic_vector(MASTER_PORTS-1 downto 0); 41 | WB_M_DIN : in std_logic_vector(MASTER_PORTS*32-1 downto 0) 42 | ); 43 | end entity; 44 | 45 | architecture RTL of WB_SPLITTER is 46 | 47 | constant PORT_SEL_W : natural := integer(ceil(log2(real(MASTER_PORTS)))); 48 | constant WB_ADDR_GND : std_logic_vector(16-ADDR_OFFSET-1 downto 0) := (others => '0'); 49 | 50 | signal wb_port_sel_bin : std_logic_vector(PORT_SEL_W-1 downto 0); 51 | signal wb_port_sel : std_logic_vector(MASTER_PORTS-1 downto 0); 52 | 53 | begin 54 | 55 | wb_port_sel_bin <= WB_S_ADDR(PORT_SEL_W+ADDR_OFFSET-1 downto ADDR_OFFSET); 56 | 57 | process (wb_port_sel_bin) 58 | begin 59 | wb_port_sel <= (others => '0'); 60 | for i in 0 to MASTER_PORTS-1 loop 61 | if (unsigned(wb_port_sel_bin) = i) then 62 | wb_port_sel(i) <= '1'; 63 | exit; 64 | end if; 65 | end loop; 66 | end process; 67 | 68 | req_g : for i in 0 to MASTER_PORTS-1 generate 69 | WB_M_CYC(i) <= WB_S_CYC and wb_port_sel(i); 70 | WB_M_STB(i) <= WB_S_STB and wb_port_sel(i); 71 | WB_M_WE(i) <= WB_S_WE and wb_port_sel(i); 72 | WB_M_ADDR((i+1)*16-1 downto i*16) <= WB_ADDR_GND & WB_S_ADDR(ADDR_OFFSET-1 downto 0); 73 | WB_M_DOUT((i+1)*32-1 downto i*32) <= WB_S_DIN; 74 | end generate; 75 | 76 | process (WB_M_STALL) 77 | begin 78 | WB_S_STALL <= '0'; 79 | for i in 0 to MASTER_PORTS-1 loop 80 | if (WB_M_STALL(i) = '1') then 81 | WB_S_STALL <= '1'; 82 | end if; 83 | end loop; 84 | end process; 85 | 86 | process (WB_M_ACK,WB_M_DIN) 87 | begin 88 | WB_S_ACK <= '0'; 89 | WB_S_DOUT <= WB_M_DIN(32-1 downto 0); 90 | for i in 0 to MASTER_PORTS-1 loop 91 | if (WB_M_ACK(i) = '1') then 92 | WB_S_ACK <= '1'; 93 | WB_S_DOUT <= WB_M_DIN((i+1)*32-1 downto i*32); 94 | end if; 95 | end loop; 96 | end process; 97 | 98 | end architecture; 99 | -------------------------------------------------------------------------------- /rtl/fpga.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- PROJECT: RMII FIREWALL FPGA 3 | -------------------------------------------------------------------------------- 4 | -- AUTHORS: Jakub Cabal 5 | -- LICENSE: The MIT License, please read LICENSE file 6 | -------------------------------------------------------------------------------- 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | entity FPGA is 13 | Port ( 14 | -- System clock and reset button 15 | CLK_12M : in std_logic; 16 | RST_BTN_N : in std_logic; 17 | -- Ethernet port 0 (RMII interface) 18 | ETH0_CLK : in std_logic; 19 | ETH0_RXD : in std_logic_vector(1 downto 0); 20 | ETH0_CSR_DV : in std_logic; 21 | ETH0_TXD : out std_logic_vector(1 downto 0); 22 | ETH0_TX_EN : out std_logic; 23 | -- Ethernet port 1 (RMII interface) 24 | ETH1_CLK : in std_logic; 25 | ETH1_RXD : in std_logic_vector(1 downto 0); 26 | ETH1_CSR_DV : in std_logic; 27 | ETH1_TXD : out std_logic_vector(1 downto 0); 28 | ETH1_TX_EN : out std_logic; 29 | -- UART interface 30 | UART_RXD : in std_logic; 31 | UART_TXD : out std_logic 32 | ); 33 | end entity; 34 | 35 | architecture FULL of FPGA is 36 | 37 | constant WB_BASE_PORTS : natural := 4; -- system, eth, app (firewall), reserved 38 | constant WB_BASE_OFFSET : natural := 14; 39 | constant WB_ETH_PORTS : natural := 2; -- eth0, eth1 40 | constant WB_ETH_OFFSET : natural := 13; 41 | constant WB_APP_PORTS : natural := 2; -- app0, app1 42 | constant WB_APP_OFFSET : natural := 13; 43 | 44 | signal rst_btn : std_logic; 45 | 46 | signal pll_locked : std_logic; 47 | signal pll_locked_n : std_logic; 48 | 49 | signal clk_usr : std_logic; 50 | signal rst_usr : std_logic; 51 | signal rst_eth0 : std_logic; 52 | signal rst_eth1 : std_logic; 53 | 54 | signal wb_master_cyc : std_logic; 55 | signal wb_master_stb : std_logic; 56 | signal wb_master_we : std_logic; 57 | signal wb_master_addr : std_logic_vector(15 downto 0); 58 | signal wb_master_dout : std_logic_vector(31 downto 0); 59 | signal wb_master_stall : std_logic; 60 | signal wb_master_ack : std_logic; 61 | signal wb_master_din : std_logic_vector(31 downto 0); 62 | 63 | signal wb_mbs_cyc : std_logic_vector(WB_BASE_PORTS-1 downto 0); 64 | signal wb_mbs_stb : std_logic_vector(WB_BASE_PORTS-1 downto 0); 65 | signal wb_mbs_we : std_logic_vector(WB_BASE_PORTS-1 downto 0); 66 | signal wb_mbs_addr : std_logic_vector(WB_BASE_PORTS*16-1 downto 0); 67 | signal wb_mbs_din : std_logic_vector(WB_BASE_PORTS*32-1 downto 0); 68 | signal wb_mbs_stall : std_logic_vector(WB_BASE_PORTS-1 downto 0); 69 | signal wb_mbs_ack : std_logic_vector(WB_BASE_PORTS-1 downto 0); 70 | signal wb_mbs_dout : std_logic_vector(WB_BASE_PORTS*32-1 downto 0); 71 | 72 | signal wb_mes_cyc : std_logic_vector(WB_ETH_PORTS-1 downto 0); 73 | signal wb_mes_stb : std_logic_vector(WB_ETH_PORTS-1 downto 0); 74 | signal wb_mes_we : std_logic_vector(WB_ETH_PORTS-1 downto 0); 75 | signal wb_mes_addr : std_logic_vector(WB_ETH_PORTS*16-1 downto 0); 76 | signal wb_mes_din : std_logic_vector(WB_ETH_PORTS*32-1 downto 0); 77 | signal wb_mes_stall : std_logic_vector(WB_ETH_PORTS-1 downto 0); 78 | signal wb_mes_ack : std_logic_vector(WB_ETH_PORTS-1 downto 0); 79 | signal wb_mes_dout : std_logic_vector(WB_ETH_PORTS*32-1 downto 0); 80 | 81 | signal wb_mas_cyc : std_logic_vector(WB_APP_PORTS-1 downto 0); 82 | signal wb_mas_stb : std_logic_vector(WB_APP_PORTS-1 downto 0); 83 | signal wb_mas_we : std_logic_vector(WB_APP_PORTS-1 downto 0); 84 | signal wb_mas_addr : std_logic_vector(WB_APP_PORTS*16-1 downto 0); 85 | signal wb_mas_din : std_logic_vector(WB_APP_PORTS*32-1 downto 0); 86 | signal wb_mas_stall : std_logic_vector(WB_APP_PORTS-1 downto 0); 87 | signal wb_mas_ack : std_logic_vector(WB_APP_PORTS-1 downto 0); 88 | signal wb_mas_dout : std_logic_vector(WB_APP_PORTS*32-1 downto 0); 89 | 90 | signal eth01_data : std_logic_vector(7 downto 0); 91 | signal eth01_sop : std_logic; 92 | signal eth01_eop : std_logic; 93 | signal eth01_vld : std_logic; 94 | signal eth01_rdy : std_logic; 95 | 96 | signal eth01f_data : std_logic_vector(7 downto 0); 97 | signal eth01f_sop : std_logic; 98 | signal eth01f_eop : std_logic; 99 | signal eth01f_vld : std_logic; 100 | signal eth01f_rdy : std_logic; 101 | 102 | signal eth10_data : std_logic_vector(7 downto 0); 103 | signal eth10_sop : std_logic; 104 | signal eth10_eop : std_logic; 105 | signal eth10_vld : std_logic; 106 | signal eth10_rdy : std_logic; 107 | 108 | signal eth10f_data : std_logic_vector(7 downto 0); 109 | signal eth10f_sop : std_logic; 110 | signal eth10f_eop : std_logic; 111 | signal eth10f_vld : std_logic; 112 | signal eth10f_rdy : std_logic; 113 | 114 | begin 115 | 116 | rst_btn <= not RST_BTN_N; 117 | 118 | pll_i : entity work.PLL 119 | port map ( 120 | IN_CLK_12M => CLK_12M, 121 | IN_RST_BTN => rst_btn, 122 | OUT_PLL_LOCKED => pll_locked, 123 | OUT_CLK_25M => clk_usr, 124 | OUT_CLK_50M => open 125 | ); 126 | 127 | pll_locked_n <= not pll_locked; 128 | 129 | rst_usr_sync_i : entity work.RST_SYNC 130 | port map ( 131 | CLK => clk_usr, 132 | ASYNC_RST => pll_locked_n, 133 | SYNCED_RST => rst_usr 134 | ); 135 | 136 | rst_eth0_sync_i : entity work.RST_SYNC 137 | port map ( 138 | CLK => ETH0_CLK, 139 | ASYNC_RST => pll_locked_n, 140 | SYNCED_RST => rst_eth0 141 | ); 142 | 143 | rst_eth1_sync_i : entity work.RST_SYNC 144 | port map ( 145 | CLK => ETH1_CLK, 146 | ASYNC_RST => pll_locked_n, 147 | SYNCED_RST => rst_eth1 148 | ); 149 | 150 | uart2wbm_i : entity work.UART2WBM 151 | generic map ( 152 | CLK_FREQ => 25e6, 153 | BAUD_RATE => 9600 154 | ) 155 | port map ( 156 | CLK => clk_usr, 157 | RST => rst_usr, 158 | -- UART INTERFACE 159 | UART_TXD => UART_TXD, 160 | UART_RXD => UART_RXD, 161 | -- WISHBONE MASTER INTERFACE 162 | WB_CYC => wb_master_cyc, 163 | WB_STB => wb_master_stb, 164 | WB_WE => wb_master_we, 165 | WB_ADDR => wb_master_addr, 166 | WB_DOUT => wb_master_dout, 167 | WB_STALL => wb_master_stall, 168 | WB_ACK => wb_master_ack, 169 | WB_DIN => wb_master_din 170 | ); 171 | 172 | wb_splitter_base_i : entity work.WB_SPLITTER 173 | generic map ( 174 | MASTER_PORTS => WB_BASE_PORTS, 175 | ADDR_OFFSET => WB_BASE_OFFSET 176 | ) 177 | port map ( 178 | CLK => clk_usr, 179 | RST => rst_usr, 180 | 181 | WB_S_CYC => wb_master_cyc, 182 | WB_S_STB => wb_master_stb, 183 | WB_S_WE => wb_master_we, 184 | WB_S_ADDR => wb_master_addr, 185 | WB_S_DIN => wb_master_dout, 186 | WB_S_STALL => wb_master_stall, 187 | WB_S_ACK => wb_master_ack, 188 | WB_S_DOUT => wb_master_din, 189 | 190 | WB_M_CYC => wb_mbs_cyc, 191 | WB_M_STB => wb_mbs_stb, 192 | WB_M_WE => wb_mbs_we, 193 | WB_M_ADDR => wb_mbs_addr, 194 | WB_M_DOUT => wb_mbs_dout, 195 | WB_M_STALL => wb_mbs_stall, 196 | WB_M_ACK => wb_mbs_ack, 197 | WB_M_DIN => wb_mbs_din 198 | ); 199 | 200 | sys_module_i : entity work.SYS_MODULE 201 | port map ( 202 | -- CLOCK AND RESET 203 | CLK => clk_usr, 204 | RST => rst_usr, 205 | 206 | -- WISHBONE SLAVE INTERFACE 207 | WB_CYC => wb_mbs_cyc(0), 208 | WB_STB => wb_mbs_stb(0), 209 | WB_WE => wb_mbs_we(0), 210 | WB_ADDR => wb_mbs_addr((0+1)*16-1 downto 0*16), 211 | WB_DIN => wb_mbs_dout((0+1)*32-1 downto 0*32), 212 | WB_STALL => wb_mbs_stall(0), 213 | WB_ACK => wb_mbs_ack(0), 214 | WB_DOUT => wb_mbs_din((0+1)*32-1 downto 0*32) 215 | ); 216 | 217 | wb_splitter_eth_i : entity work.WB_SPLITTER 218 | generic map ( 219 | MASTER_PORTS => WB_ETH_PORTS, 220 | ADDR_OFFSET => WB_ETH_OFFSET 221 | ) 222 | port map ( 223 | CLK => clk_usr, 224 | RST => rst_usr, 225 | 226 | WB_S_CYC => wb_mbs_cyc(1), 227 | WB_S_STB => wb_mbs_stb(1), 228 | WB_S_WE => wb_mbs_we(1), 229 | WB_S_ADDR => wb_mbs_addr((1+1)*16-1 downto 1*16), 230 | WB_S_DIN => wb_mbs_dout((1+1)*32-1 downto 1*32), 231 | WB_S_STALL => wb_mbs_stall(1), 232 | WB_S_ACK => wb_mbs_ack(1), 233 | WB_S_DOUT => wb_mbs_din((1+1)*32-1 downto 1*32), 234 | 235 | WB_M_CYC => wb_mes_cyc, 236 | WB_M_STB => wb_mes_stb, 237 | WB_M_WE => wb_mes_we, 238 | WB_M_ADDR => wb_mes_addr, 239 | WB_M_DOUT => wb_mes_dout, 240 | WB_M_STALL => wb_mes_stall, 241 | WB_M_ACK => wb_mes_ack, 242 | WB_M_DIN => wb_mes_din 243 | ); 244 | 245 | eth0_mac_i : entity work.RMII_MAC 246 | port map ( 247 | -- CLOCKS AND RESETS 248 | RMII_CLK => ETH0_CLK, 249 | RMII_RST => rst_eth0, 250 | USER_CLK => clk_usr, 251 | USER_RST => rst_usr, 252 | 253 | -- RMII INTERFACE (RMII_CLK) 254 | RMII_RXD => ETH0_RXD, 255 | RMII_CSR_DV => ETH0_CSR_DV, 256 | RMII_TXD => ETH0_TXD, 257 | RMII_TX_EN => ETH0_TX_EN, 258 | 259 | -- USER OUTPUT STREAM INTERFACE (USER_CLK) 260 | TX_DATA => eth01_data, 261 | TX_SOP => eth01_sop, 262 | TX_EOP => eth01_eop, 263 | TX_VLD => eth01_vld, 264 | TX_RDY => eth01_rdy, 265 | 266 | -- USER INPUT STREAM INTERFACE (USER_CLK) 267 | RX_DATA => eth10f_data, 268 | RX_SOP => eth10f_sop, 269 | RX_EOP => eth10f_eop, 270 | RX_VLD => eth10f_vld, 271 | RX_RDY => eth10f_rdy, 272 | 273 | -- WISHBONE SLAVE INTERFACE (USER_CLK) 274 | WB_CYC => wb_mes_cyc(0), 275 | WB_STB => wb_mes_stb(0), 276 | WB_WE => wb_mes_we(0), 277 | WB_ADDR => wb_mes_addr((0+1)*16-1 downto 0*16), 278 | WB_DIN => wb_mes_dout((0+1)*32-1 downto 0*32), 279 | WB_STALL => wb_mes_stall(0), 280 | WB_ACK => wb_mes_ack(0), 281 | WB_DOUT => wb_mes_din((0+1)*32-1 downto 0*32) 282 | ); 283 | 284 | wb_splitter_app_i : entity work.WB_SPLITTER 285 | generic map ( 286 | MASTER_PORTS => WB_APP_PORTS, 287 | ADDR_OFFSET => WB_APP_OFFSET 288 | ) 289 | port map ( 290 | CLK => clk_usr, 291 | RST => rst_usr, 292 | 293 | WB_S_CYC => wb_mbs_cyc(2), 294 | WB_S_STB => wb_mbs_stb(2), 295 | WB_S_WE => wb_mbs_we(2), 296 | WB_S_ADDR => wb_mbs_addr((2+1)*16-1 downto 2*16), 297 | WB_S_DIN => wb_mbs_dout((2+1)*32-1 downto 2*32), 298 | WB_S_STALL => wb_mbs_stall(2), 299 | WB_S_ACK => wb_mbs_ack(2), 300 | WB_S_DOUT => wb_mbs_din((2+1)*32-1 downto 2*32), 301 | 302 | WB_M_CYC => wb_mas_cyc, 303 | WB_M_STB => wb_mas_stb, 304 | WB_M_WE => wb_mas_we, 305 | WB_M_ADDR => wb_mas_addr, 306 | WB_M_DOUT => wb_mas_dout, 307 | WB_M_STALL => wb_mas_stall, 308 | WB_M_ACK => wb_mas_ack, 309 | WB_M_DIN => wb_mas_din 310 | ); 311 | 312 | firewall01_i : entity work.FIREWALL 313 | port map ( 314 | CLK => clk_usr, 315 | RST => rst_usr, 316 | 317 | RX_DATA => eth01_data, 318 | RX_SOP => eth01_sop, 319 | RX_EOP => eth01_eop, 320 | RX_VLD => eth01_vld, 321 | RX_RDY => eth01_rdy, 322 | 323 | TX_DATA => eth01f_data, 324 | TX_SOP => eth01f_sop, 325 | TX_EOP => eth01f_eop, 326 | TX_VLD => eth01f_vld, 327 | TX_RDY => eth01f_rdy, 328 | 329 | WB_CYC => wb_mas_cyc(0), 330 | WB_STB => wb_mas_stb(0), 331 | WB_WE => wb_mas_we(0), 332 | WB_ADDR => wb_mas_addr((0+1)*16-1 downto 0*16), 333 | WB_DIN => wb_mas_dout((0+1)*32-1 downto 0*32), 334 | WB_STALL => wb_mas_stall(0), 335 | WB_ACK => wb_mas_ack(0), 336 | WB_DOUT => wb_mas_din((0+1)*32-1 downto 0*32) 337 | ); 338 | 339 | firewall10_i : entity work.FIREWALL 340 | port map ( 341 | CLK => clk_usr, 342 | RST => rst_usr, 343 | 344 | RX_DATA => eth10_data, 345 | RX_SOP => eth10_sop, 346 | RX_EOP => eth10_eop, 347 | RX_VLD => eth10_vld, 348 | RX_RDY => eth10_rdy, 349 | 350 | TX_DATA => eth10f_data, 351 | TX_SOP => eth10f_sop, 352 | TX_EOP => eth10f_eop, 353 | TX_VLD => eth10f_vld, 354 | TX_RDY => eth10f_rdy, 355 | 356 | WB_CYC => wb_mas_cyc(1), 357 | WB_STB => wb_mas_stb(1), 358 | WB_WE => wb_mas_we(1), 359 | WB_ADDR => wb_mas_addr((1+1)*16-1 downto 1*16), 360 | WB_DIN => wb_mas_dout((1+1)*32-1 downto 1*32), 361 | WB_STALL => wb_mas_stall(1), 362 | WB_ACK => wb_mas_ack(1), 363 | WB_DOUT => wb_mas_din((1+1)*32-1 downto 1*32) 364 | ); 365 | 366 | eth1_mac_i : entity work.RMII_MAC 367 | port map ( 368 | -- CLOCKS AND RESETS 369 | RMII_CLK => ETH1_CLK, 370 | RMII_RST => rst_eth1, 371 | USER_CLK => clk_usr, 372 | USER_RST => rst_usr, 373 | 374 | -- RMII INTERFACE (RMII_CLK) 375 | RMII_RXD => ETH1_RXD, 376 | RMII_CSR_DV => ETH1_CSR_DV, 377 | RMII_TXD => ETH1_TXD, 378 | RMII_TX_EN => ETH1_TX_EN, 379 | 380 | -- USER OUTPUT STREAM INTERFACE (USER_CLK) 381 | TX_DATA => eth10_data, 382 | TX_SOP => eth10_sop, 383 | TX_EOP => eth10_eop, 384 | TX_VLD => eth10_vld, 385 | TX_RDY => eth10_rdy, 386 | 387 | -- USER INPUT STREAM INTERFACE (USER_CLK) 388 | RX_DATA => eth01f_data, 389 | RX_SOP => eth01f_sop, 390 | RX_EOP => eth01f_eop, 391 | RX_VLD => eth01f_vld, 392 | RX_RDY => eth01f_rdy, 393 | 394 | -- WISHBONE SLAVE INTERFACE (USER_CLK) 395 | WB_CYC => wb_mes_cyc(1), 396 | WB_STB => wb_mes_stb(1), 397 | WB_WE => wb_mes_we(1), 398 | WB_ADDR => wb_mes_addr((1+1)*16-1 downto 1*16), 399 | WB_DIN => wb_mes_dout((1+1)*32-1 downto 1*32), 400 | WB_STALL => wb_mes_stall(1), 401 | WB_ACK => wb_mes_ack(1), 402 | WB_DOUT => wb_mes_din((1+1)*32-1 downto 1*32) 403 | ); 404 | 405 | end architecture; 406 | -------------------------------------------------------------------------------- /rtl/synth/fpga.qpf: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # PROJECT: RMII FIREWALL FPGA 3 | #------------------------------------------------------------------------------- 4 | # AUTHORS: Jakub Cabal 5 | # LICENSE: The MIT License, please read LICENSE file 6 | #------------------------------------------------------------------------------- 7 | 8 | PROJECT_REVISION = "FPGA" 9 | -------------------------------------------------------------------------------- /rtl/synth/fpga.qsf: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # PROJECT: RMII FIREWALL FPGA 3 | #------------------------------------------------------------------------------- 4 | # AUTHORS: Jakub Cabal 5 | # LICENSE: The MIT License, please read LICENSE file 6 | #------------------------------------------------------------------------------- 7 | 8 | set_global_assignment -name FAMILY "Cyclone 10 LP" 9 | set_global_assignment -name DEVICE 10CL025YU256C8G 10 | set_global_assignment -name TOP_LEVEL_ENTITY FPGA 11 | set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" 12 | set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" 13 | 14 | # PROJECT VHDL FILES 15 | set_global_assignment -name VHDL_FILE ../comp/base/rst_sync.vhd 16 | set_global_assignment -name VHDL_FILE ../comp/base/pll.vhd 17 | set_global_assignment -name VHDL_FILE ../comp/base/fifo_mark.vhd 18 | set_global_assignment -name VHDL_FILE ../comp/base/fifo.vhd 19 | set_global_assignment -name VHDL_FILE ../comp/base/asfifo.vhd 20 | set_global_assignment -name VHDL_FILE ../comp/base/sys_module.vhd 21 | set_global_assignment -name VHDL_FILE ../comp/base/sdp_ram.vhd 22 | set_global_assignment -name VHDL_FILE ../comp/rmii_mac/rx_rmii_mac.vhd 23 | set_global_assignment -name VHDL_FILE ../comp/rmii_mac/tx_rmii_mac.vhd 24 | set_global_assignment -name VHDL_FILE ../comp/rmii_mac/rmii_mac.vhd 25 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart_debouncer.vhd 26 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart_parity.vhd 27 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart_tx.vhd 28 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart_rx.vhd 29 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart.vhd 30 | set_global_assignment -name VHDL_FILE ../comp/uart2wbm/uart2wbm.vhd 31 | set_global_assignment -name VHDL_FILE ../comp/wb_splitter/wb_splitter.vhd 32 | set_global_assignment -name VHDL_FILE ../comp/firewall/parser.vhd 33 | set_global_assignment -name VHDL_FILE ../comp/firewall/match_unit.vhd 34 | set_global_assignment -name VHDL_FILE ../comp/firewall/match_unit_wb.vhd 35 | set_global_assignment -name VHDL_FILE ../comp/firewall/eraser.vhd 36 | set_global_assignment -name VHDL_FILE ../comp/firewall/firewall.vhd 37 | set_global_assignment -name VHDL_FILE ../fpga.vhd 38 | 39 | # TIMING CONSTRAINTS 40 | set_global_assignment -name SDC_FILE fpga.sdc 41 | 42 | # FPGA PINS ASSIGNMENT 43 | set_location_assignment PIN_M2 -to CLK_12M 44 | set_location_assignment PIN_N6 -to RST_BTN_N 45 | 46 | set_location_assignment PIN_F13 -to ETH0_CLK 47 | set_location_assignment PIN_F15 -to ETH0_RXD[0] 48 | set_location_assignment PIN_F16 -to ETH0_RXD[1] 49 | set_location_assignment PIN_D16 -to ETH0_CSR_DV 50 | set_location_assignment PIN_C15 -to ETH0_TXD[0] 51 | set_location_assignment PIN_B16 -to ETH0_TXD[1] 52 | set_location_assignment PIN_C16 -to ETH0_TX_EN 53 | 54 | set_location_assignment PIN_N2 -to ETH1_CLK 55 | set_location_assignment PIN_N1 -to ETH1_RXD[0] 56 | set_location_assignment PIN_P2 -to ETH1_RXD[1] 57 | set_location_assignment PIN_J1 -to ETH1_CSR_DV 58 | set_location_assignment PIN_J2 -to ETH1_TXD[0] 59 | set_location_assignment PIN_K2 -to ETH1_TXD[1] 60 | set_location_assignment PIN_L2 -to ETH1_TX_EN 61 | 62 | set_location_assignment PIN_T7 -to UART_TXD 63 | set_location_assignment PIN_R7 -to UART_RXD 64 | -------------------------------------------------------------------------------- /rtl/synth/fpga.sdc: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # PROJECT: RMII FIREWALL FPGA 3 | #------------------------------------------------------------------------------- 4 | # AUTHORS: Jakub Cabal 5 | # LICENSE: The MIT License, please read LICENSE file 6 | #------------------------------------------------------------------------------- 7 | 8 | create_clock -name CLK12M -period 12MHz [get_ports {CLK_12M}] 9 | create_clock -name ETH0_CLK -period 50MHz [get_ports {ETH0_CLK}] 10 | create_clock -name ETH1_CLK -period 50MHz [get_ports {ETH1_CLK}] 11 | derive_pll_clocks 12 | -------------------------------------------------------------------------------- /sw/configure_match.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | from wishbone import wishbone 10 | from match_unit import match_unit 11 | 12 | print("CONFIGURATION OF MATCH UNITS:") 13 | print("========================================") 14 | 15 | wb = wishbone("COM4") 16 | mu_ipv4_dst = match_unit(wb,0x8C00,"E01_IPV4_DST") 17 | 18 | ipv4_dst_list = [0xA8C00001] #168.192.0.1 19 | mu_ipv4_dst.add_record(0,ipv4_dst_list) 20 | 21 | ipv4_dst_list = [0xE00000FB] 22 | mu_ipv4_dst.add_record(1,ipv4_dst_list) 23 | 24 | wb.close() 25 | -------------------------------------------------------------------------------- /sw/firewall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | class firewall: 10 | def __init__(self, wishbone, base_addr, port): 11 | self.wb = wishbone 12 | self.ba = base_addr 13 | self.port_id = port 14 | 15 | def firewall_report(self, full=False): 16 | version_reg = self.wb.read(self.ba+0x000) 17 | status_reg = self.wb.read(self.ba+0x004) 18 | self.wb.write(self.ba+0x000,0x3) # sample counters 19 | cnt_pkt = self.wb.read(self.ba+0x010) 20 | cnt_ipv4 = self.wb.read(self.ba+0x014) 21 | cnt_ipv6 = self.wb.read(self.ba+0x018) 22 | cnt_mac_dst_hit = self.wb.read(self.ba+0x020) 23 | cnt_mac_src_hit = self.wb.read(self.ba+0x024) 24 | cnt_ipv4_dst_hit = self.wb.read(self.ba+0x028) 25 | cnt_ipv4_src_hit = self.wb.read(self.ba+0x02C) 26 | cnt_ipv6_dst_hit = self.wb.read(self.ba+0x030) 27 | cnt_ipv6_src_hit = self.wb.read(self.ba+0x034) 28 | 29 | print("========================================") 30 | print("FIREWALL%d REPORT:" % self.port_id) 31 | print("========================================") 32 | print("Frames all: %d" % cnt_pkt) 33 | print("Frames with IPV4: %d" % cnt_ipv4) 34 | print("Frames with IPV6: %d" % cnt_ipv6) 35 | print("Frames without IPV4/6: %d" % (cnt_pkt-(cnt_ipv4+cnt_ipv6))) 36 | print("----------------------------------------") 37 | print("Match Units Statistics:") 38 | print("----------------------------------------") 39 | print("Number of MAC_DST_ADDR hits: %d" % cnt_mac_dst_hit) 40 | print("Number of MAC_SRC_ADDR hits: %d" % cnt_mac_src_hit) 41 | print("Number of IPV4_DST_ADDR hits: %d" % cnt_ipv4_dst_hit) 42 | print("Number of IPV4_SRC_ADDR hits: %d" % cnt_ipv4_src_hit) 43 | print("Number of IPV6_DST_ADDR hits: %d" % cnt_ipv6_dst_hit) 44 | print("Number of IPV6_SRC_ADDR hits: %d" % cnt_ipv6_src_hit) 45 | if full: 46 | print("----------------------------------------") 47 | print("Debug registers:") 48 | print("----------------------------------------") 49 | print("Version register: %s" % hex(version_reg)) 50 | print("Status register: %s" % hex(status_reg)) 51 | print("----------------------------------------\n") 52 | -------------------------------------------------------------------------------- /sw/match_unit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | class match_unit: 10 | def __init__(self, wishbone, base_addr, instance): 11 | self.wb = wishbone 12 | self.ba = base_addr 13 | self.inst = instance 14 | 15 | def add_record(self, id, record): 16 | # record is list of unsigned integers (dwords) 17 | dwords = self.wb.read(self.ba+0x04) # read record size in dwords (32b) 18 | print("%d dwords is supported in MatchUnit %s." % (dwords, self.inst)) 19 | self.wb.write(self.ba+0x08,id) # write record address (ID) 20 | for i in range(0, dwords): 21 | self.wb.write(self.ba+0x0C,record[i]) # write record per dwords 22 | print("Write %s to MatchUnit %s." % (hex(record[i]), self.inst)) 23 | self.wb.write(self.ba+0x00,0x0) # command add record 24 | print("Record %d added in MatchUnit %s." % (id, self.inst)) 25 | 26 | def rm_record(self, id): 27 | self.wb.write(self.ba+0x08,id) # write record address (ID) 28 | self.wb.write(self.ba+0x00,0x1) # command remove record 29 | print("Record %d removed in MatchUnit %s." % (id, self.inst)) 30 | 31 | -------------------------------------------------------------------------------- /sw/print_summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | from wishbone import wishbone 10 | from rmii_mac import rmii_mac 11 | from firewall import firewall 12 | from sys_module import sys_module 13 | 14 | print("SUMMARY REPORTS OF RMII FIREWALL FPGA:") 15 | print("========================================") 16 | 17 | wb = wishbone("COM4") 18 | sm = sys_module(wb) 19 | mac0 = rmii_mac(wb,0x4000,0) 20 | mac1 = rmii_mac(wb,0x6000,1) 21 | fw0 = firewall(wb,0x8000,0) 22 | fw1 = firewall(wb,0xA000,1) 23 | 24 | #sm.report() 25 | mac0.rx_mac_report() 26 | fw0.firewall_report() 27 | mac1.tx_mac_report() 28 | 29 | mac1.rx_mac_report() 30 | fw1.firewall_report() 31 | mac0.tx_mac_report() 32 | 33 | wb.close() 34 | -------------------------------------------------------------------------------- /sw/rmii_mac.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | class rmii_mac: 10 | def __init__(self, wishbone, base_addr, port): 11 | self.wb = wishbone 12 | self.ba = base_addr 13 | self.port_id = port 14 | 15 | def rx_mac_report(self, full=False): 16 | version_reg = self.wb.read(self.ba+0x000) 17 | status_reg = self.wb.read(self.ba+0x004) 18 | self.wb.write(self.ba+0x000,0x3) # sample counters 19 | rx_cnt_reg = self.wb.read(self.ba+0x010) 20 | tx_cnt_reg = self.wb.read(self.ba+0x014) 21 | cnt_rx_pkt_undersize = self.wb.read(self.ba+0x020) 22 | cnt_rx_pkt_64_to_127 = self.wb.read(self.ba+0x024) 23 | cnt_rx_pkt_128_to_255 = self.wb.read(self.ba+0x028) 24 | cnt_rx_pkt_256_to_511 = self.wb.read(self.ba+0x02C) 25 | cnt_rx_pkt_512_to_767 = self.wb.read(self.ba+0x030) 26 | cnt_rx_pkt_768_to_1023 = self.wb.read(self.ba+0x034) 27 | cnt_rx_pkt_1024_to_1522 = self.wb.read(self.ba+0x038) 28 | cnt_rx_pkt_oversize = self.wb.read(self.ba+0x03C) 29 | # decode status register 30 | enable_flag = True if ((status_reg & 1) == 0) else False 31 | fsm_dec_dbg_st = (status_reg & 768)/256 32 | fsm_mrk_dbg_st = (status_reg & 12288)/4096 33 | fifom_status = (status_reg & 134152192)/65536 34 | fifom_full = True if (((status_reg & 128)/128) == 0) else False 35 | 36 | print("========================================") 37 | print("ETH%d RX RMII MAC REPORT:" % self.port_id) 38 | print("========================================") 39 | print("RX MAC is enabled: %s" % enable_flag) 40 | print("----------------------------------------") 41 | print("Received frames: %d" % rx_cnt_reg) 42 | print("Discarded frames: %d" % (rx_cnt_reg-tx_cnt_reg)) 43 | print("Released frames: %d" % tx_cnt_reg) 44 | print("----------------------------------------") 45 | print("Received frames length histogram:") 46 | print("----------------------------------------") 47 | print("Frames below 64 bytes: %d" % cnt_rx_pkt_undersize) 48 | print("Frames 64 to 127 bytes: %d" % cnt_rx_pkt_64_to_127) 49 | print("Frames 128 to 255 bytes: %d" % cnt_rx_pkt_128_to_255) 50 | print("Frames 256 to 511 bytes: %d" % cnt_rx_pkt_256_to_511) 51 | print("Frames 512 to 767 bytes: %d" % cnt_rx_pkt_512_to_767) 52 | print("Frames 768 to 1023 bytes: %d" % cnt_rx_pkt_768_to_1023) 53 | print("Frames 1024 to 1522 bytes: %d" % cnt_rx_pkt_1024_to_1522) 54 | print("Frames over 1522 bytes: %d" % cnt_rx_pkt_oversize) 55 | if full: 56 | print("----------------------------------------") 57 | print("Debug registers:") 58 | print("----------------------------------------") 59 | print("Version register: %s" % hex(version_reg)) 60 | print("Decoder FSM state: %d" % fsm_dec_dbg_st) 61 | print("Mark FSM state: %d" % fsm_mrk_dbg_st) 62 | print("Mark FIFO status: %d" % fifom_status) 63 | print("Mark FIFO full: %s" % fifom_full) 64 | print("Status register: %s" % hex(status_reg)) 65 | print("----------------------------------------\n") 66 | 67 | def tx_mac_report(self, full=False): 68 | version_reg = self.wb.read(self.ba+0x100) 69 | status_reg = self.wb.read(self.ba+0x104) 70 | self.wb.write(self.ba+0x100,0x3) # sample counters 71 | tx_cnt_reg = self.wb.read(self.ba+0x110) 72 | 73 | enable_flag = True if ((status_reg & 1) == 0) else False 74 | asfifo_full = True if (((status_reg & 32)/32) == 0) else False 75 | 76 | print("========================================") 77 | print("ETH%d TX RMII MAC REPORT:" % self.port_id) 78 | print("========================================") 79 | print("TX MAC is enabled: %s" % enable_flag) 80 | print("----------------------------------------") 81 | print("Transmitted frames: %d" % tx_cnt_reg) 82 | if full: 83 | print("----------------------------------------") 84 | print("Version register: %s" % hex(version_reg)) 85 | print("TX ASFIFO full: %s" % asfifo_full) 86 | print("Status register: %s" % hex(status_reg)) 87 | print("----------------------------------------\n") 88 | -------------------------------------------------------------------------------- /sw/sys_module.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | class sys_module: 10 | 11 | def __init__(self, wishbone): 12 | self.wb = wishbone 13 | 14 | def report(self): 15 | version_reg = self.wb.read(0x0000) 16 | debug_reg = self.wb.read(0x0004) 17 | 18 | print("========================================") 19 | print("SYSTEM MODULE REPORT:") 20 | print("========================================") 21 | print("Version register: %s" % hex(version_reg)) 22 | print("Debug register: %s" % hex(debug_reg)) 23 | print("----------------------------------------\n") 24 | -------------------------------------------------------------------------------- /sw/wishbone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #------------------------------------------------------------------------------- 3 | # PROJECT: RMII FIREWALL FPGA 4 | #------------------------------------------------------------------------------- 5 | # AUTHORS: Jakub Cabal 6 | # LICENSE: The MIT License, please read LICENSE file 7 | #------------------------------------------------------------------------------- 8 | 9 | import serial 10 | 11 | byteorder="little" 12 | 13 | class wishbone: 14 | def __init__(self, port="COM1", baudrate=9600): 15 | self.uart = serial.Serial(port, baudrate, timeout=2) 16 | print("The UART on " + self.uart.name + " is open.") 17 | print("The wishbone bus is ready.\n") 18 | 19 | def read(self,addr): 20 | cmd = 0x0 21 | cmd = cmd.to_bytes(1,byteorder) 22 | self.uart.write(cmd) 23 | addr = addr.to_bytes(2,byteorder) 24 | self.uart.write(addr) 25 | rbytes=self.uart.read(1) 26 | rbytes=self.uart.read(4) 27 | drd=int.from_bytes(rbytes,byteorder) 28 | return drd 29 | 30 | def write(self, addr, data): 31 | cmd = 0x1 32 | cmd = cmd.to_bytes(1,byteorder) 33 | self.uart.write(cmd) 34 | addr = addr.to_bytes(2,byteorder) 35 | self.uart.write(addr) 36 | data = data.to_bytes(4,byteorder) 37 | self.uart.write(data) 38 | rbytes=self.uart.read(1) 39 | 40 | def close(self): 41 | self.uart.close() 42 | 43 | if __name__ == '__main__': 44 | print("Test of access to CSR (control status registers) via UART2WBM module...") 45 | print("=======================================================================") 46 | wb = wishbone("COM4") 47 | 48 | print("\nREAD from 0x0:") 49 | rd = wb.read(0x0) 50 | print("0x%02X" % rd) 51 | 52 | print("\nREAD from 0x4:") 53 | rd = wb.read(0x4) 54 | print("0x%02X" % rd) 55 | 56 | print("\nWRITE 0x12345678 to 0x4.") 57 | wb.write(0x4,0x12345678) 58 | 59 | print("\nREAD from 0x4:") 60 | rd = wb.read(0x4) 61 | print("0x%02X" % rd) 62 | 63 | print("\nWRITE 0xABCDEF12 to 0x4.") 64 | wb.write(0x4,0xABCDEF12) 65 | 66 | print("\nREAD from 0x4:") 67 | rd = wb.read(0x4) 68 | print("0x%02X" % rd) 69 | 70 | print("\nREAD from 0x8844:") 71 | rd = wb.read(0x8844) 72 | print("0x%02X" % rd) 73 | 74 | wb.close() 75 | print("\nThe UART is closed.") 76 | --------------------------------------------------------------------------------