恢復餘數除法器是一種常用的除法器,過程與手算除法的方法很類似,過程為
將除數向左位移直到比被除數大
執行被除數減除數操作,得餘數,並將商向左移位1位,空位補1
若餘數大於0,除數向右移位1位。如餘數小於0,餘數加當前除數,商最後一位置0,除數向右移位1位
重複到2,只到除數比最初的除數小
rtl**就是使用了大量的if
語句完成了以上的演算法描述,其中
module restore_divider #(
parameter width = 4
)( input clk, // clock
input rst_n, // asynchronous reset active low
input [width * 2 - 1:0]dividend,
input [width - 1:0]divisor,
input din_valid,
output reg [2 * width - 1:0]dout,
output [width - 1:0]remainder
);reg [2 * width:0]remainder_r;
reg [3 * width - 1:0]divisor_move;
reg [width - 1:0]divisor_lock;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
//初始化
<= 'b0;
end else begin
if(din_valid == 1'b1) begin
//鎖存輸入,3倍width的寬度用於保證移位後的除數大於被除數
remainder_r[width * 2 - 1:0] <= dividend;
remainder_r[2 * width] <= 'b0;
divisor_move[3 * width - 1:2 * width] <= divisor;
divisor_move[2 * width - 1:0] <= 'b0;
divisor_lock <= divisor;
dout <= 'b0;
end else if((divisor_move > ') && (dout == 'b0)) begin
//開始條件
remainder_r <= remainder_r;
dout <= 'b0;
divisor_move <= divisor_move >> 1;
divisor_lock <= divisor_lock;
end else if(divisor_move >= ') begin
if(remainder_r[2 * width] == 1'b0) begin //執行減法
remainder_r <= remainder_r - divisor_move;
dout <= ;
// divisor_move <= divisor_move >> 1;
divisor_lock <= divisor_lock;
if(remainder_r >= divisor_move) begin
divisor_move <= divisor_move >> 1;
end else begin
divisor_move <= divisor_move;
endend else begin //恢復餘數
remainder_r <= remainder_r + divisor_move;
dout <= ;
divisor_move <= divisor_move >> 1;
divisor_lock <= divisor_lock;
endend else begin
remainder_r <= remainder_r;
divisor_lock <= divisor_lock;
divisor_move <= divisor_move;
dout <= dout;
endend
endassign remainder = remainder_r[width - 1:0];
endmodule
測試平台復用了shiftsub除法器的平台,增加了「遇錯停止」的功能
module tb_divider (
);parameter width = 4;
logic clk; // clock
logic rst_n; // asynchronous reset active low
logic [2 * width - 1:0]dividend;
logic [width - 1:0]divisor;
logic din_valid;
logic [2 * width - 1:0]dout;
logic [width - 1:0]remainder;
restore_divider #(
.width(width)
) dut (
.clk(clk), // clock
.rst_n(rst_n), // asynchronous reset active low
.dividend(dividend),
.divisor(divisor),
.din_valid(din_valid),
.dout(dout),
.remainder(remainder)
);initial begin
clk = 'b0;
forever begin
#50 clk = ~clk;
endendinitial begin
rst_n = 1'b1;
# 5 rst_n = 'b0;
#10 rst_n = 1'b1;
endlogic [2 * width - 1:0]dout_exp;
logic [width - 1:0]remainder_exp;
initial begin
= 'b0;
forever begin
@(negedge clk);
dividend = (2 * width)'($urandom_range(0,2 ** (2 * width)));
divisor = (width)'($urandom_range(1,2 ** width - 1));
din_valid = 1'b1;
remainder_exp = dividend % divisor;
dout_exp = (dividend - remainder_exp) / divisor;
repeat(5 * width) begin
@(negedge clk);
din_valid = 'b0;
endif((remainder == remainder_exp) && (dout_exp == dout)) begin
$display("successfully");
end else begin
$display("failed");
$stop;
endend
endendmodule
不恢復餘數除法器
不恢復餘數除法器的基本演算法來自於恢復餘數除法器,區別在於當餘數變負時不停下恢復餘數而是繼續執行迭代,並在迭代中加上移位後除數而不是減去移位後除數,基本演算法如下所示 將除數向左移位到恰好大於被除數 若餘數為正 餘數減去移位後除數 若餘數為負 餘數加上移位後除數 若現餘數為正,該位結果為1,否則為0...
不恢復餘數除法器
不恢復餘數除法器的基本演算法來自於恢復餘數除法器,區別在於當餘數變負時不停下恢復餘數而是繼續執行迭代,並在迭代中加上移位後除數而不是減去移位後除數,基本演算法如下所示 將除數向左移位到恰好大於被除數 若餘數為正 餘數減去移位後除數 若餘數為負 餘數加上移位後除數 若現餘數為正,該位結果為1,否則為0...
HDL系列 除法器 2 不恢復餘數法
目錄 一 不恢復餘數法 non restoring division algorithm 二 不恢復餘數法流程圖以及例子 上期我們介紹了二進位制除法器中的恢復餘數法,本期介紹不恢復餘數法。不恢復餘數法商數的選擇使用代替。雖然相比於不恢復餘數法演算法複雜一些,但是硬體實現上更有優勢,每產生乙個商的位元...