做verilog网络逻辑时,需要产生正确的数据包格式激励,手写激励真烦人,现在让testbench读取pcap文件,则可以精确还原数据包的bit与时序,省去了一大批麻烦
1.设计读取逻辑
1 `timescale 1ns / 1ps 2 `define NULL 0 3 4 // Coder: joe 5 // Description: 6 // 将pcap文件中的数据包读出来,8bit位宽 7 // 8 // 9 // 10 // 11 // 12 13 module PcapParser 14 #( 15 parameter pcap_filename = "none", 16 parameter ipg = 32 17 ) ( 18 input CLOCK, 19 input pause, 20 output reg available = 0, 21 output reg datavalid = 0, 22 output reg [7:0] data = 0, 23 output reg [7:0] pktcount = 0, 24 output reg newpkt = 0, 25 output reg pcapfinished = 0 26 ); 27 28 29 30 // buffers for message 31 reg [7:0] global_header [0:23]; 32 reg [7:0] packet_header [0:15]; 33 34 integer swapped = 0; 35 integer toNanos = 0; 36 integer file = 0; 37 integer r = 0; 38 integer eof = 0; 39 integer i = 0; 40 integer pktSz = 0; 41 integer diskSz = 0; 42 integer countIPG = 0; 43 44 initial begin 45 46 47 // open pcap file 48 if (pcap_filename == "none") begin 49 $display("pcap filename parameter not set"); 50 $finish_and_return(1); 51 end 52 53 file = $fopen(pcap_filename, "rb"); 54 if (file == `NULL) begin 55 $display("can't read pcap input"); 56 $finish_and_return(1); 57 end 58 59 // read binary global_header 60 // r = $fread(file, global_header); 61 r = $fread(global_header,file); 62 63 // check magic signature to determine byte ordering 64 if (global_header[0] == 8'hD4 && global_header[1] == 8'hC3 && global_header[2] == 8'hB2) begin 65 $display(" pcap endian: swapped, ms"); 66 swapped = 1; 67 toNanos = 32'd1000000; 68 end else if (global_header[0] == 8'hA1 && global_header[1] == 8'hB2 && global_header[2] == 8'hC3) begin 69 $display(" pcap endian: native, ms"); 70 swapped = 0; 71 toNanos = 32'd1000000; 72 end else if (global_header[0] == 8'h4D && global_header[1] == 8'h3C && global_header[2] == 8'hb2) begin 73 $display(" pcap endian: swapped, nanos"); 74 swapped = 1; 75 toNanos = 32'd1; 76 end else if (global_header[0] == 8'hA1 && global_header[1] == 8'hB2 && global_header[2] == 8'h3c) begin 77 $display(" pcap endian: native, nanos"); 78 swapped = 0; 79 toNanos = 32'd1; 80 end else begin 81 $display(" pcap endian: unrecognised format %02x%02x%02x%02x", global_header[0], global_header[1], global_header[2], global_header[3] ); 82 $finish_and_return(1); 83 end 84 end 85 86 always @(posedge CLOCK) 87 begin 88 if (eof == 0 && diskSz == 0 && countIPG == 0) begin 89 // read packet header 90 // fields of interest are U32 so bear in mind the byte ordering when assembling 91 // multibyte fields 92 r = $fread(packet_header, file); 93 eof = $feof(file); 94 95 if ( eof == 0) begin 96 if (swapped == 1) begin 97 pktSz = {packet_header[11],packet_header[10],packet_header[9] ,packet_header[8] }; 98 diskSz = {packet_header[15],packet_header[14],packet_header[13],packet_header[12]}; 99 end else begin 100 pktSz = {packet_header[ 8],packet_header[ 9],packet_header[10],packet_header[11]}; 101 diskSz = {packet_header[12],packet_header[13],packet_header[14],packet_header[15]}; 102 end 103 104 $display(" packet %0d: incl_length %0d orig_length %0d eof %0d", pktcount, pktSz, diskSz, eof ); 105 106 available <= 1; 107 newpkt <= 1; 108 pktcount <= pktcount + 1; 109 countIPG <= ipg; // reload interpacket gap counter 110 end 111 end else if ( diskSz > 0) begin 112 113 // packet content is byte-aligned, no swapping required 114 if (~pause) begin 115 newpkt <= 0; 116 diskSz <= diskSz - 1; 117 data <= $fgetc(file); 118 eof = $feof(file); 119 if ( eof != 0 || diskSz == 1) begin 120 available <= 0; 121 end else begin 122 datavalid <= 1; 123 end 124 end else begin 125 datavalid <= 0; 126 end 127 end else if (countIPG > 0) begin 128 countIPG <= countIPG - 1; 129 end else if (eof != 0) begin 130 pcapfinished <= 1; // terminal loop here 131 end 132 133 134 end 135 136 endmodule
2.编写testbench文件
将 tcp-4846-connect-disconnect.pcap 文件放在工程目录下。自己随意放置一个,然后修改源码中文件的名称,才可以读到。
1 `timescale 1ns / 1ps 2 `define NULL 0 3 4 // Coder: joe 5 // Description: 6 // 测试文件,读取数据,打入模块 7 // 8 // 9 // 10 // 11 // 12 13 module PcapParser_test 14 #( 15 parameter DATA_WIDTH = 480, 16 parameter CTRL_WIDTH=32, 17 parameter STAGE_NUMBER = 2, 18 parameter NUM_QUEUES = 8 19 ); 20 21 // Inputs 22 reg CLOCK = 0; 23 reg paused = 0; 24 reg rst=0; 25 wire available; 26 wire [7:0] pktcount; 27 wire streamvalid; 28 wire [7:0] stream; 29 wire pcapfinished; 30 wire newpkt; 31 32 wire out_wr; 33 wire [CTRL_WIDTH-1:0] out_ctl; 34 wire [DATA_WIDTH-1:0] out_data; 35 36 wire out_wr1; 37 wire [CTRL_WIDTH-1:0] out_ctl1; 38 wire [DATA_WIDTH-1:0] out_data1; 39 40 // Instantiate the Unit Under Test (UUT) 41 PcapParser #( 42 .pcap_filename( "tcp-4846-connect-disconnect.pcap" ) 43 ) pcap ( 44 .CLOCK(CLOCK), 45 .pause(paused), 46 .available(available), 47 .datavalid(streamvalid), 48 .data(stream), 49 .pktcount(pktcount), 50 .newpkt(newpkt), 51 .pcapfinished(pcapfinished) 52 ); 53 54 55 always #10 CLOCK = ~CLOCK; 56 57 //always #100 paused = ~paused; 58 59 integer i; 60 61 initial begin 62 63 $dumpfile("pcap.lxt"); 64 //$dumpvars(0); 65 66 // Initialize Inputs 67 $display("Reading from pcap"); 68 69 // Wait 100 ns for global reset to finish 70 #10; 71 rst = 1; 72 73 // Add stimulus here 74 while (~pcapfinished ) begin 75 //$display("stream: %8d %x %d %x %x %c", i, paused, pktcount, streamvalid, stream, stream); 76 #20 77 i = i+1; 78 end 79 80 $finish; 81 82 end 83 84 endmodule
3.读取仿真激励结果
=====================
qsy
2018-7-5 11:39:44