数字电路基础知识——乘法器的设计(二)( 串行、流水线、有符号数八位乘法器)

数字电路基础知识——乘法器的设计(二)( 串行、流水线、有符号数八位乘法器)

前面一节关于乘法器的具体实现方式有很多种方法,均有各自的优缺点。

本节将再介绍一下两种乘法器的设计,分别用Verilog语言实现串行和流水线乘法器。

一、串行乘法器
  1. 移位相加的算法上节已经介绍,其核心算法为:
always@(a or b)
begin
	c=0;
	for (i=1; 1<=size;i=i+1) begin
		c = c + ((b[i] == 1)? (a<<[i-1]):0); 	//移位相加
	end
end
  1. 两个N位二进制数x、y的乘积用简单的方法计算就是利用移位操作来实现。
module multi_serial——mult(clk, x, y, result);
input clk;
input [7:0] x, y; 	//八位二级制数
output [15:0] result;

reg [15:0] result;

parameter s0 = 0, s1 = 1, s2 = 2;	//状态机来实现
reg [2:0] count = 0;
reg [1:0] state = 0;	//初始状态为0
reg [15:0] P, T;
reg [7:0] y_reg;

always @(posedge clk) begin
        case (state)
            s0: 
            begin		//状态s0为初始化,将y值存入寄存器y_reg,x存入T中,并将高八位置0
                count <= 0;
                P <= 0;
                y_reg <= y;
                T <= {{8{1'b0}}, x};
                state <= s1;
            end
            
            s1: 
            begin 			//循环八次
                if(count == 3'b111)	//8次累加
                    state <= s2;
                else 
                	begin
                		if (y_reg[0] == 1'b1) 
							P <= P + T;
						else beign
							P <= P;
						end	
						
                		y_reg <= y_reg >> 1; //循环一次y右移一次
                		T <= T << 1;	//并且所得值T*2
                		state <= s1;
                		count <= count + 1;
				    end	
			end	
 
            s2: 
            begin
                result <= P;
                state <= s0;
            end
            default: ;
        endcase
end

endmodule
  1. 其核心代码为状态机s1:
         s1: 
            begin 			//循环八次
                if(count == 3'b111)	//8次累加
                    state <= s2;
                else 
                	begin
                		if (y_reg[0] == 1'b1) 
							P <= P + T;
						else beign
							P <= P;
						end	
						
                		y_reg <= y_reg >> 1; //循环一次y右移一次
                		T <= T << 1;	//并且所得值T*2
                		state <= s1;
                		count <= count + 1;
				    end	
			end	
 
  1. 串行乘法器的特性:
    优点:所占用的资源是所有类型乘法器中最少的,在低速的信号处理中有着广泛的应用。
    缺点:计算一次乘法需要8个周期。速度比较慢、时延大
二、流水线乘法器
  1. 流水线乘法器的介绍
    一般的快速乘法器通常采用逐位并行的迭代阵列结构,将每个操作数的N位都并行地提交给乘法器。但是一般对于FPGA来讲,进位的速度快于加法的速度,这种阵列结构并不是最优的。所以可以采用多级流水线的形式,将相邻的两个部分乘积结果再加到最终的输出乘积上,即排成一个二叉树形式的结构。
  2. 4位流水线乘法器的实现
module multi_4bits_pipelining(mul_a, mul_b, clk, rst_n, mul_out);

    input [3:0] mul_a, mul_b;
    input       clk;
    input       rst_n;
    output [7:0] mul_out;

    reg [7:0] mul_out;

    reg [7:0] stored0;
    reg [7:0] stored1;
    reg [7:0] stored2;
    reg [7:0] stored3;

    reg [7:0] add01;
    reg [7:0] add23;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            mul_out <= 0;
            stored0 <= 0;
            stored1 <= 0;
            stored2 <= 0;
            stored3 <= 0;
            add01 <= 0;
            add23 <= 0;
        end
        else begin
            stored0 <= mul_b[0]? {4'b0, mul_a} : 8'b0;
            stored1 <= mul_b[1]? {3'b0, mul_a, 1'b0} : 8'b0;
            stored2 <= mul_b[2]? {2'b0, mul_a, 2'b0} : 8'b0;
            stored3 <= mul_b[3]? {1'b0, mul_a, 3'b0} : 8'b0;

            add01 <= stored1 + stored0;
            add23 <= stored3 + stored2;

            mul_out <= add01 + add23;
        end
    end

endmodule

流水线乘法器比串行乘法器的速度快很多很多,在非高速的信号处理中有广泛的应用。至于高速信号的乘法一般需要利用FPGA芯片中内嵌的硬核DSP单元来实现。

三、有符号数八位乘法器

对于用Verilog实现乘法y = a * b

如果考虑a和b都是8bit,并且考虑有无符号数考虑三种情况:

1) 都是无符号数
2) 都是有符号数
3) a是有符号数,b是无符号数

  1. 无符号数情况
    无符号数的情况只需使用 * 连接就可以了
module Multply_Signed_Unsigned(
    input       [7:0]   dina,
    input       [7:0]   dinb,
    output      [15:0]   dout
    );

assign  dout = dina * dinb;

endmodule
  1. 有符号数
    有符号数的情况只需使用 * 连接就可以了,和无符号数类似,用补码计算结果
module Multply_Signed_Unsigned(
    input signed    [7:0]   dina,
    input signed    [7:0]   dinb,
    output signed   [15:0]   dout
    );

assign  dout = dina * dinb;

endmodule

  1. 有符号数和无符号数相乘
    Verilog在进行运算时,如果两个操作数一个是有符号数,一个是无符号数,直接运算时,按无符号数运算的。解决这个问题用 $signed() 机制可以解决。
module Multply_Signed_Unsigned(
    input           [7:0]   dina,
    input signed    [7:0]   dinb,
    output signed   [15:0]   dout
    );

wire    [15:0]  dout_r;

assign  dout_r = dina * dinb;			//结果为无符号数
assign  dout = dina * $signed(dinb);	//结果为有符号数

endmodule
  1. 关于Verilog中关于$signed的用法
    verilog中的加法和乘法操作前,会先对操作数据扩位成结果相同的位宽,然后进行加法或者乘法处理。

    比如a/b都为4位数据,c为5位数据,c = a + b,这个运算的时候会先把a和b扩位成5位,然后按照无符号加法进行相加。

    a/b没有被signed修饰的时候会按照无符号数的扩位方式进行扩位,即高位补0,加法的结果当然也是a、b为无符号数相加的结果。

    如果想把a、b作为有符号数来相加,那么就得在a/b数据定义的时候用signed修改,或者在计算的时候用$signed()来修饰,这样在c = a + b,这个运算开始的扩位就会按照有符号数的方式进行扩位,在高位补符号位,加法得出的结果就是a、b视为有符号数的结果。当然c要视为有符号数据。

    在verilog中有时会用signed修饰符来修饰定义的数据,运算的时候也会用$signed()任务来强制转换数据,那么signed的修饰是为什么呢,是为了区分有符号数和无符号数的加法和乘法吗? 其实不是的,因为有符号数和无符号数据的加法强结果和乘法器结构是一样的,signed的真正作用是决定如何对操作数扩位的问题。

  • 23
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摆渡沧桑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值