推荐答案
测试一下
题目
除法器的Verilog RTL实现。16bitA,8bitB。C=A/B (15分)
参考答案与知识点
参考答案
采用基于移位减法的恢复余数除法器实现无符号除法。算法步骤:将16位被除数A扩展为32位(高16位为0,低16位为A),8位除数B左对齐至16位(即B<<8)。重复8次循环:每次将当前余数左移一位,将商左移一位,比较当前余数的高16位与除数B;若余数高16位≥B,则余数减B并将商的最低位设为1,否则商最低位为0。8次循环后,得到16位商C和16位余数。考虑到除法器需要组合逻辑或有限状态机实现,以下给出基于FSM的RTL代码框架:
module divider (
input clk, rst_n,
input start, // 启动信号
input [15:0] A, // 被除数
input [7:0] B, // 除数
output reg [15:0] C, // 商
output reg [15:0] rem, // 余数
output reg done // 完成标志
);
reg [4:0] cnt; // 循环计数器,0~7
reg state;
localparam IDLE=0, CALC=1;
reg [31:0] tmp_A; // 32位,低16位为被除数,高16位为当前余数
reg [15:0] tmp_C;
reg [15:0] divisor; // 除数左对齐至16位
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
done <= 0;
cnt <= 0;
C <= 0;
rem <= 0;
tmp_A <= 0;
tmp_C <= 0;
divisor <= 0;
end else begin
case(state)
IDLE: begin
if(start) begin
tmp_A <= {16'd0, A};
divisor <= {B, 8'd0};
cnt <= 0;
tmp_C <= 0;
state <= CALC;
done <= 0;
end
end
CALC: begin
if(cnt < 8) begin
// 左移一位
tmp_A <= {tmp_A[30:0], 1'b0};
tmp_C <= {tmp_C[14:0], 1'b0};
// 比较高16位与除数
if(tmp_A[31:16] >= divisor) begin
tmp_A[31:16] <= tmp_A[31:16] - divisor;
tmp_C[0] <= 1'b1;
end
cnt <= cnt + 1;
end else begin
C <= tmp_C;
rem <= tmp_A[31:16];
done <= 1;
state <= IDLE;
end
end
endcase
end
end
endmodule
注意:除法器输入需考虑除数为0的情况,可在开始前判断B是否为0,若为0则产生错误标志;本实现为无符号除法,对于有符号除法需额外处理符号位;为简化代码,未做流水线优化,实际应用中可增加流水寄存器提升吞吐量;易错点包括位宽对齐、循环次数正确性、比较器件选择(使用大于等于而非大于)以及组合逻辑与时序逻辑的混用。
涉及知识点
- 恢复余数除法算法
- 状态机设计方法
- 移位减法实现原理
- Verilog时序逻辑建模
- 除数为0的处理