前言
在FPGA中计算两个数据相加和C语言中的加法不太一样,在FPGA中是二进制相加,要考虑数据的进位、数据时单比特还是多比特,数据若位宽过大引起的时延该怎么解决,本文就对以上问题进行梳理
另外我想挖个新坑,把HDLBits中的内容整理一下,就从加法器进行入手,等写好了就过来填坑
正文
一、半加器和全加器的区别
1.1 区别
首先区别,什么是半加器,什么是全加器,从下面图中可以看到
半加器:没有来自上一级的进位(cin), {cout,sum} = a + b
全加器:有来自上一级的进位(cin), {cout,sum} = a + b + cin
并且可以使用2个半加器构成一个全加器,即第一个半加器计算 sum = a + b
,第二个半加器计算 cin + sum
1.2 表达式
全加器:
二、多比特数据怎么相加
2.1 等波纹进位加法器
此处考虑多比特全加器
由上图可知,多比特全加器,可以将数据从低到高一次使用单比特的全加器求解,他还有一个名字,叫:等波纹进位加法器
,这个名字就很形象,全加器一级一级地如同波纹传递着上一级的cin
举例:
但是此时出现一个新的问题,如果是100bit的数据进行相加,那就需要100个单比特的全加器,这样会导致时延
那如何解决这个问题呢?
2.2 超前进位加法器
为了解决等波纹进位带来的时延,提出一种基于并行处理的思想的超前进位加法器
核心思想:使用并行求解 C o u t C_{out} Cout
牛客刷题 – VL12 4bit超前进位加法器电路
三、用面积换速度
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
测试文件
`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
波形图
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};
今天的文章
常用fpga芯片的型号_常用fpga芯片的型号分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/80965.html