假设被除数与除数都是八位数据,这里的算法是:
将被除数,扩展成16位的数据,低8位为被除数的值,高八位的值全为0。有开始信号,对16位数据data赋值,然后开始运算。比较data的高八位和除数的值,如果大于0,说明被除数大,将此时商置1,赋值给data的最低位,然后将被除数高八位减去除数。然后将data向左移位一位,继续比较。最终计算8次后。Data的高8位数据就为所求的余数,低八位就为所求的商。
具体的代码:
module divison_my
#(
parameter W = 16, //扩展的位敊
parameter N = 8 //输入的除数和被除数的位数
)
(
input clk,
input rst_n,
input [N-1:0] dividend, //输入被除敊
input [N-1:0] divisor, //输入除数
input start, //输入开始计算信及
output [N-1:0] quotient, //输出啊
output [N-1:0] remainder, //输出余数
output reg ready, //该信号为1时,才允许开始计箊
output reg busy, //输出忙信及
output reg finish //输出计算借宿信号
);
//reg [N-1:0] dividend;
//reg [N-1:0] divisor;
//always @(posedge clk or negedge rst_n)begin
// dividend<=78;
// divisor<=34;
//end
parameter idle = 3'b000;
parameter start_div = 3'b001;
parameter shift = 3'b010;
parameter done = 3'b110;
reg [2:0] state;
reg [W-1:0] data;
reg [W-1:0] data_reg;
reg [5:0] n_reg; //存储计算的次敊
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state<=idle;
ready<=1'b1;
end
else begin
case(state)
idle:begin
if(start==1'b1 && ready==1'b1)begin
data_reg<=data;
finish<=1'b0;
//if(start==1)begin
//只有在空闲状态,开始信号才有效
state<=shift;
data_reg<={{W-N{1'b0}},dividend}; //赋初倊
n_reg<=N;
end
end
shift:begin
data_reg={data_reg[W-2:0],1'b0}; //注意这里是阻塞赋值=
n_reg<=n_reg-1'b1;
if(data_reg[W-1:N]>=divisor)begin
data_reg[0]<=1'b1;
data_reg[W-1:N]<=data_reg[W-1:N]-divisor;
end
if(n_reg=='d1) //移位结束后,状态跳转
state<=done;
end
done:begin
finish<=1'b1;
ready<=1'b0;
state<=idle;
end
endcase
end
end
//assign quotient = data_reg[N-1:0];
//assign remainder = data_reg[W-1:N];
assign quotient = finish ? data_reg[N-1:0] : quotient;
assign remainder = finish ? data_reg[W-1:N] : remainder;
endmodule
测试文件是:
`timescale 1 ps/ 1 ps
module divison_my_vlg_tst();
// constants
// general purpose registers
// test vector input registers
reg clk;
reg [39:0] dividend;
reg [39:0] divisor;
reg rst_n;
reg start;
// wires
wire busy;
wire finish;
wire [39:0] quotient;
wire ready;
wire [39:0] remainder;
// assign statements (if any)
divison_my i1 (
// port map - connection between master ports and signals/registers
.busy(busy),
.clk(clk),
.dividend(dividend),
.divisor(divisor),
.finish(finish),
.quotient(quotient),
.ready(ready),
.remainder(remainder),
.rst_n(rst_n),
.start(start)
);
always #1 clk = ~clk; //产生时钟
initial begin
clk = 0;
rst_n = 0;
// dividend = 40'd7681245184;
// divisor = 40'd5732674;
dividend = 8'd78;
divisor = 8'd34;
start = 0;
#100 rst_n = 1;
start = 1; //一直开启计算
end
initial begin
#200 $stop;
end
endmodule
最终的仿真结果: