Divider design

Posted by ThunderLee on Fri, 25 Feb 2022 04:58:31 +0100

The design idea of the divider is more complex, mainly shift and divide. Put the divisor and the dividend in registers B and A respectively, and then add A shift register R with the same bit width n. 8 'b0 in R is used as the high bit and the data in A is used as the low bit. The operation process requires 2n clock cycles. The process is like this.

(1) Load data A in the first cycle; The counter minus 1 signal is given, and the counter minus 1 in the next cycle indicates that the first shift has been carried out.

(2) In the second cycle, the highest data in A is shifted into R; And make two judgments: judge whether R is greater than or equal to B at this time. If greater than, gate R-B and give the loading LR signal. Load LR in the next cycle. If R is less than B, there is no LR signal, and give ER signal in the next cycle, shift it in the next cycle and compare again; Judge whether the calculation is completed at this time. The completion flag is that the counter returns to zero. If it returns to zero, jump to the completion state. If not, enter the third clock cycle and shift again

(3) In the third cycle, shift A; Give the counter minus 1 signal;

(4) In the fourth cycle, move A[7] into R and judge whether R is greater than or equal to B and whether the calculation ends at this time

After 2n clock cycles, the counter returns to zero to obtain the quotient and remainder.

1. Divider top module

Top level port signal: clock, reset, load data signal LA,EB, calculate trigger signal s, data A, B, output quotient Q, remainder R, completion signal Done.

There are some mistakes:

(1) At the beginning of writing code, after entering state S2 from S1, A is shifted, and then R is shifted. In this process, the highest bit of A is omitted. Therefore, it must be strictly followed that after loading data, ER must be effective first, and A can be shifted in the next cycle after moving into register R. [the shift signal is given immediately after entering S2, but the last state is S1 and S3 is valid, which gives the shift of A, so the highest bit of A in this cycle is actually the initial A[6]]

assign EA = (state==S1&s)|(state==S3);
assign ER = state==S2;

(2) There is a difference between setting the counter to 7 or 8. If it is set to 7, the first shift into RA should be carried out immediately after entering S2. At this time, in S1, because the signal given by s=1 is that EA and ER are both valid, er effectively ensures that the data is moved into the highest bit, and EA effectively ensures that it has been shifted in the next cycle without being shifted once less. Considering that EA is not valid, Er is valid for two consecutive cycles (S1 & S and S2) and shifts twice continuously, but EA is not valid at first, so A=11000110 will maintain two cycles and read the highest bit for two consecutive cycles. Therefore, in this case, EA should also be effective to ensure that the data moved in during the second shift is A[6] (because it is set to 7, and once the cycle S3 is entered, count - 1, count - 1 means that it has been shifted once, 0 = 7-7 means that it has been shifted seven times, and when the initial state = = S1 & S, it is shifted once (in state S2), so R is shifted eight times, which is about to jump out of the cycle. Counters 7 to 0 are correct)

Error condition:

assign EA = (state==S3);//|(state==S1&s);
assign ER = (state==S2)|(state==S1&s);

Correct situation
 

assign EA = (state==S3)|(state==S1&s);
assign ER = (state==S2)|(state==S1&s);

If the counter is set to 8, it should be the following code.

assign EA = (state==S3);
assign ER = (state==S2);

(3) For shift register A, it should be shifted in each cycle of state S2, regardless of whether cout=1 is satisfied in the previous cycle S3.

Error condition

assign EA = (state==S3)&cout;

Correct situation

assign EA = (state==S3);

(4) The reset of R and Q data is determined by done. Done determines the reset of Q. as long as done completes, it will be reset. (done is connected to the La load control signal of the register), R reset is a little more complex. Rsel and LR control the selection signal and load. The valid load can be in state S1 and s=0, or when R-B needs to be loaded (S3 and cout=1). Rsel can load the calculation result R-B only when S3 and cout is 1.

`timescale 1ns/1ps

module Division(Clk,LA,EB,s,R,Q,DataA,DataB,Rst_n,Done);

parameter n = 8;
input Clk,Rst_n,s,LA,EB;
input [n-1:0] DataA,DataB;
input Done;
output wire [n-1:0] R,Q;

parameter S1=2'b00,S2=2'b01,S3=2'b10,S4=2'b11;
reg [1:0] state,next_state;
reg [2:0] cnt;
wire EC;
wire [n-1:0] A;
wire LR,ER,Rsel;
wire [n:0] sum;
wire [n-1:0] adder_a,adder_b;
wire cout;
wire EQ;
reg [n-1:0] B;

always@(*) begin 
case(state)
S1:
	if(s) next_state = S2;
	else next_state = S1;
S2:	
	next_state = S3;
S3:
	if(cnt==0) next_state = S4;
	else next_state = S2;
S4:	if(s) next_state =S4;
	else next_state = S1;
default:;
endcase
end

always@(posedge Clk ,negedge Rst_n) begin
if(~Rst_n)
	state <= S1;
else
	state <= next_state;
end



always@(posedge Clk ,negedge Rst_n ) begin
if(~Rst_n)
	cnt <= 3'd7;
else if (EC)
	cnt <= cnt - 1'b1;
else if (Done)
	cnt <= 3'd7;
end

assign EC = state==S2;
wire [7:0] datax;
assign datax = Rsel?sum[n-1:0]:8'd0;
shiftlne shiftA(.Clk(Clk),.w(1'b0),.La(LA),.A(A),.Data(DataA),.Ea(EA));
shiftlne shiftRA(.Clk(Clk),.w(A[7]),.La(LR),.Ea(ER),.Data(datax),.A(adder_a));

//Adder adder0(.Cin(1'b1),.Cout(cout),.A(adder_a),.B(adder_b),.Sum(sum));
shiftlne shiftQ(.Clk(Clk),.La(~Rst_n|Done),.Ea(EQ),.Data(8'd0),.w(cout),.A(Q));

always@(posedge Clk,negedge Rst_n) begin
if(~Rst_n) 
	B <= 0;
else if(EB)
	B <= DataB;
end

assign adder_b = ~B;
assign EA = (state==S1&s)|(state==S3);
assign ER = (state==S1&s)|state==S2;
assign LR = ((state==S1)&(s==0))|((state==S3)&cout);
assign EQ = state==S3;
assign sum = {1'b0,adder_a}+{1'b0,adder_b}+1'b1;
assign R = adder_a;
assign cout = sum[n];
assign Done = state==S4;
assign Rsel = (state==S3)&(cout); 

endmodule

2. Shift register

`timescale 1ns/1ps 


module shiftlne (Clk,Data,A,La,Ea,w);

parameter n = 8;
input Clk,w;
input [n-1:0] Data;
output reg [n-1:0] A;
input La,Ea;

always@(posedge Clk ) begin 
if(La)
	A <= Data;
else if (Ea)
	A <= {A[14:0],w};
end


endmodule 

3. Test code

`timescale 1ns/1ps
`define clk_period 20

module tb_Div();

reg clk,rst_n,s,la,lb;
reg [7:0] a,b;
//#wire [15:0] p;
wire done;

wire [7:0] q,r;

Division Div0(.Clk(clk),.Rst_n(rst_n),.DataA(a),.DataB(b),.LA(la),.EB(lb),.s(s),.Q(q),.R(r),.Done(done));

initial clk = 1'b1;
always #(`clk_period /2) clk = ~clk;

initial begin 
rst_n = 0 ; la=0;
s = 0 ;
a = 8'd0; b=8'd0;
# (5*`clk_period/2) rst_n =1; 
# 20;a=8'd200;la=1;lb=1;b=8'd20;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(18*`clk_period);
s=0;
#100;

# 20;a=8'd156;la=1;lb=1;b=8'd3;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(18*`clk_period);
s=0;
#100;


# 20;a=8'd5;la=1;lb=1;b=8'd10;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(18*`clk_period);
s=0;
#100;


# 20;a=8'd105;la=1;lb=1;b=8'd10;
#20;a=8'd0;b=8'b0;la=0;lb=0;
s=1;
#(18*`clk_period);
s=0;
#100;


end


initial
begin
  $fsdbDumpfile("Div.fsdb");
  $fsdbDumpvars;
  $fsdbDumpon;
end

initial #5000 $finish;

endmodule

Topics: Single-Chip Microcomputer