Skip to content

Commit b0dafd3

Browse files
committed
amba/stream_meta: Add AXI4-Stream metadata packer/unpacker
Add new stream_meta subset with components for packing and unpacking AXI4-Stream metadata (ID, Dest, User) as frame prefixes: - axi4_stream_meta_packer: Extracts metadata from first beat of each frame and serializes as a prefix in the output stream - axi4_stream_meta_unpacker: Deserializes metadata prefix and applies to all beats of the output frame
1 parent a969b70 commit b0dafd3

File tree

9 files changed

+576
-0
lines changed

9 files changed

+576
-0
lines changed

lib/nsl_amba/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ packages += axi_apb
1515
packages += stream_traffic
1616
packages += stream_to_udp
1717
packages += stream_to_tcp
18+
packages += stream_meta
1819
nsl_amba-ghdl-flags += -Wno-hide

lib/nsl_amba/stream_meta/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
vhdl-sources += stream_meta.pkg.vhd
2+
vhdl-sources += axi4_stream_meta_packer.vhd
3+
vhdl-sources += axi4_stream_meta_unpacker.vhd
4+
5+
deps += nsl_amba.axi4_stream
6+
deps += nsl_data.bytestream
7+
deps += nsl_data.endian
8+
deps += nsl_logic.bool
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
library ieee;
2+
use ieee.std_logic_1164.all;
3+
use ieee.numeric_std.all;
4+
5+
library nsl_amba, nsl_data, nsl_logic;
6+
use nsl_amba.axi4_stream.all;
7+
use nsl_data.bytestream.all;
8+
use nsl_data.endian.all;
9+
use nsl_logic.bool.all;
10+
11+
entity axi4_stream_meta_packer is
12+
generic(
13+
in_config_c : config_t;
14+
out_config_c : config_t;
15+
meta_elements_c : string := "iou";
16+
endian_c : endian_t := ENDIAN_BIG
17+
);
18+
port(
19+
clock_i : in std_ulogic;
20+
reset_n_i : in std_ulogic;
21+
22+
in_i : in master_t;
23+
in_o : out slave_t;
24+
25+
out_o : out master_t;
26+
out_i : in slave_t
27+
);
28+
29+
begin
30+
31+
assert in_config_c.data_width = out_config_c.data_width
32+
report "Input and output data widths must be equal"
33+
severity failure;
34+
35+
assert in_config_c.has_last
36+
report "Input configuration must have last signal"
37+
severity failure;
38+
39+
assert out_config_c.has_last
40+
report "Output configuration must have last signal"
41+
severity failure;
42+
43+
assert in_config_c.has_ready
44+
report "Input configuration must have ready signal"
45+
severity failure;
46+
47+
assert out_config_c.has_ready
48+
report "Output configuration must have ready signal"
49+
severity failure;
50+
51+
end entity;
52+
53+
architecture beh of axi4_stream_meta_packer is
54+
55+
constant meta_bits_c : natural := vector_length(in_config_c, meta_elements_c);
56+
constant meta_bytes_c : natural := (meta_bits_c + 7) / 8;
57+
constant padding_bits_c : natural := meta_bytes_c * 8 - meta_bits_c;
58+
59+
constant meta_config_c : buffer_config_t := buffer_config(out_config_c, meta_bytes_c);
60+
61+
type state_t is (
62+
ST_RESET,
63+
ST_IDLE,
64+
ST_META,
65+
ST_DATA
66+
);
67+
68+
type regs_t is
69+
record
70+
state: state_t;
71+
meta: buffer_t;
72+
end record;
73+
74+
signal r, rin: regs_t;
75+
76+
begin
77+
78+
regs: process(clock_i, reset_n_i) is
79+
begin
80+
if rising_edge(clock_i) then
81+
r <= rin;
82+
end if;
83+
84+
if reset_n_i = '0' then
85+
r.state <= ST_RESET;
86+
end if;
87+
end process;
88+
89+
transition: process(r, in_i, out_i) is
90+
constant padding_c : std_ulogic_vector(padding_bits_c-1 downto 0) := (others => '0');
91+
variable meta_vector : std_ulogic_vector(meta_bits_c-1 downto 0);
92+
variable meta_padded : std_ulogic_vector(meta_bytes_c * 8 - 1 downto 0);
93+
variable meta_bytes : byte_string(0 to meta_bytes_c-1);
94+
begin
95+
rin <= r;
96+
97+
case r.state is
98+
when ST_RESET =>
99+
rin.state <= ST_IDLE;
100+
101+
when ST_IDLE =>
102+
if is_valid(in_config_c, in_i) then
103+
-- Sample metadata from first beat (master holds it stable)
104+
if meta_bits_c > 0 then
105+
meta_vector := vector_pack(in_config_c, meta_elements_c, in_i);
106+
meta_padded := padding_c & meta_vector;
107+
meta_bytes := to_endian(unsigned(meta_padded), endian_c);
108+
rin.meta <= reset(meta_config_c, meta_bytes);
109+
rin.state <= ST_META;
110+
else
111+
-- No metadata to pack, go straight to data
112+
rin.state <= ST_DATA;
113+
end if;
114+
end if;
115+
116+
when ST_META =>
117+
if is_ready(out_config_c, out_i) then
118+
rin.meta <= shift(meta_config_c, r.meta);
119+
if is_last(meta_config_c, r.meta) then
120+
rin.state <= ST_DATA;
121+
end if;
122+
end if;
123+
124+
when ST_DATA =>
125+
if is_valid(in_config_c, in_i) and is_ready(out_config_c, out_i) and is_last(in_config_c, in_i) then
126+
rin.state <= ST_IDLE;
127+
end if;
128+
end case;
129+
end process;
130+
131+
mealy: process(r, in_i, out_i) is
132+
begin
133+
in_o <= accept(in_config_c, false);
134+
out_o <= transfer_defaults(out_config_c);
135+
136+
case r.state is
137+
when ST_RESET =>
138+
null;
139+
140+
when ST_IDLE =>
141+
null;
142+
143+
when ST_META =>
144+
-- Send metadata prefix
145+
out_o <= next_beat(meta_config_c, r.meta, last => false);
146+
147+
when ST_DATA =>
148+
-- Forward data beats
149+
out_o <= transfer(out_config_c, in_config_c, in_i);
150+
in_o <= out_i;
151+
end case;
152+
end process;
153+
154+
end architecture;
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
library ieee;
2+
use ieee.std_logic_1164.all;
3+
use ieee.numeric_std.all;
4+
5+
library nsl_amba, nsl_data, nsl_logic;
6+
use nsl_amba.axi4_stream.all;
7+
use nsl_data.bytestream.all;
8+
use nsl_data.endian.all;
9+
use nsl_logic.bool.all;
10+
11+
entity axi4_stream_meta_unpacker is
12+
generic(
13+
in_config_c : config_t;
14+
out_config_c : config_t;
15+
meta_elements_c : string := "iou";
16+
endian_c : endian_t := ENDIAN_BIG
17+
);
18+
port(
19+
clock_i : in std_ulogic;
20+
reset_n_i : in std_ulogic;
21+
22+
in_i : in master_t;
23+
in_o : out slave_t;
24+
25+
out_o : out master_t;
26+
out_i : in slave_t
27+
);
28+
29+
begin
30+
31+
assert in_config_c.data_width = out_config_c.data_width
32+
report "Input and output data widths must be equal"
33+
severity failure;
34+
35+
assert in_config_c.has_last
36+
report "Input configuration must have last signal"
37+
severity failure;
38+
39+
assert out_config_c.has_last
40+
report "Output configuration must have last signal"
41+
severity failure;
42+
43+
assert in_config_c.has_ready
44+
report "Input configuration must have ready signal"
45+
severity failure;
46+
47+
assert out_config_c.has_ready
48+
report "Output configuration must have ready signal"
49+
severity failure;
50+
51+
end entity;
52+
53+
architecture beh of axi4_stream_meta_unpacker is
54+
55+
constant meta_bits_c : natural := vector_length(out_config_c, meta_elements_c);
56+
constant meta_bytes_c : natural := (meta_bits_c + 7) / 8;
57+
constant padding_bits_c : natural := meta_bytes_c * 8 - meta_bits_c;
58+
59+
constant meta_config_c : buffer_config_t := buffer_config(in_config_c, meta_bytes_c);
60+
61+
type state_t is (
62+
ST_RESET,
63+
ST_META,
64+
ST_DATA
65+
);
66+
67+
type regs_t is
68+
record
69+
state: state_t;
70+
meta: buffer_t;
71+
meta_beat: master_t;
72+
end record;
73+
74+
signal r, rin: regs_t;
75+
76+
begin
77+
78+
regs: process(clock_i, reset_n_i) is
79+
begin
80+
if rising_edge(clock_i) then
81+
r <= rin;
82+
end if;
83+
84+
if reset_n_i = '0' then
85+
r.state <= ST_RESET;
86+
end if;
87+
end process;
88+
89+
transition: process(r, in_i, out_i) is
90+
variable meta_bytes : byte_string(0 to meta_bytes_c-1);
91+
variable meta_padded : std_ulogic_vector(meta_bytes_c * 8 - 1 downto 0);
92+
variable meta_vector : std_ulogic_vector(meta_bits_c-1 downto 0);
93+
begin
94+
rin <= r;
95+
96+
case r.state is
97+
when ST_RESET =>
98+
if meta_bits_c > 0 then
99+
rin.meta <= reset(meta_config_c);
100+
rin.state <= ST_META;
101+
else
102+
-- No metadata to unpack, go straight to data
103+
rin.state <= ST_DATA;
104+
end if;
105+
106+
when ST_META =>
107+
if is_valid(in_config_c, in_i) then
108+
rin.meta <= shift(meta_config_c, r.meta, in_i);
109+
if is_last(meta_config_c, r.meta, in_i) then
110+
-- Extract and unpack metadata
111+
meta_bytes := bytes(meta_config_c, shift(meta_config_c, r.meta, in_i));
112+
meta_padded := std_ulogic_vector(from_endian(meta_bytes, endian_c));
113+
meta_vector := meta_padded(meta_bits_c-1 downto 0);
114+
rin.meta_beat <= vector_unpack(out_config_c, meta_elements_c, meta_vector);
115+
rin.state <= ST_DATA;
116+
end if;
117+
end if;
118+
119+
when ST_DATA =>
120+
if is_valid(in_config_c, in_i) and is_ready(out_config_c, out_i) and is_last(in_config_c, in_i) then
121+
if meta_bits_c > 0 then
122+
rin.meta <= reset(meta_config_c);
123+
rin.state <= ST_META;
124+
end if;
125+
end if;
126+
end case;
127+
end process;
128+
129+
mealy: process(r, in_i, out_i) is
130+
variable out_v : master_t;
131+
begin
132+
in_o <= accept(in_config_c, false);
133+
out_o <= transfer_defaults(out_config_c);
134+
135+
case r.state is
136+
when ST_RESET =>
137+
null;
138+
139+
when ST_META =>
140+
-- Accept metadata bytes
141+
in_o <= accept(in_config_c, true);
142+
143+
when ST_DATA =>
144+
-- Forward data beats with extracted metadata
145+
out_v := transfer(out_config_c, in_config_c, in_i);
146+
-- Apply extracted metadata
147+
out_v.id := r.meta_beat.id;
148+
out_v.dest := r.meta_beat.dest;
149+
out_v.user := r.meta_beat.user;
150+
out_o <= out_v;
151+
in_o <= out_i;
152+
end case;
153+
end process;
154+
155+
end architecture;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
library ieee;
2+
use ieee.std_logic_1164.all;
3+
use ieee.numeric_std.all;
4+
5+
library nsl_amba, nsl_data;
6+
use nsl_amba.axi4_stream.all;
7+
use nsl_data.endian.all;
8+
9+
-- This package provides components for handling AXI4-Stream metadata
10+
package stream_meta is
11+
12+
-- Takes one AXI4-Stream as input and produces one AXI4-Stream as output.
13+
-- Input stream may have metadata (ID, Dest, User).
14+
-- Metadata are assumed constant for a complete frame.
15+
-- Metadata from the first beat of every frame are extracted and serialized
16+
-- as a prefix in the output frame.
17+
-- Output configuration may have any data width.
18+
-- Backpressure (ready) and framing (last) should be present on both configurations.
19+
component axi4_stream_meta_packer is
20+
generic(
21+
in_config_c : config_t;
22+
out_config_c : config_t;
23+
meta_elements_c : string := "iou";
24+
endian_c : endian_t := ENDIAN_BIG
25+
);
26+
port(
27+
clock_i : in std_ulogic;
28+
reset_n_i : in std_ulogic;
29+
30+
in_i : in master_t;
31+
in_o : out slave_t;
32+
33+
out_o : out master_t;
34+
out_i : in slave_t
35+
);
36+
end component;
37+
38+
-- Takes one AXI4-Stream with packed metadata prefix as input and produces
39+
-- one AXI4-Stream as output.
40+
-- Extracts metadata from prefix bytes and applies them to all beats of the
41+
-- output frame.
42+
-- Input configuration may have any data width.
43+
-- Backpressure (ready) and framing (last) should be present on both configurations.
44+
component axi4_stream_meta_unpacker is
45+
generic(
46+
in_config_c : config_t;
47+
out_config_c : config_t;
48+
meta_elements_c : string := "iou";
49+
endian_c : endian_t := ENDIAN_BIG
50+
);
51+
port(
52+
clock_i : in std_ulogic;
53+
reset_n_i : in std_ulogic;
54+
55+
in_i : in master_t;
56+
in_o : out slave_t;
57+
58+
out_o : out master_t;
59+
out_i : in slave_t
60+
);
61+
end component;
62+
63+
end package;

tests/amba/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ tb += axi4_mm_types
1515
tb += axi4_stream_cdc
1616
tb += axi4_stream_fifo
1717
tb += axi4_stream_flusher
18+
tb += axi4_stream_meta
1819
tb += axi4_stream_narrower
1920
tb += axi4_stream_types
2021
tb += axi4_stream_widener

0 commit comments

Comments
 (0)