用Verilog实现一个除法器的功能
最简单的方法就是减法实现除法器(比如十进制中的a/b,可先比较a与b的大小,如果a>b,则商加1,a<=a-b,再进行比较大小,直到a<b,商不变,余数为a)。但这种方式通常速度比较慢,实际上更快速的方法是模拟手算除法的过程:
思考
:::info
- 为什么我们需要对被除数的高位补0呢?
对被除数的高位进行补0来存放商;
- 那么我们为什么要对除数的低位补0呢?
为了和被除数的低位进行匹配。
>> 通过运算我们可以发现,一个16bit的数/一个8bit的数,只有在被除数从高向低数的第8位才有可能有商的值出现,所以被除数需要向左移位逐步进行比较,我们可以将得到的商存放在一个临时声明的变量中,也可以将他直接放在被除数的低位。
:::
代码
以下就是代码的实现:
module divider(
input [15:0] A,
input [7:0] B,
output [15:0] result,
output [15:0] rmd
);
reg [31:0] a_reg;
reg [31:0] b_reg;
integer i;
always @(*) begin
a_reg = {16'h0, A};
b_reg = {B, 16'h0};
for(i = 0; i < 16; i = i+1) begin
a_reg = a_reg << 1;
if(a_reg >= b_reg) begin
a_reg = a_reg - b_reg + 1;
end
else begin
a_reg = a_reg;
end
end
end
assign result = a_reg[15:0];
assign rmd = a_reg[31:16];
endmodule
result(商)和rmd(余数)这两个变量一定要给定位宽,否则DUT出来的数据是不正常的
Testbench验证
同样的,我们也搭建一个简单的tb进行验证:
步骤就是首先定义端口;
接下来调用我们的硬件DUT模块;
最后在Initial过程块中给定激励。
module divider_tb;
bit [15:0] A;
bit [7:0] B;
bit [15:0] result;
bit [15:0] rmd;
divider dut(
.A(A),
.B(B),
.result(result),
.rmd(rmd)
);
initial begin
A = 16'd27;
B = 8'd5;
#20;
A = 16'd47;
B = 8'd7;
#20;
$finish();
end
endmodule
Reference
[1] https://www.cnblogs.com/lyc-seu/p/12507760.html
[2] https://www.bilibili.com/video/BV1iF411V7Nj?spm_id_from=333.337.search-card.all.click&vd_source=5df87fe7e859dc91e7029ea8f59c1811