verilog 任意位宽除法代码
废话不多说,直接贴代码:
`timescale 1ns / 1ps
module Divider_Module#(
parameter EXT_DIVIDEND_WIDTH = 'd8 ,
parameter EXT_DIVISOR_WIDTH = 'd8 ,
parameter DIVIDEND_WIDTH = EXT_DIVIDEND_WIDTH ,
parameter DIVISOR_WIDTH = EXT_DIVISOR_WIDTH + 1 ,
parameter DIV_WIDTH = DIVIDEND_WIDTH + DIVISOR_WIDTH ,
parameter DIV_STEP = DIVIDEND_WIDTH + 1'd1 ,
parameter WIDTH_DIVIDEND_DATA = DIV_WIDTH * DIV_STEP ,
parameter WIDTH_DIVISOR_DATA = DIVISOR_WIDTH * DIV_STEP
)(
input i_sys_clk ,
input i_sys_reset ,
//----------------------------------------------------------
input [DIVIDEND_WIDTH-1:0] i_dividend_data ,
input [DIVISOR_WIDTH-1:0] i_divisor_data ,
input i_divider_valid ,
//----------------------------------------------------------
output [DIVIDEND_WIDTH-1:0] o_quotient_data ,
output [DIVISOR_WIDTH-1:0] o_remainder_data ,
output o_calculate_valid
);
reg [WIDTH_DIVIDEND_DATA- 1 :0] r_dividend_data_step ;
reg [WIDTH_DIVISOR_DATA - 1 :0] r_divisor_data_step ;
reg [DIV_STEP - 1 :0] r_valid ;
always@(posedge i_sys_clk)begin
if(i_sys_reset == 'd1)begin
r_dividend_data_step[DIV_WIDTH-1:0] <= 'd0 ;
r_divisor_data_step[DIVISOR_WIDTH-1:0] <= 'd0 ;
r_valid[0] <= 'd0 ;
end
else begin
r_dividend_data_step[15:0] <= i_dividend_data ;
r_divisor_data_step[7:0] <= i_divisor_data ;
r_valid[0] <= i_divider_valid ;
end
end
parameter SIZE = DIV_STEP;
genvar i;
generate
for(i=1;i<SIZE;i=i+1)
begin:div
always@(posedge i_sys_clk)begin
if(i_sys_reset == 'd1)begin
r_dividend_data_step[(i+1)*DIV_WIDTH-1:i*DIV_WIDTH] <= 'd0;
r_divisor_data_step[(i+1)*DIVISOR_WIDTH-1:i*DIVISOR_WIDTH] <= 'd0;
r_valid[i] <= 'd0;
end
else begin
if(r_dividend_data_step[i*DIV_WIDTH-2:i*DIV_WIDTH - DIVISOR_WIDTH-1] >= r_divisor_data_step[i*DIVISOR_WIDTH-1:(i-1)*DIVISOR_WIDTH])
r_dividend_data_step[(i+1)*DIV_WIDTH-1:i*DIV_WIDTH] <=
{r_dividend_data_step[i*DIV_WIDTH-2:i*DIV_WIDTH - DIVISOR_WIDTH - 1]-r_divisor_data_step[i*DIVISOR_WIDTH-1:(i-1)*DIVISOR_WIDTH],
r_dividend_data_step[i*DIV_WIDTH - DIVISOR_WIDTH - 2:(i-1)*DIV_WIDTH],1'd1} ;
else
r_dividend_data_step[(i+1)*DIV_WIDTH-1:i*DIV_WIDTH] <= r_dividend_data_step[i*DIV_WIDTH-1:(i-1)*DIV_WIDTH]<<1 ;
r_divisor_data_step[(i+1)*DIVISOR_WIDTH-1:i*DIVISOR_WIDTH] <= r_divisor_data_step[i*DIVISOR_WIDTH-1:(i-1)*DIVISOR_WIDTH] ;
r_valid[i] <= r_valid[i-1] ;
end
end
end
endgenerate
assign o_quotient_data = r_dividend_data_step[SIZE*DIV_WIDTH - DIVISOR_WIDTH - 1:(SIZE-1)*DIV_WIDTH] ;
assign o_remainder_data = r_dividend_data_step[SIZE*DIV_WIDTH - 1:SIZE*DIV_WIDTH - DIVISOR_WIDTH] ;
assign o_calculate_valid = r_valid [SIZE - 1] ;
endmodule
说明:全流水除法电路,消耗资源较多,但是保证了高流量,我简单仿真了几下,没有问题,当除数出现错误,为0时,我直接将valid拉低,仿真代码如下:
`timescale 1ns / 1ps
module sim_div();
parameter DIVIDEND_WIDTH = 'd8 ;
parameter DIVISOR_WIDTH = 'd8 ;
parameter DIV_TEST_RANGE = 'd250 ;
reg r_sys_clk ;
reg r_sys_reset ;
reg [DIVIDEND_WIDTH-1:0] r_dividend_data ;
reg [DIVISOR_WIDTH-1:0] r_divisor_data ;
reg r_divider_valid ;
wire [DIVIDEND_WIDTH-1:0] w_quotient_data ;
wire [DIVISOR_WIDTH-1:0] w_remainder_data ;
wire w_calculate_valid ;
initial begin
r_sys_clk = 'd0;
r_sys_reset = 'd1;
r_dividend_data = 'd0;
r_divisor_data = 'd0;
r_divider_valid = 'd1;
#200;
r_sys_reset = 'd0;
#400;
test_div();
#500;
$finish;
end
always#5 r_sys_clk = ~r_sys_clk;
task test_div();
integer i,j;
begin
for(i=1;i<DIV_TEST_RANGE;i=i+1)begin
for(j=i;j<DIV_TEST_RANGE;j=j+1)begin
repeat(1)@(posedge r_sys_clk);
r_dividend_data = j;
r_divisor_data = i;
end
end
end
endtask
Divider_Module #(
.DIVIDEND_WIDTH(DIVIDEND_WIDTH),
.DIVISOR_WIDTH(DIVISOR_WIDTH)
)Divider_Module_inst(
.i_sys_clk (r_sys_clk ),
.i_sys_reset (r_sys_reset ),
.i_dividend_data (r_dividend_data ),
.i_divisor_data (r_divisor_data ),
.i_divider_valid (r_divider_valid ),
.o_quotient_data (w_quotient_data ),
.o_remainder_data (w_remainder_data ),
.o_calculate_valid (w_calculate_valid )
);
endmodule
算法参考:
https://blog.csdn.net/qishi2014/article/details/51945027