mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-14 06:42:54 +08:00
Add simple UDP Ethernet packet generator
This commit is contained in:
parent
bb0897a409
commit
213e17c657
180
udp_packet.sv
Normal file
180
udp_packet.sv
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// udp_packet.sv
|
||||||
|
// published as part of https://github.com/pConst/basic_verilog
|
||||||
|
// Konstantin Pavlov, pavlovconst@gmail.com
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// INFO ------------------------------------------------------------------------
|
||||||
|
// A simple hardcoded UDP packet generator
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/* --- INSTANTIATION TEMPLATE BEGIN ---
|
||||||
|
|
||||||
|
udp_packet #(
|
||||||
|
.MODE( "BYTES" ) // "BYTES" or "NIBBLES"
|
||||||
|
) UP1 (
|
||||||
|
.clk( clk ),
|
||||||
|
.nrst( nrst ),
|
||||||
|
|
||||||
|
.tx_en( ),
|
||||||
|
.od( )
|
||||||
|
);
|
||||||
|
|
||||||
|
--- INSTANTIATION TEMPLATE END ---*/
|
||||||
|
|
||||||
|
|
||||||
|
module udp_packet #( parameter
|
||||||
|
MODE = "BYTES" // "BYTES" or "NIBBLES"
|
||||||
|
)(
|
||||||
|
input clk,
|
||||||
|
input nrst,
|
||||||
|
|
||||||
|
output logic tx_en = 1'b0,
|
||||||
|
output logic [7:0] od = '0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic [15:0] seq_cntr = '0;
|
||||||
|
logic nibble_high = 1'b0;
|
||||||
|
|
||||||
|
logic [7:0] data_byte;
|
||||||
|
|
||||||
|
// tx_en and od signals are late one cycle after their respective seq_cntr[]
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if( ~nrst ) begin
|
||||||
|
tx_en = 1'b0;
|
||||||
|
od[7:0] = '0;
|
||||||
|
|
||||||
|
seq_cntr[15:0] <= '0;
|
||||||
|
nibble_high <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if ( MODE == "BYTES" ) begin
|
||||||
|
tx_en <= ( (seq_cntr[15:0] >=0) &&
|
||||||
|
(seq_cntr[15:0] <72) );
|
||||||
|
|
||||||
|
od[7:0] <= data_byte[7:0];
|
||||||
|
|
||||||
|
if (seq_cntr[15:0] == 255 ) begin
|
||||||
|
// sequence reset
|
||||||
|
seq_cntr[15:0] <= '0;
|
||||||
|
end else begin
|
||||||
|
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
tx_en <= ( (seq_cntr[15:0] >=0) &&
|
||||||
|
(seq_cntr[15:0] <72) );
|
||||||
|
|
||||||
|
if( nibble_high ) begin
|
||||||
|
od[7:0] <= {4'h0,data_byte[3:0]};
|
||||||
|
|
||||||
|
if (seq_cntr[15:0] == 127 ) begin
|
||||||
|
// sequence reset
|
||||||
|
seq_cntr[15:0] <= '0;
|
||||||
|
end else begin
|
||||||
|
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
od[7:0] <= {4'h0,data_byte[7:4]};
|
||||||
|
end // if
|
||||||
|
|
||||||
|
nibble_high <= !nibble_high;
|
||||||
|
end // if
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
case ( seq_cntr[15:0] )
|
||||||
|
// Sending the preambule and asserting tx_en
|
||||||
|
0 : data_byte[7:0] <= 8'h55;
|
||||||
|
1 : data_byte[7:0] <= 8'h55;
|
||||||
|
2 : data_byte[7:0] <= 8'h55;
|
||||||
|
3 : data_byte[7:0] <= 8'h55;
|
||||||
|
4 : data_byte[7:0] <= 8'h55;
|
||||||
|
5 : data_byte[7:0] <= 8'h55;
|
||||||
|
6 : data_byte[7:0] <= 8'h55;
|
||||||
|
7 : data_byte[7:0] <= 8'hd5;
|
||||||
|
|
||||||
|
// Sending the UDP/IP-packet itself
|
||||||
|
8 : data_byte[7:0] <= 8'hd8;
|
||||||
|
9 : data_byte[7:0] <= 8'hd3;
|
||||||
|
10: data_byte[7:0] <= 8'h85;
|
||||||
|
11: data_byte[7:0] <= 8'h26;
|
||||||
|
12: data_byte[7:0] <= 8'hc5;
|
||||||
|
13: data_byte[7:0] <= 8'h78;
|
||||||
|
14: data_byte[7:0] <= 8'h00;
|
||||||
|
15: data_byte[7:0] <= 8'h23;
|
||||||
|
|
||||||
|
16: data_byte[7:0] <= 8'h54;
|
||||||
|
17: data_byte[7:0] <= 8'h3c;
|
||||||
|
18: data_byte[7:0] <= 8'h47;
|
||||||
|
19: data_byte[7:0] <= 8'h1b;
|
||||||
|
20: data_byte[7:0] <= 8'h08;
|
||||||
|
21: data_byte[7:0] <= 8'h00;
|
||||||
|
22: data_byte[7:0] <= 8'h45;
|
||||||
|
23: data_byte[7:0] <= 8'h00;
|
||||||
|
|
||||||
|
24: data_byte[7:0] <= 8'h00;
|
||||||
|
25: data_byte[7:0] <= 8'h2e;
|
||||||
|
26: data_byte[7:0] <= 8'h00;
|
||||||
|
27: data_byte[7:0] <= 8'h00;
|
||||||
|
28: data_byte[7:0] <= 8'h00;
|
||||||
|
29: data_byte[7:0] <= 8'h00;
|
||||||
|
30: data_byte[7:0] <= 8'hc8;
|
||||||
|
31: data_byte[7:0] <= 8'h11;
|
||||||
|
|
||||||
|
32: data_byte[7:0] <= 8'hd6;
|
||||||
|
33: data_byte[7:0] <= 8'h73;
|
||||||
|
34: data_byte[7:0] <= 8'hc0;
|
||||||
|
35: data_byte[7:0] <= 8'ha8;
|
||||||
|
36: data_byte[7:0] <= 8'h4d;
|
||||||
|
37: data_byte[7:0] <= 8'h21;
|
||||||
|
38: data_byte[7:0] <= 8'hc0;
|
||||||
|
39: data_byte[7:0] <= 8'ha8;
|
||||||
|
|
||||||
|
40: data_byte[7:0] <= 8'h4d;
|
||||||
|
41: data_byte[7:0] <= 8'hd9;
|
||||||
|
42: data_byte[7:0] <= 8'hc3;
|
||||||
|
43: data_byte[7:0] <= 8'h50;
|
||||||
|
44: data_byte[7:0] <= 8'hc3;
|
||||||
|
45: data_byte[7:0] <= 8'h60;
|
||||||
|
46: data_byte[7:0] <= 8'h00;
|
||||||
|
47: data_byte[7:0] <= 8'h1a;
|
||||||
|
|
||||||
|
48: data_byte[7:0] <= 8'h00;
|
||||||
|
49: data_byte[7:0] <= 8'h00;
|
||||||
|
50: data_byte[7:0] <= 8'h01;
|
||||||
|
51: data_byte[7:0] <= 8'h02;
|
||||||
|
52: data_byte[7:0] <= 8'h03;
|
||||||
|
53: data_byte[7:0] <= 8'h04;
|
||||||
|
54: data_byte[7:0] <= 8'h01;
|
||||||
|
55: data_byte[7:0] <= 8'h01;
|
||||||
|
|
||||||
|
56: data_byte[7:0] <= 8'h01;
|
||||||
|
57: data_byte[7:0] <= 8'h01;
|
||||||
|
58: data_byte[7:0] <= 8'h01;
|
||||||
|
59: data_byte[7:0] <= 8'h01;
|
||||||
|
60: data_byte[7:0] <= 8'h01;
|
||||||
|
61: data_byte[7:0] <= 8'h01;
|
||||||
|
62: data_byte[7:0] <= 8'h01;
|
||||||
|
63: data_byte[7:0] <= 8'h01;
|
||||||
|
|
||||||
|
64: data_byte[7:0] <= 8'h01;
|
||||||
|
65: data_byte[7:0] <= 8'h01;
|
||||||
|
66: data_byte[7:0] <= 8'h01;
|
||||||
|
67: data_byte[7:0] <= 8'h01;
|
||||||
|
|
||||||
|
// CRC32 checksum
|
||||||
|
68: data_byte[7:0] <= 8'he3;
|
||||||
|
69: data_byte[7:0] <= 8'h8e;
|
||||||
|
70: data_byte[7:0] <= 8'hdf;
|
||||||
|
71: data_byte[7:0] <= 8'h1f;
|
||||||
|
|
||||||
|
default: data_byte[7:0] <= '0; // pause
|
||||||
|
endcase
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
205
udp_packet_tb.sv
Normal file
205
udp_packet_tb.sv
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// udp_packet_tb.sv
|
||||||
|
// published as part of https://github.com/pConst/basic_verilog
|
||||||
|
// Konstantin Pavlov, pavlovconst@gmail.com
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// INFO ------------------------------------------------------------------------
|
||||||
|
// udp_packet testbench
|
||||||
|
|
||||||
|
// use this define to make some things differently in simulation
|
||||||
|
`define SIMULATION yes
|
||||||
|
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module udp_packet_tb();
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// Print out time markers in nanoseconds
|
||||||
|
// Example: $display("[T=%0t] start=%d", $realtime, start);
|
||||||
|
$timeformat(-9, 3, " ns");
|
||||||
|
|
||||||
|
// seed value setting is intentionally manual to achieve repeatability between sim runs
|
||||||
|
$urandom( 1 ); // SEED value
|
||||||
|
end
|
||||||
|
|
||||||
|
logic clk200;
|
||||||
|
sim_clk_gen #(
|
||||||
|
.FREQ( 200_000_000 ), // in Hz
|
||||||
|
.PHASE( 0 ), // in degrees
|
||||||
|
.DUTY( 50 ), // in percentage
|
||||||
|
.DISTORT( 10 ) // in picoseconds
|
||||||
|
) clk200_gen (
|
||||||
|
.ena( 1'b1 ),
|
||||||
|
.clk( clk200 ),
|
||||||
|
.clkd( )
|
||||||
|
);
|
||||||
|
|
||||||
|
logic nrst_once;
|
||||||
|
|
||||||
|
logic [31:0] clk200_div;
|
||||||
|
clk_divider #(
|
||||||
|
.WIDTH( 32 )
|
||||||
|
) cd1 (
|
||||||
|
.clk( clk200 ),
|
||||||
|
.nrst( nrst_once ),
|
||||||
|
.ena( 1'b1 ),
|
||||||
|
.out( clk200_div[31:0] )
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [31:0] clk200_div_rise;
|
||||||
|
edge_detect ed1[31:0] (
|
||||||
|
.clk( {32{clk200}} ),
|
||||||
|
.anrst( {32{nrst_once}} ),
|
||||||
|
.in( clk200_div[31:0] ),
|
||||||
|
.rising( clk200_div_rise[31:0] ),
|
||||||
|
.falling( ),
|
||||||
|
.both( )
|
||||||
|
);
|
||||||
|
|
||||||
|
// external device "asynchronous" clock
|
||||||
|
logic clk33;
|
||||||
|
logic clk33d;
|
||||||
|
sim_clk_gen #(
|
||||||
|
.FREQ( 200_000_000 ), // in Hz
|
||||||
|
.PHASE( 0 ), // in degrees
|
||||||
|
.DUTY( 50 ), // in percentage
|
||||||
|
.DISTORT( 1000 ) // in picoseconds
|
||||||
|
) clk33_gen (
|
||||||
|
.ena( 1'b1 ),
|
||||||
|
.clk( clk33 ),
|
||||||
|
.clkd( clk33d )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic rst;
|
||||||
|
initial begin
|
||||||
|
rst = 1'b0; // initialization
|
||||||
|
repeat( 1 ) @(posedge clk200);
|
||||||
|
|
||||||
|
forever begin
|
||||||
|
repeat( 1 ) @(posedge clk200); // synchronous rise
|
||||||
|
rst = 1'b1;
|
||||||
|
//$urandom( 1 ); // uncomment to get the same random pattern EVERY nrst
|
||||||
|
|
||||||
|
repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst pulse width
|
||||||
|
rst = 1'b0;
|
||||||
|
|
||||||
|
repeat( 100 ) @(posedge clk200); // controls test body width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logic nrst;
|
||||||
|
assign nrst = ~rst;
|
||||||
|
|
||||||
|
|
||||||
|
logic rst_once;
|
||||||
|
initial begin
|
||||||
|
rst_once = 1'b0; // initialization
|
||||||
|
repeat( 1 ) @(posedge clk200);
|
||||||
|
|
||||||
|
repeat( 1 ) @(posedge clk200); // synchronous rise
|
||||||
|
rst_once = 1'b1;
|
||||||
|
|
||||||
|
repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst_once pulse width
|
||||||
|
rst_once = 1'b0;
|
||||||
|
end
|
||||||
|
//logic nrst_once; // declared before
|
||||||
|
assign nrst_once = ~rst_once;
|
||||||
|
|
||||||
|
|
||||||
|
// random pattern generation
|
||||||
|
logic [31:0] rnd_data;
|
||||||
|
always_ff @(posedge clk200) begin
|
||||||
|
rnd_data[31:0] <= $urandom;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial forever begin
|
||||||
|
@(posedge nrst);
|
||||||
|
$display("[T=%0t] rnd_data[]=%h", $realtime, rnd_data[31:0]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// helper start strobe appears unpredictable up to 20 clocks after nrst
|
||||||
|
logic start;
|
||||||
|
initial forever begin
|
||||||
|
start = 1'b0; // initialization
|
||||||
|
|
||||||
|
@(posedge nrst); // synchronous rise after EVERY nrst
|
||||||
|
repeat( $urandom_range(0, 20) ) @(posedge clk200);
|
||||||
|
start = 1'b1;
|
||||||
|
|
||||||
|
@(posedge clk200); // synchronous fall exactly 1 clock after rise
|
||||||
|
start = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// #10000 $stop;
|
||||||
|
// #10000 $finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// sweeping pulses
|
||||||
|
logic sp = 1'b1;
|
||||||
|
logic [4:0] sp_duty_cycle = 8'd0;
|
||||||
|
initial forever begin
|
||||||
|
if( sp_duty_cycle[4:0] == 0 ) begin
|
||||||
|
sp = 1'b1;
|
||||||
|
repeat( 10 ) @(posedge clk200);
|
||||||
|
end
|
||||||
|
sp = 1'b0;
|
||||||
|
repeat( 1 ) @(posedge clk200);
|
||||||
|
sp = 1'b1;
|
||||||
|
repeat( 1 ) @(posedge clk200);
|
||||||
|
sp = 1'b0;
|
||||||
|
repeat( sp_duty_cycle ) @(posedge clk200);
|
||||||
|
sp_duty_cycle[4:0] = sp_duty_cycle[4:0] + 1'b1; // overflow is expected here
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Module under test ===========================================================
|
||||||
|
|
||||||
|
logic [15:0] seq_cntr = '0;
|
||||||
|
|
||||||
|
logic [31:0] id = '0;
|
||||||
|
always_ff @(posedge clk200) begin
|
||||||
|
if( ~nrst_once ) begin
|
||||||
|
seq_cntr[15:0] <= '0;
|
||||||
|
id[31:0] <= '0;
|
||||||
|
end else begin
|
||||||
|
// incrementing sequence counter
|
||||||
|
if( seq_cntr[15:0]!= '1 ) begin
|
||||||
|
seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if( seq_cntr[15:0]<300 ) begin
|
||||||
|
id[31:0] <= '1;
|
||||||
|
//id[31:0] <= {4{rnd_data[15:0]}};
|
||||||
|
end else begin
|
||||||
|
id[31:0] <= '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
udp_packet #(
|
||||||
|
.MODE( "BYTES" ) // "BYTES" or "NIBBLES"
|
||||||
|
) M1 (
|
||||||
|
.clk( clk200 ),
|
||||||
|
.nrst( nrst_once ),
|
||||||
|
|
||||||
|
.tx_en( ),
|
||||||
|
.od( )
|
||||||
|
);
|
||||||
|
|
||||||
|
udp_packet #(
|
||||||
|
.MODE( "NIBBLES" ) // "BYTES" or "NIBBLES"
|
||||||
|
) M2 (
|
||||||
|
.clk( clk200 ),
|
||||||
|
.nrst( nrst_once ),
|
||||||
|
|
||||||
|
.tx_en( ),
|
||||||
|
.od( )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user