FPGA语法基础(二):SystemVerilog 数组清零方法详解

SystemVerilog 提供了比 Verilog 更强大和简洁的数组操作方法。以下是各种数组清零方法的详细说明。

1. 基础数组清零方法

方法1: 使用 default 赋值模式(推荐)

复制代码
module array_clear_basic;
    // 各种数组类型定义
    logic [7:0] byte_array [0:15];        // 打包数组
    int int_array [32];                   // 32位整数数组
    bit [3:0][7:0] multi_dim_array [8];   // 多维数组
    
    initial begin
        // 使用 default 模式清零
        byte_array = '{default:0};
        int_array = '{default:0};
        multi_dim_array = '{default:0};
        
        $display("All arrays cleared using default pattern");
    end
endmodule

方法2: 使用重复赋值模式

复制代码
module array_clear_repeat;
    logic [7:0] data_array [0:7];
    bit [15:0] wide_array [0:3];
    
    initial begin
        // 使用重复模式清零
        data_array = '{8{8'h00}};        // 重复8次,每次8位0
        wide_array = '{4{16'h0000}};     // 重复4次,每次16位0
        
        // 或者使用更简洁的写法
        data_array = '{default:'0};      // 所有位设为0
    end
endmodule

2. 动态数组清零

方法3: 动态数组的多种清零方式

复制代码
module dynamic_array_clear;
    // 动态数组定义
    int dyn_array[];
    string str_array[];
    logic [7:0] byte_dyn_array[];
    
    task automatic clear_arrays();
        // 方法3A: 重新分配空间并清零
        dyn_array = new[16](0);           // 分配16个元素,全部初始化为0
        str_array = new[8]("");           // 字符串数组清空
        byte_dyn_array = new[32]('{default:0});
        
        // 方法3B: 使用 delete() 方法
        dyn_array.delete();               // 删除数组,大小为0
        dyn_array = new[10];              // 重新分配,默认值为0
        
        // 方法3C: 遍历清零(当需要条件清零时)
        foreach(dyn_array[i]) begin
            dyn_array[i] = 0;
        end
    endtask
    
    initial begin
        clear_arrays();
        $display("Dynamic arrays cleared");
    end
endmodule

3. 关联数组清零

方法4: 关联数组清零方法

复制代码
module associative_array_clear;
    // 关联数组定义
    int assoc_array [string];     // 字符串索引
    logic [7:0] byte_assoc [int]; // 整数索引
    bit [3:0] bit_assoc [bit [7:0]]; // 位向量索引
    
    function void clear_associative_arrays();
        // 方法4A: 使用 delete() 清空整个数组
        assoc_array.delete();
        byte_assoc.delete();
        bit_assoc.delete();
        
        // 方法4B: 逐个删除特定元素
        string keys[$];
        
        // 获取所有键并删除
        keys = assoc_array.find_index() with ('1);
        foreach(keys[i]) begin
            assoc_array.delete(keys[i]);
        end
        
        // 方法4C: 重新赋值特定键为0(不清除结构)
        assoc_array["key1"] = 0;
        assoc_array["key2"] = 0;
    endfunction
    
    initial begin
        // 先添加一些数据
        assoc_array["test1"] = 42;
        assoc_array["test2"] = 100;
        
        $display("Before clear: assoc_array size = %0d", assoc_array.num());
        clear_associative_arrays();
        $display("After clear: assoc_array size = %0d", assoc_array.num());
    end
endmodule

4. 队列清零

方法5: 队列清零方法

复制代码
module queue_clear;
    // 队列定义
    int int_queue[$];
    string str_queue[$];
    logic [7:0] byte_queue[$] = {1,2,3,4,5};
    
    function void clear_queues();
        // 方法5A: 使用 delete() 清空整个队列
        int_queue.delete();
        str_queue.delete();
        
        // 方法5B: 重新赋值为空队列
        byte_queue = '{};
        
        // 方法5C: 使用循环逐个删除(从尾部删除效率更高)
        while (int_queue.size() > 0) begin
            void'(int_queue.pop_back());
        end
    endfunction
    
    initial begin
        // 添加测试数据
        for (int i = 0; i < 5; i++) begin
            int_queue.push_back(i * 10);
        end
        
        $display("Before clear: queue size = %0d", int_queue.size());
        clear_queues();
        $display("After clear: queue size = %0d", int_queue.size());
    end
endmodule

5. 多维数组清零

方法6: 多维数组清零

复制代码
module multi_dim_array_clear;
    // 多维数组定义
    logic [7:0] matrix_2d [0:3][0:3];        // 4x4 矩阵
    int array_3d [0:2][0:2][0:1];           // 3x3x2 三维数组
    bit [3:0] nested_array [4][8];          // 嵌套数组
    
    function void clear_multi_dim_arrays();
        // 方法6A: 使用嵌套 default 模式
        matrix_2d = '{'{4{8'h00}}, '{4{8'h00}}, '{4{8'h00}}, '{4{8'h00}}};
        
        // 方法6B: 更简洁的 default 写法
        array_3d = '{default:0};
        nested_array = '{default:0};
        
        // 方法6C: 使用嵌套循环
        foreach(matrix_2d[i, j]) begin
            matrix_2d[i][j] = 8'h00;
        end
        
        foreach(array_3d[i, j, k]) begin
            array_3d[i][j][k] = 0;
        end
    endfunction
    
    initial begin
        clear_multi_dim_arrays();
        $display("Multi-dimensional arrays cleared");
    end
endmodule

6. 实际工程应用

示例1: FIFO 内存清零

复制代码
module fifo_sv #(
    parameter DEPTH = 16,
    parameter DATA_WIDTH = 8
)(
    input logic clk,
    input logic rst_n,
    input logic clear
);
    
    // FIFO 内存数组
    logic [DATA_WIDTH-1:0] fifo_mem [DEPTH];
    int wr_ptr, rd_ptr;
    int count;
    
    // 清零控制
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // 复位时清零
            fifo_mem = '{default:0};
            wr_ptr <= 0;
            rd_ptr <= 0;
            count <= 0;
        end else if (clear) begin
            // 清零信号
            fifo_mem = '{default:0};
            wr_ptr <= 0;
            rd_ptr <= 0;
            count <= 0;
        end else begin
            // 正常 FIFO 操作
            // ...
        end
    end
    
endmodule

示例2: 缓存清零控制器

复制代码
module cache_controller_sv #(
    parameter CACHE_SIZE = 64,
    parameter WAYS = 4,
    parameter SETS = 16
)(
    input logic clk,
    input logic rst_n,
    input logic flush_cache
);
    
    // 缓存数据结构
    typedef struct packed {
        bit valid;
        bit dirty;
        bit [23:0] tag;
        logic [7:0] data [8];  // 64字节缓存行
    } cache_line_t;
    
    cache_line_t cache_mem [WAYS][SETS];
    bit clearing;
    int clear_way, clear_set;
    
    // 缓存清零状态机
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // 复位时清零整个缓存
            cache_mem = '{default:'0};
            clearing <= 1'b0;
        end else if (flush_cache && !clearing) begin
            // 开始缓存刷新
            clearing <= 1'b1;
            clear_way <= 0;
            clear_set <= 0;
        end else if (clearing) begin
            // 逐个缓存行清零
            cache_mem[clear_way][clear_set] <= '0;
            
            if (clear_set == SETS-1) begin
                clear_set <= 0;
                if (clear_way == WAYS-1) begin
                    clearing <= 1'b0;
                end else begin
                    clear_way <= clear_way + 1;
                end
            end else begin
                clear_set <= clear_set + 1;
            end
        end
    end
    
endmodule

示例3: 可配置数组清零模块

复制代码
module array_clear_unit_sv #(
    parameter ARRAY_SIZE = 256,
    parameter DATA_WIDTH = 32
)(
    input logic clk,
    input logic rst_n,
    input logic start_clear,
    input logic [DATA_WIDTH-1:0] clear_value,  // 可配置清零值
    output logic clear_done
);
    
    logic [DATA_WIDTH-1:0] target_array [ARRAY_SIZE];
    logic clearing;
    int clear_index;
    
    // 清零状态机
    typedef enum logic [1:0] {
        IDLE,
        CLEARING,
        DONE
    } clear_state_t;
    
    clear_state_t state;
    
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            target_array <= '{default:0};
            clear_index <= 0;
            clear_done <= 1'b0;
        end else begin
            case (state)
                IDLE: begin
                    clear_done <= 1'b0;
                    if (start_clear) begin
                        state <= CLEARING;
                        clear_index <= 0;
                    end
                end
                
                CLEARING: begin
                    target_array[clear_index] <= clear_value;
                    
                    if (clear_index == ARRAY_SIZE-1) begin
                        state <= DONE;
                        clear_done <= 1'b1;
                    end else begin
                        clear_index <= clear_index + 1;
                    end
                end
                
                DONE: begin
                    if (!start_clear) begin
                        state <= IDLE;
                        clear_done <= 1'b0;
                    end
                end
            endcase
        end
    end
    
    // 性能监控
    property clear_completion;
        @(posedge clk) (state == DONE) |-> (clear_index == ARRAY_SIZE-1);
    endproperty
    
    assert property (clear_completion)
    else $error("Clear operation did not complete correctly");
    
endmodule

7. 高级清零技巧

方法7: 使用参数化清零函数

复制代码
module advanced_clear_techniques;
    
    // 参数化清零函数
    function automatic void clear_array(ref logic arr[], input logic [31:0] clear_val = 0);
        foreach(arr[i]) begin
            arr[i] = clear_val;
        end
    endfunction
    
    function automatic void clear_assoc_array(ref int arr[string]);
        string keys[$] = arr.find_index() with ('1);
        foreach(keys[i]) begin
            arr.delete(keys[i]);
        end
    endfunction
    
    // 使用示例
    logic [7:0] test_array [16];
    int test_assoc [string];
    
    initial begin
        // 使用函数清零
        clear_array(test_array, 8'hFF);  // 清零为特定值
        clear_assoc_array(test_assoc);
        
        // 条件清零
        foreach(test_array[i]) begin
            if (i % 2 == 0) begin
                test_array[i] = 8'hAA;  // 偶数索引设为 0xAA
            end else begin
                test_array[i] = 8'h55;  // 奇数索引设为 0x55
            end
        end
    end
    
endmodule

总结

SystemVerilog 提供了多种强大的数组清零方法:

方法 适用场景 优点 缺点
'{default:0} 固定大小数组 简洁,可读性好 不能条件清零
delete() 动态数组、关联数组、队列 彻底清空 丢失数组结构
循环遍历 所有数组类型 灵活,可条件清零 代码较长
重复模式 固定模式清零 性能好 模式必须一致

最佳实践建议

  1. 对于固定数组,优先使用 '{default:0}

  2. 对于动态结构,使用 delete() 方法

  3. 需要条件清零时使用循环遍历

  4. 大数组清零考虑使用状态机分步进行

  5. 在关键路径中使用流水线清零以提高性能

这些方法可以根据具体的设计需求灵活组合使用。

相关推荐
jiushun_suanli4 小时前
FPGA(现场可编程门阵列)详解
经验分享·学习·fpga开发
Terasic友晶科技7 小时前
1-串行通信基础知识
fpga开发·串口通信·异步通信·串行通信·同步通信·并行通信·单工
FPGA_小田老师9 小时前
Xilinx Aurora 8B/10B IP核(2):Shared Logic的选择
fpga开发·aurora 8b/10b·share logic·aurora接口
嵌入式软硬件攻城狮12 小时前
4.FPGA字符格式
fpga开发
Terasic友晶科技12 小时前
2-基于FPGA开发板DE23-Lite的串口通信设计 (FT2232H)
fpga开发·串口·uart·de23-lite
第二层皮-合肥14 小时前
FPGA工程师12实战项目-基于PCIe的高速ADC采集项目
fpga开发
第二层皮-合肥21 小时前
USB3.0PHY介绍
fpga开发
czhaii1 天前
51的DSP来了, 100MHz, STC32G144K246
stm32·单片机·fpga开发
FPGA_ADDA2 天前
全国产复旦微FMQL100TAI 核心板
fpga开发·信号处理·全国产·fmql100tai·zynq7国产化