AMC13
Firmwares for the different applications of the AMC13 uTCA board made at Boston University
 All Classes Variables
udp_build_ping.vhd
1 -- Builds outbound ping response
2 --
3 -- Dave Sankey, July 2012
4 
5 library ieee;
6 use ieee.std_logic_1164.all;
7 use ieee.numeric_std.all;
8 
9 entity udp_build_ping is
10  port (
11  mac_clk: in std_logic;
12  rx_reset: in std_logic;
13  mac_rx_data: in std_logic_vector(7 downto 0);
14  mac_rx_valid: in std_logic;
15  mac_rx_last: in std_logic;
16  mac_rx_error: in std_logic;
17  pkt_drop_ping: in std_logic;
18  outbyte: in std_logic_vector(7 downto 0);
19  ping_data: out std_logic_vector(7 downto 0);
20  ping_addr: out std_logic_vector(12 downto 0);
21  ping_we: out std_logic;
22  ping_end_addr: out std_logic_vector(12 downto 0);
23  ping_send: out std_logic;
24  do_sum_ping: out std_logic;
25  clr_sum_ping: out std_logic;
26  int_data_ping: out std_logic_vector(7 downto 0);
27  int_valid_ping: out std_logic
28  );
29 end udp_build_ping;
30 
31 architecture rtl of udp_build_ping is
32 
33  signal ping_we_sig, set_addr, send_pending: std_logic;
34  signal send_buf, load_buf, low_addr: std_logic;
35  signal buf_to_load: std_logic_vector(15 downto 0);
36  signal address, addr_to_set: unsigned(12 downto 0);
37 
38 begin
39 
40  ping_we <= ping_we_sig;
41  ping_addr <= std_logic_vector(address);
42 
43 send_packet: process (mac_clk)
44  variable send_pending_i, send_i, last_we: std_logic;
45  variable end_addr_i: std_logic_vector(12 downto 0);
46  variable state, next_state: integer range 0 to 2;
47  begin
48  if rising_edge(mac_clk) then
49  if rx_reset = '1' then
50  next_state := 0;
51  end if;
52  state := next_state;
53  case state is
54  when 0 =>
55  send_i := '0';
56  end_addr_i := (Others => '0');
57  if mac_rx_last = '1' and pkt_drop_ping = '0' and
58  mac_rx_error = '0' then
59  send_pending_i := '1';
60  next_state := 1;
61  else
62  send_pending_i := '0';
63  end if;
64  when 1 =>
65  end_addr_i := std_logic_vector(address);
66  next_state := 2;
67  when 2 =>
68  if ping_we_sig = '0' and last_we = '1' then
69  send_i := '1';
70  send_pending_i := '0';
71  next_state := 0;
72  end if;
73  end case;
74  last_we := ping_we_sig;
75  ping_end_addr <= end_addr_i
76 -- pragma translate_off
77  after 4 ns
78 -- pragma translate_on
79  ;
80  ping_send <= send_i
81 -- pragma translate_off
82  after 4 ns
83 -- pragma translate_on
84  ;
85  send_pending <= send_pending_i
86 -- pragma translate_off
87  after 4 ns
88 -- pragma translate_on
89  ;
90  end if;
91  end process;
92 
93 -- Ping:
94 -- Ethernet DST_MAC(6), SRC_MAC(6), Ether_Type = x"0800"
95 -- IP VERS = x"4", HL = x"5", TOS = x"00"
96 -- IP LEN
97 -- IP ID
98 -- IP FLAG-FRAG = x"4000"
99 -- IP TTL, PROTO = x"01"
100 -- IP CKSUM
101 -- IP SPA(4)
102 -- IP DPA(4)
103 -- ICMP TYPE = "00", CODE = "00"
104 -- ICMP CKSUM
105 -- ICMP data...
106 address_block: process (mac_clk)
107  variable addr_to_set_int: unsigned(5 downto 0);
108  variable set_addr_int: std_logic;
109  begin
110  if rising_edge(mac_clk) then
111  if (rx_reset = '1') then
112  set_addr_int := '1';
113  addr_to_set_int := to_unsigned(6, 6);
114  elsif pkt_drop_ping = '0' then
115  if mac_rx_last = '1' then
116 -- ICMP cksum...
117  set_addr_int := '1';
118  addr_to_set_int := to_unsigned(36, 6);
119  elsif mac_rx_valid = '1' and low_addr = '1' then
120 -- Because address is buffered this logic needs to switch a byte early...
121  case to_integer(address(5 downto 0)) is
122 -- RX Ethernet Dest MAC bytes 0 to 5 => TX copy to Source MAC bytes 6 to 11...
123  when 10 =>
124  set_addr_int := '1';
125  addr_to_set_int := to_unsigned(0, 6);
126 -- RX Ethernet Source MAC bytes 6 to 11 => TX copy to Dest MAC bytes 0 to 5...
127  when 4 =>
128  set_addr_int := '1';
129  addr_to_set_int := to_unsigned(12, 6);
130 -- RX Eth_Type tho' to IP cksum bytes 12 to 25 => TX copy data bytes 12 to 25...
131 -- as we're just rearranging words cksum stays the same...
132  when 24 =>
133  set_addr_int := '1';
134  addr_to_set_int := to_unsigned(30, 6);
135 -- RX IP sender addr bytes 26 to 29 => TX copy to target addr bytes 30 to 33...
136  when 32 =>
137  set_addr_int := '1';
138  addr_to_set_int := to_unsigned(26, 6);
139 -- RX IP target addr bytes 30 to 33 => TX write sender addr bytes 26 to 29...
140  when 28 =>
141  set_addr_int := '1';
142  addr_to_set_int := to_unsigned(34, 6);
143  when Others =>
144  set_addr_int := '0';
145  addr_to_set_int := (Others => '0');
146  end case;
147  else
148  set_addr_int := '0';
149  addr_to_set_int := (Others => '0');
150  end if;
151  else
152  set_addr_int := '0';
153  addr_to_set_int := (Others => '0');
154  end if;
155  set_addr <= set_addr_int
156 -- pragma translate_off
157  after 4 ns
158 -- pragma translate_on
159  ;
160  addr_to_set <= "0000000" & addr_to_set_int
161 -- pragma translate_off
162  after 4 ns
163 -- pragma translate_on
164  ;
165  end if;
166  end process;
167 
168 build_packet: process (mac_clk)
169  variable cksum_pending: std_logic;
170  variable buf_to_load_int: std_logic_vector(15 downto 0);
171  variable load_buf_int, send_buf_int, ping_we_i: std_logic;
172  begin
173  if rising_edge(mac_clk) then
174  if (rx_reset = '1') then
175  send_buf_int := '0';
176  load_buf_int := '0';
177  ping_we_i := '0';
178  buf_to_load_int := (Others => '0');
179  cksum_pending := '0';
180  elsif pkt_drop_ping = '0' then
181  ping_we_i := mac_rx_valid or cksum_pending;
182  if mac_rx_last = '1' then
183 -- End of packet, prepare to send cksum
184  load_buf_int := '1';
185  send_buf_int := '1';
186  cksum_pending := '1';
187  elsif mac_rx_valid = '1' and low_addr = '1' then
188 -- Because address is buffered this logic needs to switch a byte early...
189  case to_integer(address(5 downto 0)) is
190 -- RX ICMP type code bytes 34 to 35 => TX write reply bytes 34 to 35...
191 -- ICMP TYPE = "00", CODE = "00", NB address switch at 28!
192  when 28 =>
193  load_buf_int := '1';
194  send_buf_int := '1';
195  buf_to_load_int := (Others => '0');
196  when 36 =>
197 -- RX cksum bytes 36 to 37...
198  send_buf_int := '0';
199 -- RX rest of packet => TX copy rest of packet...
200  when 43 =>
201 -- capture ICMP cksum value
202  buf_to_load_int(15 downto 8) := outbyte;
203  when 44 =>
204 -- capture ICMP cksum value
205  buf_to_load_int(7 downto 0) := outbyte;
206  when Others =>
207  load_buf_int := '0';
208  end case;
209 -- No more data => write cksum...
210  elsif cksum_pending = '1' then
211  load_buf_int := '0';
212  if address = 36 then
213  cksum_pending := '0';
214  end if;
215  end if;
216  else
217  ping_we_i := '0';
218  end if;
219  ping_we_sig <= ping_we_i
220 -- pragma translate_off
221  after 4 ns
222 -- pragma translate_on
223  ;
224  load_buf <= load_buf_int
225 -- pragma translate_off
226  after 4 ns
227 -- pragma translate_on
228  ;
229  buf_to_load <= buf_to_load_int
230 -- pragma translate_off
231  after 4 ns
232 -- pragma translate_on
233  ;
234  send_buf <= send_buf_int
235 -- pragma translate_off
236  after 4 ns
237 -- pragma translate_on
238  ;
239  end if;
240  end process;
241 
242 do_cksum: process (mac_clk)
243  variable do_sum_int, clr_sum_int, int_valid_int: std_logic;
244  variable int_data_int: std_logic_vector(7 downto 0);
245  begin
246  if rising_edge(mac_clk) then
247  if (rx_reset = '1') then
248  do_sum_int := '0';
249  clr_sum_int := '1';
250  int_valid_int := '0';
251  int_data_int := (Others => '0');
252  elsif mac_rx_valid = '1' and pkt_drop_ping = '0' and low_addr = '1' then
253 -- Because address is buffered this logic needs to switch a byte early...
254  case to_integer(address(5 downto 0)) is
255 -- RX ICMP type code bytes 34 to 35 => TX write reply bytes 34 to 35...
256 -- ICMP TYPE = "00", CODE = "00", NB address switch at 28!
257 -- zeros and start cksum calc...
258 -- we want -(-cksum - x"0800") = cksum + x"0800"...
259  when 28 =>
260  do_sum_int := '1';
261  clr_sum_int := '1';
262  int_valid_int := '1';
263  int_data_int := x"08";
264  when 29 =>
265  clr_sum_int := '0';
266  int_valid_int := '1';
267  int_data_int := (Others => '0');
268  when 36 =>
269  do_sum_int := '0';
270  clr_sum_int := '0';
271  int_valid_int := '0';
272  int_data_int := (Others => '0');
273  when Others =>
274  clr_sum_int := '0';
275  int_valid_int := '0';
276  int_data_int := (Others => '0');
277  end case;
278  else
279  clr_sum_int := '0';
280  int_valid_int := '0';
281  int_data_int := (Others => '0');
282  end if;
283  do_sum_ping <= do_sum_int
284 -- pragma translate_off
285  after 4 ns
286 -- pragma translate_on
287  ;
288  clr_sum_ping <= clr_sum_int
289 -- pragma translate_off
290  after 4 ns
291 -- pragma translate_on
292  ;
293  int_data_ping <= int_data_int
294 -- pragma translate_off
295  after 4 ns
296 -- pragma translate_on
297  ;
298  int_valid_ping <= int_valid_int
299 -- pragma translate_off
300  after 4 ns
301 -- pragma translate_on
302  ;
303  end if;
304  end process;
305 
306 next_addr: process(mac_clk)
307  variable addr_int, next_addr, addr_to_set_buf: unsigned(12 downto 0);
308  variable set_addr_buf, low_addr_i, next_low: std_logic;
309  begin
310  if rising_edge(mac_clk) then
311  if set_addr = '1' then
312  addr_to_set_buf := addr_to_set;
313  set_addr_buf := '1';
314  end if;
315  if rx_reset = '1' or mac_rx_valid = '1' or send_pending = '1' then
316  if set_addr_buf = '1' then
317  addr_int := addr_to_set_buf;
318  low_addr_i := '1';
319  set_addr_buf := '0';
320  elsif pkt_drop_ping = '0' then
321  addr_int := next_addr;
322  low_addr_i := next_low;
323  end if;
324  end if;
325  address <= addr_int
326 -- pragma translate_off
327  after 4 ns
328 -- pragma translate_on
329  ;
330  low_addr <= low_addr_i
331 -- pragma translate_off
332  after 4 ns
333 -- pragma translate_on
334  ;
335  next_addr := addr_int + 1;
336  if next_addr(12 downto 6) = "0000000" then
337  next_low := '1';
338  else
339  next_low := '0';
340  end if;
341  end if;
342  end process;
343 
344 write_data: process(mac_clk)
345  variable shift_buf: std_logic_vector(15 downto 0);
346  variable data_to_send: std_logic_vector(7 downto 0);
347  begin
348  if rising_edge(mac_clk) then
349  data_to_send := (Others => '0');
350  if load_buf = '1' then
351  shift_buf := buf_to_load;
352  end if;
353  if (mac_rx_valid = '1' or send_pending = '1') and pkt_drop_ping = '0' then
354  if send_buf = '1' then
355  data_to_send := shift_buf(15 downto 8);
356  else
357  data_to_send := mac_rx_data;
358  end if;
359  shift_buf := shift_buf(7 downto 0) & x"00";
360  end if;
361  ping_data <= data_to_send
362 -- pragma translate_off
363  after 4 ns
364 -- pragma translate_on
365  ;
366  end if;
367  end process;
368 
369 end rtl;