当前位置:   article > 正文

Verilog实现二进制乘除法器_verilog二进制乘法器

verilog二进制乘法器

一、乘法器

1.无符号数运算法则

无符号数二进制乘法运算法则:按位相乘,再按位进行二进制加法在这里插入图片描述

2.有符号数运算法则

有符号数二进制乘法运算法则:乘数与被乘数进行符号位扩展,再按照无符号数进行二进制乘法
在这里插入图片描述

(1)Verilog实现方法

从有符号数和无符号数的运算法则来看,二进制乘法可以使用移位寄存器来实现。

实现方法:
	1.被乘数左移,乘数右移
	2.当乘数的最低位为1时,进行加法操作
    3.通过(乘数=1)来控制循环(乘法)是否结束
  • 1
  • 2
  • 3
  • 4

(2)状态机

在这里插入图片描述

(3)代码

`timescale	1ns/1ns
module mul_binary(
	input		wire						sclk,
	input		wire						rst_n,
	input		wire						start,
	input		wire [7:0]					data_a,
	input		wire [7:0]					data_b,
	output		reg							prd_vld,//product is valid
	output		reg [15:0]					product							
);

reg		add_shift;
reg		shift;
reg		load_data;
reg		prd_vld_r;
wire	M_eq_1;
wire	m0;

reg	[15:0]	multiplicand;
reg	[15:0]	multiplier;

parameter	S_idle=2'b01;
parameter	S_cal=2'b10;

reg	[1:0]	state,next_state;

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	state<=S_idle;
	else	state<=next_state;
end

always	@(*)begin
	add_shift=1'b0;shift=1'b0;
	load_data=1'b0;prd_vld_r=1'b0;
	next_state=S_idle;
	case(state)
		S_idle:begin
			if(start==1'b1)	begin
				next_state=S_cal;
				load_data=1'b1;
			end
			else	next_state=S_idle;
		end
		S_cal:begin
			if(M_eq_1==1'b1)begin
				add_shift=1'b1;prd_vld_r=1'b1;
				next_state=S_idle;
			end
			else	begin
				next_state=S_cal;
				if(m0==1'b1)	add_shift=1'b1;
				else	shift=1'b1;	
			end
		end
		default:next_state=S_idle;
	endcase
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		multiplicand<=16'd0;
		multiplier<=16'd0;
		product<=16'd0;
	end
	else	if(load_data==1'b1)begin
		multiplicand<={{8{data_a[7]}},data_a};
		multiplier<={{8{data_b[7]}},data_b};
		product<=16'd0;
	end
	else	if(add_shift==1'b1)begin
		multiplier<=multiplier>>1;
		multiplicand<=multiplicand<<1;
		product<=product+multiplicand;
	end
	else	if(shift==1'b1)begin
		multiplier<=multiplier>>1;
		multiplicand<=multiplicand<<1;
	end
end


always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	prd_vld<=1'b0;
	else	prd_vld<=prd_vld_r;
end


assign	m0=multiplier[0];
assign	M_eq_1=(multiplier==1'b1) ? 1'b1:1'b0;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

仿真结果:
在这里插入图片描述

3.booth编码

booth编码方法通过将被乘数按照一定的方式进行编码而乘数保持不变,然后进行乘法运算。booth编码算法:

该算法从乘数最低位到最高位依次读取,两个相邻位(mi,mi-1)的值确定了Booth重编码乘数的各个位:BRCi。
该算法的第一步是在乘数的最右边置一位0。
  • 1
  • 2

booth编码规则

mimi-1BRCi操作状态
0000移位全0字符串
0111移位相加末尾为1的字符串
101(-)2移位相减开始为1的字符串
1103移位中间全1字符串

适用范围:该算法适用于全部范围的补码数(包括最高位为1/0)

(1)booth编码例子

在这里插入图片描述
按照二进制乘法,乘以-65需要进行7次加法操作;
booth编码,乘以-65需要进行1次加法,两次减法操作;

(2)实现方法

1.被乘数左移,乘数右移
2.根据乘数最低位进行booth编码,当BRC=2'b01时进行加法操作,当BRC=2'b10时进行减法
3.根据(乘数=1)来控制循环(乘法)是否结束
4.最后需要判断乘数是否为负数:
	(1)如果为负数,(乘数=1)则表示计算结束
    (2)如果为正数,(乘数=1)则表示此时乘数还剩2bit(2'b01),则还进行一次加法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

(3)状态机

在这里插入图片描述

(4)代码

`timescale	1ns/1ns
module mul_booth(
	input		wire						sclk,
	input		wire						rst_n,
	input		wire						start,
	input		wire	[7:0]				data_a,
	input		wire	[7:0]				data_b,
	output		reg		[15:0]				product,
	output		reg							prd_vld
);

parameter	S_idle=3'b001;
parameter	S_cal=3'b010;
parameter	S_jud=3'b100;

reg	[15:0]	multiplicand;
reg	[7:0]	multiplier;

reg			shift,add,sub;
reg			prd_vld_r,m0_del,load_data;
wire		m0,M_eq_1,datab_is_neg;
wire [1:0]	BRC;

reg	[2:0]	state,next_state;

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	m0_del<=1'b0;
	else	if(load_data==1'b1)
		m0_del<=1'b0;//LSB=0
	else	
		m0_del<=m0;
end

assign	BRC={m0,m0_del};


always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	state<=S_idle;
	else	state<=next_state;
end

always	@(*)begin
	shift=1'b0;add=1'b0;sub=1'b0;
	prd_vld_r=1'b0;load_data=1'b0;
	next_state=S_idle;
	case(state)
		S_idle:begin
			if(start==1'b1)	begin
				next_state=S_cal;
				load_data=1'b1;
			end
			else	next_state=S_idle;
		end
		S_cal:begin
			if(M_eq_1==1'b0)begin
				case(BRC)
					2'd0,2'd3:begin
						shift=1'b1;
						next_state=S_cal;
					end
					2'd1:begin
						add=1'b1;shift=1'b1;
						next_state=S_cal;
					end
					2'd2:begin
						sub=1'b1;shift=1'b1;
						next_state=S_cal;
					end
					default:next_state=S_idle;
				endcase
			end
			else	begin
				case(BRC)
					2'd2:begin
						sub=1'b1;shift=1'b1;
						next_state=S_jud;
					end
					2'd3:begin
						shift=1'b1;
						next_state=S_jud;
					end
					default:next_state=S_idle;
				endcase
			end
		end
		S_jud:begin
			case(BRC)
				2'd0,2'd2,2'd3:begin
					prd_vld_r=1'b1;
					next_state=S_idle;
				end
				2'd1:begin
					if(datab_is_neg==1'b0)begin
						add=1'b1;shift=1'b1;prd_vld_r=1'b1;
						next_state=S_idle;
					end
					else	begin
						prd_vld_r=1'b1;
						next_state=S_idle;
					end
				end
			endcase
		end
		default:next_state=S_idle;
	endcase
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		multiplier<=8'd0;
		multiplicand<=16'd0;
		product<=8'd0;
	end
	if(load_data==1'b1)begin
		multiplier<=data_b;
		multiplicand<={{8{data_a[7]}},data_a};
		product<=16'd0;
	end
	if(shift==1'b1)begin
		multiplier<=multiplier>>1;
		multiplicand<=multiplicand<<1;
	end
	if(add==1'b1)	product<=product+multiplicand;
	if(sub==1'b1)	product<=product-multiplicand;
end

assign	m0=multiplier[0];
assign	M_eq_1=(multiplier==8'd1)? 1'b1:1'b0;
assign	datab_is_neg=(data_b[7]==1'b1)? 1'b1:1'b0;

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	prd_vld<=1'b0;
	else	prd_vld<=prd_vld_r;
end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135

仿真结果
在这里插入图片描述

4.BPE编码(比特对编码)

比特对编码又称为基4编码,比特对编码可以将加法次数由n减少到n/2,提高乘法运算速度。

该算法从乘数最低位到最高位依次读取,三个相邻位(mi+1,mi,mi-1)的值确定了BPE重编码乘数的各个位:BPEi。
该算法的第一步是在乘数的最右边置一位0。如果编码数的字节为奇数,则高位进行符号位扩展
  • 1
  • 2

BPE编码规则

mi+1mimi-1CodeBRCi+1BRCi操作状态
0000000全0字符串移两位
001101+1末尾为1的字符串移位相加
010201+1单个1的字符串移位相加
011310+2末尾为1的字符串移一位,相加,移一位
10041(-)0-2开始为1的字符串移一位,相加,移一位
101501(-)-1单个0的字符串移位相减
110601(-)-1开始为1的字符串移位相减
1117000全1字符串移两位

适用范围:该算法适用于全部范围的补码数(包括最高位为1/0)

(1)BPE编码例子

在这里插入图片描述
按照该编码方法,8bit字节进行4次编码运算

(2)实现方法

1.被乘数左移,乘数右移
2.根据乘数最低位进行bpe编码,当bpe=0~7时,分别进行相应的计算
3.根据运算次数(8bit字节编码次数为4)来控制循环(乘法)是否结束
  • 1
  • 2
  • 3

(3)状态机

在这里插入图片描述

(4)代码

`timescale	1ns/1ns
module mul_BPE(
	input		wire						sclk,
	input		wire						rst_n,
	input		wire						start,
	input		wire [7:0]					data_a,
	input		wire [7:0]					data_b,
	output		reg	 [15:0]					product,
	output		reg							prd_vld
);

parameter	S_idle=4'b0001;
parameter	S_cal=4'b0010;
parameter	S_wait1=4'b0100;
parameter	S_wait2=4'b1000;

reg	[3:0]	state,next_state;

reg	[15:0]	multiplicand;
reg	[7:0]	multiplier;

reg	[2:0]	bpe_counter;

reg		load_data;
reg		shift_2,shift_1;
reg		add,sub;
reg		inc_bpe_counter,clr_bpe_counter;

wire [1:0]	m_1_0;
reg			m0_del;
wire [2:0]	BPE;

wire		BC_lt_4;

assign	BPE={m_1_0,m0_del};

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	state<=S_idle;
	else	state<=next_state;
end

always	@(*)begin
	load_data=1'b0;prd_vld=1'b0;
	shift_2=1'b0;shift_1=1'b0;
	add=1'b0;sub=1'b0;
	inc_bpe_counter=1'b0;clr_bpe_counter=1'b0;
	next_state=S_idle;
	case(state)
		S_idle:begin
			if(start==1'b1)	begin
				load_data=1'b1;
				next_state=S_cal;
			end
			else	next_state=S_idle;
		end
		S_cal:begin
			if(BC_lt_4==1'b1)begin
				case(BPE)
					3'd0,3'd7:begin
						shift_2=1'b1;inc_bpe_counter=1'b1;
						next_state=S_cal;
					end
					3'd1,3'd2:begin
						shift_2=1'b1;add=1'b1;inc_bpe_counter=1'b1;
						next_state=S_cal;
					end
					3'd3:begin
						shift_1=1'b1;
						next_state=S_wait1;
					end
					3'd4:begin
						shift_1=1'b1;
						next_state=S_wait2;
					end
					3'd5,3'd6:begin
						shift_2=1'b1;sub=1'b1;inc_bpe_counter=1'b1;
						next_state=S_cal;
					end
				endcase
			end
			else	begin
				clr_bpe_counter=1'b1;prd_vld=1'b1;
				next_state=S_idle;
			end
		end
		S_wait1:begin
			shift_1=1'b1;add=1'b1;inc_bpe_counter=1'b1;
			next_state=S_cal;
		end
		S_wait2:begin
			shift_1=1'b1;sub=1'b1;inc_bpe_counter=1'b1;
			next_state=S_cal;
		end
		default:next_state=S_idle;
	endcase
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		multiplicand<=16'd0;
		multiplier<=8'd0;
		product<=16'd0;
		m0_del<=1'b0;
	end
	if(load_data==1'b1)	begin
		multiplicand<={{8{data_a[7]}},data_a};
		multiplier<=data_b;
		product<=16'd0;
		m0_del<=1'b0;
	end
	if(shift_1==1'b1)begin
		multiplicand<=multiplicand<<1;
		{multiplier,m0_del}<={multiplier,m0_del}>>1;
		end
	if(shift_2==1'b1)begin
		multiplicand<=multiplicand<<2;
		{multiplier,m0_del}<={multiplier,m0_del}>>2;
	end
	if(add==1'b1)	product<=product+multiplicand;
	if(sub==1'b1)	product<=product-multiplicand;
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	bpe_counter<=3'd0;
	else	if(inc_bpe_counter==1'b1)
		bpe_counter<=bpe_counter+1'b1;
	else	if(clr_bpe_counter==1'b1)
		bpe_counter<=3'd0;
end

assign	m_1_0=multiplier[1:0];
assign	BC_lt_4=(bpe_counter<3'd4)? 1'b1:1'b0;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

仿真结果
在这里插入图片描述

二、除法器

除法器的实现是通过被除数不断减去除数实现的

1.基本除法器结构

两个无符号二进制数除法的时序算法是:被除数不断减去除数,直到被除数小于除数。其中商=减法执行的次数,余数=计算完成时被除数的剩余值。该除法器包括的基本结构:
	(1)减法器
	(2)比较器(用于比较被除数与除数,控制除法运算是否结束)
另外一种设计方法可以不使用比较器来控制除法运算,该方法将减法运算等价为加法(-5=+(-5)),然后通过加法器的进位来判断被除数与除数的大小,如:
5-3:5-3=5+(-3)  5=4'b0101  -3=4'b1101  5+(-3)=4'b0101+4'b1101=5'b1_0010
3-5:3-5=3+(-5)  3=4'b0011  -5=4'b1011  3+(-5)=4'b0011+4'b1011=5'b0_1110
则:
	当被减数>减数时,补码相加会产生进位  
	当被减数<减数时,补码相加不会产生进位
因此当采用补码加法来进行除法运算时,除法器包括的基本结构为:
	(1)加法器
    (2)反相器(被除数不断减去除数时,将除数取反,进行补码加法)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.实现方法

除法器实现方法:
	(1)设置与被除数相同位宽的商寄存器和余数寄存器,分别用于存放商与余数
    (2)执行一次减法,商寄存器自加一次
    (3)通过(被除数<除数)控制除法结束,余数=计算结束时被除法
  • 1
  • 2
  • 3
  • 4

3.状态机

在这里插入图片描述

4.代码

`timescale	1ns/1ns
module binary_div(
	input		wire						sclk,
	input		wire						rst_n,
	input		wire						start,
	input		wire [7:0]					data_a,
	input		wire [3:0]					data_b,
	output		wire [7:0]					reminder,
	output		reg	 [7:0]					quotient,
	output		reg							error,
	output		reg							ou_vld
);

parameter	S_idle=2'b01;
parameter	S_work=2'b10;

reg	[1:0]	state,next_state;

reg	[7:0]	dividend;
reg	[3:0]	divisor;

wire		divr_is_0,divd_is_0;
wire		dvir_lt_divd,carry;
wire[7:0]	difference;
reg			load_data,sub;

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	state<=S_idle;
	else	state<=next_state;
end

always	@(*)begin
	error=1'b0;ou_vld=1'b0;
	load_data=1'b0;sub=1'b0;
	next_state=S_idle;
	case(state)
		S_idle:begin
			if(start==1'b1)begin
				if(divr_is_0==1'b1)begin
					error=1'b1;
					next_state=S_idle;
				end
				else	begin
					if(divd_is_0==1'b1)begin
						ou_vld=1'b1;
						next_state=S_idle;
					end
					else	begin
						load_data=1'b1;
						next_state=S_work;
					end
				end
			end
			else	next_state=S_idle;
		end
		S_work:begin
			if(dvir_lt_divd==1'b1)begin
				sub=1'b1;
				next_state=S_work;
			end
			else	begin
				ou_vld=1'b1;
				next_state=S_idle;
			end
		end
		default:next_state=S_idle;
	endcase
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		dividend<=8'd0;
		divisor<=4'd0;
		quotient<=8'd0;
	end
	else	if(load_data==1'b1)begin
		dividend<=data_a;
		divisor<=data_b;
		quotient<=8'd0;
	end
	else	if(sub==1'b1)begin
		dividend<=dividend+1'b1+{{4{1'b1}},~divisor};//buma
		quotient<=quotient+1'b1;
	end
end
assign	reminder=(ou_vld==1'b1)? dividend:8'd0;
assign	divr_is_0=(data_b==4'd0)? 1'b1:1'b0;
assign	divd_is_0=(data_a==8'd0)? 1'b1:1'b0;
assign	{carry,difference}=dividend+1'b1+{{4{1'b1}},~divisor};
assign	dvir_lt_divd=(carry==1'b1)? 1'b1:1'b0;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

仿真结果
在这里插入图片描述

三、参考文献

1.Verilog实现二进制有符号定点数的乘法运算
2.符号定点二进制小数(Qn format)乘法原理
3.《VERILOG HDL 高等数字设计 第2版》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/522332
推荐阅读
相关标签
  

闽ICP备14008679号