• FPGA:什么是半加器?什么是全加器?多比特数据相加怎么求?如何用面积换速度?


    前言

    在FPGA中计算两个数据相加和C语言中的加法不太一样,在FPGA中是二进制相加,要考虑数据的进位、数据时单比特还是多比特,数据若位宽过大引起的时延该怎么解决,本文就对以上问题进行梳理

    另外我想挖个新坑,把HDLBits中的内容整理一下,就从加法器进行入手,等写好了就过来填坑

    正文

    一、半加器和全加器的区别

    首先区别,什么是半加器,什么是全加器,从下面图中可以看到
    半加器:没有来自上一级的进位(cin), {cout,sum} = a + b
    全加器:有来自上一级的进位(cin), {cout,sum} = a + b + cin
    并且可以使用2个半加器构成一个全加器,即第一个半加器计算 sum = a + b ,第二个半加器计算 cin + sum
    在这里插入图片描述

    二、多比特数据怎么相加—等波纹进位加法器

    此处考虑多比特全加器
    在这里插入图片描述
    由上图可知,多比特全加器,可以将数据从低到高一次使用单比特的全加器求解,他还有一个名字,叫:等波纹进位加法器,这个名字就很形象,全加器一级一级地如同波纹传递着上一级的cin
    举例:
    在这里插入图片描述
    但是此时出现一个新的问题,如果是100bit的数据进行相加,那就需要100个单比特的全加器,这样会导致时延
    那如何解决这个问题呢?带着这个问题,继续往下读

    三、用面积换速度

    3.1 流水线

    最开始接触到流水线是在FFT算法实现中,这里——> FFT算法实现
    再挖个坑,写一篇详细介绍流水线的文章
    填坑流水线

    通过分析发现,8bit的全加器是一种单向的、并且前面输出的cout要作为后面的cin,因此可以使用流水线来提高工作频率

    实现的效果:第一级流水线在每个时钟上升沿到来时,只负责计算数据低4位的全加结果,以及将高4位打一拍;第二级流水线只负责将第一级流水线的结果进行相加和拼接

    设计文件

    // 用流水线实现8bit加法
    module water_add8 (
        input       clk,
        input       rst_n,
        input [7:0] a,
        input [7:0] b,
        input       cin,
    
        output  [7:0] sum,
        output       cout
    );
    
    reg       cout_low4_1;
    reg [3:0] sum_low4_4;
    
    reg [3:0] a_high4_4;
    reg [3:0] b_high4_4;
    
    reg       cout_reg;
    reg [7:0] sum_reg;
    
    // 第一级流水线
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cout_low4_1 <= 1'd0;
            sum_low4_4 <= 4'd0;
        end
        else 
            {cout_low4_1, sum_low4_4[3:0]} <= a[3:0] + b[3:0] + cin;   
    end
    
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            a_high4_4 <= 1'd0;
            b_high4_4 <= 4'd0;
        end
        else 
            a_high4_4 <= a[7:4];
            b_high4_4 <= b[7:4];
    end
    
    // 第二级流水线
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cout_reg <= 1'd0;
            sum_reg <= 8'd0;
        end
        else 
            {cout_reg, sum_reg[7:0]} <= {5'd0+a_high4_4[3:0]+b_high4_4[3:0]+cout_low4_1,sum_low4_4[3:0]};   //{{{1'b0,ina_reg[3:0]}+{1'b0,inb_reg[3:0]}+cout1},sum1[3:0]}
    end
    
    assign cout = cout_reg;
    assign sum  = sum_reg;
        
    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

    测试文件

    `timescale	1ns/1ns
    module tb_add8_2;
    reg					clk;
    reg					rst_n;
    reg					cin;
    reg			[7:0]		a;
    reg			[7:0]		b;
    
    wire [7:0] sum;
    wire cout;
     
    initial	begin
    			clk=0;
    			rst_n=0;
    			cin=1;
    			a=2;
    			b=3;
    			#20
    			rst_n=1;						
    end
     
    initial begin
    	#30
    	data_ina();	
    end
    initial	begin
    	#30;
    	data_inb();		
    	end
    	
    always #10 clk	= ~clk;
     
    task	data_ina();
    		integer i;
    		begin
    			for(i=0;i<256;i=i+1)
    				begin
    					@(posedge clk)
    					a<=i;					
    				end	
    		end	
    endtask
     
    task data_inb();
    		integer j;
    		begin
    		for(j=1;j<254;j=j+1)
    			begin
    				@(posedge clk)				
    				b<=j;
    				cin<=b[0];				
    			end	
    		end	
    endtask
    
    water_add8 water_add8_inst(
        .clk(clk),
        .rst_n(rst_n),
        .a(a),
        .b(b),
        .cin(cin),
    
        .sum(sum),
        .cout(cout)
    );
     
    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

    波形图

    在这里插入图片描述

    3.2 进位选择加法器

    HDLBits-进位选择加法器这里提到过这种思想,刷了题这不就用上了哇哈哈哈
    结构:使用3个全加器模块,1个用来求解数据低16位,另外2个分别在cin=0、cin=1的情况下求解出sum,然后通过二选一选择器得到高16位的输出,最后将低16位和高16位的输出拼接即可
    在这里插入图片描述

    module top_module(
        input [31:0] a,
        input [31:0] b,
        output [31:0] sum
    );
    
    wire cout1;
    wire [15:0] sum0;
    wire [15:0] sum1;
    wire [15:0] sum2;
    wire [15:0] sum_mux;
    
    always @(*) begin
        case(cout1)
            1'd0: sum_mux = sum1;
            1'd1: sum_mux = sum2;
        default: sum_mux = sum1;
        endcase
    end
    // 上面的组合逻辑还可以使用条件判断
    // assign sum_mux = (cout1)?sum2:sum1;
    
    assign sum = {sum_mux,sum0};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    global关键字、python实现ATM简单功能
    MongoDB——centOS7安装mongodb5.0.21版本服务端(图解版)
    自定义注解实现多数据源+实现原理分析_02
    Android9 查看连接多个蓝牙耳机查看使用中的蓝牙耳机
    成都优优聚美团代运营具备专业团队!
    Python项目运行过程报错处理
    vue监听浏览器网页关闭和网页刷新
    RL 从敲门到入门
    我大抵是卷上瘾了,横竖睡不着!竟让一个Bug,搞我两次!
    电路综合-基于简化实频的集总参数电路匹配2-得出解析解并综合
  • 原文地址:https://blog.csdn.net/m0_46830519/article/details/125553345