赞
踩
无符号数二进制乘法运算法则:按位相乘,再按位进行二进制加法
有符号数二进制乘法运算法则:乘数与被乘数进行符号位扩展,再按照无符号数进行二进制乘法
从有符号数和无符号数的运算法则来看,二进制乘法可以使用移位寄存器来实现。
实现方法:
1.被乘数左移,乘数右移
2.当乘数的最低位为1时,进行加法操作
3.通过(乘数=1)来控制循环(乘法)是否结束
`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
仿真结果:
booth编码方法通过将被乘数按照一定的方式进行编码而乘数保持不变,然后进行乘法运算。booth编码算法:
该算法从乘数最低位到最高位依次读取,两个相邻位(mi,mi-1)的值确定了Booth重编码乘数的各个位:BRCi。
该算法的第一步是在乘数的最右边置一位0。
booth编码规则
mi | mi-1 | BRCi | 值 | 操作 | 状态 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 移位 | 全0字符串 |
0 | 1 | 1 | 1 | 移位相加 | 末尾为1的字符串 |
1 | 0 | 1(-) | 2 | 移位相减 | 开始为1的字符串 |
1 | 1 | 0 | 3 | 移位 | 中间全1字符串 |
适用范围:该算法适用于全部范围的补码数(包括最高位为1/0)
按照二进制乘法,乘以-65需要进行7次加法操作;
booth编码,乘以-65需要进行1次加法,两次减法操作;
1.被乘数左移,乘数右移
2.根据乘数最低位进行booth编码,当BRC=2'b01时进行加法操作,当BRC=2'b10时进行减法
3.根据(乘数=1)来控制循环(乘法)是否结束
4.最后需要判断乘数是否为负数:
(1)如果为负数,(乘数=1)则表示计算结束
(2)如果为正数,(乘数=1)则表示此时乘数还剩2bit(2'b01),则还进行一次加法
`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
仿真结果
比特对编码又称为基4编码,比特对编码可以将加法次数由n减少到n/2,提高乘法运算速度。
该算法从乘数最低位到最高位依次读取,三个相邻位(mi+1,mi,mi-1)的值确定了BPE重编码乘数的各个位:BPEi。
该算法的第一步是在乘数的最右边置一位0。如果编码数的字节为奇数,则高位进行符号位扩展
BPE编码规则
mi+1 | mi | mi-1 | Code | BRCi+1 | BRCi | 值 | 操作 | 状态 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 全0字符串 | 移两位 |
0 | 0 | 1 | 1 | 0 | 1 | +1 | 末尾为1的字符串 | 移位相加 |
0 | 1 | 0 | 2 | 0 | 1 | +1 | 单个1的字符串 | 移位相加 |
0 | 1 | 1 | 3 | 1 | 0 | +2 | 末尾为1的字符串 | 移一位,相加,移一位 |
1 | 0 | 0 | 4 | 1(-) | 0 | -2 | 开始为1的字符串 | 移一位,相加,移一位 |
1 | 0 | 1 | 5 | 0 | 1(-) | -1 | 单个0的字符串 | 移位相减 |
1 | 1 | 0 | 6 | 0 | 1(-) | -1 | 开始为1的字符串 | 移位相减 |
1 | 1 | 1 | 7 | 0 | 0 | 0 | 全1字符串 | 移两位 |
适用范围:该算法适用于全部范围的补码数(包括最高位为1/0)
按照该编码方法,8bit字节进行4次编码运算
1.被乘数左移,乘数右移
2.根据乘数最低位进行bpe编码,当bpe=0~7时,分别进行相应的计算
3.根据运算次数(8bit字节编码次数为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)比较器(用于比较被除数与除数,控制除法运算是否结束)
另外一种设计方法可以不使用比较器来控制除法运算,该方法将减法运算等价为加法(-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)通过(被除数<除数)控制除法结束,余数=计算结束时被除法
`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.Verilog实现二进制有符号定点数的乘法运算
2.符号定点二进制小数(Qn format)乘法原理
3.《VERILOG HDL 高等数字设计 第2版》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。