-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathudp_build_payload.vhd
521 lines (504 loc) · 15.4 KB
/
udp_build_payload.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
-- Builds outbound payload header and copies payload
--
-- Dave Sankey, August 2012
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity udp_build_payload is
port (
mac_clk: in std_logic;
rx_reset: in std_logic;
mac_rx_data: in std_logic_vector(7 downto 0);
mac_rx_valid: in std_logic;
mac_rx_last: in std_logic;
mac_rx_error: in std_logic;
pkt_drop_payload: in std_logic;
pkt_byteswap: in std_logic;
outbyte: in std_logic_vector(7 downto 0);
payload_data: out std_logic_vector(7 downto 0);
payload_addr: out std_logic_vector(12 downto 0);
payload_we: out std_logic;
payload_send: out std_logic;
do_sum_payload: out std_logic;
clr_sum_payload: out std_logic;
int_data_payload: out std_logic_vector(7 downto 0);
int_valid_payload: out std_logic;
cksum: out std_logic;
ipbus_in_hdr: out std_logic_vector(31 downto 0)
);
end udp_build_payload;
architecture rtl of udp_build_payload is
signal payload_we_sig, set_addr, send_pending: std_logic;
signal send_buf, load_buf, low_addr, next_low, byteswap: std_logic;
signal buf_to_load: std_logic_vector(15 downto 0);
signal address, addr_to_set, next_addr: unsigned(12 downto 0);
signal payload_data_sig: std_logic_vector(7 downto 0);
begin
payload_we <= payload_we_sig;
payload_data <= payload_data_sig;
With byteswap select payload_addr <=
std_logic_vector(address(12 downto 2) & not address(1 downto 0)) when '1',
std_logic_vector(address) when Others;
send_packet: process (mac_clk)
variable send_pending_i, send_i, last_we: std_logic;
variable state, next_state: integer range 0 to 1;
begin
if rising_edge(mac_clk) then
if rx_reset = '1' then
next_state := 0;
end if;
state := next_state;
case state is
when 0 =>
send_i := '0';
if mac_rx_last = '1' and pkt_drop_payload = '0' and
mac_rx_error = '0' then
send_pending_i := '1';
next_state := 1;
else
send_pending_i := '0';
end if;
when 1 =>
if payload_we_sig = '0' and last_we = '1' then
send_i := '1';
send_pending_i := '0';
next_state := 0;
else
send_i := '0';
end if;
end case;
last_we := payload_we_sig;
payload_send <= send_i
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
send_pending <= send_pending_i
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
-- UDP payload:
-- Ethernet DST_MAC(6), SRC_MAC(6), Ether_Type = x"0800"
-- IP VERS = x"4", HL = x"5", TOS = x"00"
-- IP LEN
-- IP ID
-- IP FLAG-FRAG = x"4000"
-- IP TTL, PROTO = x"11"
-- IP CKSUM
-- IP SPA(4)
-- IP DPA(4)
-- UDP SRCPORT
-- UDP DSTPORT (50001)
-- UDP LEN
-- UDP CKSUM
-- UDP data...
set_address_block: process(mac_clk)
variable addr_to_set_int: unsigned(5 downto 0);
variable set_addr_int, cksum_pending: std_logic;
begin
if rising_edge(mac_clk) then
if (rx_reset = '1') then
set_addr_int := '1';
addr_to_set_int := to_unsigned(12, 6);
cksum_pending := '0';
elsif pkt_drop_payload = '0' then
if mac_rx_last = '1' then
set_addr_int := '1';
addr_to_set_int := to_unsigned(4, 6);
cksum_pending := '1';
elsif mac_rx_valid = '1' and low_addr = '1' then
-- Because address is buffered this logic needs to switch a byte early...
-- But don't forget we're offset by 4 + 2 bytes for payload word alignment!
case to_integer(address(5 downto 0)) is
-- RX Ethernet Dest MAC bytes 0 to 5 => TX copy to Source MAC bytes 12 to 17...
when 16 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(6, 6);
-- RX Ethernet Source MAC bytes 6 to 11 => TX copy to Dest MAC bytes 6 to 11...
when 10 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(18, 6);
-- RX Eth_Type tho' to IP cksum bytes 12 to 25 => TX copy data bytes 18 to 31...
when 30 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(36, 6);
-- RX IP sender addr bytes 26 to 29 => TX copy to target addr bytes 36 to 39...
when 38 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(32, 6);
-- RX IP target addr bytes 30 to 33 => TX write sender addr bytes 32 to 35...
when 34 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(42, 6);
-- RX UDP source port bytes 34 to 35 => TX copy to dest port bytes 42 to 43...
when 42 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(40, 6);
-- RX UDP dest port bytes 36 to 37 => TX write source port bytes 40 to 41...
when 40 =>
set_addr_int := '1';
addr_to_set_int := to_unsigned(44, 6);
-- RX UDP length and cksum bytes 38 to 41 => TX write zeros bytes 44 to 47...
when Others =>
set_addr_int := '0';
addr_to_set_int := (Others => '0');
end case;
elsif cksum_pending = '1' and low_addr = '1' and
address(5 downto 0) = "000100" then
-- No more data => write cksum and length info...
set_addr_int := '1';
addr_to_set_int := to_unsigned(0, 6);
cksum_pending := '0';
else
set_addr_int := '0';
addr_to_set_int := (Others => '0');
end if;
else
set_addr_int := '0';
addr_to_set_int := (Others => '0');
end if;
set_addr <= set_addr_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
addr_to_set <= "0000000" & addr_to_set_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
build_packet: process(mac_clk)
variable cksum_pending: std_logic;
variable buf_to_load_int: std_logic_vector(15 downto 0);
variable load_buf_int, send_buf_int, payload_we_i: std_logic;
variable payload_len: std_logic_vector(15 downto 0);
begin
if rising_edge(mac_clk) then
if (rx_reset = '1') then
send_buf_int := '0';
load_buf_int := '0';
cksum_pending := '0';
payload_len := (Others => '0');
buf_to_load_int := (Others => '0');
elsif pkt_drop_payload = '0' then
payload_we_i := mac_rx_valid or cksum_pending;
if mac_rx_last = '1' then
load_buf_int := '1';
send_buf_int := '1';
cksum_pending := '1';
elsif mac_rx_valid = '1' and low_addr = '1' then
-- Because address is buffered this logic needs to switch a byte early...
-- But don't forget we're offset by 4 + 2 bytes for payload word alignment!
case to_integer(address(5 downto 0)) is
when 20 =>
load_buf_int := '1';
send_buf_int := '1';
-- RX IP length => ignore for cksum, write zeros, capture packet length
when 22 =>
send_buf_int := '0';
when 28 =>
send_buf_int := '1';
-- RX IP cksum => ignore for cksum calc and write zeros
when 30 =>
send_buf_int := '0';
-- RX IP sender addr bytes 26 to 29 => TX copy to target addr bytes 36 to 39...
when 40 =>
send_buf_int := '1';
-- RX UDP length and cksum bytes 38 to 41 => TX write zeros bytes 44 to 47...
when 44 =>
buf_to_load_int(7 downto 0) := outbyte;
-- capture IP cksum value and start payload length calculation...
when 45 =>
buf_to_load_int(15 downto 8) := outbyte;
-- capture IP cksum value and continue payload length calculation...
when 46 =>
send_buf_int := '0';
when 52 =>
-- capture payload length calculation...
payload_len(7 downto 0) := outbyte;
when 53 =>
-- capture payload length calculation...
payload_len(15 downto 8) := outbyte;
-- RX rest of packet => TX copy rest of packet...
when Others =>
load_buf_int := '0';
end case;
-- No more data => write cksum and length info...
elsif cksum_pending = '1' and low_addr = '1' then
case to_integer(address(5 downto 0)) is
when 4 =>
load_buf_int := '1';
buf_to_load_int := std_logic_vector(to_unsigned(12, 16));
when 0 =>
load_buf_int := '1';
buf_to_load_int := payload_len;
when 2 =>
cksum_pending := '0';
when Others =>
load_buf_int := '0';
end case;
else
load_buf_int := '0';
end if;
else
payload_we_i := '0';
end if;
payload_we_sig <= payload_we_i
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
load_buf <= load_buf_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
buf_to_load <= buf_to_load_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
send_buf <= send_buf_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
do_cksum: process(mac_clk)
variable do_sum_int, clr_sum_int, cksum_int, int_valid_int: std_logic;
variable int_data_int: std_logic_vector(7 downto 0);
variable payload_len: std_logic_vector(15 downto 0);
begin
if rising_edge(mac_clk) then
if (rx_reset = '1') then
do_sum_int := '0';
clr_sum_int := '1';
int_valid_int := '0';
cksum_int := '1';
int_data_int := (Others => '0');
payload_len := (Others => '0');
elsif mac_rx_valid = '1' and pkt_drop_payload = '0' and low_addr = '1' then
-- Because address is buffered this logic needs to switch a byte early...
-- But don't forget we're offset by 4 + 2 bytes for payload word alignment!
case to_integer(address(5 downto 0)) is
-- RX Ethernet Dest MAC bytes 0 to 5 => TX copy to Source MAC bytes 12 to 17...
when 18 =>
do_sum_int := '1';
clr_sum_int := '1';
cksum_int := '1';
-- RX IP header => start cksum calc - we'll redo length and cksum when we send...
when 20 =>
do_sum_int := '0';
-- RX IP length => ignore for cksum, write zeros, capture packet length
when 21 =>
payload_len(15 downto 6) := "00" & mac_rx_data;
-- RX IP length => ignore for cksum, write zeros, capture packet length
when 22 =>
payload_len(5 downto 0) := mac_rx_data(7 downto 2);
do_sum_int := '1';
when 28 =>
do_sum_int := '0';
-- RX IP cksum => ignore for cksum calc and write zeros
when 30 =>
do_sum_int := '1';
-- RX IP sender addr bytes 26 to 29 => TX copy to target addr bytes 36 to 39...
when 34 =>
do_sum_int := '0';
-- cksum calculation complete...
-- RX UDP source port bytes 34 to 35 => TX copy to dest port bytes 42 to 43...
when 44 =>
-- capture IP cksum value and start payload length calculation...
do_sum_int := '1';
clr_sum_int := '1';
cksum_int := '0';
int_valid_int := '1';
int_data_int := payload_len(15 downto 8);
-- RX UDP length and cksum bytes 38 to 41 => TX write zeros bytes 44 to 47...
when 45 =>
-- capture IP cksum value and continue payload length calculation...
clr_sum_int := '0';
int_valid_int := '1';
int_data_int := payload_len(7 downto 0);
when 46 =>
-- continue payload length calculation (loading -8)...
int_valid_int := '1';
int_data_int := x"FF";
when 47 =>
-- continue payload length calculation (loading -8)...
int_valid_int := '1';
int_data_int := x"F8";
when 48 =>
int_valid_int := '0';
do_sum_int := '0';
when Others =>
clr_sum_int := '0';
int_valid_int := '0';
int_data_int := (Others => '0');
end case;
else
clr_sum_int := '0';
int_valid_int := '0';
int_data_int := (Others => '0');
end if;
do_sum_payload <= do_sum_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
clr_sum_payload <= clr_sum_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
int_data_payload <= int_data_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
int_valid_payload <= int_valid_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
cksum <= cksum_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
next_addr_block: process(mac_clk)
variable addr_int, next_addr_int, addr_to_set_buf: unsigned(12 downto 0);
variable set_addr_buf, next_low_int: std_logic;
begin
if rising_edge(mac_clk) then
if set_addr = '1' then
addr_to_set_buf := addr_to_set;
set_addr_buf := '1';
end if;
if rx_reset = '1' or mac_rx_valid = '1' or send_pending = '1' then
if set_addr_buf = '1' then
addr_int := addr_to_set_buf;
set_addr_buf := '0';
elsif pkt_drop_payload = '0' then
addr_int := next_addr_int;
end if;
end if;
next_addr_int := addr_int + 1;
if next_addr(12 downto 6) = "0000000" then
next_low_int := '1';
else
next_low_int := '0';
end if;
next_addr <= next_addr_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
next_low <= next_low_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
address_block: process(mac_clk)
variable addr_int, addr_to_set_buf: unsigned(12 downto 0);
variable set_addr_buf, low_addr_i: std_logic;
begin
if rising_edge(mac_clk) then
if set_addr = '1' then
addr_to_set_buf := addr_to_set;
set_addr_buf := '1';
end if;
if rx_reset = '1' or mac_rx_valid = '1' or send_pending = '1' then
if set_addr_buf = '1' then
addr_int := addr_to_set_buf;
low_addr_i := '1';
set_addr_buf := '0';
elsif pkt_drop_payload = '0' then
addr_int := next_addr;
low_addr_i := next_low;
end if;
end if;
address <= addr_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
low_addr <= low_addr_i
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
byteswap_block: process(mac_clk)
variable set_addr_buf, byteswap_int: std_logic;
begin
if rising_edge(mac_clk) then
if set_addr = '1' then
set_addr_buf := '1';
end if;
if rx_reset = '1' or mac_rx_valid = '1' or send_pending = '1' then
if set_addr_buf = '1' then
byteswap_int := '0';
set_addr_buf := '0';
elsif next_low = '1' and next_addr(5 downto 0) = to_unsigned(52, 6) then
byteswap_int := pkt_byteswap;
end if;
end if;
byteswap <= byteswap_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
write_data: process(mac_clk)
variable shift_buf: std_logic_vector(15 downto 0);
variable data_to_send: std_logic_vector(7 downto 0);
begin
if rising_edge(mac_clk) then
data_to_send := (Others => '0');
if load_buf = '1' then
shift_buf := buf_to_load;
end if;
if (mac_rx_valid = '1' or send_pending = '1') and pkt_drop_payload = '0' then
if send_buf = '1' then
data_to_send := shift_buf(15 downto 8);
else
data_to_send := mac_rx_data;
end if;
shift_buf := shift_buf(7 downto 0) & x"00";
end if;
payload_data_sig <= data_to_send
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
do_ipbus_hdr: process(mac_clk)
variable ipbus_hdr_int: std_logic_vector(31 downto 0);
begin
if rising_edge(mac_clk) then
if rx_reset = '1' then
ipbus_hdr_int := (Others => '0');
elsif low_addr = '1' and payload_we_sig = '1' and address(5 downto 2) = "1100" then
ipbus_hdr_int := ipbus_hdr_int(23 downto 0) & payload_data_sig;
end if;
ipbus_in_hdr <= ipbus_hdr_int
-- pragma translate_off
after 4 ns
-- pragma translate_on
;
end if;
end process;
end rtl;