verilog实现16位硬件除法器(加减交替法定点补码一位除法)

一 设计思路

(一)求商的符号

  1. 若[X]与[Y]同号,[X] - [Y]
    若[X]与[Y]异号(即不够减),[X] + [Y]
  2. 如果所得余数与除数同号,商上1;
    若余数与除数异号,商上0;
    商即结果的符号位。

(二)求商的数值部分

  1. 若[Ri]与[Y]同号,商上“1”,下次操作为:[Ri+1]=2[Ri] - [Y]
  2. 若[Ri]与[Y]异号,商上“0”,下次操作为:[Ri+1]=2[Ri] + [Y]
    如此重复执行n-1次(设数值部分有n位,符号位1位)。

(三)商的最后一位恒置1

商的最后一位一般采用恒置1的办法,并省略了最低位+1的操作,此时最大的误差为±2-n

二 verilog代码

(一)程序代码变量说明

parameter N = 16 // 16位
input [N-1:0] x,y, // 输入:被除数x,除数y,16位单符号位定点小数(1位符号位+15位数值位)
output [N-1:0] quotient); // 输出:商,16位单符号位定点小数(1位符号位+15位数值位)
	
wire [N:0] yy,_y; // 双符号位定点小数表示的[y]补、[-y]补
wire [N:0] xx; // 双符号位定点小数表示的[x]补	
wire [N:0] r[0:2*(N-1)-1]; // 双符号位定点小数表示的余数,共需要2*(N-1)=30次加法、移动操作
wire [N-1:0] q[0:2*(N-1)-1]; // 双符号位定点小数表示的商
wire [N-1:0] remainder; // 最终的余数
wire [N-1:0] q_start0,q_start1; // 初始的商
wire [N:0] ry,r_y,rr; // 初始的余数

(二)程序代码结构说明

1. 除法器

module divider #(parameter N = 16)(
	input [N-1:0] x,y,
	output [N-1:0] quotient);

2. 根据余数和除数的符号进行加法操作和商的操作

module add #(parameter N = 16)(
	input [N:0] r_in,
	input [N-1:0] q_in,
	input [N:0] yy,_y,
	output [N:0] r_out,
	output [N-1:0] q_out);

3. 移位

module move #(parameter N = 16)(
	input [N:0] r_in,
	input [N-1:0] q_in,
	output [N:0] r_out,
	output [N-1:0] q_out);

4. 截取最终的商和余数

module cut #(parameter N = 16)(
	input [N-1:0] q,
	input [N:0] r,
	output [N-1:0] quotient,remainder);

(三)程序代码

组合逻辑,加减交替法定点补码一位除法
软件:Quartus II 9.0

module divider #(parameter N = 16)(
	input [N-1:0] x,y, // 1 bit for sign and 15 bit for number(decimal)
	output [N-1:0] quotient);
	
	wire [N:0] yy,_y; // 2 bit for sign + 15 bit for number
	wire [N:0] xx; // 2 bit for sign + 15 bit for number
	
	wire [N:0] r[0:2*(N-1)-1];
	wire [N-1:0] q[0:2*(N-1)-1];
	wire [N-1:0] remainder;

	// prepare
	assign yy = {y[N-1],y};
	assign _y = ~yy + 1'b1;
	assign xx = {x[N-1],x};
	
	// initialize
	wire [N-1:0] q_start0,q_start1;
	assign q_start0 = {N{1'b0}};
	assign q_start1 = {q_start0[N-1:1],1'b1};
	
	wire [N:0] ry,r_y,rr;
	assign ry = xx + yy;
	assign r_y = xx + _y;
	assign r[0] = (xx[N]==yy[N]) ? r_y : ry;
	assign rr = r[0];
	
	assign q[0] = (rr[N]==yy[N]) ? q_start1 : q_start0; 
	
	move(r[0],q[0],r[1],q[1]);
	
	// add and move
	add(r[1],q[1],yy,_y,r[2],q[2]);
	move(r[2],q[2],r[3],q[3]);
	
	add(r[3],q[3],yy,_y,r[4],q[4]);
	move(r[4],q[4],r[5],q[5]);
	
	add(r[5],q[5],yy,_y,r[6],q[6]);
	move(r[6],q[6],r[7],q[7]);
	
	add(r[7],q[7],yy,_y,r[8],q[8]);
	move(r[8],q[8],r[9],q[9]);
	
	add(r[9],q[9],yy,_y,r[10],q[10]);
	move(r[10],q[10],r[11],q[11]);
	
	add(r[11],q[11],yy,_y,r[12],q[12]);
	move(r[12],q[12],r[13],q[13]);
	
	add(r[13],q[13],yy,_y,r[14],q[14]);
	move(r[14],q[14],r[15],q[15]);
	
	add(r[15],q[15],yy,_y,r[16],q[16]);
	move(r[16],q[16],r[17],q[17]);
	
	add(r[17],q[17],yy,_y,r[18],q[18]);
	move(r[18],q[18],r[19],q[19]);
	
	add(r[19],q[19],yy,_y,r[20],q[20]);
	move(r[20],q[20],r[21],q[21]);
	
	add(r[21],q[21],yy,_y,r[22],q[22]);
	move(r[22],q[22],r[23],q[23]);
	
	add(r[23],q[23],yy,_y,r[24],q[24]);
	move(r[24],q[24],r[25],q[25]);
	
	add(r[25],q[25],yy,_y,r[26],q[26]);
	move(r[26],q[26],r[27],q[27]);
	
	add(r[27],q[27],yy,_y,r[28],q[28]);
	move(r[28],q[28],r[29],q[29]);
	
	cut(q[29],r[29],quotient,remainder);
endmodule

module add #(parameter N = 16)(
	input [N:0] r_in,
	input [N-1:0] q_in,
	input [N:0] yy,_y,
	output [N:0] r_out,
	output [N-1:0] q_out);
	
	wire [N:0] ry,r_y;
	assign ry = r_in + yy;
	assign r_y = r_in + _y;
	assign r_out = (q_in[1]==1) ? r_y : ry;
	
	wire [N-1:0] q;
	assign q = {q_in[N-1:1],1'b1};
	assign q_out = (r_out[N]==yy[N]) ? q : q_in; 
	
endmodule

module move #(parameter N = 16)(
	input [N:0] r_in,
	input [N-1:0] q_in,
	output [N:0] r_out,
	output [N-1:0] q_out);
	
	assign r_out = {r_in[N-1:0],1'b0};
	assign q_out = {q_in[N-2:0],1'b0};
endmodule

module cut#(parameter N = 16)(
	input [N-1:0] q,
	input [N:0] r,
	output [N-1:0] quotient,remainder);
	
	assign quotient = {q[N-1:1],1'b1};
	assign remainder = r[N-1:0];
endmodule

(四)时序模拟图

在这里插入图片描述

被除数x0.50.25-0.25-0.125
除数y0.75-0.50.375-0.4375
商q0.6666564941406250.666656494140625-0.6666564941406250.285736083984375
正确答案0.666666666666666-0.5-0.6666666666666660.285714285714285
误差0.0000101725260410.0000305175781250.0000101725260410.000021798270089

误差均小于最大误差=|2-n|=|2-15|=0.000030517578125

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Verilog补码一位除法设计思路如下: 1. 求商的符号: - 若被除数与除数同号,商的符号为1; - 若被除数与除数异号,商的符号为0; 2. 求商的数值部分: - 若被除数与除数同号,商的数值部分上为1; - 若被除数与除数异号,商的数值部分上为0; - 重复执行n-1次(其中n为数值部分的数),每次操作为:商的数值部分左移一位,并将其与除数做减法运算。 3. 商的最后一位恒置1。 根据这个设计思路,可以编写如下的Verilog代码实现一位补码除法器: ```verilog module one_bit_divider(clk, in1, in2, out, WR, result); input [7:0 in1; // 被除数 input [7:0 in2; // 除数 output reg [7:0 out; // 商 input clk; // 时钟 input WR; // 读写信号 reg flag; reg [8:0 reg_A; reg [8:0 reg_B; reg [8:0 reg_Bfan; reg [7:0 reg_C; reg [4:0 i; output reg [7:0 result; // 结果 always @(posedge clk) begin if (WR == 0) begin reg_A = {in1}; // 初始化被除数 flag = 1; reg_B = {in2}; // 初始化除数 reg_Bfan = ~reg_B + 1; // 求除数的补码 reg_C = 0; // 初始化商 end else if (flag == 1) begin flag = 0; if (reg_A == reg_B == reg_B = 1; // 商的数值部分左移一位,并最低置为1 reg_C = {reg_C = 0; // 商的数值部分左移一位,并最低置为0 reg_C = {reg_C = 1; // 商的最后一位恒置为1 result = reg_C; // 输出结果 end end endmodule ``` 以上是一个基于时序逻辑的Verilog补码一位除法器的代码。通过时钟和读写信号的控制,能够实现对被除数和除数的输入,以及得到商的输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值