Skip to content

Commit

Permalink
TCAM2: [MAINTENANCE] refactor TCAM2
Browse files Browse the repository at this point in the history
Fix RW address width in fragmented mem mode. Remove duplicit code (VHDL). Adjust code to comply with the coding style. Extend and refactor verification.
  • Loading branch information
haczech committed Oct 16, 2024
1 parent b55141a commit 9c71cda
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 164 deletions.
143 changes: 51 additions & 92 deletions comp/base/mem/tcam2/tcam2.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,28 @@ entity TCAM2 is

-- FPGA device
-- available are "7SERIES", "ULTRASCALE", "ARRIA10", "STRATIX10", "AGILEX"
DEVICE : string := "ULTRASCALE"
DEVICE : string := "ULTRASCALE";

-- Manufacturer of FPGA device
IS_XILINX : boolean := (DEVICE = "7SERIES" or DEVICE = "ULTRASCALE");
IS_INTEL : boolean := (DEVICE = "ARRIA10" or DEVICE = "STRATIX10" or DEVICE = "AGILEX");

-- Optimal parameters by FPGA device
INTEL_DATA_WIDTH : integer := tsel(USE_FRAGMENTED_MEM, 20, 16);
XILINX_DATA_WIDTH : integer := tsel(DEVICE = "ULTRASCALE", tsel(USE_FRAGMENTED_MEM, 14, 8), tsel(USE_FRAGMENTED_MEM, 6, 4));
MEMORY_ADDR_WIDTH : integer := 5;
MEMORY_DATA_WIDTH : integer := tsel(IS_XILINX, XILINX_DATA_WIDTH, INTEL_DATA_WIDTH);
ALIGNED_DATA_WIDTH : integer := 2**log2(MEMORY_DATA_WIDTH);
ITEMS_ALIGNED : integer := tsel(USE_FRAGMENTED_MEM, div_roundup(ITEMS,MEMORY_DATA_WIDTH)*ALIGNED_DATA_WIDTH, ITEMS);
ADDR_WIDTH : integer := max(1, log2(ITEMS_ALIGNED))
);
Port (
-- CLOCK AND RESET
CLK : in std_logic;
RST : in std_logic;

-- READ INTERFACE (READ_FROM_TCAM must be set as true)
READ_ADDR : in std_logic_vector(max(1,log2(ITEMS))-1 downto 0);
READ_ADDR : in std_logic_vector(ADDR_WIDTH-1 downto 0);
READ_EN : in std_logic;
READ_RDY : out std_logic;
READ_DATA : out std_logic_vector(DATA_WIDTH-1 downto 0);
Expand All @@ -72,7 +85,7 @@ entity TCAM2 is
-- WRITE INTERFACE
WRITE_DATA : in std_logic_vector(DATA_WIDTH-1 downto 0);
WRITE_MASK : in std_logic_vector(DATA_WIDTH-1 downto 0);
WRITE_ADDR : in std_logic_vector(max(1,log2(ITEMS))-1 downto 0);
WRITE_ADDR : in std_logic_vector(ADDR_WIDTH-1 downto 0);
WRITE_EN : in std_logic;
WRITE_RDY : out std_logic;

Expand All @@ -92,24 +105,13 @@ end entity;
-- =====================================================================
architecture FULL of TCAM2 is

-- Manufacturer of FPGA device
constant IS_XILINX : boolean := (DEVICE = "7SERIES" or DEVICE = "ULTRASCALE");
constant IS_INTEL : boolean := (DEVICE = "ARRIA10" or DEVICE = "STRATIX10" or DEVICE = "AGILEX");

-- Optimal parameters by FPGA device
constant INTEL_DATA_WIDTH : integer := tsel(USE_FRAGMENTED_MEM, 20, 16);
constant XILINX_DATA_WIDTH : integer := tsel(DEVICE = "ULTRASCALE", tsel(USE_FRAGMENTED_MEM, 14, 8), tsel(USE_FRAGMENTED_MEM, 6, 4));
constant MEMORY_ADDR_WIDTH : integer := 5;
constant MEMORY_DATA_WIDTH : integer := tsel(IS_XILINX, XILINX_DATA_WIDTH, INTEL_DATA_WIDTH);
constant ALIGNED_DATA_WIDTH : integer := 2**log2(MEMORY_DATA_WIDTH);

-- Setting TCAM2 resources parameters
constant CELL_WIDTH : integer := MEMORY_ADDR_WIDTH - RESOURCES_SAVING;
constant CELL_HEIGHT : integer := MEMORY_DATA_WIDTH * (2**RESOURCES_SAVING);
constant ALIGNED_CELL_HEIGHT : integer := ALIGNED_DATA_WIDTH * (2**RESOURCES_SAVING);
constant CELL_HEIGHT_RATIO : integer := CELL_HEIGHT/MEMORY_DATA_WIDTH;
constant COLUMNS : integer := div_roundup(DATA_WIDTH, CELL_WIDTH);
constant ROWS : integer := div_roundup(ITEMS, ALIGNED_CELL_HEIGHT);
constant ROWS : integer := div_roundup(ITEMS_ALIGNED, ALIGNED_CELL_HEIGHT);

-- --------------------------------------------------------------------------
-- I/O data signals
Expand All @@ -125,7 +127,6 @@ architecture FULL of TCAM2 is
signal input_m_data_reg_aug : std_logic_vector(COLUMNS*CELL_WIDTH-1 downto 0);
signal input_wr_data_reg_aug : std_logic_vector(COLUMNS*CELL_WIDTH-1 downto 0) := (others => '0');
signal input_wr_mask_reg_aug : std_logic_vector(COLUMNS*CELL_WIDTH-1 downto 0) := (others => '0');
signal input_wr_addr_reg_aug : std_logic_vector(log2(ROWS*ALIGNED_CELL_HEIGHT)-1 downto 0) := (others => '0');

-- Input registers augmented arrays
signal input_m_data_reg_aug_arr : slv_array_t(COLUMNS-1 downto 0)(CELL_WIDTH-1 downto 0);
Expand Down Expand Up @@ -218,14 +219,9 @@ architecture FULL of TCAM2 is
signal sf_cnt_en : std_logic;
signal sf_cnt_en_reg : std_logic;

-- output match register write enable
signal m_aug_reg_we : std_logic_vector(CELL_HEIGHT_RATIO-1 downto 0);

-- output match vector register
signal m_aug_reg : slv_array_2d_t(ROWS-1 downto 0)(CELL_HEIGHT_RATIO-1 downto 0)(ALIGNED_DATA_WIDTH-1 downto 0);

-- fit output match
signal m_aug : std_logic_vector(ROWS*ALIGNED_CELL_HEIGHT-1 downto 0);
-- output match register
signal m_reg_we : std_logic_vector(CELL_HEIGHT_RATIO-1 downto 0);
signal m_reg : slv_array_2d_t(ROWS-1 downto 0)(CELL_HEIGHT_RATIO-1 downto 0)(MEMORY_DATA_WIDTH-1 downto 0);

begin

Expand Down Expand Up @@ -289,60 +285,27 @@ begin
-- memory element generate
mem_rows_g : for r in 0 to ROWS-1 generate
mem_colums_g : for c in 0 to COLUMNS-1 generate

memory_xilinx_g : if IS_XILINX generate
-- write data block (backup other records and add new)
mem_wr_data_block(c)(r) <= (mem_match_vector(c)(r) and not mem_wr_bit_en_reg) or ((MEMORY_DATA_WIDTH-1 downto 0 => mem_wr_data_reg(c)) and mem_wr_bit_en_reg);

-- Xilinx Single Port RAM
sp_distmem_i : entity work.GEN_LUTRAM
generic map (
DATA_WIDTH => MEMORY_DATA_WIDTH,
ITEMS => 2**MEMORY_ADDR_WIDTH,
RD_PORTS => 1,
RD_LATENCY => 1,
WRITE_USE_RD_ADDR0 => False,
MLAB_CONSTR_RDW_DC => False,
DEVICE => DEVICE
)
port map (
CLK => CLK,
WR_EN => mem_wr_en_reg(r),
WR_ADDR => mem_wr_addr_reg,
WR_DATA => mem_wr_data_block(c)(r),
RD_ADDR => mem_addr_arr(c),
RD_DATA => mem_match_vector(c)(r)
);
end generate;

storage_intel_g : if IS_INTEL generate
-- write data block (backup other records and add new)
mem_wr_data_block(c)(r) <= (mem_match_vector(c)(r) and not mem_wr_bit_en_reg) or ((MEMORY_DATA_WIDTH-1 downto 0 => mem_wr_data_reg(c)) and mem_wr_bit_en_reg);

-- INTEL MLAB simple dual port RAM
sdp_mlab_ram_i : entity work.GEN_LUTRAM
generic map (
DATA_WIDTH => MEMORY_DATA_WIDTH,
ITEMS => 2**MEMORY_ADDR_WIDTH,
RD_PORTS => 1,
RD_LATENCY => 1,
WRITE_USE_RD_ADDR0 => False,
MLAB_CONSTR_RDW_DC => True,
DEVICE => DEVICE
)
port map (
CLK => CLK,
WR_EN => mem_wr_en_reg(r),
WR_ADDR => mem_wr_addr_reg,
WR_DATA => mem_wr_data_block(c)(r),
RD_ADDR => mem_addr_arr(c),
RD_DATA => mem_match_vector(c)(r)
);
end generate;

-- propagating match
-- write data block (backup other records and add new)
mem_wr_data_block(c)(r) <= (mem_match_vector(c)(r) and not mem_wr_bit_en_reg) or ((MEMORY_DATA_WIDTH-1 downto 0 => mem_wr_data_reg(c)) and mem_wr_bit_en_reg);
sp_distmem_i : entity work.GEN_LUTRAM
generic map (
DATA_WIDTH => MEMORY_DATA_WIDTH,
ITEMS => 2**MEMORY_ADDR_WIDTH,
RD_PORTS => 1,
RD_LATENCY => 1,
WRITE_USE_RD_ADDR0 => False,
MLAB_CONSTR_RDW_DC => IS_INTEL,
DEVICE => DEVICE
)
port map (
CLK => CLK,
WR_EN => mem_wr_en_reg(r),
WR_ADDR => mem_wr_addr_reg,
WR_DATA => mem_wr_data_block(c)(r),
RD_ADDR => mem_addr_arr(c),
RD_DATA => mem_match_vector(c)(r)
);
mem_match_carry(c+1)(r) <= mem_match_carry(c)(r) and mem_match_vector(c)(r);

end generate;
end generate;

Expand All @@ -359,7 +322,7 @@ begin
write_data_storage_i : entity work.SDP_BRAM_BEHAV
generic map (
DATA_WIDTH => DATA_WIDTH,
ITEMS => ITEMS,
ITEMS => ITEMS_ALIGNED,
OUTPUT_REG => OUTPUT_READ_REGS
)
port map (
Expand All @@ -382,7 +345,7 @@ begin
write_mask_storage_i : entity work.SDP_BRAM_BEHAV
generic map (
DATA_WIDTH => DATA_WIDTH,
ITEMS => ITEMS,
ITEMS => ITEMS_ALIGNED,
OUTPUT_REG => OUTPUT_READ_REGS
)
port map (
Expand Down Expand Up @@ -434,7 +397,6 @@ begin
-- write signals registers padding
input_wr_data_reg_aug(input_wr_data_reg'range) <= input_wr_data_reg;
input_wr_mask_reg_aug(input_wr_mask_reg'range) <= input_wr_mask_reg;
input_wr_addr_reg_aug(input_wr_addr_reg'range) <= input_wr_addr_reg;
-- write data and mask registers arrays
input_wr_data_reg_aug_arr <= slv_array_deser(input_wr_data_reg_aug,COLUMNS);
input_wr_mask_reg_aug_arr <= slv_array_deser(input_wr_mask_reg_aug,COLUMNS);
Expand Down Expand Up @@ -469,7 +431,7 @@ begin
ITEMS => ROWS
)
port map (
ADDR => input_wr_addr_reg_aug(input_wr_addr_reg_aug'high downto log2(ALIGNED_CELL_HEIGHT)),
ADDR => input_wr_addr_reg(input_wr_addr_reg'high downto log2(ALIGNED_CELL_HEIGHT)),
ENABLE => wr_cnt_en,
DO => mem_wr_en
);
Expand All @@ -480,7 +442,7 @@ begin

-- cell height address
mem_sf_addr_g : if CELL_HEIGHT_RATIO > 1 generate
mem_sf_addr <= input_wr_addr_reg_aug(log2(ALIGNED_CELL_HEIGHT)-1 downto log2(ALIGNED_DATA_WIDTH));
mem_sf_addr <= input_wr_addr_reg(log2(ALIGNED_CELL_HEIGHT)-1 downto log2(ALIGNED_DATA_WIDTH));
end generate;
fake_mem_sf_addr_g : if CELL_HEIGHT_RATIO = 1 generate
mem_sf_addr(0) <= '0';
Expand All @@ -493,7 +455,7 @@ begin
ITEMS => ALIGNED_DATA_WIDTH
)
port map (
ADDR => input_wr_addr_reg_aug(log2(ALIGNED_DATA_WIDTH)-1 downto 0),
ADDR => input_wr_addr_reg(log2(ALIGNED_DATA_WIDTH)-1 downto 0),
DO => mem_wr_bit_en
);
end generate;
Expand Down Expand Up @@ -603,35 +565,32 @@ begin
mem_match_en <= sf_cnt_en;

-- output match register write enable decoder
m_aug_reg_we_dec_i : entity work.dec1fn_enable
m_reg_we_dec_i : entity work.dec1fn_enable
generic map (
ITEMS => CELL_HEIGHT_RATIO
)
port map (
ADDR => sf_cnt_reg,
ENABLE => sf_cnt_en_reg,
DO => m_aug_reg_we
DO => m_reg_we
);

-- output match vector register
match_bits_reg_g : for i in 0 to ROWS-1 generate
match_words_reg_g : for j in 0 to CELL_HEIGHT_RATIO-1 generate
m_aug_reg_p : process (CLK)
m_reg_p : process (CLK)
begin
if rising_edge(CLK) then
if (m_aug_reg_we(j) = '1') then
m_aug_reg(i)(j) <= (others=>'0');
m_aug_reg(i)(j)(mem_match_out(i)'range) <= mem_match_out(i);
if (m_reg_we(j) = '1') then
m_reg(i)(j) <= mem_match_out(i);
end if;
end if;
end process;
end generate;
end generate;
-- array conversion
m_aug <= slv_array_2d_ser(m_aug_reg);

-- output length fit
MATCH_OUT_ADDR <= m_aug(MATCH_OUT_ADDR'range);
MATCH_OUT_ADDR <= slv_array_2d_ser(m_reg)(MATCH_OUT_ADDR'range);

-- match hit
MATCH_OUT_HIT <= or MATCH_OUT_ADDR;
Expand Down
20 changes: 9 additions & 11 deletions comp/base/mem/tcam2/ver/Modules.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@
#
# SPDX-License-Identifier: BSD-3-Clause

# set paths
set SV_MVB_BASE "$OFM_PATH/comp/mvb_tools/ver"
set SV_WB_BASE "$ENTITY_BASE/tbench/write_bus"
set SV_RB_BASE "$ENTITY_BASE/tbench/read_bus"

set SV_MVB_BASE "$OFM_PATH/comp/mvb_tools/ver"
set SV_WB_BASE "$ENTITY_BASE/tbench/write_bus"
lappend COMPONENTS [ list "SV_MVB" $SV_MVB_BASE "FULL" ]
lappend COMPONENTS [ list "SV_WB" $SV_WB_BASE "FULL" ]
lappend COMPONENTS [ list "SV_RB" $SV_RB_BASE "FULL" ]

set COMPONENTS [list \
[ list "SV_MVB" $SV_MVB_BASE "FULL"] \
[ list "SV_WB" $SV_WB_BASE "FULL"] \
]

set MOD "$MOD $ENTITY_BASE/tbench/test_pkg.sv"
set MOD "$MOD $ENTITY_BASE/tbench/dut.sv"
set MOD "$MOD $ENTITY_BASE/tbench/test.sv"
lappend MOD "$ENTITY_BASE/tbench/test_pkg.sv"
lappend MOD "$ENTITY_BASE/tbench/dut.sv"
lappend MOD "$ENTITY_BASE/tbench/test.sv"
13 changes: 13 additions & 0 deletions comp/base/mem/tcam2/ver/tbench/read_bus/Modules.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Modules.tcl: Local include tcl script
# Copyright (C) 2024 CESNET z. s. p. o.
# Author: Tomas Hak <[email protected]>
#
# SPDX-License-Identifier: BSD-3-Clause

set SV_COMMON_BASE "$OFM_PATH/comp/ver"
set SV_MVB_BASE "$OFM_PATH/comp/mvb_tools/ver"

lappend COMPONENTS [ list "SV_COMMON" $SV_COMMON_BASE "FULL" ]
lappend COMPONENTS [ list "SV_MVB" $SV_MVB_BASE "FULL" ]

lappend MOD "$ENTITY_BASE/sv_rb_pkg.sv"
21 changes: 21 additions & 0 deletions comp/base/mem/tcam2/ver/tbench/read_bus/rb_transaction.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// rb_transaction.sv: Read Bus transaction
// Copyright (C) 2024 CESNET z. s. p. o.
// Author: Tomas Hak <[email protected]>
//
// SPDX-License-Identifier: BSD-3-Clause

class RbTransaction #(ADDR_WIDTH = 8, FRAGMENTED_MEM = FALSE, ITEMS = 2**ADDR_WIDTH, BLOCK_ITEMS = 20) extends MvbTransaction#(.ITEM_WIDTH(ADDR_WIDTH));
constraint mem_items_constr { data < ITEMS; }
// in fragmented mode top BLOCK addresses are not used
constraint frag_mem_constr { !FRAGMENTED_MEM || data[$clog2(BLOCK_ITEMS)-1 : 0] < BLOCK_ITEMS; }

virtual function Transaction copy(Transaction to = null);
RbTransaction #(ADDR_WIDTH, FRAGMENTED_MEM, ITEMS, BLOCK_ITEMS) tr;
if (to == null)
tr = new();
else
$cast(tr, to);
copy = super.copy(tr);
endfunction

endclass
14 changes: 14 additions & 0 deletions comp/base/mem/tcam2/ver/tbench/read_bus/sv_rb_pkg.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// sv_rb_pkg.sv: SystemVerilog package with Read Bus
// Copyright (C) 2024 CESNET z. s. p. o.
// Author: Tomas Hak <[email protected]>
//
// SPDX-License-Identifier: BSD-3-Clause

package sv_rb_pkg;

import sv_common_pkg::*;
import sv_mvb_pkg::*;

`include "rb_transaction.sv"

endpackage
Loading

0 comments on commit 9c71cda

Please sign in to comment.