如何每17个时钟周期实例化Verilog的padder模块?
问题解答
可行性判断
完全可行,这是利用重叠执行/流水线调度提升哈希吞吐量的标准思路——padder耗时17周期,f_permutation仅需12周期,两者的周期差刚好允许padder提前启动下一轮填充,让硬件资源持续处于工作状态,避免空闲浪费。
为什么你之前的尝试失败
Verilog是硬件描述语言,模块实例化是静态硬件结构定义,必须在模块顶层(always块之外)完成,不能在always这种动态行为描述块内实例化模块。你需要做的不是动态生成模块,而是通过控制信号调度已有模块的工作时序。
具体实现方法(附简便方案)
1. 核心方案:静态实例化+周期计数器调度
这是最简便的实现方式,仅需给模块添加基础的启动/完成握手信号(如果原模块没有的话):
- 步骤1:静态实例化模块
在顶层模块中直接实例化padder和f_permutation,这是Verilog语法要求,所有硬件结构必须在编译阶段确定。 - 步骤2:用17周期循环计数器触发padder启动
设计一个从0到16的计数器,每计数到0时,给padder发送一个单周期的启动信号,同时送入下一轮哈希的输入数据。因为padder刚好耗时17周期,下一次启动信号到来时,上一轮填充刚好完成,padder可以持续满负荷运行。 - 步骤3:握手信号同步数据流转
当padder完成填充时(输出pad_done信号),自动触发f_permutation启动,接收填充后的数据。由于f_permutation仅需12周期,它会在padder下一次输出前提前完成,不会阻塞后续数据。
2. 代码示例(关键片段)
module shake256_top( input clk, input rst_n, input [511:0] next_hash_input, output [255:0] hash_result, output hash_valid ); // 17周期循环计数器:触发padder启动 reg [4:0] cycle_cnt; always @(posedge clk or negedge rst_n) begin if(!rst_n) cycle_cnt <= 5'd0; else cycle_cnt <= (cycle_cnt == 5'd16) ? 5'd0 : cycle_cnt + 1'b1; end wire pad_start = (cycle_cnt == 5'd0); // 每17周期启动一次padder // 静态实例化padder模块(假设已添加start/done信号) wire [1023:0] padded_data; wire pad_done; padder u_padder( .clk (clk), .rst_n (rst_n), .start (pad_start), .data_in (next_hash_input), .data_out (padded_data), .done (pad_done) ); // 静态实例化f_permutation模块(假设已添加start/done信号) wire f_start = pad_done; wire [255:0] f_result; wire f_done; f_permutation u_f_perm( .clk (clk), .rst_n (rst_n), .start (f_start), .data_in (padded_data), .data_out (f_result), .done (f_done) ); // 哈希结果输出逻辑 reg [255:0] hash_reg; reg valid_reg; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin hash_reg <= 256'd0; valid_reg <= 1'b0; end else begin if(f_done) begin hash_reg <= f_result; valid_reg <= 1'b1; end else begin valid_reg <= 1'b0; end end end assign hash_result = hash_reg; assign hash_valid = valid_reg; endmodule
3. 特殊情况处理:乒乓缓冲(可选)
如果后续调整参数后,padder的输出速率高于f_permutation的处理速率,可以在两者之间添加双端口乒乓缓冲:
- 当padder完成填充,将数据写入缓冲A;当f_permutation空闲时,从缓冲B读取数据。
- 切换逻辑:缓冲A写满后切换到缓冲B写入,缓冲B读完后切换到缓冲A读取,避免数据丢失,同时保证padder持续运行。
关键注意事项
- 模块握手信号:如果原padder/f_permutation没有
start和done信号,需要给模块添加简单的状态机控制,比如用启动寄存器触发内部流水线,用计数器计数周期数生成done信号。 - 时序约束:需要确保padder输出到f_permutation输入的路径满足时钟周期要求,避免时序违例。
- 复位同步:所有模块的复位信号要保持同步,防止异步复位导致的逻辑混乱。
内容的提问来源于stack exchange,提问作者Thearqi
相关产品推荐
相关产品推荐

