Skip to content

Commit 213e17c

Browse files
committed
Add simple UDP Ethernet packet generator
1 parent bb0897a commit 213e17c

File tree

2 files changed

+385
-0
lines changed

2 files changed

+385
-0
lines changed

udp_packet.sv

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//------------------------------------------------------------------------------
2+
// udp_packet.sv
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, pavlovconst@gmail.com
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// A simple hardcoded UDP packet generator
9+
//
10+
11+
12+
/* --- INSTANTIATION TEMPLATE BEGIN ---
13+
14+
udp_packet #(
15+
.MODE( "BYTES" ) // "BYTES" or "NIBBLES"
16+
) UP1 (
17+
.clk( clk ),
18+
.nrst( nrst ),
19+
20+
.tx_en( ),
21+
.od( )
22+
);
23+
24+
--- INSTANTIATION TEMPLATE END ---*/
25+
26+
27+
module udp_packet #( parameter
28+
MODE = "BYTES" // "BYTES" or "NIBBLES"
29+
)(
30+
input clk,
31+
input nrst,
32+
33+
output logic tx_en = 1'b0,
34+
output logic [7:0] od = '0
35+
);
36+
37+
38+
logic [15:0] seq_cntr = '0;
39+
logic nibble_high = 1'b0;
40+
41+
logic [7:0] data_byte;
42+
43+
// tx_en and od signals are late one cycle after their respective seq_cntr[]
44+
always_ff @(posedge clk) begin
45+
if( ~nrst ) begin
46+
tx_en = 1'b0;
47+
od[7:0] = '0;
48+
49+
seq_cntr[15:0] <= '0;
50+
nibble_high <= 1'b0;
51+
end else begin
52+
if ( MODE == "BYTES" ) begin
53+
tx_en <= ( (seq_cntr[15:0] >=0) &&
54+
(seq_cntr[15:0] <72) );
55+
56+
od[7:0] <= data_byte[7:0];
57+
58+
if (seq_cntr[15:0] == 255 ) begin
59+
// sequence reset
60+
seq_cntr[15:0] <= '0;
61+
end else begin
62+
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
63+
end
64+
end else begin
65+
tx_en <= ( (seq_cntr[15:0] >=0) &&
66+
(seq_cntr[15:0] <72) );
67+
68+
if( nibble_high ) begin
69+
od[7:0] <= {4'h0,data_byte[3:0]};
70+
71+
if (seq_cntr[15:0] == 127 ) begin
72+
// sequence reset
73+
seq_cntr[15:0] <= '0;
74+
end else begin
75+
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
76+
end
77+
end else begin
78+
od[7:0] <= {4'h0,data_byte[7:4]};
79+
end // if
80+
81+
nibble_high <= !nibble_high;
82+
end // if
83+
end
84+
end
85+
86+
87+
always_comb begin
88+
case ( seq_cntr[15:0] )
89+
// Sending the preambule and asserting tx_en
90+
0 : data_byte[7:0] <= 8'h55;
91+
1 : data_byte[7:0] <= 8'h55;
92+
2 : data_byte[7:0] <= 8'h55;
93+
3 : data_byte[7:0] <= 8'h55;
94+
4 : data_byte[7:0] <= 8'h55;
95+
5 : data_byte[7:0] <= 8'h55;
96+
6 : data_byte[7:0] <= 8'h55;
97+
7 : data_byte[7:0] <= 8'hd5;
98+
99+
// Sending the UDP/IP-packet itself
100+
8 : data_byte[7:0] <= 8'hd8;
101+
9 : data_byte[7:0] <= 8'hd3;
102+
10: data_byte[7:0] <= 8'h85;
103+
11: data_byte[7:0] <= 8'h26;
104+
12: data_byte[7:0] <= 8'hc5;
105+
13: data_byte[7:0] <= 8'h78;
106+
14: data_byte[7:0] <= 8'h00;
107+
15: data_byte[7:0] <= 8'h23;
108+
109+
16: data_byte[7:0] <= 8'h54;
110+
17: data_byte[7:0] <= 8'h3c;
111+
18: data_byte[7:0] <= 8'h47;
112+
19: data_byte[7:0] <= 8'h1b;
113+
20: data_byte[7:0] <= 8'h08;
114+
21: data_byte[7:0] <= 8'h00;
115+
22: data_byte[7:0] <= 8'h45;
116+
23: data_byte[7:0] <= 8'h00;
117+
118+
24: data_byte[7:0] <= 8'h00;
119+
25: data_byte[7:0] <= 8'h2e;
120+
26: data_byte[7:0] <= 8'h00;
121+
27: data_byte[7:0] <= 8'h00;
122+
28: data_byte[7:0] <= 8'h00;
123+
29: data_byte[7:0] <= 8'h00;
124+
30: data_byte[7:0] <= 8'hc8;
125+
31: data_byte[7:0] <= 8'h11;
126+
127+
32: data_byte[7:0] <= 8'hd6;
128+
33: data_byte[7:0] <= 8'h73;
129+
34: data_byte[7:0] <= 8'hc0;
130+
35: data_byte[7:0] <= 8'ha8;
131+
36: data_byte[7:0] <= 8'h4d;
132+
37: data_byte[7:0] <= 8'h21;
133+
38: data_byte[7:0] <= 8'hc0;
134+
39: data_byte[7:0] <= 8'ha8;
135+
136+
40: data_byte[7:0] <= 8'h4d;
137+
41: data_byte[7:0] <= 8'hd9;
138+
42: data_byte[7:0] <= 8'hc3;
139+
43: data_byte[7:0] <= 8'h50;
140+
44: data_byte[7:0] <= 8'hc3;
141+
45: data_byte[7:0] <= 8'h60;
142+
46: data_byte[7:0] <= 8'h00;
143+
47: data_byte[7:0] <= 8'h1a;
144+
145+
48: data_byte[7:0] <= 8'h00;
146+
49: data_byte[7:0] <= 8'h00;
147+
50: data_byte[7:0] <= 8'h01;
148+
51: data_byte[7:0] <= 8'h02;
149+
52: data_byte[7:0] <= 8'h03;
150+
53: data_byte[7:0] <= 8'h04;
151+
54: data_byte[7:0] <= 8'h01;
152+
55: data_byte[7:0] <= 8'h01;
153+
154+
56: data_byte[7:0] <= 8'h01;
155+
57: data_byte[7:0] <= 8'h01;
156+
58: data_byte[7:0] <= 8'h01;
157+
59: data_byte[7:0] <= 8'h01;
158+
60: data_byte[7:0] <= 8'h01;
159+
61: data_byte[7:0] <= 8'h01;
160+
62: data_byte[7:0] <= 8'h01;
161+
63: data_byte[7:0] <= 8'h01;
162+
163+
64: data_byte[7:0] <= 8'h01;
164+
65: data_byte[7:0] <= 8'h01;
165+
66: data_byte[7:0] <= 8'h01;
166+
67: data_byte[7:0] <= 8'h01;
167+
168+
// CRC32 checksum
169+
68: data_byte[7:0] <= 8'he3;
170+
69: data_byte[7:0] <= 8'h8e;
171+
70: data_byte[7:0] <= 8'hdf;
172+
71: data_byte[7:0] <= 8'h1f;
173+
174+
default: data_byte[7:0] <= '0; // pause
175+
endcase
176+
177+
end
178+
179+
endmodule
180+

udp_packet_tb.sv

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
//------------------------------------------------------------------------------
2+
// udp_packet_tb.sv
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, pavlovconst@gmail.com
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// udp_packet testbench
9+
10+
// use this define to make some things differently in simulation
11+
`define SIMULATION yes
12+
13+
`timescale 1ns / 1ps
14+
15+
module udp_packet_tb();
16+
17+
initial begin
18+
// Print out time markers in nanoseconds
19+
// Example: $display("[T=%0t] start=%d", $realtime, start);
20+
$timeformat(-9, 3, " ns");
21+
22+
// seed value setting is intentionally manual to achieve repeatability between sim runs
23+
$urandom( 1 ); // SEED value
24+
end
25+
26+
logic clk200;
27+
sim_clk_gen #(
28+
.FREQ( 200_000_000 ), // in Hz
29+
.PHASE( 0 ), // in degrees
30+
.DUTY( 50 ), // in percentage
31+
.DISTORT( 10 ) // in picoseconds
32+
) clk200_gen (
33+
.ena( 1'b1 ),
34+
.clk( clk200 ),
35+
.clkd( )
36+
);
37+
38+
logic nrst_once;
39+
40+
logic [31:0] clk200_div;
41+
clk_divider #(
42+
.WIDTH( 32 )
43+
) cd1 (
44+
.clk( clk200 ),
45+
.nrst( nrst_once ),
46+
.ena( 1'b1 ),
47+
.out( clk200_div[31:0] )
48+
);
49+
50+
logic [31:0] clk200_div_rise;
51+
edge_detect ed1[31:0] (
52+
.clk( {32{clk200}} ),
53+
.anrst( {32{nrst_once}} ),
54+
.in( clk200_div[31:0] ),
55+
.rising( clk200_div_rise[31:0] ),
56+
.falling( ),
57+
.both( )
58+
);
59+
60+
// external device "asynchronous" clock
61+
logic clk33;
62+
logic clk33d;
63+
sim_clk_gen #(
64+
.FREQ( 200_000_000 ), // in Hz
65+
.PHASE( 0 ), // in degrees
66+
.DUTY( 50 ), // in percentage
67+
.DISTORT( 1000 ) // in picoseconds
68+
) clk33_gen (
69+
.ena( 1'b1 ),
70+
.clk( clk33 ),
71+
.clkd( clk33d )
72+
);
73+
74+
75+
logic rst;
76+
initial begin
77+
rst = 1'b0; // initialization
78+
repeat( 1 ) @(posedge clk200);
79+
80+
forever begin
81+
repeat( 1 ) @(posedge clk200); // synchronous rise
82+
rst = 1'b1;
83+
//$urandom( 1 ); // uncomment to get the same random pattern EVERY nrst
84+
85+
repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst pulse width
86+
rst = 1'b0;
87+
88+
repeat( 100 ) @(posedge clk200); // controls test body width
89+
end
90+
end
91+
logic nrst;
92+
assign nrst = ~rst;
93+
94+
95+
logic rst_once;
96+
initial begin
97+
rst_once = 1'b0; // initialization
98+
repeat( 1 ) @(posedge clk200);
99+
100+
repeat( 1 ) @(posedge clk200); // synchronous rise
101+
rst_once = 1'b1;
102+
103+
repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst_once pulse width
104+
rst_once = 1'b0;
105+
end
106+
//logic nrst_once; // declared before
107+
assign nrst_once = ~rst_once;
108+
109+
110+
// random pattern generation
111+
logic [31:0] rnd_data;
112+
always_ff @(posedge clk200) begin
113+
rnd_data[31:0] <= $urandom;
114+
end
115+
116+
initial forever begin
117+
@(posedge nrst);
118+
$display("[T=%0t] rnd_data[]=%h", $realtime, rnd_data[31:0]);
119+
end
120+
121+
122+
// helper start strobe appears unpredictable up to 20 clocks after nrst
123+
logic start;
124+
initial forever begin
125+
start = 1'b0; // initialization
126+
127+
@(posedge nrst); // synchronous rise after EVERY nrst
128+
repeat( $urandom_range(0, 20) ) @(posedge clk200);
129+
start = 1'b1;
130+
131+
@(posedge clk200); // synchronous fall exactly 1 clock after rise
132+
start = 1'b0;
133+
end
134+
135+
136+
initial begin
137+
// #10000 $stop;
138+
// #10000 $finish;
139+
end
140+
141+
// sweeping pulses
142+
logic sp = 1'b1;
143+
logic [4:0] sp_duty_cycle = 8'd0;
144+
initial forever begin
145+
if( sp_duty_cycle[4:0] == 0 ) begin
146+
sp = 1'b1;
147+
repeat( 10 ) @(posedge clk200);
148+
end
149+
sp = 1'b0;
150+
repeat( 1 ) @(posedge clk200);
151+
sp = 1'b1;
152+
repeat( 1 ) @(posedge clk200);
153+
sp = 1'b0;
154+
repeat( sp_duty_cycle ) @(posedge clk200);
155+
sp_duty_cycle[4:0] = sp_duty_cycle[4:0] + 1'b1; // overflow is expected here
156+
end
157+
158+
159+
// Module under test ===========================================================
160+
161+
logic [15:0] seq_cntr = '0;
162+
163+
logic [31:0] id = '0;
164+
always_ff @(posedge clk200) begin
165+
if( ~nrst_once ) begin
166+
seq_cntr[15:0] <= '0;
167+
id[31:0] <= '0;
168+
end else begin
169+
// incrementing sequence counter
170+
if( seq_cntr[15:0]!= '1 ) begin
171+
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
172+
end
173+
174+
if( seq_cntr[15:0]<300 ) begin
175+
id[31:0] <= '1;
176+
//id[31:0] <= {4{rnd_data[15:0]}};
177+
end else begin
178+
id[31:0] <= '0;
179+
end
180+
end
181+
end
182+
183+
184+
udp_packet #(
185+
.MODE( "BYTES" ) // "BYTES" or "NIBBLES"
186+
) M1 (
187+
.clk( clk200 ),
188+
.nrst( nrst_once ),
189+
190+
.tx_en( ),
191+
.od( )
192+
);
193+
194+
udp_packet #(
195+
.MODE( "NIBBLES" ) // "BYTES" or "NIBBLES"
196+
) M2 (
197+
.clk( clk200 ),
198+
.nrst( nrst_once ),
199+
200+
.tx_en( ),
201+
.od( )
202+
);
203+
204+
endmodule
205+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy