Verilog实现Rosenbrock函数的循环递归赋值多驱动问题解决
问题原因说明
你原有代码的报错根源是generate循环中对全局wire类型变量重复执行assign赋值:每轮循环都会给x_i、x_im1、a、b、fitness_val这几个全局信号生成一个驱动源,Verilog中wire类型不允许多驱动,因此会输出未定义的X态。你手动展开求和的写法是单次assign对所有项求和,不存在多驱动问题,因此可以正常工作。
实现方案
你不需要用递归也可以通过参数化的generate实现可扩展的Rosenbrock函数计算,当然Verilog也支持递归模块实例化的写法,两种方案如下:
方案1:generate累加实现(推荐,写法更简洁易维护)
把每一轮循环的计算结果存到独立的wire数组中,最后对所有数组元素一次性求和即可,完全匹配你手动展开的逻辑,示例代码如下:
module rosenbrock #( parameter N = 4, // 输入变量个数 parameter WIDTH = 2 // 单个变量位宽 )( input [N*WIDTH -1:0] x, output [WIDTH-1:0] fitness ); wire [WIDTH-1:0] x_array [N-1:0]; // 每一轮循环的计算结果单独存到term数组,避免多驱动 wire [2*WIDTH-1:0] term [N-2:0]; genvar j; generate // 拆分输入到数组 for (j =0 ; j < N ; j = j+1) begin : split_input assign x_array[j] = x[WIDTH*j +: WIDTH]; end // 计算每一项的结果 for (j=1; j<N; j=j+1) begin : calc_term wire [WIDTH-1:0] x_i = x_array[j]; wire [WIDTH-1:0] x_im1 = x_array[j-1]; // 注意这里把变量定义写在循环内部,每轮生成独立的信号,不会冲突 assign term[j-1] = 100*(x_i - x_im1)*(x_i - x_im1) + (1 - x_im1)*(1 - x_im1); end // 一次性求和所有项 integer i; reg [2*WIDTH-1:0] fitness_val; always @(*) begin fitness_val = 0; for(i=0; i<N-1; i=i+1) begin fitness_val = fitness_val + term[i][2*WIDTH-1:WIDTH]; // 按你原逻辑取对应位 end end endgenerate assign fitness = fitness_val[WIDTH-1:0]; endmodule
这个写法可以直接通过修改N参数适配不同输入维度的Rosenbrock函数,不需要手动改代码。
方案2:递归模块实现
如果确实需要用递归实现,可以定义可递归实例化的子模块,示例如下:
// 递归子模块 module rosenbrock_rec #( parameter REMAIN_CNT = 3, // 剩余要计算的项数 parameter WIDTH = 2 )( input [WIDTH-1:0] x_prev, input [REMAIN_CNT*WIDTH -1:0] x_remain, output [2*WIDTH -1:0] sum_out ); wire [WIDTH-1:0] x_curr = x_remain[WIDTH-1:0]; wire [2*WIDTH-1:0] curr_term = 100*(x_curr - x_prev)*(x_curr - x_prev) + (1 - x_prev)*(1 - x_prev); generate if(REMAIN_CNT == 1) begin : end_rec assign sum_out = curr_term; end else begin : next_rec wire [2*WIDTH -1:0] next_sum; rosenbrock_rec #( .REMAIN_CNT(REMAIN_CNT-1), .WIDTH(WIDTH) ) next_inst ( .x_prev(x_curr), .x_remain(x_remain[REMAIN_CNT*WIDTH -1 : WIDTH]), .sum_out(next_sum) ); assign sum_out = curr_term + next_sum; end endgenerate endmodule // 顶层模块调用 module rosenbrock_top #( parameter N = 4, parameter WIDTH = 2 )( input [N*WIDTH -1:0] x, output [WIDTH-1:0] fitness ); wire [2*WIDTH -1:0] total_sum; rosenbrock_rec #( .REMAIN_CNT(N-1), .WIDTH(WIDTH) ) rec_inst ( .x_prev(x[WIDTH-1:0]), .x_remain(x[N*WIDTH -1 : WIDTH]), .sum_out(total_sum) ); assign fitness = total_sum[2*WIDTH-1 : WIDTH]; endmodule
注意事项
- 你原代码中的位宽截取逻辑需要根据你实际的定点数位宽定义调整,上述代码保留了你原有的高位截取逻辑,可根据需求修改
- 组合逻辑求和如果位宽较大,建议打寄存器拍避免时序违例
内容的提问来源于stack exchange,提问作者GeekyScientist
相关产品推荐
相关产品推荐

