4. MAC 接收短帧过滤验证
任务目标
构造一个最小可复现的 MAC 接收路径验证环境:向接收路径注入长度小于 64 字节的帧(runt 帧),检查 MAC 是否按以太网规范将其识别为非法帧并丢弃,同时确认合法帧(≥64 字节)能正常通过。
环境与依赖
- Verilog/SystemVerilog 仿真器(如 Icarus Verilog、VCS、QuestaSim 任一)。
- 本案例自带一个简化 MAC 接收过滤模块
mac_rx_filter,用于演示 runt 判定逻辑;真实工程中该逻辑位于 MAC 接收状态机内。 - 无需外部依赖,单文件即可编译运行。
实现思路
接收路径按字节流统计帧长:检测到 SFD 后开始计数,帧结束(EOF)时比较累计字节数。若长度 < 64 字节,判定为 runt 帧,置 rx_drop 并丢弃;否则置 rx_valid 并输出帧长。测试平台分别注入 60 字节短帧和 64 字节合法帧,观察丢弃与通过行为。
关键完整代码
// mac_rx_filter.v —— 简化 MAC 接收 runt 帧过滤
module mac_rx_filter (
input wire clk,
input wire rst_n,
input wire rx_sfd, // 检测到 SFD,开始一帧
input wire rx_byte_v, // 当前字节有效
input wire rx_eof, // 帧结束
output reg rx_valid, // 合法帧通过
output reg rx_drop, // runt 帧丢弃
output reg [15:0] rx_len // 帧长(字节)
);
localparam MIN_FRAME = 16'd64;
reg [15:0] cnt;
reg in_frame;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0; in_frame <= 0;
rx_valid <= 0; rx_drop <= 0; rx_len <= 0;
end else begin
rx_valid <= 0; rx_drop <= 0;
if (rx_sfd) begin
in_frame <= 1; cnt <= 0;
end else if (in_frame && rx_byte_v) begin
cnt <= cnt + 1;
end
if (in_frame && rx_eof) begin
in_frame <= 0;
rx_len <= cnt;
if (cnt < MIN_FRAME) rx_drop <= 1;
else rx_valid <= 1;
end
end
end
endmodule
// tb_mac_rx_filter.v —— 注入 60B 短帧与 64B 合法帧
`timescale 1ns/1ps
module tb_mac_rx_filter;
reg clk = 0, rst_n = 0;
reg rx_sfd = 0, rx_byte_v = 0, rx_eof = 0;
wire rx_valid, rx_drop;
wire [15:0] rx_len;
mac_rx_filter dut (.clk(clk), .rst_n(rst_n), .rx_sfd(rx_sfd),
.rx_byte_v(rx_byte_v), .rx_eof(rx_eof),
.rx_valid(rx_valid), .rx_drop(rx_drop), .rx_len(rx_len));
always #5 clk = ~clk;
task send_frame(input integer nbytes);
integer i;
begin
@(posedge clk); rx_sfd <= 1; @(posedge clk); rx_sfd <= 0;
for (i = 0; i < nbytes; i = i + 1) begin
@(posedge clk); rx_byte_v <= 1;
end
@(posedge clk); rx_byte_v <= 0; rx_eof <= 1;
@(posedge clk); rx_eof <= 0;
repeat (2) @(posedge clk);
end
endtask
initial begin
repeat (4) @(posedge clk);
rst_n = 1;
// 用例1:60 字节 runt 帧,应被丢弃
send_frame(60);
if (rx_drop && !rx_valid && rx_len == 60)
$display("PASS: 60B runt frame dropped, len=%0d", rx_len);
else
$display("FAIL: 60B frame valid=%b drop=%b len=%0d", rx_valid, rx_drop, rx_len);
// 用例2:64 字节合法帧,应通过
send_frame(64);
if (rx_valid && !rx_drop && rx_len == 64)
$display("PASS: 64B frame accepted, len=%0d", rx_len);
else
$display("FAIL: 64B frame valid=%b drop=%b len=%0d", rx_valid, rx_drop, rx_len);
$finish;
end
endmodule
运行与验证
# Icarus Verilog
iverilog -o sim mac_rx_filter.v tb_mac_rx_filter.v
vvp sim
观察仿真输出:
- 用例1 期望打印
PASS: 60B runt frame dropped, len=60,即rx_drop=1、rx_valid=0。 - 用例2 期望打印
PASS: 64B frame accepted, len=64,即rx_valid=1、rx_drop=0。
判定标准:两条用例均打印 PASS,说明 MAC 接收路径正确识别并丢弃了 runt 帧,同时未误伤 64 字节合法帧。若需扩展,可再注入 63 字节(应丢弃)与 65 字节(应通过)边界用例。