101 lines
4.2 KiB
Systemverilog
101 lines
4.2 KiB
Systemverilog
`timescale 1ns/1ps
|
|
`default_nettype none
|
|
|
|
module tb_ethernet_tx_mac;
|
|
logic clk=0, rst=1;
|
|
logic frame_start=0;
|
|
logic [10:0] payload_length=11'd4;
|
|
logic [7:0] payload_data;
|
|
logic payload_valid, payload_ready;
|
|
logic [7:0] gmii_txd;
|
|
logic gmii_tx_en, gmii_tx_er, busy, frame_done;
|
|
logic [63:0] frames, payload_bytes;
|
|
byte payload [0:3];
|
|
byte captured [0:255];
|
|
byte body [0:59];
|
|
integer payload_pos=0, cap_count=0, i;
|
|
logic [31:0] reference_crc;
|
|
|
|
always #4 clk=~clk;
|
|
assign payload_data = payload[payload_pos];
|
|
assign payload_valid = (payload_pos < 4);
|
|
|
|
ethernet_tx_mac dut (
|
|
.clk(clk), .rst(rst), .frame_start(frame_start), .payload_length(payload_length),
|
|
.payload_data(payload_data), .payload_valid(payload_valid), .payload_ready(payload_ready),
|
|
.gmii_txd(gmii_txd), .gmii_tx_en(gmii_tx_en), .gmii_tx_er(gmii_tx_er),
|
|
.busy(busy), .frame_done(frame_done), .frames_transmitted(frames),
|
|
.payload_bytes_transmitted(payload_bytes)
|
|
);
|
|
|
|
always @(posedge clk) begin
|
|
if (!rst && gmii_tx_en) begin
|
|
captured[cap_count] = gmii_txd;
|
|
cap_count = cap_count + 1;
|
|
if (gmii_tx_er) $fatal(1, "unexpected GMII TX error");
|
|
end
|
|
if (!rst && payload_ready && payload_valid)
|
|
payload_pos <= payload_pos + 1;
|
|
end
|
|
|
|
function automatic [31:0] crc_byte(input [31:0] cin, input [7:0] din);
|
|
reg [31:0] c;
|
|
integer b;
|
|
begin
|
|
c=cin;
|
|
for (b=0;b<8;b=b+1)
|
|
c=(c[0]^din[b]) ? ((c>>1)^32'hedb88320) : (c>>1);
|
|
crc_byte=c;
|
|
end
|
|
endfunction
|
|
|
|
initial begin
|
|
payload[0]=8'hde; payload[1]=8'had; payload[2]=8'hbe; payload[3]=8'hef;
|
|
repeat(4) @(posedge clk); rst=0;
|
|
@(posedge clk); frame_start=1;
|
|
@(posedge clk); frame_start=0;
|
|
wait(frame_done);
|
|
@(posedge clk);
|
|
|
|
if (cap_count != 72) $fatal(1, "frame byte count %0d expected 72", cap_count);
|
|
for (i=0;i<7;i=i+1) if(captured[i]!==8'h55) $fatal(1,"bad preamble byte %0d",i);
|
|
if(captured[7]!==8'hd5) $fatal(1,"bad SFD");
|
|
for (i=0;i<6;i=i+1) body[i]=8'hff;
|
|
body[6]=8'h02; body[7]=8'h27; body[8]=8'h71; body[9]=8'h00; body[10]=8'h00; body[11]=8'h01;
|
|
body[12]=8'h88; body[13]=8'hb5;
|
|
body[14]=8'hde; body[15]=8'had; body[16]=8'hbe; body[17]=8'hef;
|
|
for(i=18;i<60;i=i+1) body[i]=8'h00;
|
|
for(i=0;i<60;i=i+1) if(captured[8+i]!==body[i])
|
|
$fatal(1,"body mismatch byte %0d got %02x expected %02x",i,captured[8+i],body[i]);
|
|
reference_crc=32'hffffffff;
|
|
for(i=0;i<60;i=i+1) reference_crc=crc_byte(reference_crc,body[i]);
|
|
reference_crc=~reference_crc;
|
|
if(captured[68]!==reference_crc[7:0] || captured[69]!==reference_crc[15:8] ||
|
|
captured[70]!==reference_crc[23:16] || captured[71]!==reference_crc[31:24])
|
|
$fatal(1,"FCS mismatch got %02x%02x%02x%02x expected %08x",
|
|
captured[71],captured[70],captured[69],captured[68],reference_crc);
|
|
if(frames!==64'd1 || payload_bytes!==64'd4) $fatal(1,"MAC counters incorrect");
|
|
|
|
// Reset while idle, then send another complete frame. No TX_EN fragment
|
|
// may appear during reset or before the new preamble.
|
|
rst=1; payload_pos=0; cap_count=0;
|
|
repeat(3) begin @(posedge clk); if(gmii_tx_en) $fatal(1,"TX_EN asserted during idle reset"); end
|
|
rst=0;
|
|
repeat(2) @(posedge clk);
|
|
frame_start=1; @(posedge clk); frame_start=0;
|
|
wait(frame_done); @(posedge clk);
|
|
if(cap_count!=72) $fatal(1,"post-reset frame malformed: %0d bytes",cap_count);
|
|
for(i=0;i<7;i=i+1) if(captured[i]!==8'h55) $fatal(1,"post-reset preamble byte %0d",i);
|
|
reference_crc=32'hffffffff;
|
|
for(i=0;i<60;i=i+1) reference_crc=crc_byte(reference_crc,body[i]);
|
|
reference_crc=~reference_crc;
|
|
if({captured[71],captured[70],captured[69],captured[68]}!==reference_crc)
|
|
$fatal(1,"post-reset FCS mismatch");
|
|
$display("PASS tb_ethernet_tx_mac: frame/padding/FCS/IFG and reset-between-frames verified");
|
|
$finish;
|
|
end
|
|
initial begin #10000; $fatal(1,"MAC test timeout"); end
|
|
endmodule
|
|
|
|
`default_nettype wire
|