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 字节合法帧,观察丢弃与通过行为。

注入帧字节流 SFD 后开始 统计帧长 长度 < 64 ? runt 帧 rx_drop=1 合法帧 rx_valid=1 是 否

关键完整代码

// 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 字节(应通过)边界用例。