Skip to content

Commit 3ccfba3

Browse files
committed
Merge branch 'cabal_udp_gen' into 'devel'
feat(mfb_tools): extend MFB Generator with IPv4/UDP support See merge request ndk/ndk-fpga!240
2 parents d78dd89 + 40095c3 commit 3ccfba3

File tree

4 files changed

+94
-16
lines changed

4 files changed

+94
-16
lines changed

comp/mfb_tools/debug/generator/DevTree.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ proc dts_mfb_generator {base name} {
66
append ret "$name {"
77
append ret "compatible = \"cesnet,ofm,mfb_generator\";"
88
append ret "reg = <$base $size>;"
9-
append ret "version = <1>;"
9+
append ret "version = <2>;"
1010
append ret "};"
1111
return $ret
1212
}

comp/mfb_tools/debug/generator/mfb_generator.vhd

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
-- Copyright (C) 2023 CESNET z. s. p. o.
33
-- Author(s): Daniel Kondys <[email protected]>
44
-- Vladislav Valek <[email protected]>
5+
-- Jakub Cabal <[email protected]>
56
--
67
-- SPDX-License-Identifier: BSD-3-Clause
78

@@ -55,6 +56,7 @@ entity MFB_GENERATOR is
5556
CTRL_MAC_SRC : in std_logic_vector(48-1 downto 0);
5657
CTRL_PKT_CNT_CLR : in std_logic;
5758
CTRL_PKT_CNT : out std_logic_vector(PKT_CNT_WIDTH-1 downto 0);
59+
CTRL_SRC_IP_MASK : in std_logic_vector(32-1 downto 0);
5860

5961
-- TX interface
6062
TX_MFB_DATA : out std_logic_vector(REGIONS*REGION_SIZE*BLOCK_SIZE*ITEM_WIDTH-1 downto 0);
@@ -71,7 +73,7 @@ entity MFB_GENERATOR is
7173
architecture BEHAV of MFB_GENERATOR is
7274

7375
constant CHANNELS : natural := 2**CHANNELS_WIDTH;
74-
constant ETHER_TYPE : std_logic_vector(15 downto 0) := X"B588"; -- local experimental ethertype
76+
constant ETHER_TYPE : std_logic_vector(15 downto 0) := X"0008"; -- IPv4 ethertype
7577

7678
signal pkt_cnt : u_array_t(REGIONS downto 0)(PKT_CNT_WIDTH-1 downto 0);
7779
signal pkt_cnt_reg : unsigned(PKT_CNT_WIDTH-1 downto 0);
@@ -122,8 +124,17 @@ architecture BEHAV of MFB_GENERATOR is
122124
signal meta : slv_array_t(REGIONS-1 downto 0)(CHANNELS_WIDTH+LENGTH_WIDTH-1 downto 0);
123125
signal data : slv_array_t(REGIONS-1 downto 0)(REGION_SIZE*BLOCK_SIZE*ITEM_WIDTH-1 downto 0);
124126

125-
signal free_cnt : unsigned(16-1 downto 0);
126-
signal eth_hdr_128b : std_logic_vector(128-1 downto 0);
127+
signal free_cnt : unsigned(32-1 downto 0);
128+
signal dip : slv_array_t(REGIONS-1 downto 0)(32-1 downto 0);
129+
signal sip : slv_array_t(REGIONS-1 downto 0)(32-1 downto 0);
130+
signal dport : slv_array_t(REGIONS-1 downto 0)(16-1 downto 0);
131+
signal sport : slv_array_t(REGIONS-1 downto 0)(16-1 downto 0);
132+
signal l3len : std_logic_vector(16-1 downto 0);
133+
signal l4len : std_logic_vector(16-1 downto 0);
134+
signal ipv4_hdr : slv_array_t(REGIONS-1 downto 0)((20*8)-1 downto 0);
135+
signal udp_hdr : slv_array_t(REGIONS-1 downto 0)((8*8)-1 downto 0);
136+
signal eth_hdr_384b : slv_array_t(REGIONS-1 downto 0)(384-1 downto 0);
137+
127138
signal sof_pos_arr : slv_array_t(REGIONS-1 downto 0)(max(1, log2(REGION_SIZE))-1 downto 0);
128139
signal sof_index : u_array_t(REGIONS-1 downto 0)(max(1, log2(REGIONS*REGION_SIZE))-1 downto 0);
129140
signal data_word_plus : slv_array_t(2*REGIONS*REGION_SIZE-1 downto 0)(BLOCK_SIZE*ITEM_WIDTH-1 downto 0);
@@ -447,12 +458,26 @@ begin
447458
if (RST = '1') then
448459
free_cnt <= (others => '0');
449460
elsif (dst_rdy = '1') then
450-
free_cnt <= free_cnt + 1;
461+
free_cnt <= free_cnt + REGIONS;
451462
end if;
452463
end if;
453464
end process;
454465

455-
eth_hdr_128b <= std_logic_vector(free_cnt) & ETHER_TYPE & CTRL_MAC_SRC & CTRL_MAC_DST;
466+
l3len <= std_logic_vector(resize((unsigned(CTRL_LENGTH)-14),16));
467+
l4len <= std_logic_vector(resize((unsigned(CTRL_LENGTH)-34),16));
468+
469+
hdr_g: for i in 0 to REGIONS-1 generate
470+
dip(i) <= X"00000000";
471+
sip(i) <= std_logic_vector(free_cnt + i) and CTRL_SRC_IP_MASK;
472+
dport(i) <= X"0000";
473+
sport(i) <= X"0000";
474+
475+
--UDP proto, Time To Live, Identification+Flags+FragmentOffset, l3len, DSCP+ECN, IHL+version
476+
ipv4_hdr(i) <= dip(i) & sip(i) & X"0000" & X"11" & X"FF" & X"00000000" & l3len(7 downto 0) & l3len(15 downto 8) & X"00" & X"45";
477+
udp_hdr(i) <= X"0000" & l4len(7 downto 0) & l4len(15 downto 8) & dport(i) & sport(i);
478+
eth_hdr_384b(i) <= X"000000000000" & udp_hdr(i) & ipv4_hdr(i) & ETHER_TYPE & CTRL_MAC_SRC & CTRL_MAC_DST;
479+
end generate;
480+
456481
sof_pos_arr <= slv_array_deser(sof_pos,REGIONS,max(1, log2(REGION_SIZE)));
457482

458483
process (all)
@@ -466,8 +491,12 @@ begin
466491
for i in 0 to REGIONS-1 loop
467492
sof_index(i) <= resize(unsigned(sof_pos_arr(i)),log2(REGIONS*REGION_SIZE)) + i*REGION_SIZE;
468493
if (sof(i) = '1') then
469-
data_word_plus(to_integer(sof_index(i))) <= eth_hdr_128b(64-1 downto 0);
470-
data_word_plus(to_integer(sof_index(i))+1) <= eth_hdr_128b(128-1 downto 64);
494+
data_word_plus(to_integer(sof_index(i))) <= eth_hdr_384b(i)(64-1 downto 0);
495+
data_word_plus(to_integer(sof_index(i))+1) <= eth_hdr_384b(i)(128-1 downto 64);
496+
data_word_plus(to_integer(sof_index(i))+2) <= eth_hdr_384b(i)(192-1 downto 128);
497+
data_word_plus(to_integer(sof_index(i))+3) <= eth_hdr_384b(i)(256-1 downto 192);
498+
data_word_plus(to_integer(sof_index(i))+4) <= eth_hdr_384b(i)(320-1 downto 256);
499+
data_word_plus(to_integer(sof_index(i))+5) <= eth_hdr_384b(i)(384-1 downto 320);
471500
end if;
472501
end loop;
473502
end process;

comp/mfb_tools/debug/generator/mfb_generator_mi32.vhd

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
-- Copyright (C) 2023 CESNET z. s. p. o.
33
-- Author(s): Daniel Kondys <[email protected]>
44
-- Vladislav Valek <[email protected]>
5+
-- Jakub Cabal <[email protected]>
56
--
67
-- SPDX-License-Identifier: BSD-3-Clause
78
--
@@ -33,6 +34,7 @@ use work.math_pack.all;
3334
-- - 0x1C - Src MAC High (higher part of source MAC address)
3435
-- - 0x20 - Cntr Low (lower part of counter for generated frames)
3536
-- - 0x24 - Cntr High (higher part of counter for generated frames)
37+
-- - 0x28 - SRC IP address mask register
3638
--
3739
-- **Register format**
3840
--
@@ -132,6 +134,7 @@ architecture BEHAV of MFB_GENERATOR_MI32 is
132134
signal dmac_high_reg_sel : std_logic;
133135
signal smac_low_reg_sel : std_logic;
134136
signal smac_high_reg_sel : std_logic;
137+
signal src_ip_mask_reg_sel : std_logic;
135138
-- register signals
136139
signal en_reg : std_logic;
137140
signal clr_reg : std_logic;
@@ -146,6 +149,7 @@ architecture BEHAV of MFB_GENERATOR_MI32 is
146149
signal smac_comb_reg : std_logic_vector(MAC_ADDR_WIDTH-1 downto 0); -- combines smac_low_reg and smac_high_reg signals for the mfb_generator input
147150
signal smac_low_reg : std_logic_vector(31 downto 0); -- low bits of source mac address
148151
signal smac_high_reg : std_logic_vector(MAC_ADDR_WIDTH-33 downto 0); -- high bits of source mac address
152+
signal src_ip_mask_reg : std_logic_vector(31 downto 0);
149153

150154
begin
151155

@@ -175,6 +179,7 @@ begin
175179
CTRL_MAC_SRC => smac_comb_reg,
176180
CTRL_PKT_CNT_CLR => clr_reg,
177181
CTRL_PKT_CNT => cnt_reg,
182+
CTRL_SRC_IP_MASK => src_ip_mask_reg,
178183
-- tx interface
179184
TX_MFB_DATA => TX_MFB_DATA,
180185
TX_MFB_META => TX_MFB_META,
@@ -187,14 +192,15 @@ begin
187192
);
188193

189194
-- signals for register selection
190-
ctrl_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "000000") else '0';
191-
len_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "000100") else '0';
192-
chan_inc_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "001000") else '0';
193-
chan_val_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "001100") else '0';
194-
dmac_low_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "010000") else '0';
195-
dmac_high_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "010100") else '0';
196-
smac_low_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "011000") else '0';
197-
smac_high_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "011100") else '0';
195+
ctrl_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "000000") else '0';
196+
len_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "000100") else '0';
197+
chan_inc_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "001000") else '0';
198+
chan_val_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "001100") else '0';
199+
dmac_low_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "010000") else '0';
200+
dmac_high_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "010100") else '0';
201+
smac_low_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "011000") else '0';
202+
smac_high_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "011100") else '0';
203+
src_ip_mask_reg_sel <= '1' when (MI_ADDR(6-1 downto 0) = "101000") else '0';
198204

199205
-- ==================================================================
200206
-- transfering data to/from registers according to the select signals
@@ -308,6 +314,17 @@ begin
308314

309315
smac_comb_reg <= smac_high_reg & smac_low_reg;
310316

317+
process (CLK)
318+
begin
319+
if (rising_edge(CLK)) then
320+
if (RST = '1') then
321+
src_ip_mask_reg <= (others => '1');
322+
elsif ((src_ip_mask_reg_sel = '1') and (MI_WR = '1')) then
323+
src_ip_mask_reg <= MI_DWR;
324+
end if;
325+
end if;
326+
end process;
327+
311328
cnt_comb_reg_resize <= std_logic_vector(resize(unsigned(cnt_reg), 64));
312329

313330
-- process for reading data from the register with the current address
@@ -328,6 +345,7 @@ begin
328345
when "011100" => MI_DRD(15 downto 0) <= smac_high_reg;
329346
when "100000" => MI_DRD <= cnt_comb_reg_resize(31 downto 0);
330347
when "100100" => MI_DRD <= cnt_comb_reg_resize(63 downto 32);
348+
when "101000" => MI_DRD <= src_ip_mask_reg;
331349
when others => MI_DRD <= (others => '0');
332350
end case;
333351
end if;

python/ofm/ofm/comp/mfb_tools/debug/generator/mfb_generator.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
# Copyright (C) 2024 CESNET z. s. p. o.
33
# Author(s): Daniel Kondys <[email protected]>
44
# Ondrej Schwarz <[email protected]>
5+
# Jakub Cabal <[email protected]>
56

67
import sys
8+
import logging
79
from dataclasses import dataclass, fields
810
from typing import Any, Optional, List
911

@@ -21,6 +23,7 @@ class GeneratorConfig:
2123
maximum_channel: int
2224
dst_mac_address: bytes
2325
src_mac_address: bytes
26+
src_ip_address_mask: int
2427
generating: Optional[bool] = None # Read-only
2528
frame_count: Optional[int] = None # Read-only
2629

@@ -38,9 +41,11 @@ class MfbGenerator(nfb.BaseComp):
3841
_REG_SRC_MAC_HIGH = 0x1C
3942
_REG_FRAME_CNT_LOW = 0x20
4043
_REG_FRAME_CNT_HIGH = 0x24
44+
_REG_SRC_IP_MASK = 0x28
4145

4246
def __init__(self, *args, **kwargs):
4347
super().__init__(*args, **kwargs)
48+
self._logger = logging.getLogger("MfbGenerator")
4449

4550
# ################
4651
# Command register
@@ -285,6 +290,24 @@ def frame_count(self) -> int:
285290
"""Get the number of generated frames (may overflow frequently due to low cnt width)."""
286291
return int.from_bytes(self._comp.read(self._REG_FRAME_CNT_LOW, 8), byteorder=sys.byteorder)
287292

293+
# ################
294+
# IP mask register
295+
# ################
296+
@property
297+
def src_ip_address_mask(self) -> int:
298+
"""Get the mask of the generated SRC IP address."""
299+
if self._node.get_property("version").value >= 2:
300+
return self._comp.read32(self._REG_SRC_IP_MASK)
301+
return 0
302+
303+
@src_ip_address_mask.setter
304+
def src_ip_address_mask(self, mask: int) -> None:
305+
"""Set the mask to generate SRC IP address."""
306+
if self._node.get_property("version").value >= 2:
307+
self._comp.write32(self._REG_SRC_IP_MASK, mask)
308+
else:
309+
self._logger.warning("Unable to set SRC IP address mask in this generator version. Try using a newer FW.")
310+
288311
# #############
289312
# Configuration
290313
# #############
@@ -303,6 +326,7 @@ def get_configuration(self) -> GeneratorConfig:
303326
maximum_channel = self.maximum_channel,
304327
dst_mac_address = self.dst_mac_address,
305328
src_mac_address = self.src_mac_address,
329+
src_ip_address_mask = self.src_ip_address_mask,
306330
frame_count = self.frame_count,
307331
)
308332
return conf
@@ -318,6 +342,7 @@ def configure(self, conf: GeneratorConfig) -> None:
318342
self.maximum_channel = conf.maximum_channel
319343
self.dst_mac_address = conf.dst_mac_address
320344
self.src_mac_address = conf.src_mac_address
345+
self.src_ip_address_mask = conf.src_ip_address_mask
321346
self.enabled = conf.enabled
322347

323348
def get_fconfiguration(self) -> List:
@@ -328,6 +353,12 @@ def get_fconfiguration(self) -> List:
328353
lst = []
329354
for field in fields(conf):
330355
value = getattr(conf, field.name)
356+
# Convert src_ip_address_mask to hex if it exists
357+
if field.name == "src_ip_address_mask":
358+
if self._node.get_property("version").value >= 2:
359+
value = hex(value)
360+
else:
361+
value = "UNSUPPORTED!"
331362
# Convert booleans to strings for tabulation
332363
if isinstance(value, bool):
333364
value = str(value)

0 commit comments

Comments
 (0)