Verilog 4-bit by 4-bit加法移位乘法器仿真结果始终为0求助
你的代码存在多处逻辑错误,导致乘法计算无法正常执行,以下是具体问题和修正方案:
核心错误点
1. 状态机状态更新逻辑错误
第一个always块直接将复位后的state强制赋值为START,完全忽略了next_state的状态转移逻辑,导致状态机无法按照预期流程(IDLE→START→LSB→ADD/SHIFT→...→DONE)运行,直接卡死在START或混乱跳转。
修正:将状态更新改为跟随next_state:
always @(posedge clk, negedge rstn) begin if(!rstn) begin state <= IDLE; end else begin state <= next_state; // 替换原有的state <= START end end
2. LSB判断使用原始输入而非寄存器值
在LSB状态中,你判断的是输入b[0],但实际应该判断移位后的寄存器r_multiplier[0]——乘法过程中乘数是不断右移的,每次要看当前寄存器的最低位决定是否加被乘数。
修正:
LSB: begin if(r_multiplier[0]) // 替换b[0] next_state = ADD; else next_state = SHIFT; end
3. START状态重复初始化寄存器
每次进入START状态都重新赋值r_multiplicant = a和r_multiplier = b,会在乘法循环的每次START跳转时覆盖之前移位后的值,导致计算重置。应该只在**首次启动(从IDLE进入START)**时初始化寄存器,同时重置r_count和r_product。
修正:
START: begin // 仅从IDLE进入时初始化 if(state == IDLE) begin r_multiplicant <= {4'b0, a}; // 扩展为8位,避免左移丢失高位 r_multiplier <= b; r_product <= 8'b0; r_count <= 4; end // 状态转移逻辑 if(r_count != 0) next_state = LSB; else next_state = DONE; end
4. DONE状态错误使用assign语句
在时序always块中不能使用assign,这是语法错误,应该直接用非阻塞赋值将r_product赋值给result,同时设置done信号。
修正:
DONE: begin result <= r_product; done <= 1'b1; end
同时在IDLE状态重置done信号:
IDLE: begin done <= 1'b0; end
5. r_count递减时机错误
原代码在LSB状态递减r_count,应该在完成一次移位操作后递减,确保每次循环计数正确。
修正:将递减逻辑移到SHIFT状态:
SHIFT: begin r_multiplicant <= r_multiplicant << 1; r_multiplier <= r_multiplier >> 1; r_count <= r_count - 1; // 移位后递减计数 end
6. 测试平台信号时序问题
测试平台中start拉高后10ns才赋值a和b,此时模块已进入START状态,采样的是a/b的初始值0,导致计算结果为0。应该在start拉高前设置好a/b,且每次测试新乘数时,需拉低start再重新拉高触发计算。
修正后的测试平台:
`timescale 1ns / 1ps module tb_multi_8bit(); reg clk; reg rstn; reg start; reg [3:0] a; reg [3:0] b; wire [7:0] result; wire done; always #10 clk = ~clk; multi_8bit test( .clk(clk), .rstn(rstn), .start(start), .a(a), .b(b), .result(result), .done(done) ); initial begin clk = 0; rstn = 1; start = 0; a = 4'b0; b = 4'b0; #15 rstn = 0; #25 rstn = 1; // 第一次测试:a=6(0110), b=1(0001) #20 a = 4'b0110; b = 4'b0001; #10 start = 1; #20 start = 0; wait(done); // 等待计算完成 // 第二次测试:a=6(0110), b=2(0010) #20 a = 4'b0110; b = 4'b0010; #10 start = 1; #20 start = 0; wait(done); // 第三次测试:a=6(0110), b=1(0001) #20 a = 4'b0110; b = 4'b0001; #10 start = 1; #20 start = 0; wait(done); #20 $finish; end endmodule
修正后的完整模块代码
`timescale 1ns / 1ps module multi_8bit( input clk, input rstn, input start, input [3:0] a, input [3:0] b, output reg [7:0] result, output reg done ); localparam IDLE = 3'b000, START = 3'b001, LSB = 3'b010, ADD = 3'b011, SHIFT = 3'b100, DONE = 3'b101; reg [2:0] state, next_state; reg [7:0] r_multiplicant; reg [7:0] r_product; reg [3:0] r_multiplier; reg [2:0] r_count; always @(posedge clk, negedge rstn) begin if(!rstn) begin state <= IDLE; end else begin state <= next_state; end end always@(*) begin case(state) IDLE: begin if(start) next_state = START; else next_state = IDLE; end START: begin if(r_count != 0) next_state = LSB; else next_state = DONE; end LSB: begin if(r_multiplier[0]) next_state = ADD; else next_state = SHIFT; end ADD: begin next_state = SHIFT; end SHIFT: begin next_state = START; end DONE: begin next_state = IDLE; end endcase end always@(posedge clk, negedge rstn) begin if(!rstn) begin r_multiplicant <= 0; r_multiplier <= 0; r_product <= 0; r_count <= 4; result <= 0; done <= 0; end else begin case(state) IDLE: begin done <= 1'b0; end START: begin if(state == IDLE) begin r_multiplicant <= {4'b0, a}; r_multiplier <= b; r_product <= 8'b0; r_count <= 4; end end LSB: begin // 无操作,仅判断LSB end ADD: begin r_product <= r_product + r_multiplicant; end SHIFT: begin r_multiplicant <= r_multiplicant << 1; r_multiplier <= r_multiplier >> 1; r_count <= r_count - 1; end DONE: begin result <= r_product; done <= 1'b1; end endcase end end endmodule
内容的提问来源于stack exchange,提问作者SANTAR276

