Verilog -- 无符号整数除法器(二)
Verilog -- 无符号整数除法器(二)
在 Verilog -- 任意整数除法器(一)中已经给出了一种除法器的组合逻辑实现,但是实际使用中可能还是需要讲组合逻辑插拍才能得到更好的性能。下面给出一种基于状态机的时序逻辑除法器实现。
这边先上一下算法流程图,跟之前的一样:
graph LR
id0(32位整数a除以b)-->id1(a的高位扩展32位)
id0(32位整数a除以b)-->id2(b的低位扩展32位)
id1 --> id3(a左移一位)
id2 --> id4{a>=b?}
id3 --> id4
id4 -- 是 --> id5(a = a-b+1)
id5 -->id6{移位次数<32}
id4 --否-->id6
id6 --是--> id3
id6 --否--> id7(输出a)
下面是verilog代码:
`timescale 1ns/1ps
module div_fsm
#(
parameter DATAWIDTH=8
)
(
input clk ,
input rstn ,
input en ,
output wire ready ,
input [DATAWIDTH-1:0] dividend ,
input [DATAWIDTH-1:0] divisor ,
output wire [DATAWIDTH-1:0] quotient ,
output wire [DATAWIDTH-1:0] remainder,
output wire vld_out
);
reg [DATAWIDTH*2-1:0] dividend_e ;
reg [DATAWIDTH*2-1:0] divisor_e ;
reg [DATAWIDTH-1:0] quotient_e ;
reg [DATAWIDTH-1:0] remainder_e;
reg [1:0] current_state,next_state;
reg [DATAWIDTH-1:0] count;
parameter IDLE =2'b00 ,
SUB =2'b01 ,
SHIFT=2'b10 ,
DONE =2'b11 ;
always@(posedge clk or negedge rstn)
if(!rstn) current_state <= IDLE;
else current_state <= next_state;
always @(*) begin
next_state <= 2'bx;
case(current_state)
IDLE: if(en) next_state <= SUB;
else next_state <= IDLE;
SUB: next_state <= SHIFT;
SHIFT:if(count<DATAWIDTH) next_state <= SUB;
else next_state <= DONE;
DONE: next_state <= IDLE;
endcase
end
always@(posedge clk or negedge rstn) begin
if(!rstn)begin
dividend_e <= 0;
divisor_e <= 0;
quotient_e <= 0;
remainder_e <= 0;
count <= 0;
end
else begin
case(current_state)
IDLE:begin
dividend_e <= {{DATAWIDTH{1'b0}},dividend};
divisor_e <= {divisor,{DATAWIDTH{1'b0}}};
end
SUB:begin
if(dividend_e>=divisor_e)begin
quotient_e <= {quotient_e[DATAWIDTH-2:0],1'b1};
dividend_e <= dividend_e-divisor_e;
end
else begin
quotient_e <= {quotient_e[DATAWIDTH-2:0],1'b0};
dividend_e <= dividend_e;
end
end
SHIFT:begin
if(count<DATAWIDTH)begin
dividend_e <= dividend_e<<1;
count <= count+1;
end
else begin
remainder_e <= dividend_e[DATAWIDTH*2-1:DATAWIDTH];
end
end
DONE:begin
count <= 0;
end
endcase
end
end
assign quotient = quotient_e;
assign remainder = remainder_e;
assign ready=(current_state==IDLE)? 1'b1:1'b0;
assign vld_out=(current_state==DONE)? 1'b1:1'b0;
endmodule
testbench:
`timescale 1ns/1ps
module div_fsm_tb();
parameter DATAWIDTH = 16;
reg clk;
reg rstn;
reg en;
wire ready;
reg [DATAWIDTH-1:0] dividend;
reg [DATAWIDTH-1:0] divisor;
wire [DATAWIDTH-1:0] quotient;
wire [DATAWIDTH-1:0] remainder;
wire vld_out;
wire [DATAWIDTH-1:0] quotient_ref; // true result
wire [DATAWIDTH-1:0] remainder_ref;
assign quotient_ref = dividend/divisor;
assign remainder_ref = dividend%divisor;
always #1 clk = ~clk;
integer i;
initial begin
clk = 1;
rstn = 1;
en = 0;
#2 rstn = 0; #2 rstn = 1;
repeat(2) @(posedge clk);
for(i=0;i<10;i=i+1) begin
en <= 1;
dividend <= $urandom()%1000;
divisor <= $urandom()%100;
wait (ready == 1);
wait (vld_out == 1);
end
end
initial begin
$fsdbDumpvars();
$fsdbDumpMDA();
$dumpvars();
#1000 $finish;
end
div_fsm #(
.DATAWIDTH ( DATAWIDTH ))
U_DIV_FSM_0(
.clk ( clk ),
.rstn ( rstn ),
.en ( en ),
.ready ( ready ),
.dividend ( dividend ),
.divisor ( divisor ),
.quotient ( quotient ),
.remainder ( remainder ),
.vld_out ( vld_out )
);
endmodule
仿真波形:
对于16位的数据,计算周期为36。