MVB Lookup Table

ENTITY MVB_LOOKUP_TABLE IS

MVB Lookup Table: for every valid MVB item on the RX side, looks up the table entry addressed by RX_MVB_LUT_ADDR and presents it on the corresponding TX_MVB_LUT_DATA item, together with the (registered) RX_MVB_LUT_ADDR and RX_MVB_METADATA of that item. This is the top-level (recommended) entity: it picks one of the three available implementations (a single register, MVB_LOOKUP_TABLE_LUTRAM, or MVB_LOOKUP_TABLE_BRAM) based on LUT_ARCH/LUT_DEPTH. RX-to-TX latency depends on which of these is selected and on OUTPUT_REG, see the OUTPUT_REG generic below for the exact cycle counts.

The table content is configured through a synchronous SW_* register-file style port (address + byte-enabled data, not the CESNET MI bus) - see the port descriptions below. This component does not reset or initialize the table content on RESET; all LUT_DEPTH entries must be written through the SW_* interface before the first RX lookup that relies on them, otherwise reads of not-yet-written entries return undefined data.

Note

SW_WRITE never stalls or backpressures RX_MVB lookups - RX_MVB_DST_RDY only follows TX_MVB_DST_RDY, regardless of SW_* activity. Unlike some sibling components, there is also no atomicity guarantee here, not even for a single entry: each SW_WRITE goes straight into the table as soon as it happens, with no staging step that only commits a complete entry at once. So if LUT_WIDTH > SW_WIDTH, an entry needs several SW_WRITEs (one per slice, see above) to fully update, and an RX_MVB lookup running in between can see that one entry half-written - part old slices, part new.

The same applies, entry by entry, when updating several entries in a row. If your application needs lookups to only ever see a fully consistent entry (or a consistent snapshot across several entries), you need to arrange that yourself, e.g. by pausing RX_MVB lookups for the duration of an update; this component does not do it for you.

Warning

LUT_WIDTH must be an integer multiple of SW_WIDTH. Any other ratio is not correctly supported: depending on LUT_DEPTH/LUT_ARCH it causes the topmost bits of an entry to be silently unreachable through SW_DOUT (single register and MVB_LOOKUP_TABLE_BRAM), aliased writes (single register), or an elaboration-time width mismatch (MVB_LOOKUP_TABLE_BRAM). MVB_LOOKUP_TABLE_LUTRAM handles the entry width itself correctly, but the shared SW_SLICE port is always sized for the exact-multiple case, so higher slices can still be unreachable there too.

Generics

Generic

Type

Default

Description

MVB_ITEMS

natural

4

Number of MVB items transferred in one word.

LUT_DEPTH

natural

128

Number of entries in the lookup table. Any positive value; LUT_DEPTH = 1 is implemented directly as a single shared register regardless of LUT_ARCH.

LUT_WIDTH

natural

32

Width of one lookup table entry in bits. Should be a multiple of SW_WIDTH, see the WARNING above.

LUT_ARCH

string

“AUTO”

Select the memory implementation used when LUT_DEPTH > 1:

  • “LUT” - MVB_LOOKUP_TABLE_LUTRAM, effective for a shallow table (approx. LUT_DEPTH <= 64).

  • “BRAM” - MVB_LOOKUP_TABLE_BRAM, effective for a deep table (approx. LUT_DEPTH > 64); consumes MVB_ITEMS+1 block RAMs.

  • “AUTO” - chosen automatically from LUT_DEPTH using the same approx. 64-entry threshold as above.

SW_WIDTH

natural

32

Data width of the SW_* configuration port in bits. Must be a multiple of 8: SW_BE has one bit per byte of SW_DIN (SW_WIDTH/8, integer division), so a non-multiple silently loses byte-enable coverage over the trailing, incomplete byte.

META_WIDTH

natural

1

Width of the RX_MVB_METADATA/TX_MVB_METADATA side-channel in bits. Any non-negative value; the metadata is only delayed together with the MVB transaction, it does not influence the lookup itself.

OUTPUT_REG

boolean

True

Adds an output register stage on the TX_MVB_* path (and, for the BRAM implementation, also on the internal RAM output). Improves timing at the cost of extra registers and one additional CLK cycle of RX-to-TX latency:

  • Single register (LUT_DEPTH = 1) or LUT_ARCH = “LUT”: 0 CLK cycles when false, 1 CLK cycle when true.

  • LUT_ARCH = “BRAM”: 1 CLK cycle when false, 2 CLK cycles when true.

DEVICE

string

“AGILEX”

Target FPGA device, passed through to the underlying memory implementation.

Ports

Port

Type

Mode

Description

CLK

std_logic

in

RESET

std_logic

in

=====

RX MVB INTERFACE

=====

Lookup request: RX_MVB_LUT_ADDR addresses the entry to look up.

RX_MVB_LUT_ADDR

slv_array_t(MVB_ITEMS-1 downto 0)(max(log2(LUT_DEPTH),1)-1 downto 0)

in

RX_MVB_METADATA

slv_array_t(MVB_ITEMS-1 downto 0)(META_WIDTH-1 downto 0)

in

RX_MVB_VLD

std_logic_vector(MVB_ITEMS-1 downto 0)

in

RX_MVB_SRC_RDY

std_logic

in

RX_MVB_DST_RDY

std_logic

out

=====

TX MVB INTERFACE

=====

Lookup result, RX-to-TX latency cycles later (see OUTPUT_REG above).

TX_MVB_LUT_DATA

slv_array_t(MVB_ITEMS-1 downto 0)(LUT_WIDTH-1 downto 0)

out

Lookup table entry addressed by the corresponding (registered) TX_MVB_LUT_ADDR.

TX_MVB_LUT_ADDR

slv_array_t(MVB_ITEMS-1 downto 0)(max(log2(LUT_DEPTH),1)-1 downto 0)

out

TX_MVB_METADATA

slv_array_t(MVB_ITEMS-1 downto 0)(META_WIDTH-1 downto 0)

out

TX_MVB_VLD

std_logic_vector(MVB_ITEMS-1 downto 0)

out

TX_MVB_SRC_RDY

std_logic

out

TX_MVB_DST_RDY

std_logic

in

=====

SW CONFIGURATION INTERFACE

=====

Synchronous register-file style port used to read/write the lookup table content. Not the CESNET MI bus; intended to be driven through an external MI (or other software-accessible bus) adapter. One access addresses a single LUT entry (SW_ADDR). If LUT_WIDTH is wider than SW_WIDTH, each access only reaches one SW_WIDTH-wide slice of that entry, chosen by SW_SLICE. Writing a whole entry therefore means repeating SW_WRITE at the same SW_ADDR once per slice, SW_SLICE = 0 to LUT_WIDTH/SW_WIDTH-1.

SW_ADDR

std_logic_vector(max(log2(LUT_DEPTH),1)-1 downto 0)

in

Address of the accessed lookup table entry.

SW_SLICE

std_logic_vector(max(log2(LUT_WIDTH/SW_WIDTH),1)-1 downto 0)

in

Selects which SW_WIDTH-wide slice of the addressed entry is accessed, when LUT_WIDTH > SW_WIDTH. Unused (any value valid) when LUT_WIDTH = SW_WIDTH (the only other case the WARNING above allows).

SW_DIN

std_logic_vector(SW_WIDTH-1 downto 0)

in

Data to write; valid when SW_WRITE = ‘1’.

SW_BE

std_logic_vector(SW_WIDTH/8-1 downto 0)

in

Byte-enable for SW_DIN; only enabled bytes are written.

SW_WRITE

std_logic

in

Write request for the (SW_ADDR, SW_SLICE) location, takes effect immediately (1 CLK).

SW_READ

std_logic

in

Read request for the (SW_ADDR, SW_SLICE) location; the result appears on SW_DOUT one CLK later.

SW_DOUT

std_logic_vector(SW_WIDTH-1 downto 0)

out

Read data, valid when SW_DOUT_VLD = ‘1’ (registered, one CLK after SW_READ).

SW_DOUT_VLD

std_logic

out