Commit dddedff7 authored by Maciej Lipinski's avatar Maciej Lipinski

Importing swcore to the new repo: adding swcore files from the old repo…

Importing swcore to the new repo: adding swcore files from the old repo (hopefully with the history) to the new repo
parents 5c598e8e 5aaaade6
SRCS_VHDL = swc_swcore_pkg.vhd \
swc_block_alloc.vhd \
swc_core.vhd \
swc_input_block.vhd \
swc_lost_pck_dealloc.vhd \
swc_multiport_linked_list.vhd \
swc_multiport_page_allocator.vhd \
swc_multiport_pck_pg_free_module.vhd \
swc_ob_prio_queue.vhd \
swc_output_block.vhd \
swc_packet_mem.vhd \
swc_packet_mem_read_pump.vhd \
swc_packet_mem_write_pump.vhd \
swc_page_alloc.vhd \
swc_pck_pg_free_module.vhd \
swc_pck_transfer_arbiter.vhd \
swc_pck_transfer_input.vhd \
swc_pck_transfer_output.vhd \
swc_prio_encoder.vhd \
swc_rr_arbiter.vhd
WORK = work
#directories in which we should search for the VHDL/verilog source files
VPATH =
include ../../scripts/modules.mk
- synchronize local *platform_specific.vhd* and *generic_ssram_dualport_singleclock.vhd* with main (in hdl/latform/altera)
- fix swc_packet_mem_read_pump.vhd
\ No newline at end of file
-- megafunction wizard: %RAM: 2-PORT%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: altsyncram
-- ============================================================
-- File Name: aaa.vhd
-- Megafunction Name(s):
-- altsyncram
--
-- Simulation Library Files(s):
-- altera_mf
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 9.0 Build 132 02/25/2009 SJ Full Version
-- ************************************************************
--Copyright (C) 1991-2009 Altera Corporation
--Your use of Altera Corporation's design tools, logic functions
--and other software and tools, and its AMPP partner logic
--functions, and any output files from any of the foregoing
--(including device programming or simulation files), and any
--associated documentation or information are expressly subject
--to the terms and conditions of the Altera Program License
--Subscription Agreement, Altera MegaCore Function License
--Agreement, or other applicable license agreement, including,
--without limitation, that your use is for the sole purpose of
--programming logic devices manufactured by Altera and sold by
--Altera or its authorized distributors. Please refer to the
--applicable agreement for further details.
library ieee;
use ieee.std_logic_1164.all;
library altera_mf;
use altera_mf.all;
entity generic_ssram_dualport_singleclock is
generic (
g_width : natural := 8;
g_addr_bits : natural := 10;
g_size : natural := 1024;
g_init_file : string := "UNUSED");
port
(
data_i : in std_logic_vector (g_width-1 downto 0);
clk_i : in std_logic;
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0)
);
end generic_ssram_dualport_singleclock;
architecture SYN of generic_ssram_dualport_singleclock is
signal sub_wire0 : std_logic_vector (g_width-1 downto 0);
component altsyncram
generic (
address_aclr_b : string;
address_reg_b : string;
clock_enable_input_a : string;
clock_enable_input_b : string;
clock_enable_output_b : string;
intended_device_family : string;
lpm_type : string;
numwords_a : natural;
numwords_b : natural;
operation_mode : string;
outdata_aclr_b : string;
outdata_reg_b : string;
power_up_uninitialized : string;
read_during_write_mode_mixed_ports : string;
widthad_a : natural;
widthad_b : natural;
width_a : natural;
width_b : natural;
INIT_FILE : string ;
width_byteena_a : natural
);
port (
wren_a : in std_logic;
clock0 : in std_logic;
address_a : in std_logic_vector (g_addr_bits-1 downto 0);
address_b : in std_logic_vector (g_addr_bits-1 downto 0);
q_b : out std_logic_vector (g_width-1 downto 0);
data_a : in std_logic_vector (g_width-1 downto 0)
);
end component;
begin
q_o <= sub_wire0(g_width-1 downto 0);
altsyncram_component : altsyncram
generic map (
address_aclr_b => "NONE",
address_reg_b => "CLOCK0",
clock_enable_input_a => "BYPASS",
clock_enable_input_b => "BYPASS",
clock_enable_output_b => "BYPASS",
intended_device_family => "Cyclone III",
lpm_type => "altsyncram",
numwords_a => g_size,
numwords_b => g_size,
operation_mode => "DUAL_PORT",
outdata_aclr_b => "NONE",
outdata_reg_b => "UNREGISTERED",
power_up_uninitialized => "FALSE",
read_during_write_mode_mixed_ports => "OLD_DATA",
widthad_a => g_addr_bits,
widthad_b => g_addr_bits,
width_a => g_width,
width_b => g_width,
width_byteena_a => 1,
INIT_FILE => g_init_file
)
port map (
wren_a => wr_en_i,
clock0 => clk_i,
address_a => wr_addr_i,
address_b => rd_addr_i,
data_a => data_i,
q_b => sub_wire0
);
end SYN;
-- Copyright (C) 1991-2009 Altera Corporation
-- Your use of Altera Corporation's design tools, logic functions
-- and other software and tools, and its AMPP partner logic
-- functions, and any output files from any of the foregoing
-- (including device programming or simulation files), and any
-- associated documentation or information are expressly subject
-- to the terms and conditions of the Altera Program License
-- Subscription Agreement, Altera MegaCore Function License
-- Agreement, or other applicable license agreement, including,
-- without limitation, that your use is for the sole purpose of
-- programming logic devices manufactured by Altera and sold by
-- Altera or its authorized distributors. Please refer to the
-- applicable agreement for further details.
-- Quartus II generated Memory Initialization File (.mif)
WIDTH=32;
DEPTH=32;
ADDRESS_RADIX=UNS;
DATA_RADIX=UNS;
CONTENT BEGIN
[0..31] : 4294967295;
END;
files = ["swc_swcore_pkg.vhd",
"swc_block_alloc.vhd",
"swc_core.vhd",
"swc_input_block.vhd",
"swc_lost_pck_dealloc.vhd",
"swc_multiport_linked_list.vhd",
"swc_multiport_page_allocator.vhd",
"swc_multiport_pck_pg_free_module.vhd",
"swc_ob_prio_queue.vhd",
"swc_output_block.vhd",
"swc_packet_mem.vhd",
"swc_packet_mem_read_pump.vhd",
"swc_packet_mem_write_pump.vhd",
"swc_page_alloc.vhd",
"swc_pck_pg_free_module.vhd",
"swc_pck_transfer_arbiter.vhd",
"swc_pck_transfer_input.vhd",
"swc_pck_transfer_output.vhd",
"swc_prio_encoder.vhd",
"swc_rr_arbiter.vhd",
"generic_ssram_dualport_singleclock.vhd"]
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library lpm;
use lpm.all;
-------------------------------------------------------------------------------
package platform_specific is
-----------------------------------------------------------------------------
-- Component declarations
-----------------------------------------------------------------------------
component generic_async_fifo_2stage
generic (
g_width : natural;
g_depth : natural;
g_almostfull_bit_threshold : natural);
port (
clear_i : in std_logic := '0';
d_i : in std_logic_vector (g_width-1 downto 0);
rd_clk_i : in std_logic;
rd_req_i : in std_logic;
wr_clk_i : in std_logic;
wr_req_i : in std_logic;
q_o : out std_logic_vector (g_width-1 downto 0);
rd_empty_o : out std_logic;
wr_full_o : out std_logic;
almost_full_o : out std_logic);
end component;
component generic_ssram_dualport
generic (
g_width : natural;
g_addr_bits : natural;
g_size : natural);
port (
data_i : in std_logic_vector (g_width-1 downto 0);
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
rd_clk_i : in std_logic;
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_clk_i : in std_logic;
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0));
end component;
component generic_ssram_dualport_singleclock
generic (
g_width : natural;
g_addr_bits : natural;
g_size : natural;
g_init_file : string := "UNUSED");
port (
data_i : in std_logic_vector (g_width-1 downto 0);
clk_i : in std_logic;
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0));
end component;
component alt_clock_divider
port (
inclk0 : in std_logic := '0';
c0 : out std_logic;
c1 : out std_logic;
locked : out std_logic);
end component;
component generic_sync_fifo
generic (
g_width : natural;
g_depth : natural;
g_depth_log2 : natural);
port (
clk_i : in std_logic;
clear_i : in std_logic := '0';
wr_req_i : in std_logic;
d_i : in std_logic_vector (g_width-1 downto 0);
rd_req_i : in std_logic;
q_o : out std_logic_vector (g_width-1 downto 0);
empty_o : out std_logic;
full_o : out std_logic;
usedw_o : out std_logic_vector(g_depth_log2-1 downto 0));
end component;
component generic_pipelined_multiplier
generic (
g_width_a : natural;
g_width_b : natural;
g_width_out : natural;
g_sign_mode : string);
port (
clk_i : in std_logic;
a_i : in std_logic_vector(g_width_a -1 downto 0);
b_i : in std_logic_vector(g_width_b -1 downto 0);
q_o : out std_logic_vector(g_width_out-1 downto 0));
end component;
end platform_specific;
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity swc_block_allocator is
generic (
g_num_blocks : integer := 2048;
g_log2_num_blocks : integer := 13;
g_usecount_bits : integer := 4
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
idle_o : out std_logic;
alloc_rq_i : in std_logic;
alloc_size_i : in std_logic_vector (7 downto 0);
alloc_done_o : out std_logic;
alloc_nomem_o : out std_logic;
alloc_use_count_i : in std_logic_vector(g_usecount_bits-1 downto 0);
alloc_addr_o : out std_logic_vector (g_log2_num_blocks-1 downto 0);
free_rq_i : in std_logic;
free_addr_i : in std_logic_vector(g_log2_num_blocks-1 downto 0);
free_done_o : out std_logic
);
end swc_block_allocator;
architecture syn of swc_block_allocator is
constant c_l1_size : integer := g_num_blocks/32;
signal l1_full : std_logic_vector(c_l1_size-1 downto 0); -- 1 means block is
-- full
signal l1_empty : std_logic_vector(c_l1_size-1 downto 0); -- 1 means block is
-- empty
type t_state is (IDLE, ALLOC_LOOKUP_L1);
begin -- syn
process (clk_i, rst_n_i)
begin -- process
if rising_edge(clk_i) then
if(rst_n_i = '0') then
l1_full <= (others => '0');
l1_empty <= (others => '1');
else
end if;
end if;
end process;
end syn;
-------------------------------------------------------------------------------
-- Title : Switch Core
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_core.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-10-29
-- Last update: 2010-10-29
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
--
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-10-29 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_core is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- Fabric I/F : input (comes from the Endpoint)
-------------------------------------------------------------------------------
tx_sof_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_eof_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_data_i : in std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
tx_ctrl_i : in std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
tx_valid_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_bytesel_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_dreq_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_abort_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
tx_rerror_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
-------------------------------------------------------------------------------
-- Fabric I/F : output (goes to the Endpoint)
-------------------------------------------------------------------------------
rx_sof_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_eof_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_dreq_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_ctrl_o : out std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
rx_data_o : out std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
rx_valid_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_bytesel_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_idle_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_rerror_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_terror_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rx_tabort_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
-------------------------------------------------------------------------------
-- I/F with Routing Table Unit (RTU)
-------------------------------------------------------------------------------
rtu_rsp_valid_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rtu_rsp_ack_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
rtu_dst_port_mask_i : in std_logic_vector(c_swc_num_ports * c_swc_num_ports - 1 downto 0);
rtu_drop_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rtu_prio_i : in std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0)
);
end swc_core;
architecture rtl of swc_core is
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Memory Management Unit<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Memory Management Unit
signal ib_page_alloc_req : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_output : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_set_usecnt : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_usecnt : std_logic_vector(c_swc_num_ports * c_swc_usecount_width - 1 downto 0);
-- Memory Management Unit -> Input Block
signal mmu_page_alloc_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mmu_pageaddr_input : std_logic_vector( 1 * c_swc_page_addr_width - 1 downto 0);
signal mmu_set_usecnt_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mmu_nomem : std_logic;
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Multiport Memory<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Multiport Memory
signal ib_pckstart : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_to_mpm : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_pagereq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal ib_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
signal ib_drdy : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_flush : std_logic_vector(c_swc_num_ports - 1 downto 0);
-- Multiport Memory -> Input Block
signal mpm_pageend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_full : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_wr_sync : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Pck Transfer Arbiter<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Pck Transfer Arbiter
signal ib_transfer_pck : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_to_pta : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_mask : std_logic_vector(c_swc_num_ports * c_swc_num_ports - 1 downto 0);
signal ib_prio : std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
signal ib_pck_size : std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
-- Pck Transfer Arbiter -> Input Block
signal pta_transfer_ack : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Pck Transfer Arbiter<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Pck Transfer Arbiter
signal pta_data_valid : std_logic_vector(c_swc_num_ports -1 downto 0);
signal pta_pageaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal pta_prio : std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
signal pta_pck_size : std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
-- Input Block -> Pck Transfer Arbiter
signal ob_ack : std_logic_vector(c_swc_num_ports -1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Multiport Memory<<
----------------------------------------------------------------------------------------------------
-- Output Block -> Multiport Memory
signal ob_pgreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ob_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ob_dreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
-- Multiport Memory -> Output Block
signal mpm_pckend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_pgend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_drdy : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal mpm_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
signal mpm_rd_sync : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Muliport Memory<< with >>Linked List<<
----------------------------------------------------------------------------------------------------
-- Multiport Memory -> Linked List
signal mpm_write : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_write_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal mpm_write_data : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal mpm_read_pump_read : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_read_pump_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- Linked List -> Multiport memory
-- signal ll_free_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_write_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_read_pump_read_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_data : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Pck's pages freeeing module<<
----------------------------------------------------------------------------------------------------
-- Input block -> Lost pck dealloc
signal ib_force_free : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_force_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- lost pck dealloc -> input block
signal ppfm_force_free_done_to_ib : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Pck's Pages Freeing Module (PPFM)<<
----------------------------------------------------------------------------------------------------
-- output block -> Lost pck dealloc
signal ob_free : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ob_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- lost pck dealloc -> output block
signal ppfm_free_done_to_ob : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Pck's pages freeeing module<< with >>Linkded List<<
----------------------------------------------------------------------------------------------------
-- LPD -> LL
signal ppfm_read_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
signal ppfm_read_req : std_logic_vector(c_swc_num_ports-1 downto 0);
-- LL -> LPD
signal ll_read_valid_data : std_logic_vector(c_swc_num_ports-1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Pck's pages freeing module (PPFM)<< with >>Page allocator (MMU)<<
----------------------------------------------------------------------------------------------------
-- PPFM -> MMU
signal ppfm_force_free : std_logic_vector(c_swc_num_ports-1 downto 0);
signal ppfm_force_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
signal ppfm_free : std_logic_vector(c_swc_num_ports-1 downto 0);
signal ppfm_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
-- MMU -> PPFM
signal mmu_force_free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal mmu_free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
---- end tmp
begin --rtl
---- end timp
gen_blocks : for i in 0 to c_swc_num_ports-1 generate
INPUT_BLOCK : swc_input_block
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- Fabric I/F
------------------------------------------------------------------------------
tx_sof_p1_i => tx_sof_p1_i(i),
tx_eof_p1_i => tx_eof_p1_i(i),
tx_data_i => tx_data_i ((i + 1) * c_swc_data_width -1 downto i * c_swc_data_width),
tx_ctrl_i => tx_ctrl_i((i + 1) * c_swc_ctrl_width -1 downto i * c_swc_ctrl_width),
tx_valid_i => tx_valid_i(i),
tx_bytesel_i => tx_bytesel_i(i),
tx_dreq_o => tx_dreq_o(i),
tx_abort_p1_i => tx_abort_p1_i(i),
tx_rerror_p1_i => tx_rerror_p1_i(i),
-------------------------------------------------------------------------------
-- I/F with Page allocator (MMU)
-------------------------------------------------------------------------------
mmu_page_alloc_req_o => ib_page_alloc_req(i),
mmu_page_alloc_done_i => mmu_page_alloc_done(i),
mmu_pageaddr_i => mmu_pageaddr_input,
mmu_set_usecnt_o => ib_set_usecnt(i),
mmu_set_usecnt_done_i => mmu_set_usecnt_done(i),
mmu_usecnt_o => ib_usecnt((i + 1) * c_swc_usecount_width -1 downto i * c_swc_usecount_width),
mmu_nomem_i => mmu_nomem,
mmu_pageaddr_o => ib_pageaddr_output((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
-------------------------------------------------------------------------------
-- I/F with Pck's Pages Freeing Module (PPFM)
-------------------------------------------------------------------------------
mmu_force_free_o => ib_force_free(i),
mmu_force_free_done_i => ppfm_force_free_done_to_ib(i),
mmu_force_free_addr_o => ib_force_free_pgaddr((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
-------------------------------------------------------------------------------
-- I/F with Routing Table Unit (RTU)
-------------------------------------------------------------------------------
rtu_rsp_valid_i => rtu_rsp_valid_i(i),
rtu_rsp_ack_o => rtu_rsp_ack_o(i),
rtu_dst_port_mask_i => rtu_dst_port_mask_i((i + 1) * c_swc_num_ports -1 downto i * c_swc_num_ports),
rtu_drop_i => rtu_drop_i(i),
rtu_prio_i => rtu_prio_i((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
-------------------------------------------------------------------------------
-- I/F with Multiport Memory (MPU)
-------------------------------------------------------------------------------
mpm_pckstart_o => ib_pckstart(i),
mpm_pageaddr_o => ib_pageaddr_to_mpm((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
mpm_pagereq_o => ib_pagereq(i),
mpm_pageend_i => mpm_pageend(i),
mpm_data_o => ib_data((i + 1) * c_swc_data_width - 1 downto i * c_swc_data_width),
mpm_ctrl_o => ib_ctrl((i + 1) * c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width),
mpm_drdy_o => ib_drdy(i),
mpm_full_i => mpm_full(i),
mpm_flush_o => ib_flush(i),
mpm_wr_sync_i => mpm_wr_sync(i),
-------------------------------------------------------------------------------
-- I/F with Page Transfer Arbiter (PTA)
-------------------------------------------------------------------------------
pta_transfer_pck_o => ib_transfer_pck(i),
pta_transfer_ack_i => pta_transfer_ack(i),
pta_pageaddr_o => ib_pageaddr_to_pta((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
pta_mask_o => ib_mask ((i + 1) * c_swc_num_ports -1 downto i * c_swc_num_ports),
pta_prio_o => ib_prio ((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
pta_pck_size_o => ib_pck_size ((i + 1) * c_swc_max_pck_size_width -1 downto i * c_swc_max_pck_size_width)
);
OUTPUT_BLOCK: swc_output_block
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Page Transfer Arbiter (PTA)
-------------------------------------------------------------------------------
pta_transfer_data_valid_i=> pta_data_valid(i),
pta_pageaddr_i => pta_pageaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
pta_prio_i => pta_prio ((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
pta_pck_size_i => pta_pck_size((i + 1) * c_swc_max_pck_size_width -1 downto i * c_swc_max_pck_size_width),
pta_transfer_data_ack_o => ob_ack(i),
-------------------------------------------------------------------------------
-- I/F with Multiport Memory (MPM)
-------------------------------------------------------------------------------
mpm_pgreq_o => ob_pgreq(i),
mpm_pgaddr_o => ob_pgaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
mpm_pckend_i => mpm_pckend(i),
mpm_pgend_i => mpm_pgend(i),
mpm_drdy_i => mpm_drdy(i),
mpm_dreq_o => ob_dreq(i),
mpm_data_i => mpm_data((i + 1) * c_swc_data_width - 1 downto i * c_swc_data_width),
mpm_ctrl_i => mpm_ctrl((i + 1) * c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width),
mpm_sync_i => mpm_rd_sync(i),
-------------------------------------------------------------------------------
-- I/F with Pck's Pages Freeing Module (PPFM)
-------------------------------------------------------------------------------
ppfm_free_o => ob_free(i),
ppfm_free_done_i => ppfm_free_done_to_ob(i),
ppfm_free_pgaddr_o => ob_free_pgaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
-------------------------------------------------------------------------------
-- Fabric I/F
-------------------------------------------------------------------------------
rx_sof_p1_o => rx_sof_p1_o(i),
rx_eof_p1_o => rx_eof_p1_o(i),
rx_dreq_i => rx_dreq_i(i),
rx_ctrl_o => rx_ctrl_o((i + 1) * c_swc_ctrl_width -1 downto i * c_swc_ctrl_width),
rx_data_o => rx_data_o((i + 1) * c_swc_data_width -1 downto i * c_swc_data_width),
rx_valid_o => rx_valid_o(i),
rx_bytesel_o => rx_bytesel_o(i),
rx_idle_o => rx_idle_o(i),
rx_rerror_p1_o => rx_rerror_p1_o(i),
rx_terror_p1_i => rx_terror_p1_i(i),
rx_tabort_p1_i => rx_tabort_p1_i(i)
);
end generate gen_blocks;
PCK_PAGES_FREEEING_MODULE: swc_multiport_pck_pg_free_module
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
ib_force_free_i => ib_force_free,
ib_force_free_done_o => ppfm_force_free_done_to_ib,
ib_force_free_pgaddr_i => ib_force_free_pgaddr,
ob_free_i => ob_free,
ob_free_done_o => ppfm_free_done_to_ob,
ob_free_pgaddr_i => ob_free_pgaddr,
ll_read_addr_o => ppfm_read_addr,
ll_read_data_i => ll_data,
ll_read_req_o => ppfm_read_req,
ll_read_valid_data_i => ll_read_valid_data,
mmu_force_free_o => ppfm_force_free,
mmu_force_free_done_i => mmu_force_free_done,
mmu_force_free_pgaddr_o => ppfm_force_free_pgaddr,
mmu_free_o => ppfm_free,
mmu_free_done_i => mmu_free_done,
mmu_free_pgaddr_o => ppfm_free_pgaddr
);
LINKED_LIST: swc_multiport_linked_list
port map(
rst_n_i => rst_n_i,
clk_i => clk_i,
write_i => mpm_write,
write_done_o => ll_write_done,
write_addr_i => mpm_write_addr,
write_data_i => mpm_write_data,
-- not used for the time being
free_i => (others => '0'),
free_done_o => open,
free_addr_i => (others => '0'),
read_pump_read_i => mpm_read_pump_read,
read_pump_read_done_o => ll_read_pump_read_done,
read_pump_addr_i => mpm_read_pump_addr,
free_pck_read_i => ppfm_read_req,
free_pck_read_done_o => ll_read_valid_data,
free_pck_addr_i => ppfm_read_addr,
data_o => ll_data
);
----------------------------------------------------------------------
-- Memory Mangement Unit (MMU)
----------------------------------------------------------------------
MEMORY_MANAGEMENT_UNIT: swc_multiport_page_allocator
port map (
rst_n_i => rst_n_i,
clk_i => clk_i,
alloc_i => ib_page_alloc_req,
alloc_done_o => mmu_page_alloc_done,
pgaddr_alloc_o => mmu_pageaddr_input,
set_usecnt_i => ib_set_usecnt,
set_usecnt_done_o => mmu_set_usecnt_done,
usecnt_i => ib_usecnt,
pgaddr_usecnt_i => ib_pageaddr_output,
free_i => ppfm_free,
free_done_o => mmu_free_done,
pgaddr_free_i => ppfm_free_pgaddr,
force_free_i => ppfm_force_free,
force_free_done_o => mmu_force_free_done,
pgaddr_force_free_i => ppfm_force_free_pgaddr,
nomem_o => mmu_nomem
);
----------------------------------------------------------------------
-- MultiPort Memory (MPM) [ 1 module]
----------------------------------------------------------------------
MUPTIPORT_MEMORY: swc_packet_mem
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Input Block (IB)
-------------------------------------------------------------------------------
wr_pagereq_i => ib_pagereq,
wr_pckstart_i => ib_pckstart,
wr_pageaddr_i => ib_pageaddr_to_mpm,
wr_pageend_o => mpm_pageend,
wr_ctrl_i => ib_ctrl,
wr_data_i => ib_data,
wr_drdy_i => ib_drdy,
wr_full_o => mpm_full,
wr_flush_i => ib_flush,
wr_sync_o => mpm_wr_sync,
-------------------------------------------------------------------------------
-- I/F with Output Block
-------------------------------------------------------------------------------
rd_pagereq_i => ob_pgreq,
rd_pageaddr_i => ob_pgaddr,
rd_pageend_o => mpm_pgend,
rd_pckend_o => mpm_pckend,
rd_drdy_o => mpm_drdy,
rd_dreq_i => ob_dreq,
--!!!!!!!!!!
rd_sync_read_i => ob_pgreq, -- TODO ???
--!!!!!!!!!!!!!!!!!!
rd_data_o => mpm_data,
rd_ctrl_o => mpm_ctrl,
rd_sync_o => mpm_rd_sync,
write_o => mpm_write,
write_done_i => ll_write_done,
write_addr_o => mpm_write_addr,
write_data_o => mpm_write_data,
read_pump_read_o => mpm_read_pump_read,
read_pump_read_done_i => ll_read_pump_read_done,
read_pump_addr_o => mpm_read_pump_addr,
data_i => ll_data
);
----------------------------------------------------------------------
-- Page Transfer Arbiter [ 1 module]
----------------------------------------------------------------------
TRANSER_ARBITER: swc_pck_transfer_arbiter
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Output Block (OB)
-------------------------------------------------------------------------------
ob_data_valid_o => pta_data_valid,
ob_ack_i => ob_ack,
ob_pageaddr_o => pta_pageaddr,
ob_prio_o => pta_prio,
ob_pck_size_o => pta_pck_size,
-------------------------------------------------------------------------------
-- I/F with Input Block (IB)
-------------------------------------------------------------------------------
ib_transfer_pck_i => ib_transfer_pck,
ib_transfer_ack_o => pta_transfer_ack,
ib_busy_o => open,
ib_pageaddr_i => ib_pageaddr_to_pta,
ib_mask_i => ib_mask,
ib_prio_i => ib_prio,
ib_pck_size_i => ib_pck_size
);
end rtl;
-------------------------------------------------------------------------------
-- Title : Switch Core
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_core.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-10-29
-- Last update: 2010-10-29
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
--
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-10-29 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_core is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- Fabric I/F : input (comes from the Endpoint)
-------------------------------------------------------------------------------
tx_sof_p1_i : in std_logic;
tx_eof_p1_i : in std_logic;
tx_data_i : in std_logic_vector(c_swc_data_width - 1 downto 0);
tx_ctrl_i : in std_logic_vector(c_swc_ctrl_width - 1 downto 0);
tx_valid_i : in std_logic;
tx_bytesel_i : in std_logic;
tx_dreq_o : out std_logic;
tx_abort_p1_i : in std_logic;
tx_rerror_p1_i : in std_logic;
-------------------------------------------------------------------------------
-- Fabric I/F : output (goes to the Endpoint)
-------------------------------------------------------------------------------
rx_sof_p1_o : out std_logic;
rx_eof_p1_o : out std_logic;
rx_dreq_i : in std_logic;
rx_ctrl_o : out std_logic_vector(c_swc_ctrl_width - 1 downto 0);
rx_data_o : out std_logic_vector(c_swc_data_width - 1 downto 0);
rx_valid_o : out std_logic;
rx_bytesel_o : out std_logic;
rx_idle_o : out std_logic;
rx_rerror_p1_o : out std_logic;
rx_terror_p1_i : in std_logic;
rx_rabort_p1_i : in std_logic;
-- rx_sof_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_eof_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_dreq_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_ctrl_o : out std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
-- rx_data_o : out std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
-- rx_valid_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_bytesel_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_idle_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_rerror_p1_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_terror_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
-- rx_rabort_p1_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
-------------------------------------------------------------------------------
-- I/F with Routing Table Unit (RTU)
-------------------------------------------------------------------------------
rtu_rsp_valid_i : in std_logic;
rtu_rsp_ack_o : out std_logic;
rtu_dst_port_mask_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rtu_drop_i : in std_logic;
rtu_prio_i : in std_logic_vector(c_swc_prio_width - 1 downto 0)
);
end swc_core;
architecture rtl of swc_core is
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Memory Management Unit<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Memory Management Unit
signal ib_page_alloc_req : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_output : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_set_usecnt : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_usecnt : std_logic_vector(c_swc_num_ports * c_swc_usecount_width - 1 downto 0);
-- Memory Management Unit -> Input Block
signal mmu_page_alloc_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mmu_pageaddr_input : std_logic_vector( 1 * c_swc_page_addr_width - 1 downto 0);
signal mmu_set_usecnt_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mmu_nomem : std_logic;
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Multiport Memory<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Multiport Memory
signal ib_pckstart : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_to_mpm : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_pagereq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal ib_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
signal ib_drdy : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_flush : std_logic_vector(c_swc_num_ports - 1 downto 0);
-- Multiport Memory -> Input Block
signal mpm_pageend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_full : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Pck Transfer Arbiter<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Pck Transfer Arbiter
signal ib_transfer_pck : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_pageaddr_to_pta : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ib_mask : std_logic_vector(c_swc_num_ports * c_swc_num_ports - 1 downto 0);
signal ib_prio : std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
signal ib_pck_size : std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
-- Pck Transfer Arbiter -> Input Block
signal pta_transfer_ack : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Pck Transfer Arbiter<<
----------------------------------------------------------------------------------------------------
-- Input Block -> Pck Transfer Arbiter
signal pta_data_valid : std_logic_vector(c_swc_num_ports -1 downto 0);
signal pta_pageaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal pta_prio : std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
signal pta_pck_size : std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
-- Input Block -> Pck Transfer Arbiter
signal ob_ack : std_logic_vector(c_swc_num_ports -1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Multiport Memory<<
----------------------------------------------------------------------------------------------------
-- Output Block -> Multiport Memory
signal ob_pgreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ob_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal ob_dreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
-- Multiport Memory -> Output Block
signal mpm_pckend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_pgend : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_drdy : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal mpm_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Muliport Memory<< with >>Linked List<<
----------------------------------------------------------------------------------------------------
-- Multiport Memory -> Linked List
signal mpm_write : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_write_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal mpm_write_data : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
signal mpm_read_pump_read : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal mpm_read_pump_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- Linked List -> Multiport memory
-- signal ll_free_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_write_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_read_pump_read_done : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_data : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Input Block<< with >>Pck's pages freeeing module<<
----------------------------------------------------------------------------------------------------
-- Input block -> Lost pck dealloc
signal ib_force_free : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ib_force_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- lost pck dealloc -> input block
signal ppfm_force_free_done_to_ib : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Output Block<< with >>Pck's Pages Freeing Module (PPFM)<<
----------------------------------------------------------------------------------------------------
-- output block -> Lost pck dealloc
signal ob_free : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ob_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- lost pck dealloc -> output block
signal ppfm_free_done_to_ob : std_logic_vector(c_swc_num_ports - 1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Pck's pages freeeing module<< with >>Linkded List<<
----------------------------------------------------------------------------------------------------
-- LPD -> LL
signal ppfm_read_addr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
signal ppfm_read_req : std_logic_vector(c_swc_num_ports-1 downto 0);
-- LL -> LPD
signal ll_read_valid_data : std_logic_vector(c_swc_num_ports-1 downto 0);
----------------------------------------------------------------------------------------------------
-- signals connecting >>Pck's pages freeing module (PPFM)<< with >>Page allocator (MMU)<<
----------------------------------------------------------------------------------------------------
-- PPFM -> MMU
signal ppfm_force_free : std_logic_vector(c_swc_num_ports-1 downto 0);
signal ppfm_force_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
signal ppfm_free : std_logic_vector(c_swc_num_ports-1 downto 0);
signal ppfm_free_pgaddr : std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
-- MMU -> PPFM
signal mmu_force_free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal mmu_free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
----------------------------------------------------------------------------------------------------
-- tmp
----------------------------------------------------------------------------------------------------
signal tx_sof_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_eof_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal tx_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
signal tx_valid : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_bytesel : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_dreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_abort_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal tx_rerror_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_sof_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_eof_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_dreq : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_ctrl : std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
signal rx_data : std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
signal rx_valid : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_bytesel : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_idle : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_rerror_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_terror_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rx_rabort_p1 : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rtu_rsp_valid : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rtu_rsp_ack : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rtu_dst_port_mask : std_logic_vector(c_swc_num_ports * c_swc_num_ports - 1 downto 0);
signal rtu_drop : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal rtu_prio : std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
---- end tmp
begin --rtl
---- tmp
tx_sof_p1(0) <= tx_sof_p1_i;
tx_sof_p1(c_swc_num_ports - 1 downto 1) <= (others=>'0');
tx_eof_p1(0) <= tx_eof_p1_i;
tx_eof_p1(c_swc_num_ports - 1 downto 1) <= (others=>'0');
tx_data(c_swc_data_width - 1 downto 0) <= tx_data_i;
tx_data(c_swc_num_ports * c_swc_data_width - 1 downto c_swc_data_width) <= (others=>'0');
tx_ctrl(c_swc_ctrl_width - 1 downto 0) <= tx_ctrl_i;
tx_ctrl(c_swc_num_ports * c_swc_ctrl_width - 1 downto c_swc_ctrl_width) <= (others=>'0');
tx_valid(0) <= tx_valid_i;
tx_valid(c_swc_num_ports - 1 downto 1) <= (others=>'0');
tx_bytesel(0) <= tx_bytesel_i;
tx_bytesel(c_swc_num_ports - 1 downto 1) <= (others=>'0');
tx_dreq_o <= tx_dreq(0);
tx_abort_p1(0) <= tx_abort_p1_i;
tx_abort_p1(c_swc_num_ports - 1 downto 1) <= (others=>'0');
tx_rerror_p1(0) <= tx_rerror_p1_i;
tx_rerror_p1(c_swc_num_ports - 1 downto 1) <= (others=>'0');
rx_sof_p1_o <= rx_sof_p1(0);
rx_eof_p1_o <= rx_eof_p1(0);
rx_ctrl_o <= rx_ctrl(c_swc_ctrl_width - 1 downto 0);
rx_data_o <= rx_data(c_swc_data_width - 1 downto 0);
rx_valid_o <= rx_valid(0) ;
rx_bytesel_o <= rx_bytesel(0) ;
rx_idle_o <= rx_idle(0);
rx_rerror_p1_o<= rx_rerror_p1(0);
rx_terror_p1(0) <= rx_terror_p1_i;
rx_terror_p1(c_swc_num_ports - 1 downto 1) <= (others => '0');
rx_rabort_p1(0) <= rx_rabort_p1_i;
rx_rabort_p1(c_swc_num_ports - 1 downto 1) <= (others => '0');
rx_dreq(0) <= rx_dreq_i;
rx_dreq(c_swc_num_ports - 1 downto 1) <= (others => '0');
rtu_rsp_valid(0) <= rtu_rsp_valid_i;
rtu_rsp_valid(c_swc_num_ports - 1 downto 1) <= (others=> '0');
rtu_rsp_ack_o <= rtu_rsp_ack(0);
rtu_drop(0) <= rtu_drop_i;
rtu_drop(c_swc_num_ports - 1 downto 1) <= (others=> '0');
rtu_dst_port_mask(c_swc_num_ports - 1 downto 0) <= rtu_dst_port_mask_i;
rtu_dst_port_mask(c_swc_num_ports * c_swc_num_ports - 1 downto c_swc_num_ports) <= (others=> '0');
rtu_prio(c_swc_prio_width - 1 downto 0) <= rtu_prio_i;
rtu_prio(c_swc_prio_width * c_swc_num_ports - 1 downto c_swc_prio_width)<= (others=> '0');
---- end timp
gen_blocks : for i in 0 to c_swc_num_ports-1 generate
INPUT_BLOCK : swc_input_block
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- Fabric I/F
------------------------------------------------------------------------------
tx_sof_p1_i => tx_sof_p1(i),
tx_eof_p1_i => tx_eof_p1(i),
tx_data_i => tx_data((i + 1) * c_swc_data_width -1 downto i * c_swc_data_width),
tx_ctrl_i => tx_ctrl((i + 1) * c_swc_ctrl_width -1 downto i * c_swc_ctrl_width),
tx_valid_i => tx_valid(i),
tx_bytesel_i => tx_bytesel(i),
tx_dreq_o => tx_dreq(i),
tx_abort_p1_i => tx_abort_p1(i),
tx_rerror_p1_i => tx_rerror_p1(i),
-------------------------------------------------------------------------------
-- I/F with Page allocator (MMU)
-------------------------------------------------------------------------------
mmu_page_alloc_req_o => ib_page_alloc_req(i),
mmu_page_alloc_done_i => mmu_page_alloc_done(i),
mmu_pageaddr_i => mmu_pageaddr_input,
mmu_pageaddr_o => ib_pageaddr_output((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
mmu_set_usecnt_o => ib_set_usecnt(i),
mmu_set_usecnt_done_i => mmu_set_usecnt_done(i),
mmu_usecnt_o => ib_usecnt((i + 1) * c_swc_usecount_width -1 downto i * c_swc_usecount_width),
mmu_nomem_i => mmu_nomem,
-------------------------------------------------------------------------------
-- I/F with Pck's Pages Freeing Module (PPFM)
-------------------------------------------------------------------------------
mmu_force_free_o => ib_force_free(i),
mmu_force_free_done_i => ppfm_force_free_done_to_ib(i),
mmu_force_free_addr_o => ib_force_free_pgaddr((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
-------------------------------------------------------------------------------
-- I/F with Routing Table Unit (RTU)
-------------------------------------------------------------------------------
rtu_rsp_valid_i => rtu_rsp_valid(i),
rtu_rsp_ack_o => rtu_rsp_ack(i),
rtu_dst_port_mask_i => rtu_dst_port_mask((i + 1) * c_swc_num_ports -1 downto i * c_swc_num_ports),
rtu_drop_i => rtu_drop(i),
rtu_prio_i => rtu_prio((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
-------------------------------------------------------------------------------
-- I/F with Multiport Memory (MPU)
-------------------------------------------------------------------------------
mpm_pckstart_o => ib_pckstart(i),
mpm_pageaddr_o => ib_pageaddr_to_mpm((i + 1) * c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
mpm_pagereq_o => ib_pagereq(i),
mpm_pageend_i => mpm_pageend(i),
mpm_data_o => ib_data((i + 1) * c_swc_data_width - 1 downto i * c_swc_data_width),
mpm_ctrl_o => ib_ctrl((i + 1) * c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width),
mpm_drdy_o => ib_drdy(i),
mpm_full_i => mpm_full(i),
mpm_flush_o => ib_flush(i),
-------------------------------------------------------------------------------
-- I/F with Page Transfer Arbiter (PTA)
-------------------------------------------------------------------------------
pta_transfer_pck_o => ib_transfer_pck(i),
pta_transfer_ack_i => pta_transfer_ack(i),
pta_pageaddr_o => ib_pageaddr_to_pta((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
pta_mask_o => ib_mask ((i + 1) * c_swc_num_ports -1 downto i * c_swc_num_ports),
pta_prio_o => ib_prio ((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
pta_pck_size_o => ib_pck_size ((i + 1) * c_swc_max_pck_size_width -1 downto i * c_swc_max_pck_size_width)
);
OUTPUT_BLOCK: swc_output_block
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Page Transfer Arbiter (PTA)
-------------------------------------------------------------------------------
pta_transfer_data_valid_i=> pta_data_valid(i),
pta_pageaddr_i => pta_pageaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
pta_prio_i => pta_prio ((i + 1) * c_swc_prio_width -1 downto i * c_swc_prio_width),
pta_pck_size_i => pta_pck_size((i + 1) * c_swc_max_pck_size_width -1 downto i * c_swc_max_pck_size_width),
pta_transfer_data_ack_o => ob_ack(i),
-------------------------------------------------------------------------------
-- I/F with Multiport Memory (MPM)
-------------------------------------------------------------------------------
mpm_pgreq_o => ob_pgreq(i),
mpm_pgaddr_o => ob_pgaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
mpm_pckend_i => mpm_pckend(i),
mpm_pgend_i => mpm_pgend(i),
mpm_drdy_i => mpm_drdy(i),
mpm_dreq_o => ob_dreq(i),
mpm_data_i => mpm_data((i + 1) * c_swc_data_width - 1 downto i * c_swc_data_width),
mpm_ctrl_i => mpm_ctrl((i + 1) * c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width),
-------------------------------------------------------------------------------
-- I/F with Pck's Pages Freeing Module (PPFM)
-------------------------------------------------------------------------------
ppfm_free_o => ob_free(i),
ppfm_free_done_i => ppfm_free_done_to_ob(i),
ppfm_free_pgaddr_o => ob_free_pgaddr((i + 1) * c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
-------------------------------------------------------------------------------
-- Fabric I/F
-------------------------------------------------------------------------------
rx_sof_p1_o => rx_sof_p1(i),
rx_eof_p1_o => rx_eof_p1(i),
rx_dreq_i => rx_dreq(i),
rx_ctrl_o => rx_ctrl((i + 1) * c_swc_ctrl_width -1 downto i * c_swc_ctrl_width),
rx_data_o => rx_data((i + 1) * c_swc_data_width -1 downto i * c_swc_data_width),
rx_valid_o => rx_valid(i),
rx_bytesel_o => rx_bytesel(i),
rx_idle_o => rx_idle(i),
rx_rerror_p1_o => rx_rerror_p1(i),
rx_terror_p1_i => rx_terror_p1(i),
rx_rabort_p1_i => rx_rabort_p1(i)
);
end generate gen_blocks;
PCK_PAGES_FREEEING_MODULE: swc_multiport_pck_pg_free_module
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
ib_force_free_i => ib_force_free,
ib_force_free_done_o => ppfm_force_free_done_to_ib,
ib_force_free_pgaddr_i => ib_force_free_pgaddr,
ob_free_i => ob_free,
ob_free_done_o => ppfm_free_done_to_ob,
ob_free_pgaddr_i => ob_free_pgaddr,
ll_read_addr_o => ppfm_read_addr,
ll_read_data_i => ll_data,
ll_read_req_o => ppfm_read_req,
ll_read_valid_data_i => ll_read_valid_data,
mmu_force_free_o => ppfm_force_free,
mmu_force_free_done_i => mmu_force_free_done,
mmu_force_free_pgaddr_o => ppfm_force_free_pgaddr,
mmu_free_o => ppfm_free,
mmu_free_done_i => mmu_free_done,
mmu_free_pgaddr_o => ppfm_free_pgaddr
);
LINKED_LIST: swc_multiport_linked_list
port map(
rst_n_i => rst_n_i,
clk_i => clk_i,
write_i => mpm_write,
write_done_o => ll_write_done,
write_addr_i => mpm_write_addr,
write_data_i => mpm_write_data,
-- not used for the time being
free_i => (others => '0'),
free_done_o => open,
free_addr_i => (others => '0'),
read_pump_read_i => mpm_read_pump_read,
read_pump_read_done_o => ll_read_pump_read_done,
read_pump_addr_i => mpm_read_pump_addr,
free_pck_read_i => ppfm_read_req,
free_pck_read_done_o => ll_read_valid_data,
free_pck_addr_i => ppfm_read_addr,
data_o => ll_data
);
----------------------------------------------------------------------
-- Memory Mangement Unit (MMU)
----------------------------------------------------------------------
MEMORY_MANAGEMENT_UNIT: swc_multiport_page_allocator
port map (
rst_n_i => rst_n_i,
clk_i => clk_i,
alloc_i => ib_page_alloc_req,
alloc_done_o => mmu_page_alloc_done,
pgaddr_alloc_o => mmu_pageaddr_input,
set_usecnt_i => ib_set_usecnt,
set_usecnt_done_o => mmu_set_usecnt_done,
usecnt_i => ib_usecnt,
free_i => ppfm_free,
free_done_o => mmu_free_done,
pgaddr_free_i => ppfm_free_pgaddr,
force_free_i => ppfm_force_free,
force_free_done_o => mmu_force_free_done,
pgaddr_force_free_i => ppfm_force_free_pgaddr,
nomem_o => mmu_nomem
);
----------------------------------------------------------------------
-- MultiPort Memory (MPM) [ 1 module]
----------------------------------------------------------------------
MUPTIPORT_MEMORY: swc_packet_mem
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Input Block (IB)
-------------------------------------------------------------------------------
wr_pagereq_i => ib_pagereq,
wr_pckstart_i => ib_pckstart,
wr_pageaddr_i => ib_pageaddr_to_mpm,
wr_pageend_o => mpm_pageend,
wr_ctrl_i => ib_ctrl,
wr_data_i => ib_data,
wr_drdy_i => ib_drdy,
wr_full_o => mpm_full,
wr_flush_i => ib_flush,
-------------------------------------------------------------------------------
-- I/F with Output Block
-------------------------------------------------------------------------------
rd_pagereq_i => ob_pgreq,
rd_pageaddr_i => ob_pgaddr,
rd_pageend_o => mpm_pckend,
rd_pckend_o => mpm_pgend,
rd_drdy_o => mpm_drdy,
rd_dreq_i => ob_dreq,
--!!!!!!!!!!
rd_sync_read_i => ob_pgreq, -- TODO ???
--!!!!!!!!!!!!!!!!!!
rd_data_o => mpm_data,
rd_ctrl_o => mpm_ctrl,
write_o => mpm_write,
write_done_i => ll_write_done,
write_addr_o => mpm_write_addr,
write_data_o => mpm_write_data,
read_pump_read_o => mpm_read_pump_read,
read_pump_read_done_i => ll_read_pump_read_done,
read_pump_addr_o => mpm_read_pump_addr,
data_i => ll_data
);
----------------------------------------------------------------------
-- Page Transfer Arbiter [ 1 module]
----------------------------------------------------------------------
TRANSER_ARBITER: swc_pck_transfer_arbiter
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
-------------------------------------------------------------------------------
-- I/F with Output Block (OB)
-------------------------------------------------------------------------------
ob_data_valid_o => pta_data_valid,
ob_ack_i => ob_ack,
ob_pageaddr_o => pta_pageaddr,
ob_prio_o => pta_prio,
ob_pck_size_o => pta_pck_size,
-------------------------------------------------------------------------------
-- I/F with Input Block (IB)
-------------------------------------------------------------------------------
ib_transfer_pck_i => ib_transfer_pck,
ib_transfer_ack_o => pta_transfer_ack,
ib_busy_o => open,
ib_pageaddr_i => ib_pageaddr_to_pta,
ib_mask_i => ib_mask,
ib_prio_i => ib_prio,
ib_pck_size_i => ib_pck_size
);
end rtl;
-------------------------------------------------------------------------------
-- Title : Input block
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_input_block.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-10-28
-- Last update: 2011-03-16
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: This block controls input to SW Core. It consists of a three
-- Finite State Machines (FSMs):
-- 1) Read FSM - read information from Fabric Interface and stores it in FIFO
--
-- 2) Write FSM - reads data from FIFO and writes it into write pump
--
-- 3) Page FSM - allocates pages in advance and sets usecnt of pages, i.e
-- * it allocates in advance one page to be used as the first page
-- of the pck (pckstart)
-- * it allocates in advnace one page to be used within the pck (interpck)
-- * it sets usecnt of pckstart page if it's different then the one set
-- durring allocation
-- * it sets usecnt of interpck page if it's different then the one set
-- durring allocation
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-01 1.0 mlipinsk created
-- 2010-11-29 2.0 mlipinsk added FIFO, major changes
--
-------------------------------------------------------------------------------
-- TODO:
-- 1) dreq HIGH in idle ?
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
use work.genram_pkg.all;
entity swc_input_block is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- Fabric I/F
-------------------------------------------------------------------------------
tx_sof_p1_i : in std_logic;
tx_eof_p1_i : in std_logic;
tx_data_i : in std_logic_vector(c_swc_data_width - 1 downto 0);
tx_ctrl_i : in std_logic_vector(c_swc_ctrl_width - 1 downto 0);
tx_valid_i : in std_logic;
tx_bytesel_i : in std_logic;
tx_dreq_o : out std_logic;
tx_abort_p1_i : in std_logic;
tx_rerror_p1_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Page allocator (MMU)
-------------------------------------------------------------------------------
-- indicates that a port X wants to write page address of the "write" access
mmu_page_alloc_req_o : out std_logic;
mmu_page_alloc_done_i : in std_logic;
-- array of pages' addresses to which ports want to write
mmu_pageaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
mmu_pageaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- force freeing package starting with page outputed on mmu_pageaddr_o
mmu_force_free_o : out std_logic;
mmu_force_free_done_i : in std_logic;
mmu_force_free_addr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- set user count to the already allocated page (on mmu_pageaddr_o)
mmu_set_usecnt_o : out std_logic;
mmu_set_usecnt_done_i : in std_logic;
-- user count to be set (associated with an allocated page) in two cases:
-- * mmu_pagereq_o is HIGH - normal allocation
-- * mmu_set_usecnt_o is HIGH - force user count to existing page alloc
mmu_usecnt_o : out std_logic_vector(c_swc_usecount_width - 1 downto 0);
-- memory full
mmu_nomem_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Routing Table Unit (RTU)
-------------------------------------------------------------------------------
rtu_rsp_valid_i : in std_logic;
rtu_rsp_ack_o : out std_logic;
rtu_dst_port_mask_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
rtu_drop_i : in std_logic;
rtu_prio_i : in std_logic_vector(c_swc_prio_width - 1 downto 0);
-------------------------------------------------------------------------------
-- I/F with Multiport Memory (MPU)
-------------------------------------------------------------------------------
-- indicates the beginning of the package
mpm_pckstart_o : out std_logic;
-- array of pages' addresses to which ports want to write
mpm_pageaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
mpm_pagereq_o : out std_logic;
-- indicator that the current page is about to be full (the last FB SRAM word
-- is being pumped in currently), after ~c_swc_packet_mem_multiply cycles
-- from the rising edge of this signal this page will finish
mpm_pageend_i : in std_logic;
mpm_data_o : out std_logic_vector(c_swc_data_width - 1 downto 0);
mpm_ctrl_o : out std_logic_vector(c_swc_ctrl_width - 1 downto 0);
-- data ready - request from each port to write data to port's pump
mpm_drdy_o : out std_logic;
-- the input register of a pump is full, this means that the pump cannot
-- be written by the port. As soon as the data which is in the input registet
-- is written to FB SRAM memory, the signal goes LOW and writing is possible
mpm_full_i : in std_logic;
-- request to write the content of pump's input register to FB SRAM memory,
-- thus flash/clean input register of the pump
mpm_flush_o : out std_logic;
mpm_wr_sync_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Page Transfer Arbiter (PTA)
-------------------------------------------------------------------------------
-- indicates the beginning of the package, strobe
pta_transfer_pck_o : out std_logic;
pta_transfer_ack_i : in std_logic;
-- array of pages' addresses to which ports want to write
pta_pageaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- destination mask - indicates to which ports the packet should be
-- forwarded
pta_mask_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
pta_pck_size_o : out std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
pta_prio_o : out std_logic_vector(c_swc_prio_width - 1 downto 0)
);
end swc_input_block;
architecture syn of swc_input_block is
signal fifo_data_in : std_logic_vector(c_swc_data_width + c_swc_ctrl_width + 2 - 1 downto 0);
signal fifo_wr : std_logic;
signal fifo_clean : std_logic;
signal fifo_clear_n : std_logic;
signal fifo_rd : std_logic;
signal fifo_data_out : std_logic_vector(c_swc_data_width + c_swc_ctrl_width + 2 - 1 downto 0);
signal fifo_empty : std_logic;
signal fifo_full : std_logic;
signal fifo_usedw : std_logic_vector(5 -1 downto 0);
signal tx_ctrl_trans : std_logic_vector(c_swc_ctrl_width - 1 downto 0);
signal transfering_pck : std_logic;
signal pta_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal pta_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal pta_prio : std_logic_vector(c_swc_prio_width - 1 downto 0);
signal pta_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal write_ctrl_in : std_logic_vector(1 downto 0);
signal write_ctrl_out : std_logic_vector(1 downto 0);
signal write_ctrl : std_logic_vector(c_swc_ctrl_width - 1 downto 0);
signal write_data : std_logic_vector(c_swc_data_width - 1 downto 0);
signal read_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal read_prio : std_logic_vector(c_swc_prio_width - 1 downto 0);
signal read_usecnt : std_logic_vector(c_swc_usecount_width - 1 downto 0);
signal write_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal write_prio : std_logic_vector(c_swc_prio_width - 1 downto 0);
signal write_usecnt : std_logic_vector(c_swc_usecount_width - 1 downto 0);
signal pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal current_pckstart_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal usecnt_d0 : std_logic_vector(c_swc_usecount_width - 1 downto 0);
type t_read_state is (S_IDLE, -- we wait for other processes (page fsm and
-- transfer) to be ready
S_READY_FOR_PCK, -- this is introduced to diminish optimization
-- (optimized design did not work) in this state,
S_WAIT_FOR_SOF, -- we've got RTU response, but there is no SOF
S_WAIT_FOR_RTU_RSP, -- we've got SOF (request from previous pck) but
-- there is no RTU valid signal (quite improbable)
S_WRITE_FIFO, -- all the writing to FIFO done here
S_WRITE_DUMMY_EOF, -- in case the EOF signal is not when VALID is high
-- we write dummy word to FIFO with fifo_ctrl data
-- saying that it's dummy end of pck
S_WAIT_FOR_CLEAN_FIFO, -- if the pck which is to be dropped is not the only
-- one in the fifo, we need to wait for the other one
-- to be written to the write_pump, and than we can
-- clean the fifo
S_DROP_PCK); -- droping pck
type t_page_state is (S_IDLE, -- waiting for some work :)
S_PCKSTART_SET_USECNT, -- setting usecnt to a page which was allocated
-- in advance to be used for the first page of
-- the pck
-- (only in case of the initially allocated usecnt
-- is different than required)
S_INTERPCK_SET_USECNT, -- setting usecnt to a page which was allocated
-- in advance to be used for the page which is
-- not first
-- in the pck, this is needed, only if the page
-- was allocated during transfer of previous pck
-- but was not used in the previous pck,
-- only if usecnt of both pcks are different
S_PCKSTART_PAGE_REQ, -- allocating in advnace first page of the pck
S_INTERPCK_PAGE_REQ); -- allocating in advance page to be used by
-- all but first page of the pck
type t_write_state is (S_IDLE,
S_START_FIFO_RD, -- start requesting data from FIFO, but still
-- not outputing to write_pump (initial cycle)
-- trick: drdy restricted only to S_WRITE_MPM
-- (see comments in the FSM)
S_WRITE_MPM, -- reading FIFO, writing write_pump
S_LAST_MPM_WR, -- last word of pck already written, finishing
-- pck writting
S_NEW_PCK_IN_FIFO, -- if there is beginning of new pck in the fifo
-- we use this state (not IDLE) to wait for the
-- possibilty to start new new pck write
S_WAIT_WITH_TRANSFER, -- if we get to the end of the pck, in normal case
-- we transfer startpck address, pcksize and pck prio
-- to output ports. If the transfer of the previous pck
-- data has not finished yet (only in case the traffic
-- is really heavy), we need to wait for it to be
-- finished
S_PERROR -- handling perror
);
-- we love VHDL
signal zeros : std_logic_vector(63 downto 0);
-- FSMs
signal read_state : t_read_state;
signal write_state : t_write_state;
signal page_state : t_page_state;
-- pckstart page allocation in advance
signal pckstart_page_in_advance : std_logic;
signal pckstart_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal pckstart_page_alloc_req : std_logic;
signal pckstart_usecnt_req : std_logic;
signal pckstart_usecnt_in_advance: std_logic_vector(c_swc_usecount_width - 1 downto 0);
-- interpck page allocation in advance
signal interpck_page_in_advance : std_logic;
signal interpck_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal interpck_page_alloc_req : std_logic;
signal interpck_usecnt_req : std_logic;
signal interpck_usecnt_in_advance: std_logic_vector(c_swc_usecount_width - 1 downto 0);
-- pck usecnt setting
signal need_pckstart_usecnt_set : std_logic;
signal need_interpck_usecnt_set : std_logic;
-- errored pck freeing
signal mmu_force_free_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal mmu_force_free : std_logic;
-- error signal handling
signal tx_rerror_reg : std_logic;
signal tx_rerror_or : std_logic;
signal tx_rerror : std_logic;
-- data requset
signal tx_dreq : std_logic;
-- multiport memory I/F
signal mpm_pckstart : std_logic;
signal mpm_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal mpm_pagereq : std_logic;
signal mpm_flush : std_logic;
-- help signal for MPM I/F
signal flush_sig : std_logic;
signal flush_reg : std_logic;
-- pck info transfer signal
signal start_transfer : std_logic;
-- RTU I/F
signal rtu_rsp_ack : std_logic;
signal tmp_cnt : std_logic_vector(7 downto 0);
signal fifo_populated_enough : std_logic;
signal first_pck_word : std_logic;
signal clean_pck_cnt : std_logic;
-- signals used to check whether there is only
-- one pck in the FIFO by detecting SOF and EOF
-- in the FIFO, used for error handling
signal sof_in_fifo : std_logic;
signal eof_in_fifo : std_logic;
-- indicates that FIFO is going to be full
-- this is to simplify things: disable dreq
-- when FIFO full
signal fifo_full_in_advance : std_logic;
signal drdy : std_logic;
-- to make if-condition simpler
signal flush_with_valid_data : std_logic;
-------------------------------------------------------------------------------
-- Function which calculates number of 1's in a vector
-------------------------------------------------------------------------------
function cnt (a : std_logic_vector) return integer is
variable nmb : integer range 0 to a'length;
variable ai : std_logic_vector(a'length-1 downto 0);
constant middle : integer := a'length/2;
begin
ai := a;
if ai'length >= 2 then
nmb := cnt(ai(ai'length-1 downto middle)) + cnt(ai(middle-1 downto 0));
else
if ai(0) = '1' then
nmb := 1;
else
nmb := 0;
end if;
end if;
return nmb;
end cnt;
begin --arch
zeros <= (others => '0');
-- adding info about tx_bytesel
tx_ctrl_trans <= b"1111" when (tx_ctrl_i = x"7" and tx_bytesel_i = '1') else tx_ctrl_i;
--==================================================================================================
-- FIFO
--==================================================================================================
fifo_data_in(c_swc_data_width - 1 downto 0) <= tx_data_i;
fifo_data_in(c_swc_data_width +
c_swc_ctrl_width - 1 downto c_swc_data_width) <= tx_ctrl_trans;
fifo_data_in(c_swc_data_width +
c_swc_ctrl_width + 1 downto c_swc_data_width +
c_swc_ctrl_width) <= write_ctrl_in;
write_ctrl_in <= b"01" when (first_pck_word = '1') else
b"10" when (tx_valid_i = '1' and tx_eof_p1_i = '1') else
b"11" when (read_state = S_WRITE_DUMMY_EOF) else
b"00";
write_ctrl_out <= fifo_data_out(c_swc_data_width + c_swc_ctrl_width + 1 downto c_swc_data_width +
c_swc_ctrl_width);
write_data <= fifo_data_out(c_swc_data_width - 1 downto 0);
write_ctrl <= fifo_data_out(c_swc_data_width + c_swc_ctrl_width - 1 downto c_swc_data_width);
fifo_wr <= '1' when (read_state = S_WRITE_DUMMY_EOF)
else tx_valid_i when (read_state = S_WRITE_FIFO) else '0';
fifo_rd <= ((not fifo_empty) and (not mpm_full_i)) when (write_state = S_WRITE_MPM or
write_state = S_START_FIFO_RD) else '0';
fifo_populated_enough <= '1' when
((fifo_usedw > std_logic_vector(to_unsigned(c_swc_packet_mem_multiply, c_swc_input_fifo_size_log2)))
or fifo_full = '1') else '0';
fifo_full_in_advance <= '1'
when ((fifo_usedw > std_logic_vector(to_unsigned(c_swc_fifo_full_in_advance, c_swc_input_fifo_size_log2)))
or fifo_full = '1') else '0';
fifo_clear_n <= not fifo_clean;
U_FIFO : generic_sync_fifo
generic map(
g_data_width => c_swc_data_width + c_swc_ctrl_width + 2,
g_size => c_swc_input_fifo_size,
g_with_count => true
)
port map (
clk_i => clk_i,
rst_n_i => fifo_clear_n,
we_i => fifo_wr,
d_i => fifo_data_in,
rd_i => fifo_rd,
q_o => fifo_data_out,
empty_o => fifo_empty,
full_o => fifo_full,
count_o => fifo_usedw
);
--==================================================================================================
-- PCK size cnt
--==================================================================================================
-- here we calculate pck size: we increment when
-- the valid_i is HIGH
-- cleaning counter
clean_pck_cnt <= '1' when ((write_state = S_START_FIFO_RD) or
(write_state = S_NEW_PCK_IN_FIFO)) else '0';
pck_size_cnt : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
pck_size <= (others => '0');
else
if(clean_pck_cnt = '1') then
pck_size <= (others => '0');
elsif(drdy = '1') then
pck_size <= std_logic_vector(unsigned(pck_size) + 1);
end if;
end if;
end if;
end process;
--==================================================================================================
-- PCK transition (after pck has been received)
--==================================================================================================
-- we need to know whether there is Start of Pck or End of Pck in the FIFO in order to handle
-- errors correctly
transition_check : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--================================================
sof_in_fifo <= '0';
eof_in_fifo <= '0';
--================================================
else
if(tx_sof_p1_i = '1') then
sof_in_fifo <= '1';
elsif(write_ctrl_out = b"01" or tx_rerror = '1') then
sof_in_fifo <= '0';
end if;
--if(tx_eof_p1_i = '1' or tx_rerror_p1_i = '0' ) then
if(tx_eof_p1_i = '1') then
eof_in_fifo <= '1';
elsif(flush_sig = '1') then
eof_in_fifo <= '0';
end if;
end if;
end if;
end process;
--==================================================================================================
-- FSM to read pck from Fabric Interface (F/I <-> FIFO) and RTU response
--==================================================================================================
--
read_fsm : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--================================================
read_state <= S_IDLE;
tx_dreq <= '0';
rtu_rsp_ack <= '0';
read_mask <= (others => '0');
read_prio <= (others => '0');
read_usecnt <= (others => '0');
tx_rerror <= '0';
first_pck_word <= '0';
--================================================
else
-- needed for additionl info we attache to
-- data written to FIFO
if(tx_sof_p1_i = '1') then
first_pck_word <= '1';
elsif(first_pck_word = '1' and tx_valid_i = '1') then
first_pck_word <= '0';
end if;
-- main finite state machine
case read_state is
--========================================================================================
when S_IDLE =>
--========================================================================================
tx_dreq <= '0';
fifo_clean <= '0';
tx_rerror <= '0';
--if(fifo_full = '0' ) then -- obvious: fifo full, no writing
if(fifo_full_in_advance = '0') then -- obvious: fifo full, no writing
-- prepared to be accepting new package
read_state <= S_READY_FOR_PCK;
end if;
--========================================================================================
when S_READY_FOR_PCK =>
--========================================================================================
-- [TODO: conseder change]: merge IDLE and READY_FOR_PCK
fifo_clean <= '0';
tx_dreq <= '0';
if(rtu_rsp_valid_i = '1' and -- we've got RTU decision
(rtu_drop_i = '1' or -- RTU says DROP
rtu_dst_port_mask_i = zeros(c_swc_num_ports - 1 downto 0))) then -- mask = 0 means DROP !!!
-- if we've got RTU decision to drop, we don't give a damn about
-- anything else, just pretend to be receiving the msg
tx_dreq <= '1';
rtu_rsp_ack <= '1';
read_state <= S_DROP_PCK;
elsif(fifo_full = '0') then
if(rtu_rsp_valid_i = '1' and tx_sof_p1_i = '1') then
-- beutifull, everything that is needed, is there:
-- * RTU decision
-- * SOF
read_state <= S_WRITE_FIFO;
tx_dreq <= '1';
rtu_rsp_ack <= '1';
-- remember
read_mask <= rtu_dst_port_mask_i;
read_prio <= rtu_prio_i;
read_usecnt <= std_logic_vector(to_signed(cnt(rtu_dst_port_mask_i), read_usecnt'length));
elsif(rtu_rsp_valid_i = '1' and tx_sof_p1_i = '0') then
-- so we've got RTU decision, but no SOF, let's wait for SOF
-- but remember RTU RSP and ack it, so RTU is free
rtu_rsp_ack <= '1';
read_state <= S_WAIT_FOR_SOF;
tx_dreq <= '1';
--- remember
read_mask <= rtu_dst_port_mask_i;
read_prio <= rtu_prio_i;
read_usecnt <= std_logic_vector(to_signed(cnt(rtu_dst_port_mask_i), read_usecnt'length));
elsif(rtu_rsp_valid_i = '0' and tx_sof_p1_i = '1') then
-- we've got SOF because it was requested at the end of the last PCK
-- but the RTU is still processing
rtu_rsp_ack <= '0';
read_state <= S_WAIT_FOR_RTU_RSP;
tx_dreq <= '0';
end if;
end if;
--========================================================================================
when S_WAIT_FOR_SOF =>
--========================================================================================
rtu_rsp_ack <= '0';
if(tx_sof_p1_i = '1') then
-- very nicely, everything is in place, we can go ahead
tx_dreq <= '1';
read_state <= S_WRITE_FIFO;
end if;
--========================================================================================
when S_WAIT_FOR_RTU_RSP =>
--========================================================================================
if(tx_rerror_p1_i = '1') then
read_state <= S_IDLE;
tx_dreq <= '0';
elsif(rtu_rsp_valid_i = '1') then
tx_dreq <= '1';
rtu_rsp_ack <= '1';
if(rtu_drop_i = '1' or -- RTU says DROP
rtu_dst_port_mask_i = zeros(c_swc_num_ports - 1 downto 0) -- mask = 0 means DROP !!!
) then
read_state <= S_DROP_PCK;
else
read_state <= S_WRITE_FIFO;
--remember
read_mask <= rtu_dst_port_mask_i;
read_prio <= rtu_prio_i;
read_usecnt <= std_logic_vector(to_signed(cnt(rtu_dst_port_mask_i), read_usecnt'length));
end if;
end if;
--========================================================================================
when S_WRITE_FIFO =>
--========================================================================================
if(tx_rerror_p1_i = '1')then
--if(sof_in_fifo = '1') then
if(eof_in_fifo = '1' and sof_in_fifo = '1') then
-- StartOfFrame and EndOfFrame are in the fifo, his means that the error refers to
-- the second pck which is in the FIFO, we have to wait for teh first PCK to be
-- written to MPM and than just clean the second pck from the fifo
read_state <= S_WAIT_FOR_CLEAN_FIFO;
tx_dreq <= '0';
else
-- there is only one pck in the fifo, just stap reception and indicate to
-- Error FSM (tx_rerror) that there is job for it to do, clean what is in
-- the FIFO
read_state <= S_IDLE;
tx_dreq <= '0';
fifo_clean <= '1';
tx_rerror <= '1';
end if;
elsif(tx_valid_i = '1' and tx_eof_p1_i = '1') then
read_state <= S_IDLE;
tx_dreq <= '0';
elsif(tx_valid_i = '0' and tx_eof_p1_i = '1') then
read_state <= S_WRITE_DUMMY_EOF;
tx_dreq <= '0';
else
-- if the fifo usecnt > (max - 3), this enables us to stop
-- Fabric Interface just in time for the FIFO to be full
if(fifo_full_in_advance = '1') then
tx_dreq <= '0';
else
tx_dreq <= '1';
end if;
end if;
--========================================================================================
when S_WAIT_FOR_CLEAN_FIFO =>
--========================================================================================
if(eof_in_fifo = '0') then
-- the valid pck transfered
read_state <= S_IDLE;
tx_dreq <= '0';
fifo_clean <= '1';
tx_rerror <= '1';
end if;
--========================================================================================
when S_WRITE_DUMMY_EOF =>
--========================================================================================
read_state <= S_IDLE;
--========================================================================================
when S_DROP_PCK =>
--========================================================================================
rtu_rsp_ack <= '0';
if(tx_eof_p1_i = '1' or tx_rerror_p1_i = '1') then
read_state <= S_IDLE;
tx_dreq <= '0';
end if;
--========================================================================================
when others =>
--========================================================================================
read_state <= S_IDLE;
tx_dreq <= '0';
--========================================================================================
--========================================================================================
end case;
end if;
end if;
end process;
--==================================================================================================
-- FSM to write pck to Multiport memory write pump (FIFO -> MPM)
--==================================================================================================
--
write_fsm : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--================================================
write_state <= S_IDLE;
start_transfer <= '0';
mpm_pckstart <= '0';
mpm_pagereq <= '0';
current_pckstart_pageaddr <= (others => '1');
write_mask <= (others => '0');
write_prio <= (others => '0');
write_usecnt <= (others => '0');
mpm_pckstart <= '0';
mpm_pageaddr <= (others => '1');
mpm_pagereq <= '0';
flush_reg <= '0';
mmu_force_free_addr <= (others => '0');
mmu_force_free <= '0';
--================================================
else
-- main finite state machine
case write_state is
--========================================================================================
when S_IDLE =>
--========================================================================================
start_transfer <= '0';
flush_reg <= '0';
start_transfer <= '0';
mpm_pagereq <= '0';
if((fifo_populated_enough = '1') and -- at least on "c_swc_packet_mem_multiply"
(pckstart_page_in_advance = '1') and -- needed to write first page
mpm_full_i = '0') then -- obvious, no write to full MPM
write_state <= S_START_FIFO_RD;
end if;
--========================================================================================
when S_START_FIFO_RD =>
--========================================================================================
-- here is a small trick, we already request data from FIFO with fifo_rd HIHG
-- but the drdy (which is the same signal as fifo_rd) is not HIGH here because
-- drdy is restricted only to S_WRITE_MPM !!! thanx to this trick we can have things
-- simple
write_state <= S_WRITE_MPM;
-- first word of the pck, need to be remembered (for i.e. transfer, force free)
current_pckstart_pageaddr <= pckstart_pageaddr;
write_mask <= read_mask;
write_prio <= read_prio;
write_usecnt <= read_usecnt;
-- indicate this is the first pck, set page
mpm_pckstart <= '1';
mpm_pagereq <= '1';
mpm_pageaddr <= pckstart_pageaddr;
--========================================================================================
when S_WRITE_MPM =>
--========================================================================================
mpm_pckstart <= '0';
mpm_pagereq <= '0';
------------------------------------------------------------------------------------------
if(tx_rerror = '1') then -- handling error, this signal is generated by read_fsm
------------------------------------------------------------------------------------------
flush_reg <= '1';
write_state <= S_PERROR;
mmu_force_free_addr <= current_pckstart_pageaddr;
mmu_force_free <= '1';
------------------------------------------------------------------------------------------
elsif(write_ctrl_out /= b"01" and -- the data coming from FIFO indicates its not first
-- word of PCK
mpm_pckstart = '1') then -- we are saying to MPM it's first word of PCK
------------------------------------------------------------------------------------------
-- this is pathologic situation, bad, not sure what to do
assert false
report "write_fsm: S_WRITE_MPM, should not go here";
write_state <= S_START_FIFO_RD;
------------------------------------------------------------------------------------------
else -- in normal case, we end up here
------------------------------------------------------------------------------------------
if(mpm_pagereq = '0' and -- not setting yet new page
mpm_pageend_i = '1' and -- detecting info from MPM: new page needed
interpck_page_in_advance = '1') then -- we have a spare page allocated
mpm_pageaddr <= interpck_pageaddr;
mpm_pagereq <= '1';
else
mpm_pageaddr <= (others => '1');
mpm_pagereq <= '0';
end if;
if(write_ctrl_out = b"11" or -- EOF with valid data
write_ctrl_out = b"10") then -- EOF without valid data
write_state <= S_LAST_MPM_WR;
end if;
------------------------------------------------------------------------------------------
end if;
--===========================================================================================
when S_LAST_MPM_WR =>
--===========================================================================================
start_transfer <= '0';
flush_reg <= '0';
mpm_pageaddr <= (others => '1');
mpm_pagereq <= '0';
-- if another page needs to be allocated for the last chunck
-- of date, transfer only if we have spare page for that.
-- otherwise, we can end up reading pck without last piece of data !!!!
-- if(interpck_page_in_advance = '0' and -- no spare page
if(mpm_pageend_i = '1') then -- new page needed to write last chucnk of data
write_state <= S_WAIT_WITH_TRANSFER;
else
start_transfer <= '1';
if(write_ctrl_out = b"01") then
write_state <= S_NEW_PCK_IN_FIFO;
else
write_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when S_WAIT_WITH_TRANSFER =>
--===========================================================================================
-- we need to be sure that the last chunk of data is written to MPM before it's read
-- on the other side, if the MPM is full, allocating new page may take looooong time
-- so we transfer only if there is page prepared
-- Of course, this is the case only if the pck finished while pgend request HIGH
if(interpck_page_in_advance = '1') then
start_transfer <= '1';
mpm_pageaddr <= interpck_pageaddr;
mpm_pagereq <= '1';
if(write_ctrl_out = b"01") then
write_state <= S_NEW_PCK_IN_FIFO;
else
write_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when S_NEW_PCK_IN_FIFO =>
--===========================================================================================
start_transfer <= '0';
mpm_pagereq <= '0';
-- i'm not usre here
-- if(mpm_pagereq = '0' and -- not setting yet new page
-- mpm_pageend_i = '1' and -- detecting info from MPM: new page needed
-- interpck_page_in_advance = '1') then -- we have a spare page allocated
--
-- mpm_pageaddr <= interpck_pageaddr;
-- mpm_pagereq <= '1';
--
-- else
--
-- mpm_pageaddr <= (others => '1');
-- mpm_pagereq <= '0';
--
-- end if;
if((fifo_populated_enough = '1') and -- at least on "c_swc_packet_mem_multiply"
(pckstart_page_in_advance = '1') and -- needed to write first page
mpm_full_i = '0') then -- obvious, no write to full MPM
-- first word of the pck
current_pckstart_pageaddr <= pckstart_pageaddr;
write_mask <= read_mask;
write_prio <= read_prio;
write_usecnt <= read_usecnt;
mpm_pckstart <= '1';
mpm_pagereq <= '1';
mpm_pageaddr <= pckstart_pageaddr;
write_state <= S_WRITE_MPM;
end if;
--===========================================================================================
when S_PERROR =>
--===========================================================================================
flush_reg <= '0';
if(mmu_force_free_done_i = '1') then
mmu_force_free <= '0';
write_state <= S_IDLE;
end if;
--===========================================================================================
when others =>
--===========================================================================================
write_state <= S_IDLE;
start_transfer <= '0';
mpm_pckstart <= '0';
mpm_pagereq <= '0';
--===========================================================================================
end case;
--===========================================================================================
end if;
end if;
end process;
--==================================================================================================
-- FSM to allocate pages in advance and set USECNT of pages allocated in advance
--==================================================================================================
-- Auxiliary Finite State Machine which talks with
-- Memory Management Unit, it controls:
-- * page allocation
-- * usecnt setting
fsm_page : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--========================================
page_state <= S_IDLE;
interpck_pageaddr <= (others => '0');
interpck_page_alloc_req <= '0';
interpck_usecnt_in_advance <= (others => '0');
interpck_usecnt_req <= '0';
pckstart_pageaddr <= (others => '0');
pckstart_page_alloc_req <= '0';
pckstart_usecnt_req <= '0';
pckstart_usecnt_in_advance <= (others => '0');
--========================================
else
-- main finite state machine
case page_state is
--===========================================================================================
when S_IDLE =>
--===========================================================================================
interpck_page_alloc_req <= '0';
interpck_usecnt_req <= '0';
pckstart_page_alloc_req <= '0';
pckstart_usecnt_req <= '0';
if((need_pckstart_usecnt_set = '1' and need_interpck_usecnt_set = '1') or
(need_pckstart_usecnt_set = '1' and need_interpck_usecnt_set = '0')) then
page_state <= S_PCKSTART_SET_USECNT;
pckstart_usecnt_req <= '1';
elsif(pckstart_page_in_advance = '0') then
pckstart_page_alloc_req <= '1';
page_state <= S_PCKSTART_PAGE_REQ;
elsif(interpck_page_in_advance = '0') then
interpck_page_alloc_req <= '1';
page_state <= S_INTERPCK_PAGE_REQ;
elsif(need_interpck_usecnt_set = '1') then
page_state <= S_INTERPCK_SET_USECNT;
interpck_usecnt_req <= '1';
end if;
--===========================================================================================
when S_PCKSTART_SET_USECNT =>
--===========================================================================================
if(mmu_set_usecnt_done_i = '1') then
pckstart_usecnt_req <= '0';
-- remember the count of allocated page
-- this is becuase, we will use it for different
-- pck with probably different uscnt
pckstart_usecnt_in_advance <= usecnt_d0;
if(pckstart_page_in_advance = '0') then
pckstart_page_alloc_req <= '1';
page_state <= S_PCKSTART_PAGE_REQ;
elsif(interpck_page_in_advance = '0') then
interpck_page_alloc_req <= '1';
page_state <= S_INTERPCK_PAGE_REQ;
elsif(need_interpck_usecnt_set = '1') then
page_state <= S_INTERPCK_SET_USECNT;
interpck_usecnt_req <= '1';
else
page_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when S_INTERPCK_SET_USECNT =>
--===========================================================================================
if(mmu_set_usecnt_done_i = '1') then
interpck_usecnt_req <= '0';
-- remember the count of allocated page
-- this is becuase, we will use it for different
-- pck with probably different uscnt
-- we do it here as well, because it's possible
-- that this page is not used by the pck
-- which set the USECNT
interpck_usecnt_in_advance <= usecnt_d0;
if(pckstart_page_in_advance = '0') then
pckstart_page_alloc_req <= '1';
page_state <= S_PCKSTART_PAGE_REQ;
elsif(need_pckstart_usecnt_set = '0') then
page_state <= S_PCKSTART_SET_USECNT;
pckstart_usecnt_req <= '1';
elsif(need_interpck_usecnt_set = '1') then
page_state <= S_INTERPCK_SET_USECNT;
interpck_usecnt_req <= '1';
else
page_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when S_PCKSTART_PAGE_REQ =>
--===========================================================================================
if(mmu_page_alloc_done_i = '1') then
pckstart_page_alloc_req <= '0';
-- remember the page start addr
pckstart_pageaddr <= mmu_pageaddr_i;
pckstart_usecnt_in_advance <= usecnt_d0;
if(need_pckstart_usecnt_set = '1') then
page_state <= S_PCKSTART_SET_USECNT;
pckstart_usecnt_req <= '1';
elsif(interpck_page_in_advance = '0') then
interpck_page_alloc_req <= '1';
page_state <= S_INTERPCK_PAGE_REQ;
elsif(need_interpck_usecnt_set = '1') then
page_state <= S_INTERPCK_SET_USECNT;
interpck_usecnt_req <= '1';
else
page_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when S_INTERPCK_PAGE_REQ =>
--===========================================================================================
if(mmu_page_alloc_done_i = '1') then
interpck_page_alloc_req <= '0';
interpck_pageaddr <= mmu_pageaddr_i;
--remember the usecnt which was at the time of
-- page allocation, this is in case that the page
-- is used to store another pck then the current one.
-- therefore we compare this stored value with the
-- current usecnt
interpck_usecnt_in_advance <= usecnt_d0;
interpck_page_alloc_req <= '0';
if(need_pckstart_usecnt_set = '1') then
page_state <= S_PCKSTART_SET_USECNT;
pckstart_usecnt_req <= '1';
elsif(pckstart_page_in_advance = '0') then
pckstart_page_alloc_req <= '1';
page_state <= S_PCKSTART_PAGE_REQ;
elsif(need_interpck_usecnt_set = '1') then
page_state <= S_INTERPCK_SET_USECNT;
interpck_usecnt_req <= '1';
else
page_state <= S_IDLE;
end if;
end if;
--===========================================================================================
when others =>
--===========================================================================================
page_state <= S_IDLE;
end case;
usecnt_d0 <= write_usecnt;
end if;
end if;
end process;
--================================================================================================
-- this proces controls Package Transfer Arbiter
--================================================================================================
pta_if : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--===================================================
transfering_pck <= '0';
pta_pageaddr <= (others => '0');
pta_mask <= (others => '0');
pta_prio <= (others => '0');
pta_pck_size <= (others => '0');
--===================================================
else
if(start_transfer = '1') then
-- normal case, transfer arbiter free
transfering_pck <= '1';
pta_pageaddr <= current_pckstart_pageaddr;
pta_mask <= write_mask;
pta_prio <= write_prio;
pta_pck_size <= pck_size;
pta_pck_size <= std_logic_vector(unsigned(pck_size) - 1);
elsif(pta_transfer_ack_i = '1' and transfering_pck = '1') then
--transfer finished
transfering_pck <= '0';
pta_pageaddr <= (others => '0');
pta_mask <= (others => '0');
pta_prio <= (others => '0');
pta_pck_size <= (others => '0');
end if;
end if;
end if;
end process;
--================================================================================================
-- for page allocation
--================================================================================================
page_if : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--===================================================
pckstart_page_in_advance <= '0';
interpck_page_in_advance <= '0';
need_pckstart_usecnt_set <= '0';
need_interpck_usecnt_set <= '0';
--===================================================
else
if(mpm_pckstart = '1') then
if(read_usecnt = pckstart_usecnt_in_advance) then
need_pckstart_usecnt_set <= '0';
pckstart_page_in_advance <= '0';
else
need_pckstart_usecnt_set <= '1';
end if;
if(read_usecnt = interpck_usecnt_in_advance) then
need_interpck_usecnt_set <= '0';
else
need_interpck_usecnt_set <= '1';
end if;
elsif(page_state = S_INTERPCK_SET_USECNT and mmu_set_usecnt_done_i = '1') then
need_interpck_usecnt_set <= '0';
elsif(page_state = S_PCKSTART_SET_USECNT and mmu_set_usecnt_done_i = '1')then
need_pckstart_usecnt_set <= '0';
end if;
--if(write_state = S_SET_NEXT_PAGE or write_state = S_SET_LAST_NEXT_PAGE) then
if(mpm_pagereq = '1' and mpm_pckstart = '0') then
interpck_page_in_advance <= '0';
elsif(mmu_page_alloc_done_i = '1' and interpck_page_alloc_req = '1') then
interpck_page_in_advance <= '1';
end if;
if(mmu_set_usecnt_done_i = '1' and page_state = S_PCKSTART_SET_USECNT) then
pckstart_page_in_advance <= '0';
elsif(mmu_page_alloc_done_i = '1' and pckstart_page_alloc_req = '1') then
pckstart_page_in_advance <= '1';
end if;
end if;
end if;
end process;
--================================================================================================
-- Output signals
--================================================================================================
tx_dreq_o <=
'0' when tx_eof_p1_i = '1' else
'0' when (read_state = S_IDLE) else
'1' when (read_state = S_DROP_PCK) else
tx_dreq;
flush_with_valid_data <= '1' when (write_ctrl_out = b"10") else '0';
drdy <= ((not (fifo_empty and (not flush_with_valid_data))) and (not mpm_full_i))
when (write_state = S_WRITE_MPM) else '0';
flush_sig <= (write_ctrl_out(1)) when (write_state = S_WRITE_MPM) else '0';
mpm_flush <= flush_reg or flush_sig;
rtu_rsp_ack_o <= rtu_rsp_ack;
mmu_force_free_addr_o <= mmu_force_free_addr;
mmu_set_usecnt_o <= pckstart_usecnt_req or interpck_usecnt_req;
mmu_usecnt_o <= write_usecnt; --read_usecnt;
mmu_page_alloc_req_o <= interpck_page_alloc_req or pckstart_page_alloc_req;
mmu_force_free_o <= mmu_force_free;
mmu_pageaddr_o <= interpck_pageaddr when (page_state = S_INTERPCK_SET_USECNT) else
pckstart_pageaddr when (page_state = S_PCKSTART_SET_USECNT) else (others => '0');
mpm_pckstart_o <= mpm_pckstart;
mpm_pageaddr_o <= mpm_pageaddr;
mpm_pagereq_o <= mpm_pagereq;
mpm_data_o <= write_data;
mpm_ctrl_o <= write_ctrl;
mpm_drdy_o <= drdy;
mpm_flush_o <= mpm_flush;
pta_transfer_pck_o <= transfering_pck;
pta_pageaddr_o <= pta_pageaddr;
pta_mask_o <= pta_mask;
pta_prio_o <= pta_prio;
pta_pck_size_o <= pta_pck_size;
end syn; -- arch
-------------------------------------------------------------------------------
-- Title : Lost Pck Deallocator
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_lost_pck_dealloc.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-15
-- Last update: 2011-03-15
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
--
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-15 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
use work.genram_pkg.all;
entity swc_lost_pck_dealloc is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
ib_force_free_i : in std_logic;
ib_force_free_done_o : out std_logic;
ib_force_free_pgaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ob_force_free_i : in std_logic;
ob_force_free_done_o : out std_logic;
ob_force_free_pgaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_addr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
ll_read_data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_req_o : out std_logic;
ll_read_valid_data_i : in std_logic;
mmu_force_free_o : out std_logic;
mmu_force_free_done_i : in std_logic;
mmu_force_free_pgaddr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0)
);
end swc_lost_pck_dealloc;
architecture syn of swc_lost_pck_dealloc is
type t_state is (S_IDLE,
S_REQ_READ_FIFO,
S_READ_FIFO,
S_READ_NEXT_PAGE_ADDR,
S_FREE_CURRENT_PAGE_ADDR
);
signal state : t_state;
signal ib_force_free_done : std_logic;
signal ob_force_free_done : std_logic;
signal fifo_wr : std_logic;
signal fifo_data_in : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
signal fifo_data_out : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal fifo_rd : std_logic;
signal fifo_clean : std_logic;
signal current_page : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal next_page : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_read_req : std_logic;
signal mmu_force_free : std_logic;
signal ones : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
begin -- syn
ones <= (others => '1');
INPUT: process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
ib_force_free_done <= '0';
ob_force_free_done <= '0';
fifo_wr <= '0';
fifo_data_in <= (others => '0');
else
-- serve Input request, unless it's already served ( ib_force_free_done = '1')
if(ib_force_free_i = '1' and fifo_full = '0' and ib_force_free_done = '0') then
fifo_wr <= '1';
fifo_data_in <= ib_force_free_pgaddr_i;
ib_force_free_done <= '1';
ob_force_free_done <= '0';
elsif(ob_force_free_done = '1' and fifo_full = '0') then
fifo_wr <= '1';
fifo_data_in <= ob_force_free_pgaddr_i;
ob_force_free_done <= '1';
ib_force_free_done <= '0';
else
fifo_wr <= '0';
fifo_data_in <= (others => '0');
ib_force_free_done <= '0';
ob_force_free_done <= '0';
end if;
end if;
end if;
end process;
U_FIFO: generic_sync_fifo
generic map(
g_data_width => c_swc_page_addr_width,
g_size => 16
)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
we_i => fifo_wr,
d_i => fifo_data_in,
rd_i => fifo_rd,
q_o => fifo_data_out,
empty_o => fifo_empty,
full_o => fifo_full,
count_o => open
);
fsm_force_free : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--================================================
state <= S_IDLE;
fifo_rd <= '0';
current_page <= (others => '0');
next_page <= (others => '0');
ll_read_req <= '0';
mmu_force_free <= '0';
--================================================
else
-- main finite state machine
case state is
when S_IDLE =>
fifo_rd <= '0';
mmu_force_free <= '0';
if(fifo_empty = '0') then
fifo_rd <= '1';
state <= S_REQ_READ_FIFO;
end if;
when S_REQ_READ_FIFO =>
fifo_rd <= '0';
state <= S_READ_FIFO;
when S_READ_FIFO =>
current_page <= fifo_data_out;
ll_read_req <= '1';
state <= S_READ_NEXT_PAGE_ADDR;
when S_READ_NEXT_PAGE_ADDR =>
if(ll_read_valid_data_i = '1') then
ll_read_req <= '0';
state <= S_FREE_CURRENT_PAGE_ADDR;
next_page <= ll_read_data_i;
mmu_force_free <= '1';
end if;
when S_FREE_CURRENT_PAGE_ADDR =>
if(mmu_force_free_done_i = '1') then
mmu_force_free <= '0';
if(next_page = ones ) then
state <= S_IDLE;
else
current_page <= next_page;
ll_read_req <= '1';
state <= S_READ_NEXT_PAGE_ADDR;
end if;
end if;
when others =>
state <= S_IDLE;
fifo_rd <= '0';
current_page <= (others => '0');
next_page <= (others => '0');
ll_read_req <= '0';
mmu_force_free <= '0';
end case;
end if;
end if;
end process;
ll_read_addr_o <= current_page;
ll_read_req_o <= ll_read_req;
mmu_force_free_pgaddr_o <= current_page;
mmu_force_free_o <= mmu_force_free;
ib_force_free_done_o <= ib_force_free_done;
ob_force_free_done_o <= ob_force_free_done;
end syn;
-------------------------------------------------------------------------------
-- Title : multiport linked list
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_multiport_linked_list.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-20-26
-- Last update: 2010-20-26
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-10-26 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_multiport_linked_list is
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
write_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
free_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
read_pump_read_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
free_pck_read_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
write_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
free_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
read_pump_read_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
free_pck_read_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
read_pump_addr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
free_pck_addr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
write_addr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
free_addr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
write_data_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
data_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0)
);
end swc_multiport_linked_list;
architecture syn of swc_multiport_linked_list is
component generic_ssram_dualport_singleclock
generic (
g_width : natural;
g_addr_bits : natural;
g_size : natural);
port (
data_i : in std_logic_vector (g_width-1 downto 0);
clk_i : in std_logic;
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0));
end component;
signal ll_write_enable : std_logic;
-- not needed for the SSRAM, needed for the valid/done signal
signal ll_read_enable : std_logic;
signal ll_write_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_free_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_wr_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_rd_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_read_pump_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_free_pck_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_write_data : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal ll_read_data : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal ll_wr_data : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal write_request_vec : std_logic_vector(c_swc_num_ports*2-1 downto 0);
signal read_request_vec : std_logic_vector(c_swc_num_ports*2-1 downto 0);
signal write_request_grant : std_logic_vector(4 downto 0);
signal read_request_grant : std_logic_vector(4 downto 0);
-- indicates that the granted request is valid
signal write_request_grant_valid : std_logic;
signal read_request_grant_valid : std_logic;
-- the number of the port to which request has been granted
signal in_sel_write : integer range 0 to c_swc_num_ports-1;
signal in_sel_read : integer range 0 to c_swc_num_ports-1;
signal write_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal write_done : std_logic_vector(c_swc_num_ports-1 downto 0);
-- indicates that an free has been performed successfully for the
-- given port. Used to prevent considering the currently process
-- port for request to RR arbiter
signal free_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal read_pump_read_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal read_pump_read_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal free_pck_read_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal free_pck_read_done : std_logic_vector(c_swc_num_ports-1 downto 0);
begin -- syn
PAGE_INDEX_LINKED_LIST : generic_ssram_dualport_singleclock
generic map (
g_width => c_swc_page_addr_width,
g_addr_bits => c_swc_page_addr_width,
g_size => c_swc_packet_mem_num_pages --c_swc_packet_mem_size / c_swc_packet_mem_multiply
)
port map (
clk_i => clk_i,
rd_addr_i => ll_rd_addr,
wr_addr_i => ll_wr_addr,
data_i => ll_wr_data,
wr_en_i => ll_write_enable ,
q_o => ll_read_data);
gen_write_request_vec : for i in 0 to c_swc_num_ports - 1 generate
write_request_vec(2 * i + 0) <= write_i(i) and (not (write_done_feedback(i) or write_done(i)));
write_request_vec(2 * i + 1) <= free_i(i) and (not (free_done_feedback(i) or free_done(i)));
end generate gen_write_request_vec;
gen_read_request_vec : for i in 0 to c_swc_num_ports - 1 generate
read_request_vec(2 * i + 0) <= read_pump_read_i(i) and (not (read_pump_read_done_feedback(i) or read_pump_read_done(i)));
read_request_vec(2 * i + 1) <= free_pck_read_i(i) and (not (free_pck_read_done_feedback(i) or free_pck_read_done(i)));
end generate gen_read_request_vec;
-- Round Robin arbiter, quite specific for the usage, since it has the "next"
-- input. It is used to start processing next request well in advance, to prevent
-- unnecessary delays
WRITE_ARB : swc_rr_arbiter
generic map (
g_num_ports => c_swc_num_ports * 2,
g_num_ports_log2 => 5)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
next_i => '1',
request_i => write_request_vec,
grant_o => write_request_grant,
grant_valid_o => write_request_grant_valid);
READ_ARB : swc_rr_arbiter
generic map (
g_num_ports => c_swc_num_ports * 2,
g_num_ports_log2 => 5
)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
next_i => '1',
request_i => read_request_vec,
grant_o => read_request_grant,
grant_valid_o => read_request_grant_valid);
-- port number to which request has been granted.
in_sel_write <= to_integer(unsigned(write_request_grant(write_request_grant'length-1 downto 1)));
in_sel_read <= to_integer(unsigned( read_request_grant( read_request_grant'length-1 downto 1)));
ll_write_enable <= write_request_grant_valid;
ll_read_enable <= read_request_grant_valid;
data_o <= ll_read_data;
-- Getting the address of the page we want to free
-- ======= writing =======
-- data
ll_write_data <= write_data_i(in_sel_write * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel_write * c_swc_page_addr_width);
ll_wr_data <= ll_write_data when (write_request_grant(0) = '0') else (others=>'1');
-- address
ll_write_addr <= write_addr_i(in_sel_write * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel_write * c_swc_page_addr_width);
ll_free_addr <= free_addr_i (in_sel_write * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel_write * c_swc_page_addr_width);
ll_wr_addr <= ll_write_addr when (write_request_grant(0) = '0') else ll_free_addr;
-- ======= reading =======
-- address
ll_read_pump_addr <= read_pump_addr_i(in_sel_read * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel_read * c_swc_page_addr_width);
ll_free_pck_addr <= free_pck_addr_i (in_sel_read * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel_read * c_swc_page_addr_width);
ll_rd_addr <= ll_read_pump_addr when ( read_request_grant(0) = '0') else ll_free_pck_addr;
process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
write_done_feedback <= (others => '0');
free_done_feedback <= (others => '0');
read_pump_read_done_feedback <= (others => '0');
free_pck_read_done_feedback <= (others => '0');
else
-- recognizing on which port the allocation/deallocation/freeing process
-- is about to finish. It's solely for request vector composition purpose
for i in 0 to c_swc_num_ports-1 loop
if(ll_write_enable = '1' and (in_sel_write = i)) then
--if(in_sel_write = i) then
write_done_feedback(i) <= not write_request_grant(0);
free_done_feedback(i) <= write_request_grant(0);
else
write_done_feedback(i) <= '0';
free_done_feedback(i) <= '0';
end if;
end loop; -- i
for i in 0 to c_swc_num_ports-1 loop
if(ll_read_enable = '1' and (in_sel_read = i)) then
--if(in_sel_read = i) then
read_pump_read_done_feedback(i) <= not read_request_grant(0);
free_pck_read_done_feedback(i) <= read_request_grant(0);
else
read_pump_read_done_feedback(i) <= '0';
free_pck_read_done_feedback(i) <= '0';
end if;
end loop; -- i
write_done <= write_done_feedback;
free_done <= free_done_feedback;
read_pump_read_done <= read_pump_read_done_feedback;
free_pck_read_done <= free_pck_read_done_feedback;
end if;
end if;
end process;
write_done_o <= write_done_feedback;
free_done_o <= free_done_feedback;
read_pump_read_done_o <= read_pump_read_done_feedback;
free_pck_read_done_o <= free_pck_read_done_feedback;
end syn;
\ No newline at end of file
-------------------------------------------------------------------------------
-- Title : multiport lost pck deallocator
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_multiport_plost_pck_dealloc.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-13
-- Last update: 2010-11-13
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-13 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
use work.platform_specific.all;
entity swc_multiport_lost_pck_dealloc is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
ib_force_free_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
ib_force_free_done_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ib_force_free_pgaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ob_force_free_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
ob_force_free_done_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ob_force_free_pgaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ll_read_addr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
--ll_read_data_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ll_read_data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_req_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ll_read_valid_data_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_force_free_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_force_free_done_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_force_free_pgaddr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0)
);
end swc_multiport_lost_pck_dealloc;
architecture syn of swc_multiport_lost_pck_dealloc is
begin -- syn
lpd_gen : for i in 0 to c_swc_num_ports-1 generate
LPD: swc_lost_pck_dealloc
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
ib_force_free_i => ib_force_free_i(i),
ib_force_free_done_o => ib_force_free_done_o(i),
ib_force_free_pgaddr_i => ib_force_free_pgaddr_i((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
ob_force_free_i => ob_force_free_i(i),
ob_force_free_done_o => ob_force_free_done_o(i),
ob_force_free_pgaddr_i => ob_force_free_pgaddr_i((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
ll_read_addr_o => ll_read_addr_o((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
--ll_read_data_i => ll_read_data_i((i+1)*c_swc_num_ports - 1 downto i * c_swc_num_ports),
ll_read_data_i => ll_read_data_i,
ll_read_req_o => ll_read_req_o(i),
ll_read_valid_data_i => ll_read_valid_data_i(i),
mmu_force_free_o => mmu_force_free_o(i),
mmu_force_free_done_i => mmu_force_free_done_i(i),
mmu_force_free_pgaddr_o => mmu_force_free_pgaddr_o((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width)
);
end generate lpd_gen;
end syn;
-------------------------------------------------------------------------------
-- Title : multiport page allocator
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_multiport_page_allocator.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-04-08
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-11 1.1 mlipinsk comments added !!!!!
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_multiport_page_allocator is
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
alloc_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
free_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
force_free_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
set_usecnt_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
alloc_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
free_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
force_free_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
set_usecnt_done_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
pgaddr_free_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
pgaddr_force_free_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
pgaddr_usecnt_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
usecnt_i : in std_logic_vector(c_swc_num_ports * c_swc_usecount_width - 1 downto 0);
pgaddr_alloc_o : out std_logic_vector(c_swc_page_addr_width-1 downto 0);
nomem_o : out std_logic
);
end swc_multiport_page_allocator;
architecture syn of swc_multiport_page_allocator is
signal pg_alloc : std_logic;
signal pg_free : std_logic;
signal pg_force_free : std_logic;
signal pg_set_usecnt : std_logic;
signal pg_usecnt : std_logic_vector(c_swc_usecount_width-1 downto 0);
signal pg_addr_alloc : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal pg_addr_free : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal pg_addr_force_free : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal pg_addr_usecnt : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal pg_addr : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal pg_addr_valid : std_logic; -- used by symulation , don't remove
-- signal pg_idle : std_logic;
signal pg_done : std_logic;
signal pg_nomem : std_logic;
-- vector of requests to the Round Robin arbiter
-- both alloc and free request
-- the address of the bit :
-- * representing alloc request - is even [i*2]
-- * representing free request - is odd [i*2 + 1]
signal request_vec : std_logic_vector(c_swc_num_ports*4-1 downto 0);
-- address of the request which has been granted access
-- to page alloation core. the LSB bit indicates the kind of
-- operation:
-- * '0' - even address, so alloc operation
-- * '1' - odd address, so free operation
signal request_grant : std_logic_vector(5 downto 0);
-- used to indicate to the RR arbiter to start
-- processing next request,
signal request_next : std_logic;
-- indicates that the granted request is valid
signal request_grant_valid : std_logic;
-- the number of the port to which request has been granted
signal in_sel : integer range 0 to c_swc_num_ports-1;
-- >????
signal in_sel_prev : integer range 0 to c_swc_num_ports-1;
-- ??
signal af_prev : std_logic;
-- OR of two different free_i signals, they are functionally exclusive
-- which means that it's not possible for them to be high simultaneously
signal any_free_i : std_logic;
-- indicates that an alloc has been performed successfully for the
-- given port. Used to prevent considering the currently process
-- port for request to RR arbiter
signal alloc_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal alloc_done : std_logic_vector(c_swc_num_ports-1 downto 0);
-- indicates that an free has been performed successfully for the
-- given port. Used to prevent considering the currently process
-- port for request to RR arbiter
signal free_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal force_free_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
signal force_free_done : std_logic_vector(c_swc_num_ports-1 downto 0);
signal set_usecnt_done_feedback : std_logic_vector(c_swc_num_ports-1 downto 0);
-- signal set_usecnt_done : std_logic_vector(c_swc_num_ports-1 downto 0);
begin -- syn
-- one allocator/deallocator for all ports
ALLOC_CORE : swc_page_allocator
generic map (
g_num_pages => c_swc_packet_mem_num_pages,
g_page_addr_bits => c_swc_page_addr_width,
g_use_count_bits => c_swc_usecount_width)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
alloc_i => pg_alloc,
free_i => pg_free,
force_free_i => pg_force_free,
set_usecnt_i => pg_set_usecnt,
usecnt_i => pg_usecnt,
pgaddr_i => pg_addr,--pg_addr_free,
pgaddr_o => pg_addr_alloc,
pgaddr_valid_o => pg_addr_valid,
idle_o => open, --pg_idle,
done_o => pg_done,
nomem_o => pg_nomem);
-- creating request vector with 'alloc' requests at even addresses
-- and 'free' requests on odd addresses. The condition prevents
-- considertion of actually processed port for the request to arbiter
gen_request_vec : for i in 0 to c_swc_num_ports - 1 generate
request_vec(4 * i + 0) <= alloc_i(i) and (not (alloc_done_feedback(i) or alloc_done(i))) and (not pg_nomem);
request_vec(4 * i + 1) <= free_i(i) and (not (free_done_feedback(i) or free_done(i)));
request_vec(4 * i + 2) <= set_usecnt_i(i) and (not (set_usecnt_done_feedback(i)));-- or set_usecnt_done(i)));
request_vec(4 * i + 3) <= force_free_i(i) and (not (force_free_done_feedback(i) or force_free_done(i)));
end generate gen_request_vec;
-- Round Robin arbiter, quite specific for the usage, since it has the "next"
-- input. It is used to start processing next request well in advance, to prevent
-- unnecessary delays
ARB : swc_rr_arbiter
generic map (
g_num_ports => c_swc_num_ports * 4,
g_num_ports_log2 => 6)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
next_i => request_next,
request_i => request_vec,
grant_o => request_grant,
grant_valid_o => request_grant_valid);
-- port number to which request has been granted.
in_sel <= to_integer(unsigned(request_grant(request_grant'length-1 downto 2)));
-- if the granted request has even address (LSB = '0'), it means that
-- the request was of 'alloc' type
pg_alloc <= '1' when ((request_grant(1 downto 0) = b"00") and request_grant_valid='1') else '0';
pg_free <= '1' when ((request_grant(1 downto 0) = b"01") and request_grant_valid='1') else '0';
pg_set_usecnt <= '1' when ((request_grant(1 downto 0) = b"10") and request_grant_valid='1') else '0';
pg_force_free <= '1' when ((request_grant(1 downto 0) = b"11") and request_grant_valid='1') else '0';
-- This is special to prevent unnecessary delays.
-- The allocator indicates that the arbiter may start
-- processing next request as in 2 cycles, net allocator
-- will finish the current job and will be ready for the next one
request_next <= pg_done;
-- the address of the allocated page
pgaddr_alloc_o <= pg_addr_alloc;
-- Getting the address of the page we want to free
pg_addr_free <= pgaddr_free_i (in_sel * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel * c_swc_page_addr_width);
pg_addr_force_free <= pgaddr_force_free_i(in_sel * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel * c_swc_page_addr_width);
pg_addr_usecnt <= pgaddr_usecnt_i (in_sel * c_swc_page_addr_width + c_swc_page_addr_width - 1 downto in_sel * c_swc_page_addr_width);
---
pg_addr <= pg_addr_force_free when (pg_force_free = '1') else
pg_addr_free when (pg_free = '1') else
pg_addr_usecnt when (pg_set_usecnt = '1') else
(others => '0');
-- getting the ouser count which should be assigned to freshly allocated page
pg_usecnt <= usecnt_i(in_sel * c_swc_usecount_width + c_swc_usecount_width - 1 downto in_sel * c_swc_usecount_width);
process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
alloc_done_feedback <= (others => '0');
free_done_feedback <= (others => '0');
set_usecnt_done_feedback <= (others => '0');
force_free_done_feedback <= (others => '0');
else
-- recognizing on which port the allocation/deallocation/freeing process
-- is about to finish. It's solely for request vector composition purpose
for i in 0 to c_swc_num_ports-1 loop
if(pg_done = '1' and (in_sel = i)) then
if(request_grant(1 downto 0) = b"00") then
alloc_done_feedback(i) <= '1';
else
alloc_done_feedback(i) <= '0';
end if;
if(request_grant(1 downto 0) = b"01") then
free_done_feedback(i) <= '1';
else
free_done_feedback(i) <= '0';
end if;
if(request_grant(1 downto 0) = b"10") then
set_usecnt_done_feedback(i) <= '1';
else
set_usecnt_done_feedback(i) <= '0';
end if;
if(request_grant(1 downto 0) = b"11") then
force_free_done_feedback(i) <= '1';
else
force_free_done_feedback(i) <= '0';
end if;
else
alloc_done_feedback(i) <= '0';
free_done_feedback(i) <= '0';
set_usecnt_done_feedback(i) <= '0';
force_free_done_feedback(i) <= '0';
end if;
end loop; -- i
alloc_done <= alloc_done_feedback;
free_done <= free_done_feedback;
-- set_usecnt_done <= set_usecnt_done_feedback;
force_free_done <= force_free_done_feedback;
end if;
end if;
end process;
alloc_done_o <= alloc_done;
free_done_o <= free_done;
set_usecnt_done_o <= set_usecnt_done_feedback;--set_usecnt_done;
force_free_done_o <= force_free_done;
nomem_o <= pg_nomem;
end syn;
-------------------------------------------------------------------------------
-- Title : Pck's Pages Freeing Module
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_multiport_pck_pg_free_module.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-13
-- Last update: 2010-11-13
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: this modules free pages of read/dropped modules
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-16 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
use work.platform_specific.all;
entity swc_multiport_pck_pg_free_module is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
ib_force_free_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
ib_force_free_done_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ib_force_free_pgaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ob_free_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
ob_free_done_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ob_free_pgaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ll_read_addr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
--ll_read_data_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ll_read_data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_req_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
ll_read_valid_data_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_free_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_free_done_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_free_pgaddr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0);
mmu_force_free_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_force_free_done_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
mmu_force_free_pgaddr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width -1 downto 0)
);
end swc_multiport_pck_pg_free_module;
architecture syn of swc_multiport_pck_pg_free_module is
begin -- syn
lpd_gen : for i in 0 to c_swc_num_ports-1 generate
LPD: swc_pck_pg_free_module
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
ib_force_free_i => ib_force_free_i(i),
ib_force_free_done_o => ib_force_free_done_o(i),
ib_force_free_pgaddr_i => ib_force_free_pgaddr_i((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
ob_free_i => ob_free_i(i),
ob_free_done_o => ob_free_done_o(i),
ob_free_pgaddr_i => ob_free_pgaddr_i((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
ll_read_addr_o => ll_read_addr_o((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
ll_read_data_i => ll_read_data_i,
ll_read_req_o => ll_read_req_o(i),
ll_read_valid_data_i => ll_read_valid_data_i(i),
mmu_free_o => mmu_free_o(i),
mmu_free_done_i => mmu_free_done_i(i),
mmu_free_pgaddr_o => mmu_free_pgaddr_o((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width),
mmu_force_free_o => mmu_force_free_o(i),
mmu_force_free_done_i => mmu_force_free_done_i(i),
mmu_force_free_pgaddr_o => mmu_force_free_pgaddr_o((i+1)*c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width)
);
end generate lpd_gen;
end syn;
-------------------------------------------------------------------------------
-- Title : Priority Queue
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_ob_prio_queue.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-03
-- Last update: 2010-11-03
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-09 1.0 mlipinsk created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_ob_prio_queue is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F
-------------------------------------------------------------------------------
write_i : in std_logic;
read_i : in std_logic;
not_full_o : out std_logic;
not_empty_o : out std_logic;
-------------------------------------------------------------------------------
-- I/F with SRAM
-------------------------------------------------------------------------------
wr_en_o : out std_logic;
wr_addr_o : out std_logic_vector(c_swc_output_fifo_addr_width - 1 downto 0);
rd_addr_o : out std_logic_vector(c_swc_output_fifo_addr_width - 1 downto 0)
);
end swc_ob_prio_queue;
architecture behavoural of swc_ob_prio_queue is
signal head : std_logic_vector(c_swc_output_fifo_addr_width - 1 downto 0);
signal tail : std_logic_vector(c_swc_output_fifo_addr_width - 1 downto 0);
signal not_full : std_logic;
signal not_empty : std_logic;
begin -- behavoural
sram_if : process (clk_i, rst_n_i)
begin -- process
if rising_edge(clk_i) then
if(rst_n_i = '0') then
head <= (others => '0');
tail <= (others => '0');
else
if(write_i = '1' and not_full = '1') then
head <= std_logic_vector(unsigned(head) + 1);
end if;
if(read_i = '1' and not_empty = '1') then
tail <= std_logic_vector(unsigned(tail) + 1);
end if;
end if;
end if;
end process;
not_full <= '0' when (head = std_logic_vector(unsigned(tail) - 1)) else '1';
not_empty <= '0' when (tail = head ) else '1';
wr_addr_o <= head;
rd_addr_o <= tail;
wr_en_o <= write_i and not_full;
not_full_o <= not_full;
not_empty_o <= not_empty;
end behavoural;
\ No newline at end of file
-------------------------------------------------------------------------------
-- Title : Output Block
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_output_block.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-03
-- Last update: 2010-11-03
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-09 1.0 mlipinsk created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_output_block is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Pck Transfer Arbiter
-------------------------------------------------------------------------------
pta_transfer_data_valid_i : in std_logic;
pta_pageaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
pta_prio_i : in std_logic_vector(c_swc_prio_width - 1 downto 0);
pta_pck_size_i : in std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
pta_transfer_data_ack_o : out std_logic;
-------------------------------------------------------------------------------
-- I/F with Multiport Memory's Read Pump (MMP)
-------------------------------------------------------------------------------
mpm_pgreq_o : out std_logic;
mpm_pgaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
mpm_pckend_i : in std_logic;
mpm_pgend_i : in std_logic;
mpm_drdy_i : in std_logic;
mpm_dreq_o : out std_logic;
mpm_data_i : in std_logic_vector(c_swc_data_width - 1 downto 0);
mpm_ctrl_i : in std_logic_vector(c_swc_ctrl_width - 1 downto 0);
mpm_sync_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Pck's Pages Free Module(PPFM)
-------------------------------------------------------------------------------
-- correctly read pck
ppfm_free_o : out std_logic;
ppfm_free_done_i : in std_logic;
ppfm_free_pgaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-------------------------------------------------------------------------------
-- Fabric I/F : output (goes to the Endpoint)
-------------------------------------------------------------------------------
rx_sof_p1_o : out std_logic;
rx_eof_p1_o : out std_logic;
rx_dreq_i : in std_logic;
rx_ctrl_o : out std_logic_vector(c_swc_ctrl_width - 1 downto 0);
rx_data_o : out std_logic_vector(c_swc_data_width - 1 downto 0);
rx_valid_o : out std_logic;
rx_bytesel_o : out std_logic;
rx_idle_o : out std_logic;
rx_rerror_p1_o : out std_logic;
-- drop the pck in case of WRF error
rx_terror_p1_i : in std_logic;
-- retransmit the pck in case of WRF abort
rx_tabort_p1_i : in std_logic
);
end swc_output_block;
architecture behavoural of swc_output_block is
component generic_ssram_dualport_singleclock
generic (
g_width : natural;
g_addr_bits : natural;
g_size : natural);
port (
data_i : in std_logic_vector (g_width-1 downto 0);
clk_i : in std_logic;
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0));
end component;
signal pta_transfer_data_ack : std_logic;
signal wr_addr : std_logic_vector(c_swc_output_prio_num_width + c_swc_output_fifo_addr_width -1 downto 0);
signal rd_addr : std_logic_vector(c_swc_output_prio_num_width + c_swc_output_fifo_addr_width -1 downto 0);
signal wr_prio : std_logic_vector(c_swc_output_prio_num_width - 1 downto 0);
signal rd_prio : std_logic_vector(c_swc_output_prio_num_width - 1 downto 0);
signal not_full_array : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal not_empty_array : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal read_array : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal read : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal write_array : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal write : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
-- signal wr_en_array : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
signal wr_en : std_logic;
signal rd_data_valid : std_logic;
signal zeros : std_logic_vector(c_swc_output_prio_num - 1 downto 0);
subtype t_head_and_head is std_logic_vector(c_swc_output_fifo_addr_width - 1 downto 0);
type t_addr_array is array (c_swc_output_prio_num - 1 downto 0) of t_head_and_head;
signal wr_array : t_addr_array;
signal rd_array : t_addr_array;
type t_state is (IDLE, SET_PAGE, RE_SET_PAGE, READ_MPM, PAUSE_BY_SRC, PAUSE_BY_SINK, READ_LAST_WORD,WAIT_FREE_PCK, WAIT_DREQ, TABORT);
signal state : t_state;
signal pgreq : std_logic;
signal re_pgreq : std_logic;
signal pgreq_d0 : std_logic;
signal re_pgreq_d0 : std_logic;
signal pgreq_or : std_logic;
signal wr_data : std_logic_vector(c_swc_max_pck_size_width + c_swc_page_addr_width - 1 downto 0);
signal rd_data : std_logic_vector(c_swc_max_pck_size_width + c_swc_page_addr_width - 1 downto 0);
signal rd_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal current_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal cnt_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal dreq : std_logic;
signal rx_sof_p1 : std_logic;
signal rx_eof_p1 : std_logic;
signal rx_valid : std_logic;
signal rx_rerror_p1 : std_logic;
signal rx_ctrl : std_logic_vector(c_swc_ctrl_width - 1 downto 0);
signal rx_data : std_logic_vector(c_swc_data_width - 1 downto 0);
signal rx_bytesel : std_logic;
signal ppfm_free : std_logic;
signal ppfm_free_pgaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal pck_start_pgaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal cnt_last_word : std_logic;
signal cnt_one_but_last_word : std_logic;
signal start_free_pck : std_logic;
signal waiting_pck_start : std_logic;
begin -- behavoural
zeros <=(others => '0');
wr_prio <= not pta_prio_i;
wr_data <= pta_pck_size_i & pta_pageaddr_i;
wr_addr <= wr_prio & wr_array(0) when wr_prio = "000" else
wr_prio & wr_array(1) when wr_prio = "001" else
wr_prio & wr_array(2) when wr_prio = "010" else
wr_prio & wr_array(3) when wr_prio = "011" else
wr_prio & wr_array(4) when wr_prio = "100" else
wr_prio & wr_array(5) when wr_prio = "101" else
wr_prio & wr_array(6) when wr_prio = "110" else
wr_prio & wr_array(7) when wr_prio = "111" else
(others => 'X');
rd_addr <= rd_prio & rd_array(0) when rd_prio = "000" else
rd_prio & rd_array(1) when rd_prio = "001" else
rd_prio & rd_array(2) when rd_prio = "010" else
rd_prio & rd_array(3) when rd_prio = "011" else
rd_prio & rd_array(4) when rd_prio = "100" else
rd_prio & rd_array(5) when rd_prio = "101" else
rd_prio & rd_array(6) when rd_prio = "110" else
rd_prio & rd_array(7) when rd_prio = "111" else
(others => 'X');
RD_ENCODE : swc_prio_encoder
generic map (
g_num_inputs => 8,
g_output_bits => 3)
port map (
in_i => not_empty_array,
onehot_o => read_array,
out_o => rd_prio);
write_array <= "00000001" when wr_prio = "000" else
"00000010" when wr_prio = "001" else
"00000100" when wr_prio = "010" else
"00001000" when wr_prio = "011" else
"00010000" when wr_prio = "100" else
"00100000" when wr_prio = "101" else
"01000000" when wr_prio = "110" else
"10000000" when wr_prio = "111" else
"00000000" ;
wr_en <= write(0) and not_full_array(0) when wr_prio = "000" else
write(1) and not_full_array(1) when wr_prio = "001" else
write(2) and not_full_array(2) when wr_prio = "010" else
write(3) and not_full_array(3) when wr_prio = "011" else
write(4) and not_full_array(4) when wr_prio = "100" else
write(5) and not_full_array(5) when wr_prio = "101" else
write(6) and not_full_array(6) when wr_prio = "110" else
write(7) and not_full_array(7) when wr_prio = "111" else
'0';
pta_transfer_data_ack_o <= not_full_array(0) when wr_prio = "000" else
not_full_array(1) when wr_prio = "001" else
not_full_array(2) when wr_prio = "010" else
not_full_array(3) when wr_prio = "011" else
not_full_array(4) when wr_prio = "100" else
not_full_array(5) when wr_prio = "101" else
not_full_array(6) when wr_prio = "110" else
not_full_array(7) when wr_prio = "111" else
'0';
prio_ctrl : for i in 0 to c_swc_output_prio_num - 1 generate
write(i) <= write_array(i) and pta_transfer_data_valid_i ;
read(i) <= read_array(i) when (state = SET_PAGE) else '0';--rx_dreq_i;
PRIO_QUEUE_CTRL : swc_ob_prio_queue
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
write_i => write(i),
read_i => read(i),
not_full_o => not_full_array(i),
not_empty_o => not_empty_array(i),
wr_en_o => open, --wr_en_array(i),
wr_addr_o => wr_array(i),
rd_addr_o => rd_array(i)
);
end generate prio_ctrl;
PRIO_QUEUE : generic_ssram_dualport_singleclock
generic map (
g_width => c_swc_page_addr_width + c_swc_max_pck_size_width,
g_addr_bits => c_swc_output_prio_num_width + c_swc_output_fifo_addr_width,
g_size => (c_swc_output_prio_num * c_swc_output_fifo_size)
)
port map (
clk_i => clk_i,
rd_addr_i => rd_addr,
wr_addr_i => wr_addr,
data_i => wr_data,
wr_en_i => wr_en,
q_o => rd_data
);
rd_valid : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
rd_data_valid <= '0';
else
if(not_empty_array = zeros) then
rd_data_valid <= '0';
else
rd_data_valid <= '1';
end if;
end if;
end if;
end process;
--rd_data_valid <= '0' when (not_empty_array = zeros) else '1';
pck_size_cnt : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
cnt_last_word <= '0';
cnt_pck_size <= (others => '0');
cnt_one_but_last_word <= '0';
else
-- if(rx_eof_p1 = '1' or ) then
if(state = SET_PAGE or state = RE_SET_PAGE) then
cnt_pck_size <= (others =>'0');
cnt_one_but_last_word <= '0';
cnt_last_word <= '0';
elsif(rx_valid = '1' and rx_eof_p1 = '0') then
cnt_last_word <= '0';
cnt_one_but_last_word <= '0';
if(current_pck_size = std_logic_vector(unsigned(cnt_pck_size) + 1)) then
cnt_last_word <= '1';
elsif(current_pck_size = std_logic_vector(unsigned(cnt_pck_size) + 2)) then
cnt_one_but_last_word <= '1';
end if;
cnt_pck_size <= std_logic_vector(unsigned(cnt_pck_size) + 1);
end if;
end if;
end if;
end process;
fsm : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
pgreq <= '0';
current_pck_size <= (others => '0');
rx_sof_p1 <= '0';
pck_start_pgaddr <= (others => '0');
ppfm_free_pgaddr <= (others => '0');
dreq <= '0';
start_free_pck <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
rx_eof_p1 <= '0';
rx_bytesel <= '0';
re_pgreq <= '0';
waiting_pck_start <= '0';
pgreq_d0 <= '0';
re_pgreq_d0 <= '0';
else
-- IMPORTANT : nasty trick here !!!
-- basically, the 'read' is HIGH, to confirm reading from
-- queue output, when state = SET_PAGE, but this is sync with
-- the address in the queue, the data is available one cycle later !!
-- basically, the data is available when 'pgreq' is HIGH (this is
-- how FSM works), so we capture the data when 'pgreq' is HIGH (to avoid
-- extra states and waiting). to optimize the performance, during the
-- 'pgreq' strobe (HIGH), the data is outputed directly from queue to
-- mpm_pgaddr_o.
if(pgreq = '1') then
current_pck_size <= rd_pck_size;
pck_start_pgaddr <= rd_data(c_swc_page_addr_width - 1 downto 0);
end if;
-- main finite state machine
pgreq_d0 <= pgreq;
re_pgreq_d0 <= re_pgreq;
case state is
when IDLE =>
rx_eof_p1 <= '0';
dreq <= '0';
start_free_pck <= '0';
rx_sof_p1 <= '0';
--
if(rd_data_valid = '1' and rx_dreq_i = '1'
--and pta_transfer_data_valid_i = '0'
) then -- we can't start when transfering data, because the dataa is changing
state <= SET_PAGE;
--rx_sof_p1 <= '1';
rx_sof_p1 <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
end if;
when SET_PAGE =>
rx_sof_p1 <= '0';
pgreq <= '1';
--dreq <= '1';
dreq <= '0';
waiting_pck_start <='1';
rx_valid <= '0';
state <= PAUSE_BY_SRC;
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
when RE_SET_PAGE =>
rx_sof_p1 <= '0';
re_pgreq <= '1';
--dreq <= '1';
dreq <= '0';--added
waiting_pck_start<='1';
rx_valid <= '0';
state <= PAUSE_BY_SRC;
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
when PAUSE_BY_SINK =>
pgreq <= '0';
-- if(rx_dreq_i = '1' and mpm_drdy_i = '1') then
if(rx_tabort_p1_i = '1' and rx_dreq_i = '1') then
state <= RE_SET_PAGE;
dreq <= '0';
--rx_sof_p1 <= '1';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_tabort_p1_i = '1' and rx_dreq_i = '0') then
state <= WAIT_DREQ;
dreq <= '0';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_terror_p1_i = '1') then
-- we release pages of this package for this port
-- no "force free" here, since other ports
-- may want to use the pck
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
if(ppfm_free = '0') then
-- for WTF, refer 'nasty trick above'
-- improbable to be used
if(pgreq = '1') then
ppfm_free_pgaddr <= rd_data(c_swc_page_addr_width - 1 downto 0);
else
ppfm_free_pgaddr <= pck_start_pgaddr;
end if;
start_free_pck <= '1';
state <= IDLE;
else
state <= WAIT_FREE_PCK;
end if;
elsif( rx_dreq_i = '1') then
rx_valid <= '1';
rx_bytesel <= '0';
if(rx_ctrl = b"1111") then
rx_ctrl <= b"0111";
rx_bytesel <= '1';
end if;
if(cnt_one_but_last_word = '1') then
state <= READ_MPM;
elsif(cnt_last_word = '1') then
rx_eof_p1 <= '1';
state <= READ_LAST_WORD;
else
state <= READ_MPM;
end if;
end if;
when PAUSE_BY_SRC =>
pgreq <= '0';
re_pgreq <= '0';
rx_sof_p1 <= '0';
-- if(rx_dreq_i = '1' and mpm_drdy_i = '1') then
if(rx_tabort_p1_i = '1' and rx_dreq_i = '1') then
state <= RE_SET_PAGE;
dreq <= '0';
--rx_sof_p1 <= '1';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_tabort_p1_i = '1' and rx_dreq_i = '0') then
state <= WAIT_DREQ;
dreq <= '0';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_terror_p1_i = '1') then
-- we release pages of this package for this port
-- no "force free" here, since other ports
-- may want to use the pck
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
if(ppfm_free = '0') then
-- for WTF, refer 'nasty trick above'
-- improbable to be used
if(pgreq = '1') then
ppfm_free_pgaddr <= rd_data(c_swc_page_addr_width - 1 downto 0);
else
ppfm_free_pgaddr <= pck_start_pgaddr;
end if;
start_free_pck <= '1';
state <= IDLE;
else
state <= WAIT_FREE_PCK;
end if;
elsif( (mpm_drdy_i = '1' or rx_sof_p1 = '1') and waiting_pck_start = '0') then
rx_valid <= '1';
rx_bytesel <= '0';
dreq <= '1'; --added
if(mpm_ctrl_i = b"1111") then
rx_ctrl <= b"0111";
rx_bytesel <= '1';
else
rx_ctrl <= mpm_ctrl_i;
end if;
rx_data <= mpm_data_i;
if(cnt_last_word = '1') then
rx_eof_p1 <= '1';
state <= READ_LAST_WORD;
else
state <= READ_MPM;
end if;
else
if(rx_dreq_i = '1' and
waiting_pck_start = '1' and -- this is the start of pck, not a pause in the middle
mpm_sync_i = '1' and -- we've got sync, which means that data will be read
pgreq_or = '0' ) then -- if page is request on the sync, it will be read in next sync
dreq <= '1'; -- added
rx_sof_p1 <= '1';
waiting_pck_start <= '0';
else
rx_sof_p1 <= '0';
end if;
end if;
when READ_MPM =>
pgreq <= '0';
if(rx_tabort_p1_i = '1' and rx_dreq_i = '1') then
state <= RE_SET_PAGE;
dreq <= '0';
--rx_sof_p1 <= '1';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_tabort_p1_i = '1' and rx_dreq_i = '0') then
state <= WAIT_DREQ;
dreq <= '0';
rx_sof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_terror_p1_i = '1') then
-- we release pages of this package for this port
-- no "force free" here, since other ports
-- may want to use the pck
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
if(ppfm_free = '0') then
-- for WTF, refer 'nasty trick above'
-- improbable to be used
if(pgreq = '1') then
ppfm_free_pgaddr <= rd_data(c_swc_page_addr_width - 1 downto 0);
else
ppfm_free_pgaddr <= pck_start_pgaddr;
end if;
start_free_pck <= '1';
state <= IDLE;
else
state <= WAIT_FREE_PCK;
end if;
elsif(rx_dreq_i = '0' and mpm_drdy_i = '0') then
rx_valid <= '0';
state <= PAUSE_BY_SRC;
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(rx_dreq_i = '0' and mpm_drdy_i = '1') then
rx_valid <= '0';
state <= PAUSE_BY_SINK;
rx_ctrl <= mpm_ctrl_i;
rx_data <= mpm_data_i;
elsif(rx_dreq_i = '1' and mpm_drdy_i = '0') then
rx_valid <= '0';
state <= PAUSE_BY_SRC;
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
elsif(mpm_drdy_i = '1' and mpm_drdy_i = '1') then
rx_valid <= '1';
rx_bytesel <= '0';
if(mpm_ctrl_i = b"1111") then
rx_ctrl <= b"0111";
rx_bytesel <= '1';
else
rx_ctrl <= mpm_ctrl_i;
end if;
rx_data <= mpm_data_i;
-- we need to make sure that the last word has been read
-- so we can only go to IDLE, if the last word was validated
-- with rx_valid
--if(cnt_pck_size = current_pck_size and rx_valid = '1') then
if(cnt_one_but_last_word = '1') then
-- writing request to freeing FIFO to free
-- the previous pck is finished
-- so no problem to write new freeing request
dreq <= '0';
rx_eof_p1 <= '1';
rx_valid <= '1';
rx_bytesel <= '0';
if(mpm_ctrl_i = b"1111") then
rx_ctrl <= b"0111";
rx_bytesel <= '1';
else
rx_ctrl <= mpm_ctrl_i;
end if;
rx_data <= mpm_data_i;
state <= READ_LAST_WORD;
end if;
else
-- should not get here ?????????
rx_valid <= '0';
state <= PAUSE_BY_SRC;
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
end if;
when READ_LAST_WORD =>
rx_eof_p1 <= '0';
rx_valid <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
if(ppfm_free = '0') then
start_free_pck <= '1';
-- remember the starting page address
-- for the free-ing process
ppfm_free_pgaddr <= pck_start_pgaddr;
state <= IDLE;
-- very unlikely, but if writing request (to freeing FIFO)
-- to free the previous pck, has not finished yet,
-- we just wait.
else
state <= WAIT_FREE_PCK;
end if;-- if(ppfm_free = '0') then
when WAIT_DREQ =>
if(rx_dreq_i = '1') then
state <= RE_SET_PAGE;
--rx_sof_p1 <= '1';
rx_sof_p1 <= '0';
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
end if;
when WAIT_FREE_PCK =>
rx_ctrl <= (others =>'0');
rx_data <= (others =>'0');
rx_valid <= '1';
rx_eof_p1 <= '0';
if(ppfm_free = '0') then
start_free_pck <= '1';
state <= IDLE;
end if;
when others =>
state <= IDLE;
end case;
end if;
end if;
end process fsm;
-- here we perform the "free pages of the pck" process,
-- we do it while reading already the next pck
free : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
ppfm_free <= '0';
else
if(start_free_pck = '1') then
ppfm_free <= '1';
elsif(ppfm_free_done_i = '1') then
ppfm_free <='0';
end if;
end if;
end if;
end process free;
rd_pck_size <= rd_data(c_swc_max_pck_size_width + c_swc_page_addr_width - 1 downto c_swc_page_addr_width);
mpm_pgreq_o <= pgreq or re_pgreq;
pgreq_or <= pgreq_d0 or pgreq or re_pgreq_d0 or re_pgreq;
-- IMPORTANT : a trick needed here, to make things faster, we provide pgaddr straight
-- from quque output, otherwise, in the rare case when the queue is written
-- with new data (so the output can change accordingly) there was a problem
-- of acknowledging the wrong data (we ack'ed the address, but the data is one c
-- cycle later !!!),
mpm_pgaddr_o <= rd_data(c_swc_page_addr_width - 1 downto 0) when (pgreq = '1') else pck_start_pgaddr;
--rd_data(c_swc_page_addr_width - 1 downto 0); -- read_data;
mpm_dreq_o <= (dreq and rx_dreq_i and (not rx_tabort_p1_i)) or pgreq;-- and (not waiting_pck_start);
-- rx_valid <= mpm_drdy_i when (state = READ_MPM) else '0';
-- rx_eof_p1 <= cnt_last_word and rx_valid;
rx_sof_p1_o <= rx_sof_p1;
rx_eof_p1_o <= rx_eof_p1;
rx_ctrl_o <= rx_ctrl;
rx_data_o <= rx_data;
rx_valid_o <= rx_valid;
-- rx_bytesel_o <= mpm_ctrl_i(3);
rx_bytesel_o <= rx_bytesel;
rx_idle_o <= '1' when (state = IDLE) else '0';
rx_rerror_p1_o <= '0'; --???
ppfm_free_o <= ppfm_free;
ppfm_free_pgaddr_o <= ppfm_free_pgaddr;
end behavoural;
\ No newline at end of file
-------------------------------------------------------------------------------
-- Title : Pack packets to memory :)
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_packet_mem.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-10-12
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: Here we enable 'c_swc_num_ports' ports to write and read to/from
-- shared memory. We assume we know the memory page (provided by page
-- allocator/deallocator, another component).
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
-- Packets from each port are written/read to/from memory pumps. Each port has
-- its own write and read pump. The pumps are an intermediate step (buffer)
-- between port and shared memory (Fucking Big SRAM). Each pump has its own
-- time slot to access FB SRAM. The time slot is one cycle. The time slot is
-- granted every 'c_swc_packet_mem_multiply' cycles (regardless it's requested
-- by the pump).
--
-- ** writing **
-- 'c_swc_packet_mem_multiply' number of words written to a pump are saved in
-- FB SRAM (when the access is granted). Writting to a pump can be done
-- regardless of the time slots granted to the pumps. It can be done as long as
-- the pump's buffer (register of c_swc_packet_mem_multiply words) is not full.
-- Provided data (c_swc_packet_mem_multiply words) is written to one FB SRAM
-- word. The address of the word is determined by the provided to the pump
-- pgaddr (page address, which comes from page allocator) and internal page
-- address. When the register being filled in currently will be written to the
-- last word of the page, the rd_pageend_o is high indicating that next page
-- needs to be allocated.
--
-- ** reading **
-- similar to writing. there is a register of c_swc_packet_mem_multiply words
-- (ctrl+data) which are read from FB SRAM in the pump's time slot (one cycle).
-- Each word of the register is made available consequtivelly, so first the
-- LSB word can be read by the port (availability of data is indicated by
-- rd_drdy_o being set to HIGH. Next word can be requested by setting rd_dreq_i
-- HIGH (while the previous word is read).
--
-- If the date which is written to a page by a port does not fill entire
-- input register (the number is not modulo c_swc_packet_mem_multiply), but
-- the port wants to write next data to new page and save the "not-full-input-reg"
-- in the FB SRAM, e.g. new package is to be saved, then wr_flush_i should be
-- set HIGH, it forces the pump to save "not-entirely-full" input register
-- in FB SRAM during the next time slot for this port
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-12 1.1 mlipinsk comments added !!!!!
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_packet_mem is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------------------------
-- Write ports
---------------------------------------------------------------------------
------------------- writing to the shared memory --------------------------
-- indicates that a port X wants to write page address of the "write" access
wr_pagereq_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
-- indicates the beginning of the package
wr_pckstart_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
-- array of pages' addresses to which ports want to write
wr_pageaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- indicator that the current page is about to be full (the last FB SRAM word
-- is being pumped in currently), after ~c_swc_packet_mem_multiply cycles
-- from the rising edge of this signal this page will finish
wr_pageend_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
-- array of control data from each port to be written to memoroy
wr_ctrl_i : in std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
-- array of data from each port to be written to memory
wr_data_i : in std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
-- data ready - request from each port to write data to port's pump
wr_drdy_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
-- the input register of a pump is full, this means that the pump cannot
-- be written by the port. As soon as the data which is in the input registet
-- is written to FB SRAM memory, the signal goes LOW and writing is possible
wr_full_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
-- request to write the content of pump's input register to FB SRAM memory,
-- thus flash/clean input register of the pump
wr_flush_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
wr_sync_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
------------------- reading from the shared memory --------------------------
-- indicates that a port X wants to write page address of the "read" access
rd_pagereq_i : in std_logic_vector(c_swc_num_ports-1 downto 0);
-- array of pages' addresses from which ports want to read
rd_pageaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
-- indicates that the page being read is about to finish (the last FB SRAM word
-- is being pumped out currently), after ~c_swc_packet_mem_multiply cycles
-- from the rising edge of this signal this page will finish
rd_pageend_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
-- end of the package, new package start-page-address needs to be provided
-- the best if it is before the last page's word is read
rd_pckend_o : out std_logic_vector(c_swc_num_ports-1 downto 0);
-- data ready to be read
rd_drdy_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
-- request next word (ctrl + data) from the pump
rd_dreq_i : in std_logic_vector(c_swc_num_ports -1 downto 0);
rd_sync_read_i : in std_logic_vector(c_swc_num_ports -1 downto 0);
-- data read from the shared memory
rd_data_o : out std_logic_vector(c_swc_num_ports * c_swc_data_width - 1 downto 0);
-- control data read from the shared memory
rd_ctrl_o : out std_logic_vector(c_swc_num_ports * c_swc_ctrl_width - 1 downto 0);
rd_sync_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
-- pa_free_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
-- pa_free_done_i : in std_logic_vector(c_swc_num_ports -1 downto 0);
-- pa_free_pgaddr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
write_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
write_done_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
write_addr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
write_data_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
read_pump_read_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
read_pump_read_done_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
read_pump_addr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0)
);
end swc_packet_mem;
architecture rtl of swc_packet_mem is
component generic_ssram_dualport_singleclock
generic (
g_width : natural;
g_addr_bits : natural;
g_size : natural);
port (
data_i : in std_logic_vector (g_width-1 downto 0);
clk_i : in std_logic;
rd_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_addr_i : in std_logic_vector (g_addr_bits-1 downto 0);
wr_en_i : in std_logic := '1';
q_o : out std_logic_vector (g_width-1 downto 0));
end component;
--
subtype t_pump_data_in is std_logic_vector(c_swc_pump_width-1 downto 0);
subtype t_pump_data_out is std_logic_vector(c_swc_packet_mem_multiply * c_swc_pump_width-1 downto 0);
subtype t_pump_addr is std_logic_vector(c_swc_packet_mem_addr_width - 1 downto 0);
subtype t_pump_page_addr is std_logic_vector(c_swc_page_addr_width - 1 downto 0);
type t_pump_addr_array is array (c_swc_packet_mem_multiply - 1 downto 0) of t_pump_addr;
type t_pump_data_in_array is array (c_swc_packet_mem_multiply - 1 downto 0) of t_pump_data_in;
type t_pump_data_out_array is array (c_swc_packet_mem_multiply - 1 downto 0) of t_pump_data_out;
type t_pump_page_addr_array is array (c_swc_packet_mem_multiply - 1 downto 0) of t_pump_page_addr;
---------------------------------------------------------------------------
------------------ arrays consisting of data from all pumps ---------------
---------------------------------------------------------------------------
-- array of addresses to which each pump wants to write its data (FB SRAM word)
-- in FB SRAM word (page addr + internal addr)
-- *Signal inputed to mux*
signal wr_pump_addr_out : t_pump_addr_array;
-- data pumped in from the ports: array of words (ctrl + data) from all ports
-- *Signal inputed to mux*
signal wr_pump_data_in : t_pump_data_in_array;
-- data outputed by the pump and inputed to FB SRAM,
-- it consists of c_swc_packet_mem_multiply words (ctrl + data) which
-- are written to one FB SRAM word, this is array of such FB SRAM words
-- from all pumps.
-- *Signal inputed to mux*
signal wr_pump_data_out : t_pump_data_out_array;
-- write enable coming from each pump, it needs to be synchronozed with
-- the time slot given to each pump, synch by the pump.
-- *Signal inputed to mux*
signal wr_pump_we : std_logic_vector(c_swc_num_ports-1 downto 0);
-- indicates address of the next page in the packet, it is written to
-- a linked list of addresses
signal wr_pump_ll_data_out :t_pump_page_addr_array;
signal wr_pump_ll_addr_out :t_pump_page_addr_array;
signal wr_pump_ll_wr_req_out : std_logic_vector(c_swc_num_ports-1 downto 0);
signal wr_pump_ll_wr_req_done_in : std_logic_vector(c_swc_num_ports-1 downto 0);
---------------------------------------------------------------------------
---------------------- direct input to FB SRAM (muxed)---------------------
---------------------------------------------------------------------------
-- data currently being written to FB SRAM, depending which pump
-- is granted a time slot
signal ram_wr_data_muxed : std_logic_vector(c_swc_pump_width * c_swc_packet_mem_multiply - 1 downto 0);
-- address to which the data from the given pump is written
signal ram_wr_addr_muxed : std_logic_vector(c_swc_packet_mem_addr_width-1 downto 0);
-- write enable
signal ram_we_muxed : std_logic;
---------------------------------------------------------------------------
---------------------- direct input to Linked List (muxed) ----------------
---------------------------------------------------------------------------
signal ll_write_i : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_write_done_o : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_write_addr_i : std_logic_vector(c_swc_page_addr_width * c_swc_num_ports - 1 downto 0);
signal ll_write_data_i : std_logic_vector(c_swc_page_addr_width * c_swc_num_ports - 1 downto 0);
signal ll_read_pump_read_i : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_read_pump_read_done_o : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal ll_read_pump_addr_i : std_logic_vector(c_swc_page_addr_width * c_swc_num_ports - 1 downto 0);
---------------------------------------------------------------------------
------------ input to all pumps which is demuxed from FB SRAM -------------
---------------------------------------------------------------------------
-- address of the FB SRAM word which is read from FB SRAM from a given pump
signal rd_pump_addr_out : t_pump_addr_array;
-- unused
signal rd_pump_data_in : t_pump_data_out_array;
-- array of outputs from the pumps to the ports
signal rd_pump_data_out : t_pump_data_in_array;
signal rd_pump_ll_addr_out : t_pump_page_addr_array;
signal rd_pump_ll_rd_req_out : std_logic_vector(c_swc_num_ports-1 downto 0);
signal rd_pump_ll_rd_req_done_in : std_logic_vector(c_swc_num_ports-1 downto 0);
---------------------------------------------------------------------------
------------------------- direct output from FB SRAM ----------------------
---------------------------------------------------------------------------
-- data (FB SRAM word) read from the FB SRAM and inputted to the pump
-- which is requesting it
signal ram_rd_data : std_logic_vector(c_swc_pump_width * c_swc_packet_mem_multiply - 1 downto 0);
-- read address muxed from the array of addresses from all the pumps
signal ram_rd_addr_muxed : std_logic_vector(c_swc_packet_mem_addr_width-1 downto 0);
---------------------------------------------------------------------------
------------------------- direct output from Linked List ------------------
---------------------------------------------------------------------------
signal llist_rd_data : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal llist_rd_addr_muxed : std_logic_vector(c_swc_page_addr_width-1 downto 0);
---------------------------------------------------------------------------
------------------------- synchronization of pumps ------------------------
---------------------------------------------------------------------------
-- produces a strobe indicating the pump to which current time slot for
-- for writing is assigned (time slot == one cycle)
signal sync_sreg : std_logic_vector(c_swc_packet_mem_multiply-1 downto 0);
-- produces a strobe indicating the pump to which current time slot for
-- for writing is assigned (time slot == one cycle)
signal sync_sreg_rd : std_logic_vector(c_swc_packet_mem_multiply-1 downto 0);
-- used for multiplexing of data in arrays (write data)
-- into *_muxed data inputed into FB SRAM.
-- not necesserely occures in the same time as sync, since e.g. address
-- may be needed advance, etc
signal sync_cntr : integer range 0 to c_swc_packet_mem_multiply-1;
-- used for multiplexing of data in arrays of rd_addr
-- and for demultiplexing of data ouputed by FB SRAM to
-- arrays inputed to pumps
-- not necesserely occures in the same time as sync, since e.g. address
-- may be needed advance, etc
signal sync_cntr_rd : integer range 0 to c_swc_packet_mem_multiply-1;
begin -- rtl
-- managing synchronization of the pumps, so each pump is given one-cycle
-- time slot in which it can read and write.
-- the sync_sreg produces a strobe to indicate the timeslot
-- synch_cntr produces a number indicating pump number to mux/demux data
sync_gen : process (clk_i, rst_n_i)
begin -- process
if rising_edge(clk_i) then
if(rst_n_i = '0') then
sync_sreg (0) <= '1';
sync_sreg (sync_sreg'length - 1 downto 1) <= (others => '0');
sync_cntr <= c_swc_packet_mem_multiply-1;
-- ML: BUGFIX ?????????
sync_cntr_rd <= 1; -- c_swc_packet_mem_multiply-1;
else
sync_sreg <= sync_sreg(sync_sreg'length-2 downto 0) & sync_sreg(sync_sreg'length-1);
if(sync_cntr = c_swc_packet_mem_multiply-1) then
sync_cntr <= 0;
else
sync_cntr <= sync_cntr + 1;
end if;
if(sync_cntr_rd = c_swc_packet_mem_multiply-1) then
sync_cntr_rd <= 0;
else
sync_cntr_rd <= sync_cntr_rd + 1;
end if;
end if;
end if;
end process;
sync_sreg_rd <= sync_sreg;
rd_sync_o <= sync_sreg(c_swc_num_ports - 1 downto 0);
-- sync_sreg_rd(c_swc_packet_mem_multiply-1 downto 0) <= sync_sreg(1 downto 0) & sync_sreg(c_swc_num_ports-1 downto 2);
-- producing pump output data
merge_ctrl_data_wr : for i in 0 to c_swc_num_ports-1 generate
wr_pump_data_in(i) <= wr_ctrl_i(i * c_swc_ctrl_width + c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width)
& wr_data_i(i * c_swc_data_width + c_swc_data_width - 1 downto i * c_swc_data_width);
end generate merge_ctrl_data_wr;
------------------------------------------------------------------------------------------------------------
------------------------------------- mutiport memory modul --------------------------------------------
------------------------------------------------------------------------------------------------------------
-- write pump: it saves c_swc_packet_mem_multiply words (ctrl + data) into an input register (regardless
-- of the above synch and time slot). As soon as the reg is full (or flush req), it is written to
-- FB SRAM (one word). The pump accepts page number of the FB SRAM to which data shall be written.
-- The pump handles page-internal address. There is one pump for each port.
gen_write_pumps : for i in 0 to c_swc_num_ports-1 generate
WRPUMP : swc_packet_mem_write_pump
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
pgaddr_i => wr_pageaddr_i(c_swc_page_addr_width * i + c_swc_page_addr_width - 1 downto c_swc_page_addr_width * i),
pgreq_i => wr_pagereq_i(i),
pckstart_i => wr_pckstart_i(i),
pgend_o => wr_pageend_o(i),
drdy_i => wr_drdy_i(i),
full_o => wr_full_o(i),
flush_i => wr_flush_i(i),
ll_addr_o => wr_pump_ll_addr_out(i),
ll_data_o => wr_pump_ll_data_out(i),
ll_wr_req_o => wr_pump_ll_wr_req_out(i),
ll_wr_done_i => wr_pump_ll_wr_req_done_in(i),
-- current_page_addr_o => wr_pump_current_page_addr_out(i),
-- next_page_addr_o => wr_pump_next_page_addr_out(i),
-- next_page_addr_we_o => wr_pump_next_page_addr_we_out(i),
sync_i => sync_sreg(i),
d_i => wr_pump_data_in(i),
q_o => wr_pump_data_out(i),
addr_o => wr_pump_addr_out(i),
we_o => wr_pump_we(i));
end generate gen_write_pumps;
-- Muxing of data from each pump (array) into data inputted into FB SRAM.
-- which data is muxed, depends on the current time slot.
ram_write_mux : process(sync_cntr, wr_pump_addr_out, wr_pump_data_out, wr_pump_we)
begin
if(sync_cntr < c_swc_num_ports) then
ram_we_muxed <= wr_pump_we(sync_cntr);
ram_wr_addr_muxed <= wr_pump_addr_out(sync_cntr);
ram_wr_data_muxed <= wr_pump_data_out(sync_cntr);
else
ram_we_muxed <= '0';
ram_wr_data_muxed <= (others => '0');
ram_wr_addr_muxed <= (others => '0');
end if;
end process;
-- The most important part, the shared memory
FUCKING_BIG_MEMORY : generic_ssram_dualport_singleclock
generic map (
g_width => c_swc_packet_mem_multiply * c_swc_pump_width,
g_addr_bits => c_swc_packet_mem_addr_width,
g_size => c_swc_packet_mem_size / c_swc_packet_mem_multiply)
port map (
clk_i => clk_i,
rd_addr_i => ram_rd_addr_muxed,
wr_addr_i => ram_wr_addr_muxed,
data_i => ram_wr_data_muxed,
wr_en_i => ram_we_muxed,
q_o => ram_rd_data);
-- read pump: it reads c_swc_packet_mem_multiply words (ctrl + data) from FB SRAM and makes it
-- available to be read by port (word by wrod, word=ctrl+data). Reading of output register can be
-- done regardless of the synch and time slot. As soon as the reg is empty and more reading is
-- requested by a port, new FB SRAM word is read
-- The pump accepts page number of the FB SRAM from which data shall be read.
-- The pump handles page-internal address. There is one pump for each port.
gen_read_pumps : for i in 0 to c_swc_num_ports-1 generate
RDPUMP : swc_packet_mem_read_pump
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
pgreq_i => rd_pagereq_i(i),
pgaddr_i => rd_pageaddr_i(c_swc_page_addr_width * i + c_swc_page_addr_width - 1 downto c_swc_page_addr_width * i),
pckend_o => rd_pckend_o(i),
pgend_o => rd_pageend_o(i),
drdy_o => rd_drdy_o(i),
dreq_i => rd_dreq_i(i),
sync_read_i => rd_sync_read_i(i),
ll_read_addr_o => rd_pump_ll_addr_out(i),
ll_read_data_i => llist_rd_data,
ll_read_req_o => rd_pump_ll_rd_req_out(i),
ll_read_valid_data_i=> rd_pump_ll_rd_req_done_in(i),
-- free_o => pa_free_o(i),
-- free_done_i => pa_free_done_i(i),
-- free_pgaddr_o => pa_free_pgaddr_o((i + 1)*c_swc_page_addr_width -1 downto i * c_swc_page_addr_width),
-- current_page_addr_o => rd_pump_current_page_addr_out(i),
-- next_page_addr_i => llist_rd_data,
d_o => rd_pump_data_out(i),
sync_i => sync_sreg_rd(i),
addr_o => rd_pump_addr_out(i),
q_i => ram_rd_data);
end generate gen_read_pumps;
-- data from the pump to the ports (demux)
split_ctrl_data_rd : for i in 0 to c_swc_num_ports-1 generate
rd_ctrl_o(i * c_swc_ctrl_width + c_swc_ctrl_width - 1 downto i * c_swc_ctrl_width) <= rd_pump_data_out(i)(c_swc_data_width + c_swc_ctrl_width -1 downto c_swc_data_width);
rd_data_o(i * c_swc_data_width + c_swc_data_width - 1 downto i * c_swc_data_width) <= rd_pump_data_out(i)(c_swc_data_width-1 downto 0);
end generate split_ctrl_data_rd;
-- muxing read address
ram_read_mux : process(sync_cntr_rd, rd_pump_addr_out)
begin
if(sync_cntr_rd < c_swc_num_ports) then
ram_rd_addr_muxed <= rd_pump_addr_out(sync_cntr_rd);
else
ram_rd_addr_muxed <= (others => '0');
end if;
end process;
------------------------------------------------------------------------------------------------------------
------------------------------------- linkded list modul --------------------------------------------
------------------------------------------------------------------------------------------------------------
-- llist_write_mux : process(sync_cntr,wr_pump_next_page_addr_we_out , wr_pump_current_page_addr_out, wr_pump_next_page_addr_out)
-- begin
-- if(sync_cntr < c_swc_num_ports) then
-- llist_we_muxed <= wr_pump_next_page_addr_we_out(sync_cntr);
-- llist_wr_addr_muxed <= wr_pump_current_page_addr_out(sync_cntr);
-- llist_wr_data_muxed <= wr_pump_next_page_addr_out(sync_cntr);
-- else
-- llist_we_muxed <= '0';
-- llist_wr_data_muxed <= (others => '0');
-- llist_wr_addr_muxed <= (others => '0');
-- end if;
-- end process;
--
-- -- muxing read address
-- llist_read_mux : process(sync_cntr_rd, wr_pump_current_page_addr_out)
-- begin
-- if(sync_cntr_rd < c_swc_num_ports) then
-- llist_rd_addr_muxed <= rd_pump_current_page_addr_out(sync_cntr_rd);
-- else
-- llist_rd_addr_muxed <= (others => '0');
-- end if;
-- end process;
--
-- -- The most important part, the shared memory
-- PAGE_INDEX_LINKED_LIST : generic_ssram_dualport_singleclock
-- generic map (
-- g_width => c_swc_page_addr_width,
-- g_addr_bits => c_swc_page_addr_width,
-- g_size => c_swc_packet_mem_size / c_swc_packet_mem_multiply)
-- port map (
-- clk_i => clk_i,
-- rd_addr_i => llist_rd_addr_muxed,
-- wr_addr_i => llist_wr_addr_muxed,
-- data_i => llist_wr_data_muxed,
-- wr_en_i => llist_we_muxed ,
-- q_o => llist_rd_data);
linked_list_data : for i in 0 to c_swc_num_ports-1 generate
ll_write_addr_i (i* c_swc_page_addr_width + c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width) <= wr_pump_ll_addr_out(i);
ll_write_data_i (i* c_swc_page_addr_width + c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width) <= wr_pump_ll_data_out(i);
ll_read_pump_addr_i(i* c_swc_page_addr_width + c_swc_page_addr_width - 1 downto i * c_swc_page_addr_width) <= rd_pump_ll_addr_out(i);
end generate linked_list_data;
ll_read_pump_read_i <= rd_pump_ll_rd_req_out;
rd_pump_ll_rd_req_done_in <= ll_read_pump_read_done_o;
ll_write_i <= wr_pump_ll_wr_req_out;
wr_pump_ll_wr_req_done_in <= ll_write_done_o;
-- LINKED_LIST : swc_multiport_linked_list
-- port map (
-- rst_n_i => rst_n_i,
-- clk_i => clk_i,
--
-- -- IF with write pump
-- write_i => ll_write_i,
-- write_done_o => ll_write_done_o,
-- write_addr_i => ll_write_addr_i,
-- write_data_i => ll_write_data_i,
--
-- -- IF with page allocator
-- free_i => (others =>'0'),
-- free_done_o => open,
-- free_addr_i => (others =>'0'),
--
-- -- IF with read pump
-- read_pump_read_i => ll_read_pump_read_i,
-- read_pump_read_done_o => ll_read_pump_read_done_o,
-- read_pump_addr_i => ll_read_pump_addr_i,
--
-- -- IF with Lost Pck Dealloc (LPD)
-- free_pck_read_i => (others =>'0'),
-- free_pck_read_done_o => open,
-- free_pck_addr_i => (others =>'0'),
--
-- -- output data for all reads
-- data_o => llist_rd_data
-- );
-------------------------------------------------
-- Interface with Linked List
-- [a bit strange naming due to the fact that
-- the LL module was initialy inside packet_mem]
------------------------------------------------
write_o <= ll_write_i;
write_addr_o <= ll_write_addr_i;
write_data_o <= ll_write_data_i;
read_pump_read_o <= ll_read_pump_read_i;
read_pump_addr_o <= ll_read_pump_addr_i;
-- output data for all reads
ll_read_pump_read_done_o <= read_pump_read_done_i;
ll_write_done_o <= write_done_i;
llist_rd_data <= data_i ;
wr_sync_o <= sync_sreg(c_swc_num_ports-1 downto 0);
end rtl;
-------------------------------------------------------------------------------
-- Title : Memory Read Pump
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_packet_mem_read_pump.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-10-12
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: This piece of code reads a bunch ('c_swc_packet_mem_multiply'
-- of words = ctrl + data) from the FUCKING BIG SRAM and makes it available
-- for read by port. There is one read_pump for each port. Each pump has its
-- time slot to read from FB SRAM.
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
-- Detailed description:
-- the thing works in the following way:
-- 1) it takes the address (FB SRAM addr) of the page
-- 2) it reads it in its time slot which is one cycle every
-- c_swc_packet_mem_multiply cycles
-- 3) it makes it available on its output (d_o) word by word (in number of
-- c_swc_packet_mem_multiply words, this is how many words is saved in
-- on FB SRAM word)
-- 4) it announces it with 'drdy_o' HIGH
-- 5) the next word is available after setting dreq_i high
--
--
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-12 1.1 mlipinsk comments added !!!!!
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_packet_mem_read_pump is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Next page address input strobe (active HI) - loads internal
-- memory address register with the address of new page
pgreq_i : in std_logic;
-- Next page address input (from page allocator)
pgaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- end of package
pckend_o : out std_logic;
-- HI indicates that current page is done, and that the parent entity must
-- select another page in following clock cycles (c_swc_packet_mem_multiply
-- 2) if it wants to write more data into the memory
-- ML: BUG : it's assigned directly to the output, that sucks, it should be
-- done through register, I presume
pgend_o : out std_logic;
-- data ready to be read by the host entity
drdy_o : out std_logic;
-- data request (request next word)
dreq_i : in std_logic;
-- used to synchronize first read attempt with synch,
-- in other words, it tells the read_pump that this is the
-- first attempt to read, and the data that is now availabel (some rubbish)
-- is not interesting for us, so itm (reg_out) does not need to be read to
-- the end
-- to be HIGH during first cycle of dreq_i HIGH (and also most often preq_i)
sync_read_i : in std_logic;
-- address in LL SRAM which corresponds to the page address
--current_page_addr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
ll_read_addr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
-- data output for LL SRAM - it is the address of the next page or 0xF...F
-- if this is the last page of the package
--next_page_addr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_req_o : out std_logic;
ll_read_valid_data_i : in std_logic;
-- the data we want: one word= ctrl+data
d_o : out std_logic_vector(c_swc_pump_width - 1 downto 0);
-- strobe indicating the time slot for this pump
sync_i : in std_logic;
-- address in FB SRAM from which the FB SRAM word ( c_swc_packet_mem_multiply
-- of words=ctrl+data) is to be read in the pump's time slot
--------------
-- IMPORTANT :
--------------
-- this address output needs to be multiplexed so that it is 'visible' by
-- FBSRAM during the pump's time slot (sync_i is HIGH). It means that
-- the timeslot for reading addr_o by multiplexer is one cycle before sync_i !!!
addr_o : out std_logic_vector(c_swc_packet_mem_addr_width - 1 downto 0);
-- data read from FB SRAM
q_i : in std_logic_vector(c_swc_pump_width * c_swc_packet_mem_multiply -1 downto 0)
);
end swc_packet_mem_read_pump;
architecture syn of swc_packet_mem_read_pump is
-- the register to hold c_swc_packet_mem_multiply words(ctrl+data) read from
-- one FB SRAM word
signal out_reg : t_pump_reg;
-- count the words already read by the host entity
signal cntr : unsigned(3 downto 0);
-- some delaying of synch strobe
signal sync_d0 : std_logic;
signal sync_d1 : std_logic;
-- out_reg not empty yet,
signal reg_not_empty : std_logic;
-- all words in the out_reg have been read by the host entity
signal cntr_full : std_logic;
-- address to be suplied to FB SRAM, consists of the pgaddr and page-internal address
signal mem_addr : std_logic_vector (c_swc_packet_mem_addr_width - 1 downto 0);
-- ... we love VHDL ...
signal allones : std_logic_vector(63 downto 0);
signal zeros : std_logic_vector(63 downto 0);
-- for the condition needed to increase page-internal address
signal advance_addr : std_logic;
-- indicates whether the next FB SRAM word is bo be read and loaded to out_reg
signal load_out_reg : std_logic;
-- seems not used ....
-- signal nothing_read : std_logic;
-- HI indicates that current page is done, and that the parent entity must
-- select another page in following clock cycles (c_swc_packet_mem_multiply
-- 2) if it wants to write more data into the memory
signal pgend : std_logic;
-- page end
signal pckend : std_logic;
signal current_page_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal next_page_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_read_req : std_logic;
signal reading_pck : std_logic;
signal read_valid : std_logic;
signal pgreq_d0 : std_logic;
begin -- syn
allones <= (others => '1');
zeros <= (others => '0');
-- last word from out_reg read
cntr_full <= '1' when cntr = to_unsigned(c_swc_packet_mem_multiply-1, cntr'length) else '0';
-- reading new FB SRAM word is needed. it happens in the pump's time slot only if :
-- * out_reg is empty (used in case there is no request to read data from the pump ????)
-- * the last word from the out_reg has been read and there host entity wants more !!!)
-- load_out_reg <= '1' when sync_i = '1' and (reg_not_empty = '0' or (cntr_full = '1' and dreq_i = '1')) else '0';
load_out_reg <= '1' when (sync_i = '1' and (reg_not_empty = '0' or (cntr_full = '1' and dreq_i = '1')) and pgreq_d0 = '0' and pgreq_i = '0') else '0';
process (clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
sync_d1 <= '0';
sync_d0 <= '0';
pgreq_d0<= '0';
else
sync_d1 <= sync_d0;
sync_d0 <= sync_i;
pgreq_d0<= pgreq_i;
end if;
end if;
end process;
process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
cntr <= (others => '0');
reg_not_empty <= '0';
mem_addr <= (others => '0');
advance_addr <= '0';
-- nothing_read <= '0';
pgend <= '0';
pckend <= '0';
current_page_addr <= (others => '0');
next_page_addr <= (others => '0');
ll_read_req <= '0';
reading_pck <= '0';
read_valid <= '0';
else
if(pgreq_i = '1') then
-- writing FB SRAM web address which consists of page address and page-internal address
mem_addr(c_swc_packet_mem_addr_width-1 downto c_swc_page_offset_width) <= pgaddr_i;
mem_addr(c_swc_page_offset_width-1 downto 0) <= (others => '0');
pgend <= '0';
current_page_addr <= pgaddr_i;
pckend <='0';
reading_pck <='1';
-----------------------------
reg_not_empty <= '0'; -- added by ML
cntr <= (others=>'0');
-----------------------------
--ll_read_req <= '1';
elsif(sync_d1 = '1' and advance_addr = '1' and pgreq_i = '0' and pgreq_d0 = '0') then
-- incrementing address inside the same page
mem_addr(c_swc_page_offset_width-1 downto 0) <= std_logic_vector(unsigned(mem_addr(c_swc_page_offset_width-1 downto 0)) + 1);
-- we are approaching the end of current page. Inform the host entity some
-- cycles in advance.
advance_addr <= '0';
if(mem_addr(c_swc_page_offset_width-1 downto 0) = allones(c_swc_page_offset_width-1 downto 0)) then
if(next_page_addr = allones(c_swc_page_addr_width - 1 downto 0)) then
pckend <= '1';
reading_pck <= '0';
else
mem_addr(c_swc_packet_mem_addr_width-1 downto c_swc_page_offset_width) <= next_page_addr;
mem_addr(c_swc_page_offset_width-1 downto 0) <= (others => '0');
end if;
pgend <= '1';
end if;
if(mem_addr(c_swc_page_offset_width-1 downto 0) = zeros(c_swc_page_offset_width-1 downto 0)) then
current_page_addr <= mem_addr(c_swc_packet_mem_addr_width-1 downto c_swc_page_offset_width);
pgend <= '0';
-- start requesting next address
if(reading_pck = '1') then
ll_read_req <= '1';
end if;
end if;
end if;
-- we want to read next FB SRAM word and laod it into out_reg (this s our
-- time slot
if(load_out_reg = '1' and pckend = '0') then
reg_not_empty <= '1';
advance_addr <= '1';
-- next_page_addr <= next_page_addr_i;
for i in 0 to c_swc_packet_mem_multiply-1 loop
-- reading the word and putting it into out_reg array
out_reg (i) <= q_i(c_swc_pump_width * (i+1) - 1 downto c_swc_pump_width * i);
end loop;
-- we read all the words from out_reg, we want more but it's not
-- our time slot yet, so we indicate with reg_not_empty that
-- in the next time slot read from FB SRAM should be done
elsif(sync_i = '0' and cntr_full = '1' and dreq_i = '1') then
reg_not_empty <= '0';
end if;
-- request for the next word from out_reg, increment the counter
if(dreq_i = '1' and reg_not_empty = '1') then
if(sync_read_i = '1') then
reg_not_empty <= '0';
cntr <= (others=>'0');
else
cntr <= cntr + 1;
end if;
-- we don't load new stuff from the FB SRAM, so
-- this is normal situation, this means that
-- the currently available word has been read and
-- we want to provide new word to the outside word
-- so we shift right the words in the array
if(load_out_reg = '0') then
for i in 1 to c_swc_packet_mem_multiply-1 loop
out_reg (i-1) <= out_reg(i);
end loop;
out_reg(c_swc_packet_mem_multiply-1) <= (others => 'X');
end if;
end if;
if(ll_read_valid_data_i = '1' ) then
next_page_addr <= ll_read_data_i;
ll_read_req <= '0';
end if;
if(dreq_i = '1' and reg_not_empty = '1' and load_out_reg = '0') then
read_valid <= '1';
elsif(load_out_reg = '1' and pckend = '0') then
read_valid <= '1';
else
read_valid <= '0';
end if;
end if;
end if;
end process;
drdy_o <= reg_not_empty and read_valid;
addr_o <= mem_addr;
d_o <= out_reg (0);
pgend_o <= pgend;
pckend_o <= pckend;
ll_read_addr_o <= current_page_addr; -- current_page_addr_o <= current_page_addr;
ll_read_req_o <= ll_read_req;
end syn;
-------------------------------------------------------------------------------
-- Title : Memory Write Pump
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_packet_mem_write_pump.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-10-12
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: Collectes data (words of ctrl+data seq) from one port and
-- pumps (saves) sequence of such data to one word of SRAM memory with the
-- page address allocated by mutiport memory allocator. The access to
-- SSRAM is shared equally between many such pumps, each pump represents
-- one port.
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
-- A pump works in the following way:
-- 1) it collects data from a port, data can be written continuously.
-- - data consits of a word of ctrl + data seq
-- - one word can be written at one clock cycle, in such case drdy_i is
-- - constantly HIGH
-- 2) if entire "vector" of data words is collected ('c_swc_packet_mem_multiply'
-- number of data words), such a vector is written to SSRAM to one word:
-- - the dats is written to SRAM memory address = page_addr + offset
-- - each "memory page" (indicated by page_addr) consists of a few
-- SRAM consecutive addresses
-- 3) when the vector to be written to the last address of the page is being
-- filled in, the 'pend_o' indicates that the end of the page
--
-- Each pump has its 'time slot' (one cycle) to read/write from/to
-- *FUCKING BIG SRAM (FB SRAM)*. The access is granted to each pump in sequence:
-- 1,2,3...(c_swc_packet_mem_multiply - 1). The access is multiplexed
-- between the pumps.
--
-- If we want to write to the FB SRAM vector not fully filled in with data,
-- we can use 'flush_i'. High stribe on flush input enforces the pump to
-- behave as if it was full and the write to FB SRAM was needed in the
-- next available 'time slot'.
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-- -------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-12 1.1 mlipinsk comments added !!!!!
-- 2010-10-18 1.2 mlipinsk clearing register
-- 2010-11-24 1.3 mlipinsk adding main FSM !
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.log2;
use ieee.math_real.ceil;
--use std.textio.all;
library work;
use work.swc_swcore_pkg.all;
--use work.pck_fio.all;
entity swc_packet_mem_write_pump is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- paging interface
-------------------------------------------------------------------------------
-- Next page address input (from page allocator)
pgaddr_i : in std_logic_vector(c_swc_page_addr_width-1 downto 0);
-- Next page address input strobe (active HI) - loads internal
-- memory address register with the address of new page
pgreq_i : in std_logic;
-- HI indicates that current page is done, and that the parent entity must
-- select another page in following clock cycles (c_swc_packet_mem_multiply
-- 2) if it wants to write more data into the memory
pgend_o : out std_logic;
-- it indicates the start of a package, it need to be high when writing the
-- first data of the new package
pckstart_i: in std_logic;
-------------------------------------------------------------------------------
-- data channel interface
-------------------------------------------------------------------------------
-- data input. data consists of 'c_swc_ctrl_width' of control data and
-- 'c_swc_data_width' of data
-- sequence (of 'c_swc_packet_mem_multiply' number) of such data is saved
-- in one SRAM memory word at the pgaddr_i
d_i : in std_logic_vector(c_swc_pump_width -1 downto 0);
-- data input ready strobe (active HI). Clocks in the data. drdy_i cannot
-- be asserted when full_o is active.
drdy_i : in std_logic;
-- input register full (active HI). Indicates that the memory input
-- register is full ('c_swc_packet_mem_multiply' words have been written)
-- it will go back to 0 as soon as the memory input reg is synced to the
-- shared memory.
full_o : out std_logic;
-- Memory input register flush (active HI). Forces a flush of memory input
-- register to the shared memory on the next sync pulse even if the number
-- of words clocked into the pump is less than c_swc_packet_mem_multiply.
flush_i : in std_logic;
-------------------------------------------------------------------------------
-- Linked List of page addresses (LL SRAM) interface
-------------------------------------------------------------------------------
-- address in LL SRAM which corresponds to the page address
ll_addr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
-- data output for LL SRAM - it is the address of the next page or 0xF...F
-- if this is the last page of the package
ll_data_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- request to write to Linked List, should be high until
-- ll_wr_done_i indicates successfull write
ll_wr_req_o : out std_logic;
ll_wr_done_i : in std_logic;
-------------------------------------------------------------------------------
-- shared memory (FB SRAM) interface
-- The access is multiplexed with other pumps. Each pump has a one-cycle-timeslot
-- to access the FB SRAM every 'c_swc_packet_mem_multiply' cycles.
-------------------------------------------------------------------------------
-- synchronization pulse. HI indicates a time-slot assigned to this write pump.
-- One cycle after reception of pulse on sync_i, the pump must provide valid
-- values of addr_o, q_o and we_o, eventually commiting the contents of memory
-- input register to the shared mem block.
sync_i : in std_logic;
-- address output for shared memory block
addr_o : out std_logic_vector(c_swc_packet_mem_addr_width -1 downto 0);
-- data output for shared memory block
q_o : out std_logic_vector(c_swc_pump_width * c_swc_packet_mem_multiply - 1 downto 0);
-- write strobe output for shared memory block (FB SRAM), multiplexed with other pumps
we_o : out std_logic
);
end swc_packet_mem_write_pump;
architecture rtl of swc_packet_mem_write_pump is
-- word counter (word consists of ctrl + data), counts words in the 'in_reg' register
signal cntr : unsigned(3 downto 0);
-- memory input register organized as an array of (c_swc_packet_mem_multiply) input
-- wordsn (ctrl + data).
signal in_reg : t_pump_reg;
-- indicates that in_reg is full, 'c_swc_packet_mem_multiply' words has been written)
signal reg_full : std_logic;
-- memory register, consists of 'pg_addr' and in-page count (the number of inside
-- page FB SRAM words is: (c_swc_page_size / c_swc_packet_mem_multiply)
signal mem_addr : std_logic_vector (c_swc_packet_mem_addr_width - 1 downto 0);
-- FB SRAM write enable (internal). Translate into write request to FB SRAM.
-- the access is multiplexed, so the write request has to be issued in this
-- pump's time slot.
signal we_int : std_logic;
-- stores the flush request from 'hihger up'
signal flush_reg : std_logic;
-- combinatorial signal: attempt to write when counter is max
signal write_on_sync : std_logic;
-- indicates that the 'page' is full, so the internal
-- FB SRAM address counter is 1..1
signal cntr_full : std_logic;
-- we all love VHDL :)
signal allones : std_logic_vector(63 downto 0);
--signal zeros : std_logic_vector(63 downto 0);
-- HI indicates that current page is done, and that the parent entity must
-- select another page in following clock cycles (c_swc_packet_mem_multiply
-- 2) if it wants to write more data into the memory
signal pgend : std_logic;
-- start of package
signal pckstart : std_logic;
-- signal before_sync : std_logic;
--=================================================================================
-- address in LL SRAM which corresponds to the page address
signal current_page_addr_int : std_logic_vector(c_swc_page_addr_width -1 downto 0);
-- stored during FSM cycle (next->eop), this is needed for the last page of the pck
-- in such case we need to remember it, otherwise we have problems
signal current_page_addr_fsm : std_logic_vector(c_swc_page_addr_width -1 downto 0);
signal previous_page_addr_int : std_logic_vector(c_swc_page_addr_width -1 downto 0);
-- internal
signal ll_write_addr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- internal
signal ll_write_data : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- indicatest that the next address shall be writtent to
-- Linked List SRAM
signal ll_wr_req : std_logic;
signal ll_idle : std_logic;
signal ll_wr_done_reg : std_logic;
signal no_next_page_addr: std_logic;
signal writing_last_page : std_logic;
type t_state is (IDLE, WR_NEXT, WR_EOP, WR_LAST_EOP, WR_TRANS_EOP);
signal state : t_state;
type t_state_write is (S_IDLE, S_READ_DATA,
S_READ_LAST_DATA_WORD,
S_WRITE_DATA,
S_WRITE_ON_FLUSH,
S_FLUSH,
S_WAIT_WRITE,
S_WAIT_LL_READY,
S_NASTY_WAIT);
signal state_write : t_state_write;
-- signal cnt_last_word : std_logic;
-- signal next_page_loaded : std_logic;
signal pgreq_reg : std_logic;
signal pckstart_reg : std_logic;
signal pgreq_or : std_logic;
signal pckstart_or : std_logic;
signal sync_d : std_logic_vector(c_swc_packet_mem_multiply - 1 downto 0);
-- signal nasty_wait_full : std_logic;
begin -- rtl
-- VHDL sucks...
allones <= (others => '1');
-- zeros <= (others => '0');
write_on_sync <= '1' when (cntr = to_unsigned(0,cntr'length)) else '0';
synch_delay : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
sync_d <= (others =>'0');
else
sync_d(0) <= sync_i;
for i in 1 to c_swc_packet_mem_multiply-1 loop
sync_d(i) <= sync_d(i - 1);
end loop;
end if;
end if;
end process;
-- before_sync <= sync_d(c_swc_packet_mem_multiply - 2);
write_fsm : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
we_int <= '0';
reg_full <= '0';
-- cnt_last_word <='0';
else
-- main finite state machine
case state_write is
when S_IDLE =>
if(drdy_i = '1') then
state_write <= S_READ_DATA;
end if;
when S_READ_DATA =>
if(flush_i = '1') then
state_write <= S_FLUSH;
reg_full <= '1';
elsif(cntr = to_unsigned(c_swc_packet_mem_multiply - 2,cntr'length) and drdy_i ='1') then
state_write <= S_READ_LAST_DATA_WORD;
-- cnt_last_word <= '1';
end if;
when S_READ_LAST_DATA_WORD =>
if( sync_i = '1') then
if(pgend = '1' and drdy_i = '1') then -- see screenshot: swcore-writepump-p1
reg_full <= '1';
state_write <= S_WAIT_WRITE;
-- cnt_last_word <= '0';
-- during the last address of the page, the Linked list is being written, so we need
-- to wait for it to finish
elsif(mem_addr(c_swc_page_offset_width-1 downto 0) = allones(c_swc_page_offset_width-1 downto 0) and ll_idle = '0' ) then
state_write <= S_WAIT_LL_READY;
reg_full <= '1';
elsif(drdy_i ='1') then
state_write <= S_WRITE_DATA;
we_int <= '1';
reg_full <= '0';
-- cnt_last_word <= '0';
elsif(flush_i = '1') then
state_write <= S_WRITE_DATA;
we_int <= '1';
reg_full <= '0';
else
state_write <= S_NASTY_WAIT;
we_int <= '0';
reg_full <= '0';
-- cnt_last_word <= '0';
end if;
-- elsif(drdy_i = '1' and flush_i ='1') then
--
-- state_write <= S_WRITE_DATA;
-- we_int <= '1';
-- reg_full <= '0';
-- cnt_last_word <= '0';
--
else -- synch_i = '0'
-- if(cntr = to_unsigned(c_swc_packet_mem_multiply -1,cntr'length) and drdy_i = '1') then
--
--==== needs test - start ===
if( drdy_i = '1') then
--==== needs test - end ===
reg_full <= '1';
state_write <= S_WAIT_WRITE;
-- cnt_last_word <= '0';
--==== needs test - start ===
end if;
--==== needs test - end ===
--
-- else
--
--- reg_full <= '0';
-- state_write <= S_NASTY_WAIT;
-- cnt_last_word <= '0';
-- end if;
end if;
when S_NASTY_WAIT =>
if(drdy_i = '1' and sync_i = '1' and cntr = to_unsigned(c_swc_packet_mem_multiply -1,cntr'length)) then
state_write <= S_WRITE_DATA;
we_int <= '1';
reg_full <= '0';
-- cnt_last_word <= '0';
elsif(drdy_i = '1' and sync_i = '0' ) then
reg_full <= '1';
state_write <= S_WAIT_WRITE;
-- cnt_last_word <= '0';
end if;
when S_WRITE_DATA =>
we_int <= '0';
reg_full <= '0';
-- flushed precisely when writing data
-- when there is new data available
-- in such case, there will be one word
-- to write in new page
if(drdy_i = '1' and flush_i ='1') then
state_write <= S_FLUSH;
reg_full <= '1';
-- NORMAL CASE: writing when new data available
elsif(drdy_i = '1' and flush_i ='0') then
state_write <= S_READ_DATA;
elsif(drdy_i = '1' and ll_idle = '0') then
state_write <= S_WAIT_LL_READY;
reg_full <= '1';
-- flush when there is no new data, it means that
-- the data that is being written is the last
elsif(drdy_i = '0' and flush_i ='1') then
state_write <= S_IDLE;
else
-- state_write <= S_IDLE;
state_write <= S_READ_DATA;
end if;
when S_FLUSH =>
if(sync_i = '1' and pgend = '0') then
state_write <= S_WRITE_DATA;
reg_full <= '0';
we_int <= '1';
end if;
when S_WAIT_WRITE =>
if(sync_i = '1' and pgend = '0') then
if(mem_addr(c_swc_page_offset_width-1 downto 0) = allones(c_swc_page_offset_width-1 downto 0) and ll_idle = '0') then
state_write <= S_WAIT_LL_READY;
reg_full <= '1';
elsif(drdy_i = '1' or write_on_sync = '1' or flush_reg = '1') then
-- else
state_write <= S_WRITE_DATA;
we_int <= '1';
reg_full <= '0';
end if;
end if;
when S_WAIT_LL_READY =>
if(drdy_i = '0' and ll_idle = '1') then
state_write <= S_WRITE_DATA;
we_int <= '1';
reg_full <= '0';
-- cnt_last_word <= '0';
end if;
when others =>
state_write <= S_IDLE;
end case;
end if;
end if;
end process;
-- cntr_full <= '1' when cntr = to_unsigned(c_swc_packet_mem_multiply-1, cntr'length) else '0';
process(clk_i, rst_n_i)
begin
if rising_edge (clk_i) then
if(rst_n_i = '0') then
cntr <= (others => '0');
mem_addr <= (others => '0');
pgend <= '0';
-- next_page_loaded <= '0';
--pckstart <= '0';
for i in 0 to c_swc_packet_mem_multiply-1 loop
in_reg(i) <= (others => '0');
end loop; -- i
pckstart_reg <= '0';
pgreq_reg <= '0';
flush_reg <='0';
else
if(flush_i = '1' and sync_i = '0') then
flush_reg <= '1';
elsif(sync_i = '1' and flush_reg ='1') then
flush_reg <= '0';
end if;
if(pgreq_i = '1') then
pgend <= '0';
elsif(mem_addr(c_swc_page_offset_width-1 downto 0) = allones(c_swc_page_offset_width-1 downto 0) ) then
if(cntr = to_unsigned(c_swc_packet_mem_multiply -1,cntr'length) and sync_i = '1' and drdy_i = '1') then
pgend <= '1';
elsif(write_on_sync = '1' and sync_i = '1') then
pgend <= '1';
end if;
end if;
if(pgreq_i = '1') then
mem_addr(c_swc_packet_mem_addr_width-1 downto c_swc_page_offset_width) <= pgaddr_i;
mem_addr(c_swc_page_offset_width-1 downto 0) <= (others => '0');
-- pgend <= '0';
-- next_page_loaded <= '1';
elsif(state_write = S_WRITE_DATA) then
if(mem_addr(c_swc_page_offset_width-1 downto 0) = allones(c_swc_page_offset_width-1 downto 0) ) then
-- pgend <= '1';
-- next_page_loaded <= '0';
else
mem_addr(c_swc_page_offset_width-1 downto 0) <= std_logic_vector(unsigned(mem_addr(c_swc_page_offset_width-1 downto 0)) + 1);
end if;
end if;
if(drdy_i = '1') then
-- if( cntr = 0 and pckstart_i = '1') then
-- pckstart <= '1';
-- end if;
-- if new address is set when the previous is
-- being written to Linked List, we need to remember
-- this to be able to come to it later
if(pgreq_i ='1' and state /= IDLE ) then
pgreq_reg <='1';
end if;
if(pckstart_i = '1' and state /=IDLE ) then
pckstart_reg <= '1';
end if;
for i in 0 to c_swc_packet_mem_multiply-1 loop
if(i >= to_integer(cntr)) then
in_reg(i) <= (others => '0');
end if;
end loop;
in_reg(to_integer(cntr)) <= d_i;
-- wrap around the 'in_reg' indicating that the reg is full to the host
-- entity
-- if(state_write = S_IDLE) then
-- cntr <= (others =>'1');
-- elsif(cntr = to_unsigned(c_swc_packet_mem_multiply -1,cntr'length)) then
if(cntr = to_unsigned(c_swc_packet_mem_multiply -1,cntr'length)) then
cntr <= (others => '0');
elsif((state_write = S_READ_LAST_DATA_WORD) and sync_i = '1') then
cntr <= (others => '0');
-- elsif(reg_full = '1') then
-- cntr <= (others => '0');
else
cntr <= cntr + 1;
end if;
else
if(((state_write = S_FLUSH or state_write = S_WAIT_LL_READY ) or flush_i = '1') and sync_i = '1') then
cntr <= (others => '0');
end if;
end if;
if(ll_wr_done_i = '1') then
pckstart_reg <= '0';
pgreq_reg <='0';
end if;
end if;
end if;
end process;
pg : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
current_page_addr_int <= (others => '0');
previous_page_addr_int <= (others => '0');
else
if(pgreq_i = '1') then
current_page_addr_int <= pgaddr_i;
end if;
if(ll_wr_done_i = '1') then
previous_page_addr_int <= current_page_addr_int;
end if;
end if;
end if;
end process;
-- IMPORTANT, see below WR_EOP
pgreq_or <= pgreq_i or pgreq_reg;
pckstart_or <= pckstart_i or pckstart_reg;
fsm : process(clk_i, rst_n_i)
-- variable l:line;
-- file fout:text open write_mode is "stdout" ;
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
state <= IDLE;
ll_write_data <=(others =>'0');
ll_write_addr <=(others =>'0');
ll_wr_req <='0';
current_page_addr_fsm <=(others =>'0');
else
-- main finite state machine
case state is
when IDLE =>
--fprint(fout, l, "Jou, ziom!\n");
--if((pgreq_i = '1') and (pckstart = '0') and (pckstart_i = '0')) then
if((pgreq_or = '1') and (pckstart_or = '0') ) then
-- normal case: load new page within the package (not the
-- beginning of the package)
-- this will not happen during the staart of the frame
-- within the frame, pgaddr_i will have the appripriate value
state <= WR_NEXT;
ll_write_data <= pgaddr_i;
ll_write_addr <= previous_page_addr_int;
-- we remember the current (new address)
-- just in case, the pck finishes during NEXT OR EOP state
-- and new page is set, or just new page is set
current_page_addr_fsm <= pgaddr_i;
ll_wr_req <= '1';
elsif((pgreq_or = '1') and (pckstart_or = '1')) then
-- first package, page provided at the same time as pckstart_i strobe
-- so we remember the address from input
--if((pgreq_i = '1') and (pckstart = '0') and (pckstart_i = '1')) then
state <= WR_EOP;
ll_write_data <= (others =>'1');
ll_write_addr <= pgaddr_i;
ll_wr_req <= '1';
end if;
-- page provided not in the first cycle of the new package
--if((pgreq_i = '1') and (pckstart = '1') and (pckstart_i = '0')) then
-- state <= WR_EOP;
-- ll_write_data <= (others =>'1');
-- ll_write_addr <= pgaddr_i;
-- ll_wr_req <= '1';
--end if;
when WR_NEXT =>
if (ll_wr_done_i = '1') then
if((pgreq_or = '1') and (pckstart_or = '1') ) then
-- this means that the pck finished during NEXT state
--
state <= WR_LAST_EOP;
ll_write_data <= (others =>'1');
--ll_write_addr <= current_page_addr_int;
ll_write_addr <= current_page_addr_fsm;
ll_wr_req <= '1';
elsif((pgreq_or = '1') and (pckstart_or = '0') ) then
-- this means that new page was set during NEXT state
--
state <= WR_TRANS_EOP;
ll_write_data <= (others =>'1');
--ll_write_addr <= current_page_addr_int;
ll_write_addr <= current_page_addr_fsm;
ll_wr_req <= '1';
else
state <= WR_EOP;
ll_write_data <= (others =>'1');
--ll_write_addr <= current_page_addr_int;
ll_write_addr <= current_page_addr_fsm;
ll_wr_req <= '1';
end if;
end if;
when WR_EOP =>
if (ll_wr_done_i = '1') then
if((pgreq_or = '1') and (pckstart_or = '0') ) then
-- this foresees the situation when new page was set
-- while the linked list was being written, so
-- we don't go to idle, but write LL again.
-- in theory, should not get here, because the
-- writing FSM, waits for ll_FSM to be IDLE
state <= WR_NEXT;
ll_write_data <= pgaddr_i;
ll_write_addr <= previous_page_addr_int;
ll_wr_req <= '1';
elsif((pgreq_or = '1') and (pckstart_or = '1')) then
-- this foresees quite often situation when the
-- address of previous pck is written to LL while
-- new pck's first page is already being set,
-- so we remember the request and set the page as soon
-- as previous' pck's operations to LL are finished
state <= WR_EOP;
ll_write_data <= (others =>'1');
ll_write_addr <= pgaddr_i;
ll_wr_req <= '1';
else
-- normal functioning
state <= IDLE;
ll_write_data <= (others =>'0');
ll_write_addr <= (others =>'0');
ll_wr_req <= '0';
end if;
end if;
when WR_LAST_EOP =>
if (ll_wr_done_i = '1') then
state <= WR_EOP;
ll_write_data <= (others =>'1');
ll_write_addr <= current_page_addr_int;
ll_wr_req <= '1';
end if;
when WR_TRANS_EOP =>
if (ll_wr_done_i = '1') then
state <= WR_NEXT;
ll_write_data <= current_page_addr_int;
ll_write_addr <= previous_page_addr_int;
end if;
when others =>
state <= IDLE;
end case;
end if;
end if;
end process;
-- nasty_wait_full <= '1' when (state_write = S_NASTY_WAIT) else '0';
ll_idle <= '1' when (state = IDLE) else '0';
we_o <= we_int;
full_o <= reg_full;
--
-- (((reg_full -- obvous
-- or
-- (cnt_last_word and drdy_i)
-- or
-- (nasty_wait_full and drdy_i))
-- and
-- (not sync_i)) or(pgend and sync_i));-- or (sync_i and (not drdy_i)));-- and not before_sync;
--addr_o <= pgaddr_i & zeros (c_swc_page_offset_width-1 downto 0) when (we_int = '1' and pgreq_i = '1') else mem_addr;
addr_o <= mem_addr;
pgend_o <= pgend;
gen_q1 : for i in 0 to c_swc_packet_mem_multiply-1 generate
q_o(c_swc_pump_width * (i+1) - 1 downto c_swc_pump_width * i) <= in_reg(i);
end generate gen_q1;
ll_addr_o <= ll_write_addr;
ll_data_o <= ll_write_data;
ll_wr_req_o <= ll_wr_req;
end rtl;
-------------------------------------------------------------------------------
-- Title : Fast page allocator/deallocator
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_page_allocator.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2011-03-15
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: Module implements a fast (3 cycle) paged memory allocator.
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
-- Detailed description of the magic (by mlipinsk):
-- The address of allocated page is made up of two parts:
-- * high: bits [x downto 5]
-- * low : bits [4 downto 0]
--
-- The low part of the page address (the low bits) is mapped to
-- a bit of 32 bit word in L0_LUT SRAM.
-- The high part of the page address is the address of the word in
-- the L0_LUT_SRAM memory. The address of the word in SRAM is
-- mapped into a bit of l1_bitmap register (high bits of the address).
--
-- Address mapped into bit means that the position of the bit (from LSB)
-- is equal to the address.
--
-- '1' means that a give address is free
-- '0' means that a give address is used
--
-- Tha page allocator looks for the lowest free (unused) page address. It uses
-- prio_encoder for this purpose.
--
-- prio_encoder's input is a bit vector, the output is the position of the
-- least significant bit set to '1' (see description of prio_encoder).
-- Additionally, prio_encoder returns the position encoded as one_hot and
-- a mask.
--
-- In the L0_UCNTMEM SRAM, the number of users assigned to a particular
-- page address is stored. the address in L0_UCNTMEM SRAM corresponds
-- directly to the page address. The default value to fill in the
-- SRAM are all '1s'.
--
-- The default value to fill in the l1_bitmap register is all '1s'.
--
-- Page allocation:
-- When page allocation is requested, the number of users (usecnt) needs
-- to be provided. The allocation of the page is not complited until
-- the provided number of users have read the page (attempted to free
-- the page). During allocation, the lowest free page address is sought.
-- As soon as the address is determined, the requested user count is
-- written to L0_UCNTMEM SRAM and allocation is finished.
--
-- Page Deallocation:
-- When free_page is attempted, the address of the page needs to be provided.
-- The address is decoded into high and low parts. First, the count in
-- L0_UCNTMEM SRAM is checked, if it's greater than 1, it is decreased.
-- If the usecount == 1, it means that this was the last page user, and thus
-- the page is freed. this means that '1' is written to the bit corresponding
-- to the page low part of the address in the word in L0_LUT SRAM. And '1' is
-- written to the l1_bitmap register to the bit corresponding to the high part
-- of the address.
--
--
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-11 1.1 mlipinsk comments added !!!!!
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.swc_swcore_pkg.all;
use work.genram_pkg.all;
--use std.textio.all;
--use work.pck_fio.all;
entity swc_page_allocator is
generic (
-- number of pages we consider
g_num_pages : integer := 2048;
-- number of bits of the page address
g_page_addr_bits : integer := 11;
-- number of bits of the user count value
g_use_count_bits : integer := 4
);
port (
clk_i : in std_logic; -- clock & reset
rst_n_i : in std_logic;
alloc_i : in std_logic; -- alloc strobe (active HI), starts
-- allocation process of a page with use
-- count given on usecnt_i. Address of
-- the allocated page is returned on
-- pgaddr_o and is valid when
-- pgaddr_valid_o is HI..
free_i : in std_logic; -- free strobe (active HI), releases the page
-- at address pgaddr_i if it's current
-- use count is equal to 1, otherwise
-- decreases the use count
force_free_i : in std_logic; -- free strobe (active HI), releases the page
-- at address pgaddr_i regardless of the user
-- count of the page
-- it is used in case a package is corrupted
-- and what have already been
-- saved, needs to be released
set_usecnt_i : in std_logic; -- enables to set user count to already
-- alocated page, used in the case of the
-- address of the first page of a package,
-- we need to allocate this page in advance
-- not knowing the user count, so the user count
-- needs to be set to already allocated page
-- "Use count" value for the page to be allocated. If the page is to be
-- used by multiple output queues, each of them will attempt to free it.
usecnt_i : in std_logic_vector(g_use_count_bits-1 downto 0);
pgaddr_i : in std_logic_vector(g_page_addr_bits -1 downto 0);
pgaddr_o : out std_logic_vector(g_page_addr_bits -1 downto 0);
pgaddr_valid_o : out std_logic;
idle_o : out std_logic;
done_o : out std_logic; -- "early" done output (active HI).
-- Indicates that
-- the alloc/release cycle is going to
-- end 1 cycle in advance, so the
-- multiport scheduler can optimize
-- it's performance
nomem_o : out std_logic
);
end swc_page_allocator;
architecture syn of swc_page_allocator is
signal nomem : std_logic;
function f_onehot_decode(x : std_logic_vector) return std_logic_vector is
variable tmp : std_logic_vector(2**x'length-1 downto 0);
begin
tmp := (others => '0');
tmp(to_integer(unsigned(x))) := '1';
return tmp;
end function;
constant c_l1_bitmap_size : integer := g_num_pages/32;
constant c_l1_bitmap_addrbits : integer := g_page_addr_bits - 5;
type t_state is (IDLE, ALLOC_LOOKUP_L1, ALLOC_LOOKUP_L0_UPDATE,
FREE_CHECK_USECNT, FREE_RELEASE_PAGE, FREE_DECREASE_UCNT,
SET_UCNT, NASTY_WAIT, DUMMY --, FORCE_FREE_RELEASE_PAGE
);
-- this represents high part of the page address (bit mapping)
signal l1_bitmap : std_logic_vector(c_l1_bitmap_size-1 downto 0);
signal l1_first_free : std_logic_vector (c_l1_bitmap_addrbits-1 downto 0);
-- mask is used whe
signal l1_mask : std_logic_vector (c_l1_bitmap_size -1 downto 0);
-- this mask (which is in reallity hot-one) is used when allocating the page
-- it cancels '1' at the address
signal l0_mask : std_logic_vector(31 downto 0);
-- low part of the page address (decoded from the L0_LUT SRAM
signal l0_first_free : std_logic_vector(4 downto 0);
signal state : t_state;
signal free_blocks : unsigned(g_page_addr_bits downto 0);
-- address decoded from l1_bitmap, we read data from this address
-- to decode the low part of the page address
signal l0_wr_data, l0_rd_data : std_logic_vector(31 downto 0);
signal l0_wr_addr, l0_rd_addr : std_logic_vector(c_l1_bitmap_addrbits-1 downto 0);
signal l0_wr : std_logic;
-- this is used for storing user count
signal usecnt_mem_wraddr : std_logic_vector(g_page_addr_bits-1 downto 0);
signal usecnt_mem_rdaddr : std_logic_vector(g_page_addr_bits-1 downto 0);
signal usecnt_mem_wr : std_logic;
signal usecnt_mem_rddata : std_logic_vector(g_use_count_bits-1 downto 0);
signal usecnt_mem_wrdata : std_logic_vector(g_use_count_bits-1 downto 0);
signal pgaddr_to_free : std_logic_vector(g_page_addr_bits -1 downto 0);
signal page_freeing_in_last_operation : std_logic;
signal previously_freed_page : std_logic_vector(g_page_addr_bits -1 downto 0);
signal tmp_page : std_logic_vector(g_page_addr_bits -1 downto 0);
-- signal tmp_pgs : std_logic_vector(1023 downto 0);
signal tmp_dbg_dealloc : std_logic; -- used for symulation debugging, don't remove
signal was_reset : std_logic;
signal first_addr : std_logic;
signal ones : std_logic_vector(c_l1_bitmap_addrbits-1 downto 0);
-- signal tmp_dbg_alloc : std_logic;
begin -- syn
ones <= (others => '1');
tmp_dbg_dealloc <= '1' when (state = FREE_RELEASE_PAGE) else '0';
-- this guy is responsible for decoding
-- the bits of l1_bitmap register into the
-- high part of the page address
L1_ENCODE : swc_prio_encoder
generic map (
g_num_inputs => c_l1_bitmap_size,
g_output_bits => c_l1_bitmap_addrbits)
port map (
in_i => l1_bitmap,
out_o => l1_first_free,
onehot_o => l1_mask);
-- this guy is responsible for the low part of
-- the page address.
L0_ENCODE : swc_prio_encoder
generic map (
g_num_inputs => 32,
g_output_bits => 5)
port map (
in_i => l0_rd_data,
onehot_o => l0_mask,
out_o => l0_first_free);
L0_LUT : generic_dpram
generic map (
g_data_width => 32,
-- g_addr_bits => c_l1_bitmap_addrbits,
g_size => c_l1_bitmap_size,
g_dual_clock => false)
port map (
clka_i => clk_i,
clkb_i => clk_i,
aa_i => l0_wr_addr,
da_i => l0_wr_data,
qa_o => open,
bwea_i => x"0",
wea_i => l0_wr,
ab_i => l0_rd_addr,
db_i => x"00000000",
qb_o => l0_rd_data,
bweb_i => x"0",
web_i => '0');
L0_UCNTMEM : generic_dpram
generic map (
g_data_width => g_use_count_bits,
-- g_addr_bits => g_page_addr_bits,
g_size => g_num_pages)
port map (
clka_i => clk_i,
clkb_i => clk_i,
da_i => usecnt_mem_wrdata,
aa_i => usecnt_mem_wraddr,
qa_o => open,
wea_i => usecnt_mem_wr,
bwea_i => ones(g_use_count_bits/8 -1 downto 0),
ab_i => usecnt_mem_rdaddr,
qb_o => usecnt_mem_rddata,
db_i => ones(g_use_count_bits-1 downto 0),
bweb_i => ones(g_use_count_bits/8-1 downto 0),
web_i => '0'
);
fsm : process(clk_i, rst_n_i)
-- variable l:line;
-- file fout:text open write_mode is "dupa.txt";--"stdout" ;
variable cnt : integer := -1;
variable usecnt_mem_rdaddr_v : integer := 0;
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
l1_bitmap <= (others => '1');
idle_o <= '1';
state <= IDLE;
usecnt_mem_wr <= '0';
--usecnt_mem_rdaddr <= (others => '0');
usecnt_mem_wraddr <= (others => '0');
free_blocks <= to_unsigned(g_num_pages, free_blocks'length);
done_o <= '0';
l0_wr_addr <= (others => '0');
l0_rd_addr <= (others => '0');
l0_wr_data <= (others => '0');
pgaddr_valid_o <= '0';
nomem <= '0';
usecnt_mem_wrdata <= (others => '0');
pgaddr_o <= (others => '0');
tmp_page <= (others => '0'); -- used for symulation debugging, don't remove
--tmp_pgs <= (others => '0');
-- bugfix by ML (two consecutive page free of the same page addr)
page_freeing_in_last_operation <= '0';
previously_freed_page <= (others => '0');
pgaddr_to_free <= (others => '0');
was_reset <= '1';
first_addr <= '1';
elsif(was_reset = '1') then
if(first_addr = '1') then
l0_wr_data <= (others => '1');
l0_wr <= '1';
first_addr <= '0';
elsif(l0_wr_addr = ones) then
was_reset <= '0';
l0_wr <= '0';
else
l0_wr_addr <= std_logic_vector(unsigned(l0_wr_addr) + 1);
end if;
else
-- main finite state machine
case state is
-- idle state: wait for alloc/release requests
when IDLE =>
done_o <= '0';
idle_o <= '1';
l0_wr <= '0';
pgaddr_valid_o <= '0';
usecnt_mem_wr <= '0';
page_freeing_in_last_operation <= '0';
--usecnt_mem_rdaddr <= pgaddr_i;
usecnt_mem_wraddr <= pgaddr_i;
-- check if we have any free blocks and drive the nomem_o line.
-- last address (all '1') reserved for end-of-page marker in
-- linked list
-- ========= hystheresis ===========================
if(nomem = '0' and (free_blocks < 3)) then
nomem <= '1';
elsif(nomem = '1' and (free_blocks > (3*c_swc_num_ports))) then
nomem <= '0';
end if;
-- ========= =========== ===========================
-- got page allocation request
if(alloc_i = '1' and free_blocks > 0) then
-- initiate read from L0 bitmap at address of first free entry in
-- L1. The address of L0_LUT maps into the position of the first
-- LSB '1' in the l1_bitmap register (high part of the page address)
-- The word at the l1_first_free address represents the low part
-- of the page address (mapping of the first '1' LSB bit, again)
l0_rd_addr <= l1_first_free;
idle_o <= '0';
state <= ALLOC_LOOKUP_L1;
done_o <= '1';
end if;
-- got page release request
if(free_i = '1') then
idle_o <= '0';
if(page_freeing_in_last_operation = '1' and previously_freed_page = pgaddr_i) then
state <= NASTY_WAIT;
else
idle_o <= '0';
pgaddr_to_free <= pgaddr_i;
state <= FREE_CHECK_USECNT;
-- decoding of provided code into low and high part
l0_wr_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
l0_rd_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
--usecnt_mem_rdaddr <= pgaddr_i;
usecnt_mem_wraddr <= pgaddr_i;
done_o <= '1'; -- assert the done signal early enough
-- so the multiport allocator will also
-- take 3 cycles per request
page_freeing_in_last_operation <= '1';
previously_freed_page <= pgaddr_i;
end if;
end if;
if(force_free_i = '1') then
idle_o <= '0';
pgaddr_to_free <= pgaddr_i;
state <= DUMMY; -- FREE_RELEASE_PAGE;
-- decoding of provided code into low and high part
l0_wr_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
l0_rd_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
--usecnt_mem_rdaddr <= pgaddr_i;
usecnt_mem_wraddr <= pgaddr_i;
done_o <= '1'; -- assert the done signal early enough
-- so the multiport allocator will also
-- take 3 cycles per request
end if;
if(set_usecnt_i = '1') then
idle_o <= '0';
state <= SET_UCNT;
usecnt_mem_wrdata <= usecnt_i;
usecnt_mem_wraddr <= pgaddr_i;
done_o <= '1'; -- assert the done signal early enough
-- so the multiport allocator will also
-- take 3 cycles per request
end if;
when DUMMY =>
state <= FREE_RELEASE_PAGE;
done_o <= '0';
when NASTY_WAIT =>
idle_o <= '0';
pgaddr_to_free <= pgaddr_i;
state <= FREE_CHECK_USECNT;
-- decoding of provided code into low and high part
l0_wr_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
l0_rd_addr <= pgaddr_i(g_page_addr_bits-1 downto 5);
--usecnt_mem_rdaddr <= pgaddr_i;
usecnt_mem_wraddr <= pgaddr_i;
done_o <= '1'; -- assert the done signal early enough
-- so the multiport allocator will also
-- take 3 cycles per request
page_freeing_in_last_operation <= '1';
previously_freed_page <= pgaddr_i;
when ALLOC_LOOKUP_L1 =>
-- wait until read from L0 bitmap memory is complete
state <= ALLOC_LOOKUP_L0_UPDATE;
-- drive "done" output early, so the arbiter will now that it can initiate
-- another operation in the next cycle.
done_o <= '0';
when ALLOC_LOOKUP_L0_UPDATE =>
l0_wr_addr <= l0_rd_addr;
-- change the '1' at the position of the chosen address to '0'..
-- in other words, the LSB '1' is zerod
l0_wr_data <= l0_rd_data xor l0_mask;
l0_wr <= '1';
if(unsigned(l0_rd_data xor l0_mask) = 0) then -- full L0 entry?
-- if the word in L0_LUT at particular address is 0, all pages
-- at this range have been used. So after allocating the current page address
-- there will be no more space in thsi range. So set the corresponding bit to '0'
l1_bitmap <= l1_bitmap xor l1_mask;
end if;
pgaddr_o <= l1_first_free & l0_first_free;
usecnt_mem_wraddr <= l1_first_free & l0_first_free;
usecnt_mem_wrdata <= usecnt_i;
usecnt_mem_wr <= '1';
pgaddr_valid_o <= '1';
free_blocks <= free_blocks-1;
state <= IDLE;
--if(l1_first_free & l0_first_free = x"0E5")
-- fprint(fout, l, "==> Allocate page %d , usecnt %d, free blocks: %d \n", fo(l1_first_free & l0_first_free),fo(usecnt_i), fo(free_blocks-1));
-- tmp_pgs(to_integer(unsigned(l1_first_free & l0_first_free))) <= '1';
-- done_o <= '0';
when FREE_CHECK_USECNT =>
-- use count = 1 - release the page
done_o <= '0';
-- last user, free page
if(usecnt_mem_rddata = std_logic_vector(to_unsigned(1, usecnt_mem_rddata'length))) then
state <= FREE_RELEASE_PAGE;
-- attempte to free empty page
elsif(usecnt_mem_rddata = std_logic_vector(to_unsigned(0, usecnt_mem_rddata'length))) then
state <= IDLE;
-- there are still users,
else
state <= FREE_DECREASE_UCNT;
end if;
when FREE_RELEASE_PAGE =>
-- l0_wr_data <= l0_rd_data or f_onehot_decode(pgaddr_i(4 downto 0));
l0_wr_data <= l0_rd_data or f_onehot_decode(pgaddr_to_free(4 downto 0));
l0_wr <= '1';
l1_bitmap <= l1_bitmap or f_onehot_decode(pgaddr_to_free(g_page_addr_bits-1 downto 5));
-- l1_bitmap <= l1_bitmap or f_onehot_decode(pgaddr_i(g_page_addr_bits-1 downto 5));
free_blocks <= free_blocks+ 1;
usecnt_mem_wrdata <= (others => '0');
usecnt_mem_wr <= '1';
state <= IDLE;
done_o <= '0';
-- fprint(fout, l, "<== Release page: %d, free blocks: %d \n",fo(tmp_page),fo(free_blocks+ 1));
--tmp_pgs(to_integer(unsigned(tmp_page))) <= '0';
when FREE_DECREASE_UCNT =>
usecnt_mem_wrdata <= std_logic_vector(unsigned(usecnt_mem_rddata) - 1);
usecnt_mem_wr <= '1';
state <= IDLE;
-- fprint(fout, l, " Free page: %d (usecnt = %d)\n",fo(tmp_page),fo(std_logic_vector(unsigned(usecnt_mem_rddata) - 1)));
when SET_UCNT =>
usecnt_mem_wrdata <= usecnt_i;
usecnt_mem_wr <= '1';
state <= IDLE;
done_o <= '0';
-- fprint(fout, l, " Usecnt set: %d (usecnt = %d)\n",fo(tmp_page),fo(usecnt_i));
when others =>
state <= IDLE;
done_o <= '0';
end case;
--usecnt_mem_rdaddr <= pgaddr_i;
tmp_page <= pgaddr_i;
end if;
end if;
end process;
-- IMPORTANT :
-- we need to set the usercnt read address as early as possible
-- so that the data is available at the end of the first stata after IDLE
usecnt_mem_rdaddr <= pgaddr_i;
nomem_o <= nomem;
end syn;
-------------------------------------------------------------------------------
-- Title : Pck's pages feeing module
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_pck_pg_free_module.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-15
-- Last update: 2011-03-15
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
--
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-16 1.0 mlipinsk Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
use work.genram_pkg.all;
entity swc_pck_pg_free_module is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
ib_force_free_i : in std_logic;
ib_force_free_done_o : out std_logic;
ib_force_free_pgaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ob_free_i : in std_logic;
ob_free_done_o : out std_logic;
ob_free_pgaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_addr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
ll_read_data_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ll_read_req_o : out std_logic;
ll_read_valid_data_i : in std_logic;
mmu_free_o : out std_logic;
mmu_free_done_i : in std_logic;
mmu_free_pgaddr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0);
mmu_force_free_o : out std_logic;
mmu_force_free_done_i : in std_logic;
mmu_force_free_pgaddr_o : out std_logic_vector(c_swc_page_addr_width -1 downto 0)
);
end swc_pck_pg_free_module;
architecture syn of swc_pck_pg_free_module is
type t_state is (S_IDLE,
S_REQ_READ_FIFO,
S_READ_FIFO,
S_READ_NEXT_PAGE_ADDR,
S_FREE_CURRENT_PAGE_ADDR,
S_FORCE_FREE_CURRENT_PAGE_ADDR
);
signal state : t_state;
signal ib_force_free_done : std_logic;
signal ob_free_done : std_logic;
signal fifo_wr : std_logic;
signal fifo_data_in : std_logic_vector(c_swc_page_addr_width + 2 - 1 downto 0);
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
signal fifo_data_out : std_logic_vector(c_swc_page_addr_width + 2 - 1 downto 0);
signal fifo_rd : std_logic;
signal fifo_clean : std_logic;
signal current_page : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal next_page : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ll_read_req : std_logic;
signal mmu_force_free : std_logic;
signal mmu_free : std_logic;
signal ones : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal freeing_mode : std_logic_vector(1 downto 0);
signal fifo_clear_n : std_logic;
begin -- syn
ones <= (others => '1');
fifo_clean <= not rst_n_i;
INPUT: process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
ib_force_free_done <= '0';
ob_free_done <= '0';
fifo_wr <= '0';
fifo_data_in <= (others => '0');
else
-- serve Input request, unless it's already served ( ib_force_free_done = '1')
if(ib_force_free_i = '1' and fifo_full = '0' and ib_force_free_done = '0') then
fifo_wr <= '1';
fifo_data_in(c_swc_page_addr_width - 1 downto 0) <= ib_force_free_pgaddr_i;
fifo_data_in(c_swc_page_addr_width) <= '1';
fifo_data_in(c_swc_page_addr_width + 1) <= '0';
ib_force_free_done <= '1';
ob_free_done <= '0';
elsif(ob_free_i = '1' and fifo_full = '0' and ob_free_done = '0') then
fifo_wr <= '1';
fifo_data_in(c_swc_page_addr_width - 1 downto 0) <= ob_free_pgaddr_i;
fifo_data_in(c_swc_page_addr_width) <= '0';
fifo_data_in(c_swc_page_addr_width + 1) <= '1';
ob_free_done <= '1';
ib_force_free_done <= '0';
else
fifo_wr <= '0';
fifo_data_in <= (others => '0');
ib_force_free_done <= '0';
ob_free_done <= '0';
end if;
end if;
end if;
end process;
fifo_clear_n <= not fifo_clean;
-- replaced by GenRams component: TW
U_FIFO: generic_sync_fifo
generic map (
g_data_width => c_swc_page_addr_width + 2,
g_size => c_swc_freeing_fifo_size
)
port map (
rst_n_i => fifo_clear_n,
clk_i => clk_i,
d_i => fifo_data_in,
we_i => fifo_wr,
q_o => fifo_data_out,
rd_i => fifo_rd,
empty_o => fifo_empty,
full_o => fifo_full,
almost_empty_o => open,
almost_full_o => open,
count_o => open);
fsm_force_free : process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--================================================
state <= S_IDLE;
fifo_rd <= '0';
current_page <= (others => '0');
next_page <= (others => '0');
ll_read_req <= '0';
mmu_force_free <= '0';
mmu_free <= '0';
freeing_mode <= (others => '0');
--================================================
else
-- main finite state machine
case state is
when S_IDLE =>
fifo_rd <= '0';
mmu_force_free <= '0';
mmu_free <= '0';
if(fifo_empty = '0') then
fifo_rd <= '1';
state <= S_REQ_READ_FIFO;
end if;
when S_REQ_READ_FIFO =>
fifo_rd <= '0';
state <= S_READ_FIFO;
when S_READ_FIFO =>
freeing_mode <= fifo_data_out(c_swc_page_addr_width + 2 - 1 downto c_swc_page_addr_width);
current_page <= fifo_data_out(c_swc_page_addr_width - 1 downto 0);
ll_read_req <= '1';
state <= S_READ_NEXT_PAGE_ADDR;
when S_READ_NEXT_PAGE_ADDR =>
if(ll_read_valid_data_i = '1') then
ll_read_req <= '0';
next_page <= ll_read_data_i;
-- force free
if(freeing_mode = b"01") then
state <= S_FORCE_FREE_CURRENT_PAGE_ADDR;
mmu_force_free <= '1';
-- standard free
elsif(freeing_mode = b"10") then
state <= S_FREE_CURRENT_PAGE_ADDR;
mmu_free <= '1';
else
-- should not get here !!!
state <= S_IDLE;
fifo_rd <= '0';
current_page <= (others => '0');
next_page <= (others => '0');
ll_read_req <= '0';
mmu_force_free <= '0';
freeing_mode <= (others => '0');
end if;
end if;
when S_FORCE_FREE_CURRENT_PAGE_ADDR =>
if(mmu_force_free_done_i = '1') then
mmu_force_free <= '0';
if(next_page = ones ) then
state <= S_IDLE;
else
current_page <= next_page;
ll_read_req <= '1';
state <= S_READ_NEXT_PAGE_ADDR;
end if;
end if;
when S_FREE_CURRENT_PAGE_ADDR =>
if(mmu_free_done_i = '1') then
mmu_free <= '0';
if(next_page = ones ) then
state <= S_IDLE;
else
current_page <= next_page;
ll_read_req <= '1';
state <= S_READ_NEXT_PAGE_ADDR;
end if;
end if;
when others =>
state <= S_IDLE;
fifo_rd <= '0';
current_page <= (others => '0');
next_page <= (others => '0');
ll_read_req <= '0';
mmu_force_free <= '0';
mmu_free <= '0';
end case;
end if;
end if;
end process;
ll_read_addr_o <= current_page;
ll_read_req_o <= ll_read_req;
mmu_force_free_pgaddr_o <= current_page;
mmu_force_free_o <= mmu_force_free;
mmu_free_pgaddr_o <= current_page;
mmu_free_o <= mmu_free;
ib_force_free_done_o <= ib_force_free_done;
ob_free_done_o <= ob_free_done;
end syn;
-------------------------------------------------------------------------------
-- Title : Packet Transfer Arbiter
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_pck_transfer_arbiter.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-03
-- Last update: 2011-03-25
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-03 1.0 mlipinsk created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_pck_transfer_arbiter is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with output block
-------------------------------------------------------------------------------
ob_data_valid_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
ob_ack_i : in std_logic_vector(c_swc_num_ports -1 downto 0);
ob_pageaddr_o : out std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ob_prio_o : out std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0);
ob_pck_size_o : out std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
-------------------------------------------------------------------------------
-- I/F with Input Block
-------------------------------------------------------------------------------
ib_transfer_pck_i : in std_logic_vector(c_swc_num_ports -1 downto 0);
ib_transfer_ack_o : out std_logic_vector(c_swc_num_ports -1 downto 0);
ib_busy_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
ib_pck_size_i : in std_logic_vector(c_swc_num_ports * c_swc_max_pck_size_width - 1 downto 0);
ib_pageaddr_i : in std_logic_vector(c_swc_num_ports * c_swc_page_addr_width - 1 downto 0);
ib_mask_i : in std_logic_vector(c_swc_num_ports * c_swc_num_ports - 1 downto 0);
ib_prio_i : in std_logic_vector(c_swc_num_ports * c_swc_prio_width - 1 downto 0)
);
end swc_pck_transfer_arbiter;
architecture syn of swc_pck_transfer_arbiter is
function f_modulo_numports(x : integer) return integer is
begin
if(x < c_swc_num_ports) then
return x;
elsif(x < 2*c_swc_num_ports) then
return (x-c_swc_num_ports);
elsif(x < 3 * c_swc_num_ports) then
return (x-2*c_swc_num_ports);
else
return 0;
end if;
end function;
subtype t_pageaddr is std_logic_vector(c_swc_page_addr_width - 1 downto 0);
subtype t_prio is std_logic_vector(c_swc_prio_width - 1 downto 0);
subtype t_mask is std_logic_vector(c_swc_num_ports - 1 downto 0);
subtype t_pck_size is std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
type t_pageaddr_array is array (c_swc_num_ports - 1 downto 0) of t_pageaddr;
type t_prio_array is array (c_swc_num_ports - 1 downto 0) of t_prio;
type t_mask_array is array (c_swc_num_ports - 1 downto 0) of t_mask;
type t_pck_size_array is array (c_swc_num_ports - 1 downto 0) of t_pck_size;
---------------------------------------------------------------------------
-- signals outputed from Pck Transfer Input (PTI)
-- before MUX !!!!
---------------------------------------------------------------------------
signal pto_pageaddr : t_pageaddr_array;
signal pto_output_mask : t_mask_array;
signal pto_read_mask : t_mask_array;
signal pto_prio : t_prio_array;
signal pto_pck_size : t_pck_size_array;
---------------------------------------------------------------------------
-- signals inputed to Pck Transfer Output (PTO) from Pck Transfer Input (TPI)
-- MUXED !!!!!!!!!!
---------------------------------------------------------------------------
signal pti_transfer_data_valid : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal pti_transfer_data_ack : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal pti_pageaddr : t_pageaddr_array;
signal pti_prio : t_prio_array;
signal pti_pck_size : t_pck_size_array;
signal sync_sreg : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal sync_cntr : integer range 0 to c_swc_num_ports - 1;
signal sync_cntr_ack : integer range 0 to c_swc_num_ports-1;
begin --arch
sync_gen : process (clk_i, rst_n_i)
begin -- process
if rising_edge(clk_i) then
if(rst_n_i = '0') then
sync_sreg (0) <= '1';
sync_sreg (sync_sreg'length - 1 downto 1) <= (others => '0');
sync_cntr <= 0; --c_swc_num_ports - 1;
sync_cntr_ack <= c_swc_num_ports - 1; --c_swc_num_ports - 2; -- c_swc_packet_mem_multiply-1;
else
sync_sreg <= sync_sreg(sync_sreg'length-2 downto 0) & sync_sreg(sync_sreg'length-1);
if(sync_cntr = c_swc_num_ports-1) then
sync_cntr <= 0;
else
sync_cntr <= sync_cntr + 1;
end if;
if(sync_cntr_ack = c_swc_num_ports-1) then
sync_cntr_ack <= 0;
else
sync_cntr_ack <= sync_cntr_ack + 1;
end if;
end if;
end if;
end process;
-- multiplex mask from input to output
--multimux_out : process(sync_cntr,pto_output_mask,pto_pageaddr,pto_prio)
multimux_out : process(sync_cntr, pto_output_mask, pto_pageaddr, pto_prio, pto_pck_size)
begin
for i in 0 to c_swc_num_ports - 1 loop
pti_transfer_data_valid(i) <= pto_output_mask(f_modulo_numports(sync_cntr + i))(i);
pti_pageaddr (i) <= pto_pageaddr (f_modulo_numports(sync_cntr + i));
pti_prio (i) <= pto_prio (f_modulo_numports(sync_cntr + i));
pti_pck_size (i) <= pto_pck_size (f_modulo_numports(sync_cntr + i));
end loop;
end process;
-- we get ack from output ports and translate it into masks' bits in input ports
multidemux_in : process (clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
for i in 0 to c_swc_num_ports -1 loop
pto_read_mask(i) <= (others => '0');
end loop;
else
for i in 0 to c_swc_num_ports-1 loop
if(i = 1) then
pto_read_mask(f_modulo_numports(sync_cntr_ack + i))((i - 1)) <= '0';
elsif(i > 1) then
pto_read_mask(f_modulo_numports(sync_cntr_ack + i))((i - 1) downto 0) <= (others => '0');
end if;
pto_read_mask(f_modulo_numports(sync_cntr_ack + i))(i) <= pti_transfer_data_ack(i);
if(i < c_swc_num_ports - 2) then
pto_read_mask(f_modulo_numports(sync_cntr_ack + i))(c_swc_num_ports - 1 downto (i + 1)) <= (others => '0');
elsif(i = c_swc_num_ports - 2) then
pto_read_mask(f_modulo_numports(sync_cntr_ack + i))((i + 1)) <= '0';
end if;
end loop;
end if;
end if;
end process;
gen_input : for i in 0 to c_swc_num_ports-1 generate
TRANSFER_INPUT : swc_pck_transfer_input
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
pto_transfer_pck_o => open,
pto_pageaddr_o => pto_pageaddr (i),
pto_output_mask_o => pto_output_mask (i),
pto_read_mask_i => pto_read_mask (i),
pto_prio_o => pto_prio (i),
pto_pck_size_o => pto_pck_size (i),
ib_transfer_pck_i => ib_transfer_pck_i (i),
ib_pageaddr_i => ib_pageaddr_i ((i + 1)*c_swc_page_addr_width - 1 downto i*c_swc_page_addr_width),
ib_mask_i => ib_mask_i ((i + 1)*c_swc_num_ports - 1 downto i*c_swc_num_ports),
ib_prio_i => ib_prio_i ((i + 1)*c_swc_prio_width - 1 downto i*c_swc_prio_width),
ib_pck_size_i => ib_pck_size_i ((i + 1)*c_swc_max_pck_size_width - 1 downto i*c_swc_max_pck_size_width),
ib_transfer_ack_o => ib_transfer_ack_o (i),
ib_busy_o => ib_busy_o (i)
);
end generate gen_input;
gen_output : for i in 0 to c_swc_num_ports-1 generate
TRANSFER_OUTPUT : swc_pck_transfer_output
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
ob_transfer_data_valid_o => ob_data_valid_o (i),
ob_pageaddr_o => ob_pageaddr_o ((i + 1)*c_swc_page_addr_width - 1 downto i*c_swc_page_addr_width),
ob_prio_o => ob_prio_o ((i + 1)*c_swc_prio_width - 1 downto i*c_swc_prio_width),
ob_pck_size_o => ob_pck_size_o ((i + 1)*c_swc_max_pck_size_width - 1 downto i*c_swc_max_pck_size_width),
ob_transfer_data_ack_i => ob_ack_i (i),
pti_transfer_data_valid_i => pti_transfer_data_valid(i),
pti_transfer_data_ack_o => pti_transfer_data_ack (i),
pti_pageaddr_i => pti_pageaddr (i),
pti_prio_i => pti_prio (i),
pti_pck_size_i => pti_pck_size (i)
);
end generate gen_output;
end syn; -- arch
-------------------------------------------------------------------------------
-- Title : Packet Transfer Input
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_pck_transfer_input.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-03
-- Last update: 2010-11-03
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-03 1.0 mlipinsk created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_pck_transfer_input is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with pck transfer output (PTO)
-------------------------------------------------------------------------------
pto_transfer_pck_o : out std_logic;
pto_pageaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
pto_output_mask_o : out std_logic_vector(c_swc_num_ports - 1 downto 0);
pto_read_mask_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
pto_prio_o : out std_logic_vector(c_swc_prio_width - 1 downto 0);
pto_pck_size_o : out std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
-------------------------------------------------------------------------------
-- I/F with Input Block (IB)
-------------------------------------------------------------------------------
-- indicates the beginning of the package, strobe
ib_transfer_pck_i : in std_logic;
-- array of pages' addresses to which ports want to write
ib_pageaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
-- destination mask - indicates to which ports the packet should be
-- forwarded
ib_mask_i : in std_logic_vector(c_swc_num_ports - 1 downto 0);
ib_prio_i : in std_logic_vector(c_swc_prio_width - 1 downto 0);
ib_pck_size_i : in std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
ib_transfer_ack_o : out std_logic;
ib_busy_o : out std_logic
);
end swc_pck_transfer_input;
architecture syn of swc_pck_transfer_input is
signal ib_transfer_ack: std_logic;
signal ib_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ib_prio : std_logic_vector(c_swc_prio_width - 1 downto 0);
signal ib_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
signal ib_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
--signal pto_read_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal pto_output_mask : std_logic_vector(c_swc_num_ports - 1 downto 0);
signal zeros : std_logic_vector(c_swc_num_ports - 1 downto 0);
begin --arch
zeros <= (others => '0');
input: process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--===================================================
ib_mask <= (others => '0');
--pto_read_mask <= (others => '0');
pto_output_mask <= (others => '0');
ib_prio <= (others => '0');
ib_pck_size <= (others => '0');
ib_pageaddr <= (others => '0');
ib_transfer_ack <= '0';
--===================================================
else
if(ib_transfer_pck_i = '1' and pto_output_mask = zeros) then
ib_mask <= ib_mask_i;
ib_prio <= ib_prio_i;
ib_pageaddr <= ib_pageaddr_i;
ib_pck_size <= ib_pck_size_i;
end if;
if(ib_transfer_pck_i = '1' and pto_output_mask = zeros) then
--pto_read_mask <= (others => '0');
pto_output_mask <= ib_mask_i;--(others => '0');
else
-- pto_read_mask <= pto_read_mask or (pto_read_mask_i and ib_mask);
-- pto_output_mask <= (((pto_read_mask_i and ib_mask) -- filter read mask, if a port which
-- -- is not supposed to read the data, reads it
-- -- we see no difference
-- or pto_read_mask) -- add to the mask of the outputs_block which
-- -- already read the data, the one currently reading
-- xor ib_mask);
--
pto_output_mask <= (not(pto_read_mask_i and ib_mask) ) and pto_output_mask;
end if;
if(ib_transfer_ack = '1') then
ib_transfer_ack <= '0';
elsif(ib_transfer_pck_i = '1' and pto_output_mask = zeros) then
ib_transfer_ack <= '1';
else
ib_transfer_ack <= '0';
end if;
--
--===================================================
end if;
end if;
end process;
pto_output_mask_o <= pto_output_mask;
pto_transfer_pck_o <= '0';
pto_pageaddr_o <= ib_pageaddr;
pto_prio_o <= ib_prio;
pto_pck_size_o <= ib_pck_size;
ib_transfer_ack_o <= ib_transfer_ack;
ib_busy_o <= '0' when (pto_output_mask = zeros) else '1';
end syn; -- arch
\ No newline at end of file
-------------------------------------------------------------------------------
-- Title : Packet Transfer Output
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_pck_transfer_output.vhd
-- Author : Maciej Lipinski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-03
-- Last update: 2010-11-03
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-03 1.0 mlipinsk created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.swc_swcore_pkg.all;
entity swc_pck_transfer_output is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with output blocks (OB)
-------------------------------------------------------------------------------
ob_transfer_data_valid_o : out std_logic;
ob_pageaddr_o : out std_logic_vector(c_swc_page_addr_width - 1 downto 0);
ob_prio_o : out std_logic_vector(c_swc_prio_width - 1 downto 0);
ob_pck_size_o : out std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
ob_transfer_data_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- I/F with Page Transfer Input (PTI)
-------------------------------------------------------------------------------
pti_transfer_data_valid_i : in std_logic;
pti_transfer_data_ack_o : out std_logic;
pti_pageaddr_i : in std_logic_vector(c_swc_page_addr_width - 1 downto 0);
pti_prio_i : in std_logic_vector(c_swc_prio_width - 1 downto 0);
pti_pck_size_i : in std_logic_vector(c_swc_max_pck_size_width - 1 downto 0)
);
end swc_pck_transfer_output;
architecture syn of swc_pck_transfer_output is
signal pti_transfer_data_ack : std_logic;
signal ob_transfer_data_valid : std_logic;
signal ob_pageaddr : std_logic_vector(c_swc_page_addr_width - 1 downto 0);
signal ob_prio : std_logic_vector(c_swc_prio_width - 1 downto 0);
signal ob_pck_size : std_logic_vector(c_swc_max_pck_size_width - 1 downto 0);
begin --arch
output: process(clk_i, rst_n_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
--===================================================
ob_pageaddr <= (others => '0');
ob_prio <= (others => '0');
ob_pck_size <= (others => '0');
ob_transfer_data_valid <= '0';
pti_transfer_data_ack <= '0';
--===================================================
else
if(pti_transfer_data_valid_i = '1' and ( ob_transfer_data_valid = '0' or ob_transfer_data_ack_i = '1')) then
ob_pageaddr <= pti_pageaddr_i;
ob_prio <= pti_prio_i;
ob_pck_size <= pti_pck_size_i;
end if;
if(pti_transfer_data_valid_i = '1' and ( ob_transfer_data_valid = '0' or ob_transfer_data_ack_i = '1')) then
pti_transfer_data_ack <= '1';
else
pti_transfer_data_ack <= '0';
end if;
if(ob_transfer_data_ack_i = '1' and pti_transfer_data_valid_i = '0') then
ob_transfer_data_valid <= '0';
elsif (pti_transfer_data_valid_i = '1') then
ob_transfer_data_valid <= '1';
end if;
--===================================================
end if;
end if;
end process;
pti_transfer_data_ack_o <= pti_transfer_data_ack;
ob_transfer_data_valid_o <= ob_transfer_data_valid;
ob_pageaddr_o <= ob_pageaddr;
ob_prio_o <= ob_prio;
ob_pck_size_o <= ob_pck_size;
end syn; -- arch
\ No newline at end of file
-------------------------------------------------------------------------------
-- Title : Priority encoder
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_prio_encoder.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-04-08
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-- 2010-10-11 1.1 mlipinsk comments added !!!!!
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity swc_prio_encoder is
generic (
g_num_inputs : integer range 2 to 64 := 32;
g_output_bits : integer range 1 to 6 := 5);
port (
-- input vector having some sequence of '1s' and '0s'
-- the encoder detects the first least significant
-- '1' (the most to the right)
in_i : in std_logic_vector(g_num_inputs-1 downto 0);
-- a number representing the position of bit on which
-- a '1' is set (the least significant)
-- e.g.: for
-- in_i = 1110101011000
-- out_o = 3
out_o : out std_logic_vector(g_output_bits-1 downto 0);
-- one hot representation of out_o number
-- e.g.: for
-- in_i = 1110101011000
-- out_o = 3
-- onehot_o = 0000000001000
onehot_o : out std_logic_vector(g_num_inputs-1 downto 0);
-- bit mask : '1s' from LSB to the position of first '1'
-- detected, excluding; '0s' from the first '1' detected
-- (inclusive) to the MSB
-- e.g.: for
-- in_i = 1110101011000
-- out_o = 3
-- mask_o = 0000000000111
mask_o: out std_logic_vector(g_num_inputs-1 downto 0);
-- indicates that the input vector has no '1s'
zero_o: out std_logic
);
end swc_prio_encoder;
architecture syn of swc_prio_encoder is
signal w : std_logic_vector(63 downto 0);
signal q : std_logic_vector(5 downto 0);
signal zero : std_logic;
begin -- syn
w(63 downto g_num_inputs) <= (others => '0');
w(g_num_inputs-1 downto 0) <= in_i;
q <= "000000" when w(0) = '1' else
"000001" when w(1) = '1' else
"000010" when w(2) = '1' else
"000011" when w(3) = '1' else
"000100" when w(4) = '1' else
"000101" when w(5) = '1' else
"000110" when w(6) = '1' else
"000111" when w(7) = '1' else
"001000" when w(8+0) = '1' else
"001001" when w(8+1) = '1' else
"001010" when w(8+2) = '1' else
"001011" when w(8+3) = '1' else
"001100" when w(8+4) = '1' else
"001101" when w(8+5) = '1' else
"001110" when w(8+6) = '1' else
"001111" when w(8+7) = '1' else
"010000" when w(16+0) = '1' else
"010001" when w(16+1) = '1' else
"010010" when w(16+2) = '1' else
"010011" when w(16+3) = '1' else
"010100" when w(16+4) = '1' else
"010101" when w(16+5) = '1' else
"010110" when w(16+6) = '1' else
"010111" when w(16+7) = '1' else
"011000" when w(24+0) = '1' else
"011001" when w(24+1) = '1' else
"011010" when w(24+2) = '1' else
"011011" when w(24+3) = '1' else
"011100" when w(24+4) = '1' else
"011101" when w(24+5) = '1' else
"011110" when w(24+6) = '1' else
"011111" when w(24+7) = '1' else
"100000" when w(32+0) = '1' else
"100001" when w(32+1) = '1' else
"100010" when w(32+2) = '1' else
"100011" when w(32+3) = '1' else
"100100" when w(32+4) = '1' else
"100101" when w(32+5) = '1' else
"100110" when w(32+6) = '1' else
"100111" when w(32+7) = '1' else
"101000" when w(32+8+0) = '1' else
"101001" when w(32+8+1) = '1' else
"101010" when w(32+8+2) = '1' else
"101011" when w(32+8+3) = '1' else
"101100" when w(32+8+4) = '1' else
"101101" when w(32+8+5) = '1' else
"101110" when w(32+8+6) = '1' else
"101111" when w(32+8+7) = '1' else
"110000" when w(32+16+0) = '1' else
"110001" when w(32+16+1) = '1' else
"110010" when w(32+16+2) = '1' else
"110011" when w(32+16+3) = '1' else
"110100" when w(32+16+4) = '1' else
"110101" when w(32+16+5) = '1' else
"110110" when w(32+16+6) = '1' else
"110111" when w(32+16+7) = '1' else
"111000" when w(32+24+0) = '1' else
"111001" when w(32+24+1) = '1' else
"111010" when w(32+24+2) = '1' else
"111011" when w(32+24+3) = '1' else
"111100" when w(32+24+4) = '1' else
"111101" when w(32+24+5) = '1' else
"111110" when w(32+24+6) = '1' else
"111111" when w(32+24+7) = '1' else
"000000";
out_o <= q(g_output_bits-1 downto 0);
zero <= '1' when (in_i = std_logic_vector(to_unsigned(0, g_num_inputs))) else '0';
zero_o <= zero;
onehot_o(0) <= w(0);
gen_onehot: for i in 1 to g_num_inputs-1 generate
onehot_o(i) <= '1' when (w(i) = '1' and w(i-1 downto 0) = std_logic_vector(to_unsigned(0, i))) else '0';
end generate gen_onehot;
gen_mask: for i in 0 to g_num_inputs-1 generate
mask_o(i) <= '1' when (to_integer(unsigned(q)) < i) else '0';
end generate gen_mask;
end syn;
-------------------------------------------------------------------------------
-- Title : Round Robin Arbiter
-- Project : WhiteRabbit switch
-------------------------------------------------------------------------------
-- File : swc_rr_arbiter.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-08
-- Last update: 2010-04-08
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 Tomasz Wlostowski, Maciej Lipinski / CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-08 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity swc_rr_arbiter is
generic (
g_num_ports : natural := 22;
g_num_ports_log2 : natural := 5
);
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
next_i : in std_logic;
request_i : in std_logic_vector(g_num_ports -1 downto 0);
grant_o : out std_logic_vector(g_num_ports_log2 - 1 downto 0);
grant_valid_o : out std_logic
);
end swc_rr_arbiter;
architecture syn of swc_rr_arbiter is
component swc_prio_encoder
generic (
g_num_inputs : integer range 2 to 64;
g_output_bits : integer range 1 to 6);
port (
in_i : in std_logic_vector(g_num_inputs-1 downto 0);
out_o : out std_logic_vector(g_output_bits-1 downto 0);
onehot_o : out std_logic_vector(g_num_inputs-1 downto 0);
mask_o : out std_logic_vector(g_num_inputs-1 downto 0);
zero_o : out std_logic);
end component;
signal request_mask : std_logic_vector(g_num_ports -1 downto 0);
signal request_mask_saved : std_logic_vector(g_num_ports -1 downto 0);
signal request_vec_masked : std_logic_vector(g_num_ports -1 downto 0);
type t_state is (WAIT_REQUEST, HANDLE_REQUEST);
signal state : t_state;
signal rq_decoded : std_logic_vector(g_num_ports_log2-1 downto 0);
signal rq_decoded_mask : std_logic_vector(g_num_ports-1 downto 0);
signal rq_zero : std_logic;
signal rq_wait_next : std_logic;
begin -- syn
ENC : swc_prio_encoder
generic map (
g_num_inputs => g_num_ports,
g_output_bits => g_num_ports_log2)
port map (
in_i => request_vec_masked,
out_o => rq_decoded,
mask_o => rq_decoded_mask,
zero_o => rq_zero);
arbitrate : process (clk_i, rst_n_i)
begin -- process arbitrate
if rising_edge (clk_i) then
if(rst_n_i = '0') then
request_mask <= (others => '1');
request_vec_masked <= (others => '0');
grant_o <= (others => '0');
grant_valid_o <= '0';
rq_wait_next <= '0';
else
if(rq_wait_next = '1') then
if(next_i = '1') then
request_vec_masked <= request_i and request_mask;
rq_wait_next <= '0';
grant_valid_o <= '0';
end if;
else
if(rq_zero = '0') then
grant_o <= rq_decoded;
request_mask <= rq_decoded_mask;
request_vec_masked <= request_i and request_mask;
grant_valid_o <= '1';
rq_wait_next <= '1';
else
grant_valid_o <= '0';
request_mask <= (others => '1');
request_vec_masked <= request_i;
rq_wait_next <= '0';
end if;
end if;
end if;
end if;
end process arbitrate;
end syn;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment