任何人都可以告诉我在连续分割中应该分红和除数的宽度。截至目前,我已经设计了具有WIDTH_DIVID = 2 * wIDTH_DIVIS的分频器。如果我说出这种关系,我的分裂就会失败。谁能帮我这个 我的verilog代码如下所示
// Description: module for serial Divider
// The dividend is loaded into the accumulator along with the guard bit.
// Then the 2's complement of the divisor is added to the upperpart of the
// accumulator along with the guard bit.Then the MSB of the accumulator is
// tested.
// 1. If it is cleared then 1 bit left shift of the accumulator is done and
// one is concantinated to the LSB of the accumulator.
// 2. If is is not cleared then the accumulator contents are shifted 1 bit
// left.
// After the division upper part of the accumulator contains the remainder
// and lower part contains the quotient.
// --------------------------------------------- -----------------------------
module division(//global inputs
i_clk,i_rst,
//outputs
o_quotient,o_remainder,o_done,o_overflow,
//input
i_dividend,i_divisor,i_start
);
//parameter declarations
parameter DIVIS_WIDTH =2; //width for divisor
parameter DIVID_WIDTH =2*DIVIS_WIDTH; //width for dividend,DIVID_WIDTH=2*DIVIS_WIDTH
localparam NPOWER = 6; //divisor width<=2**NPOWER
localparam NULL_VECTOR_S=32'h00000000;
localparam S0= 2'd0;
localparam S1= 2'd1;
localparam S2= 2'd2;
//global inputs
input i_clk;
input i_rst;
//outputs
output reg [DIVIS_WIDTH:0] o_quotient;
output reg [DIVIS_WIDTH-1:0] o_remainder;
output reg o_overflow;
output reg o_done;
//input
input [DIVID_WIDTH-1:0] i_dividend;
input [DIVIS_WIDTH-1:0] i_divisor;
input i_start; //indicates start of division
// reg and wire declarations
reg [DIVID_WIDTH:0] dividend_i; //Add extra guard bit
reg [DIVIS_WIDTH:0] divisor_i; //Add extra guard bit
reg [DIVIS_WIDTH-1:0] divisor_rect_i; //divisor used to check overflow
wire signquot_i; //Sign of quotient
wire signremain_i; //Sign of remainder
reg [DIVID_WIDTH+DIVIS_WIDTH-1:0] accumulator_i; // Shift register which holds both remainder and quotient
reg [DIVIS_WIDTH:0] aluout_i; //Used to add the upperpart of the shift register and the divisor
reg [NPOWER-1:0] count_i; //No.of iterations
reg pos_i;
reg neg_i;
reg [2:0] state;
reg [2:0] nextstate;
reg done_i;
//Sign product of quotient and remainder
assign signquot_i=((i_dividend[DIVID_WIDTH-1] ^ i_divisor[DIVIS_WIDTH-1]));
assign signremain_i=(i_dividend[DIVID_WIDTH-1]);
always@(posedge i_clk or posedge i_rst)
begin
if(i_rst==1)begin
dividend_i<=0;
divisor_i<=0;
divisor_rect_i<=0;
end else begin
divisor_rect_i<=i_divisor;
dividend_i<=({1'b0,i_dividend});
divisor_i<=(~({1'b0,i_divisor})+1);
end
end // else: !if(i_rst==1)
//Sequential Division
always@(posedge i_clk or posedge i_rst)
begin
if (i_rst==1)
accumulator_i <=0;
else begin
if(i_start==1)
accumulator_i<={dividend_i[DIVID_WIDTH-1:0],1'b0}; // Load Dividend in shift register
else if(pos_i==1)
accumulator_i<=({aluout_i[DIVIS_WIDTH-1:0],accumulator_i[DIVID_WIDTH-DIVIS_WIDTH-1:0],1'b1});//({newaccu_i[DIVID_WIDTH-1:0],1'b1});//shiting the new register value by one bit left and concantinatinf one at the LSB
else if(neg_i==1)
accumulator_i<=({accumulator_i[DIVID_WIDTH-1:0],1'b0});//Use the previous register value and shift 1 bit left
end
end // always@ (posedge i_clk or posedge i_rst or posedge i_start)
//Adding the divisor to the upper part of the Shift register
always@(accumulator_i,divisor_i)
begin
aluout_i<=accumulator_i[DIVID_WIDTH : DIVID_WIDTH-DIVIS_WIDTH]+ divisor_i;
// newaccu_i<= ({aluout_i, accumulator_i[DIVID_WIDTH-DIVIS_WIDTH-1:0]});
end
//Control of states for division
always@(posedge i_clk or posedge i_rst)
begin
if (i_rst == 1) begin
state <= S0;
count_i <=0;
end else begin
state <= nextstate;
if (state==S1)
count_i <= count_i - 1;
else if (state==S0)
count_i <= (DIVIS_WIDTH);
end
end // always@ (posedge i_clk or posedge i_rst)
//generating the control signals pos_i and neg_i to control division
always@(state,i_start,aluout_i,count_i)
begin
case (state)
S0 :begin
pos_i <= 0;
neg_i <= 0;
if (i_start==1)
nextstate <= S1;
else
nextstate <= S0;
end
S1 : begin
neg_i <= aluout_i[DIVIS_WIDTH];
pos_i <= ~(aluout_i[DIVIS_WIDTH]);
if (count_i==NULL_VECTOR_S[NPOWER_WIDTH-1])
nextstate <= S2; // Done
else
nextstate <= S1;// Next sub&shift
end
S2 : begin
pos_i <= 0;
neg_i <= 0;
nextstate <= S0;
end
default: begin
pos_i <= 0;
neg_i <= 0;
nextstate <= S0;
end
endcase // case (state)
end // always@ (state,i_start,aluout_i,count_i)
//done signal to indicate end of division
always@(posedge i_clk or posedge i_rst)
begin
if(i_rst==1) begin
done_i<= 0;
end else begin
done_i <= (count_i==1)? 1'b1 : 1'b0;
end
end
//Assigning the outputs for unsigned division
always@(accumulator_i,done_i)
begin
o_done<=done_i;
o_remainder<=accumulator_i[DIVID_WIDTH:DIVID_WIDTH-DIVIS_WIDTH+1];
o_quotient<=(accumulator_i[DIVIS_WIDTH:0]);
o_overflow<=(((accumulator_i[DIVID_WIDTH:DIVID_WIDTH-DIVIS_WIDTH+1])>=divisor_rect_i))? 1'b1 : 1'b0;
end
endmodule // division
答案 0 :(得分:1)
只是要明确使用的术语:
a÷b = c,a称为被除数或除数,b为除数或 分母和结果c称为商
来源Wikipedia。
被除数(分子)和除数(分母)的输入宽度将决定商的大小。将lsbs(小数位)添加到输入将增加商的精度。
最终所需宽度应与使用/
运算符相同。尝试在代码旁边运行此代码以帮助发现错误。对于所需的宽度计算,我强烈建议在纸上进行一些示例。首先划分4位数字,然后向上移动到更大的数字5,6位,以了解位增长的模式。
答案 1 :(得分:0)
这是系统verilog中的参数化串行分隔符。
// returns max value ('1) if divide by zero or overflow occurs.
module unsigned_serial_divide #(
parameter N_WIDTH = 16 // Size of dividend
,parameter D_WIDTH = 16 // Size of divisor
,parameter Q_WIDTH = 16 // Size of quotient
,parameter F_WIDTH = 0 // Number of fractional bits in quotient.
)(
input wire clk
,input wire reset
,input wire go // hold high for continuous calculation or stobe high for single calculation
,input wire [N_WIDTH-1:0] dividend
,input wire [D_WIDTH-1:0] divisor
,output reg [Q_WIDTH-1:0] quotient // maintains last complete calculation.
//,output wire overflow // NOT IMPLEMENTED
,output wire done // stobes high if go is held high or indicated when single calculation complete
);
localparam COUNT_WIDTH = $clog2(Q_WIDTH);
localparam [COUNT_WIDTH-1:0] DIVIDE_COUNTS = (COUNT_WIDTH)'(Q_WIDTH - 1'b1);
localparam WN_WIDTH = N_WIDTH + F_WIDTH;
localparam WD_WIDTH = D_WIDTH + DIVIDE_COUNTS;
localparam CALC_WIDTH = ((WN_WIDTH > WD_WIDTH) ? WN_WIDTH : WD_WIDTH) + 1;
reg busy;
reg [COUNT_WIDTH-1:0] divide_count;
reg [WN_WIDTH-1:0] working_dividend;
reg [WD_WIDTH-1:0] working_divisor;
reg [Q_WIDTH-1:0] working_quotient;
initial begin
busy <= 0;
divide_count <= 0;
working_dividend <= 0;
working_divisor <= 0;
working_quotient <= 0;
quotient <= 0;
end
// Subtract with sign bit
wire [CALC_WIDTH-1:0] subtract_calc = {1'b0, working_dividend} - {1'b0, working_divisor};
// subtract_positive = (working_dividend > working_divisor);
wire subtract_positive = ~subtract_calc[CALC_WIDTH-1];
// if the next bit in quotient should be set then subtract working_divisor from working_dividend
wire [WN_WIDTH-1:0] dividend_next = (subtract_positive) ? subtract_calc[WN_WIDTH-1:0] : working_dividend;
wire [WD_WIDTH-1:0] divisor_next = working_divisor >> 1;
wire [Q_WIDTH-1:0] quotient_next = (working_quotient << 1) | (subtract_positive);
always @(posedge clk or posedge reset) begin
if (reset) begin
busy <= 0;
divide_count <= 0;
working_dividend <= 0;
working_divisor <= 0;
working_quotient <= 0;
quotient <= 0;
end else begin
if (go & ~busy) begin
busy <= 1;
divide_count <= DIVIDE_COUNTS;
working_dividend <= dividend << F_WIDTH; // scale the numerator up by the fractional bits
working_divisor <= divisor << DIVIDE_COUNTS; // align divisor to the quotient
working_quotient <= 0;
end else begin
if (divide_count == 0) begin
if (busy == 1) begin
quotient <= quotient_next;
end
busy <= 0;
end else begin
divide_count <= divide_count - 1'b1;
end
working_dividend <= dividend_next;
working_divisor <= divisor_next;
working_quotient <= quotient_next;
end
end
end
assign done = ~busy;
endmodule