-
Notifications
You must be signed in to change notification settings - Fork 0
/
AVTPDUProcessor.vhd
181 lines (143 loc) · 5.52 KB
/
AVTPDUProcessor.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
-- Filename:
-- AVTPDUProccesor.vhd
-- Description:
-- Processes AVTP Data Units and extracts relevant information
-- Stores received timestamps in a dual clock FIFO for use by CSGEN
-- Author:
-- Keegan Crankshaw
-- Date:
-- December 2020
-- Available on GitHub:
-- https://github.com/kcranky/IEEE1722CRFImplementation
-- Licence:
-- MIT
-- https://github.com/kcranky/IEEE1722CRFImplementation/blob/main/LICENSE
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity AVTPDUProcessor is
port (
clk : in std_logic;
reset : in std_logic;
datain : in std_logic_vector (31 downto 0);
processing: in std_logic;
timestamp_valid : out std_logic := '0';
timestamp_out : out std_logic_vector(63 downto 0);
first_ts_received : out std_logic := '0';
buffer_full : in std_logic
);
end AVTPDUProcessor;
architecture rtl of AVTPDUProcessor is
-- constants
constant AVTP_SUBTYPE : std_logic_vector(7 downto 0) := x"04"; -- something we're looking for
-- Timestamp array
type T_timestamp_arr is array (1 to 6) of std_logic_vector(63 downto 0);
signal timestamp_array : T_timestamp_arr;
signal ts : std_logic_vector(63 downto 0);
signal ts_val : std_logic := '0';
-- Data from the CRF Frame
signal SUB_TYPE : std_logic_vector (7 downto 0);
signal SV : std_logic; -- Stream valid
signal MR : std_logic; -- Media Clock Reset
signal TU : std_logic; -- timestamp uncertain
signal SEQ_NUM: std_logic_vector (7 downto 0) := (others => '0'); -- Increases with each new frame sent
signal CRF_TYPE : std_logic_vector (7 downto 0); -- expect AVTP subtype of x04 here
signal STREAM_ID : std_logic_vector (127 downto 0);
signal PULL : std_logic_vector (2 downto 0);
signal BASE_FREQ : std_logic_vector (28 downto 0);
signal CRF_DATA_LEN : std_logic_vector (15 downto 0);
signal TS_INTERVAL : std_logic_vector (15 downto 0); -- number of clock events between timestamps
-- FSM
type State_type is (ST_WAIT, ST_CONFIG, ST_TIMESTAMPS);
signal state : State_Type := ST_WAIT; -- Create a signal that uses the state
-- FSM for config data
type config_states is (C_ST_STREAMID, C_ST_FREQ, C_ST_CRF_DATA);
signal CONFIG_STATE : config_states := C_ST_STREAMID; -- Create a signal that uses the state
begin
output: process (clk, reset)
variable s_id_count : integer range 0 to 1 := 0; -- Stream ID count
variable ts_count : integer range 1 to 7 := 1; -- 1722 specifies a max possible 6 timestamps per AVTPDU
-- keep track of upper/lower 32 bits
variable timestamp_msb : boolean := true;
begin
-- reset triggered
if reset = '0' then
state <= ST_WAIT;
elsif rising_edge(clk) then
-- if at any point the processing flag goes low, we need to treat that as a reset
if processing = '0' then
state <= ST_WAIT;
end if;
case state is
when ST_WAIT =>
timestamp_valid <= '0';
if processing = '1' then -- we need a way to ensure we get the FIRST set of 32 bits here, otherwise we end up with garbage.
first_ts_received <= '1'; -- set the first time we get a timestamp, sent to genFIFO to start generating timestamps there.
-- we get the first 32 bits here
if datain(31 downto 24) = AVTP_SUBTYPE then -- the trigger for the config process
SV <= datain(23);
-- Version <= datain(22 downto 20)
MR <= datain(19);
-- R <= datain(18)
-- FS <= datain(17)
TU <= datain(16);
SEQ_NUM <= datain(15 downto 8);
CRF_TYPE <= datain(7 downto 0);
s_id_count := 0;
state <= ST_CONFIG;
end if;
end if;
when ST_CONFIG =>
case CONFIG_STATE is
-- the next 2 * 32 bits are stream_id
when C_ST_STREAMID =>
if s_id_count = 0 then
STREAM_ID(127 downto 96) <= datain;
elsif s_id_count = 1 then
STREAM_ID(31 downto 0) <= datain;
CONFIG_STATE <= C_ST_FREQ;
end if;
s_id_count := s_id_count +1;
-- the next 32 bits are pull(3) and base freq(29)
when C_ST_FREQ =>
PULL <= datain(31 downto 29);
BASE_FREQ <= datain(28 downto 0);
CONFIG_STATE <= C_ST_CRF_DATA;
-- the next 32 bits are crf_DATA_LEN (16) and ts_INTERVAL(16)
when C_ST_CRF_DATA =>
CRF_DATA_LEN <= std_logic_vector(unsigned(datain(31 downto 16))/8);
TS_INTERVAL <= datain(15 downto 0);
CONFIG_STATE <= C_ST_STREAMID;
state <= ST_TIMESTAMPS;
ts_count := 1;
timestamp_msb := true; -- FORCED MSB HIGH HERE
end case;
when ST_TIMESTAMPS =>
if ts_val = '1' then
-- write to the fifo
timestamp_valid <= '1';
end if;
if timestamp_msb = true then -- we make the assumption we start here
timestamp_array(ts_count)(63 downto 32) <= datain;
timestamp_msb := not timestamp_msb;
timestamp_valid <= '0';
timestamp_out(63 downto 32) <= datain;
ts_val <= '0';
else -- timestamp msb is false (0)
timestamp_array(ts_count)(31 downto 0) <= datain;
timestamp_msb := not timestamp_msb;
ts_count := ts_count + 1;
timestamp_out(31 downto 0) <= datain;
ts_val <= '1';
if buffer_full = '0' then
timestamp_valid <= '1';
end if;
end if;
if (ts_count = to_integer(unsigned(CRF_DATA_LEN)) +1) and (timestamp_msb = false) then
state <= ST_WAIT;
timestamp_valid <= '0';
end if;
end case;
end if;
end process;
end architecture;