数字设计笔试Verilog手撕代码 - 累加器

news/2024/12/1 18:54:56/

前言

本系列整理关于数字设计的笔试或面试的设计问题,手撕代码继续撕,今天撕一个百度昆仑笔试题的累加器设计。

设计需求

题目来源:

【数字IC/FPGA】百度昆仑芯手撕代码–累加器

已知一个加法器IP,其功能是计算两个数的和,但这个和延迟两个周期才会输出。现在有一串连续的数据输入,每个周期都不间断,试问最少需要例化几个上述的加法器IP,才可以实现累加的功能。

设计分析

实现累加器的加法器例化的个数。按照原文大佬的设计方法,因为数据连续且加法器的延迟周期是2,使用使用一个实现累加,会有一半的数据丢失。那这样设计他就将奇数偶数的数据进行了分开做一级累加,然后第二级将奇数偶数的累加结果再累加。这样做共需消耗3个加法器。

这样设计当然没问题,但是这样设计是否是最少呢?我先抛出我的思考,我认为在允许少量逻辑设计的情况下,最少需要例化两个上述的加法器IP可以实现累加。

如果比较极限的情况下,一个都可以,先把一串数据使用寄存器缓存,然后一个一个取出来慢慢算即可,但这样是不太可取的,首先,数据是连续的并没有给出数据的极限长度,也就是说不论用任何涉及存储结构进行缓存,都没法确保该次数据能完全被存储。如果题目改成一串连续数据输入,长度最大为10,那我认为用寄存器缓存这样的设计是合理的。

设计架构

回到设计思路:用两个加法器的结构如图示。

image-20230422180629926

设计实现

加法器设计

假设两个时钟周期延时加法器代码如下,通过例化加法器进行构建累加器。

//加法器IP
module adder
#(parameter DATA_WIDTH = 8)(input clk,input rst_n,input [DATA_WIDTH-1:0] a_in,input [DATA_WIDTH-1:0] b_in,output reg [DATA_WIDTH-1:0] out);reg [DATA_WIDTH-1:0] sum;always @(posedge clk or negedge rst_n)beginif(rst_n == 'd0)beginsum <= 'd0;out <= 'd0;endelse beginsum <= a_in + b_in;out <= sum;endend
endmodule

累加器设计

//累加器实现
module adder_for_acc#(parameter DATA_WIDTH = 8)(input                        clk,input                      rst_n,input       [DATA_WIDTH-1:0] din,input                  din_valid,output reg            dout_valid,output reg [DATA_WIDTH-1:0] dout);reg [DATA_WIDTH-1:0]din_r0;//打一拍always @(posedge clk or negedge rst_n)beginif(rst_n == 'd0)begindin_r0 <= 'd0;endelse if(din_valid==1'B1)begindin_r0<= din;endelse begindin_r0<='d0;endend//adder0_valid信号reg adder0_valid;always @(posedge clk or negedge rst_n)beginif(rst_n == 'd0)beginadder0_valid <= 'd0;endelse if(din_valid==1'B1)beginadder0_valid<=!adder0_valid;endelse beginadder0_valid<='d0;endendwire[DATA_WIDTH-1:0] a_in = (adder0_valid && din_valid)?din:0;wire[DATA_WIDTH-1:0] b_in = (adder0_valid)?din_r0:0;wire[DATA_WIDTH-1:0] ab_sum;adder adder0_dut (.clk  (clk   ),.rst_n(rst_n ),.a_in (a_in  ),.b_in (b_in  ),.out  (ab_sum));//第一级加法器输出有效信号reg [1:0]adder0_valid_dly;wire ab_sum_valid = adder0_valid_dly[1];always @(posedge clk ) beginadder0_valid_dly<={adder0_valid_dly[0],adder0_valid};endwire [DATA_WIDTH-1:0] sum_in;wire [DATA_WIDTH-1:0] ab_sum_in = (ab_sum_valid)?ab_sum:0;wire [DATA_WIDTH-1:0] accsum_in = (ab_sum_valid)?sum_in:dout;adder adder1_dut (.clk  (clk      ),.rst_n(rst_n    ),.a_in (ab_sum_in),.b_in (accsum_in),.out  (sum_in   ));//第二级加法器输出有效信号reg [3:0]din_valid_r0;reg [1:0]adder1_valid_dly;wire adder1_outvld = adder1_valid_dly[1];always @(posedge clk ) beginadder1_valid_dly<={adder1_valid_dly[0],ab_sum_valid};end//输出always @(posedge clk ) begindin_valid_r0<={din_valid_r0[2:0],(din_valid || adder0_valid)};endalways @(posedge clk or negedge rst_n) beginif(rst_n == 'd0)begindout <= 'd0;dout_valid <= 'd0;endelse if(adder1_outvld == 1 && (din_valid_r0[3]==1 && din_valid_r0[2]==0))begindout <= sum_in ;dout_valid <= 'd1;endelse begindout <= dout ;dout_valid <= 'd0;endendendmodule

代码架构设计

  1. 打拍:先对数据用寄存器缓存一拍,输入数据暂时用in[i]表示,缓存。
  2. 第一级加法器输入选择valid:因为前级积累一拍的数据,设计valid用于指示加法器的输入数据。
  3. 第一级加法器信号输入:根据valid信号进行选择数据输入。
  4. 调用第一级加法器,同时对输入valid信号进行打两拍处理,指示有效的输出数据。
  5. 第二级加法器信号输入:根据valid信号进行选择数据输入。
  6. 调用第二级加法器,同时对输入valid信号进行打两拍处理,指示有效的输出数据。
  7. 输出结果和valid信号。

经过分析,目前设计延时是4拍,也即两级,这里dout和valid使用的是时序逻辑输出,所以在输入valid拉低后的第五个时钟周期输出正确的结果。

仿真测试

设计仿真测试代码对代码进行测试,这里使用了递增数测试代码可用性,在实际测试时,可通过改变DATA_LEN的大小测试单次递增累加后的结果,后续结果依次递增为第一次的N倍。

`timescale 1ns/1ps
module adder_for_acc_tb;// Parameterslocalparam  DATA_WIDTH = 8;localparam  DATA_LEN = 5;// Portsreg clk = 1;reg rst_n = 0;reg [DATA_WIDTH-1:0] din;reg din_valid = 0;wire  dout_valid;wire [DATA_WIDTH-1:0] dout;adder_for_acc #(.DATA_WIDTH (DATA_WIDTH ))adder_for_acc_dut (.clk (clk ),.rst_n (rst_n ),.din (din ),.din_valid (din_valid ),.dout_valid (dout_valid ),.dout  ( dout));always @(posedge clk or negedge rst_n)beginif(rst_n == 'd0)begindin <= 'd0;din_valid <= 'd0;endelse if(dout_valid == 1)begindin <= 'd0;din_valid <= 'd1;endelse if(din == DATA_LEN)begindin <= din;din_valid <= 'd0;endelse if(din != DATA_LEN)begindin <= din + 1;din_valid <= 'd1;endelse begindin <= din;din_valid <= 'd0;endendalways #5  clk = ! clk ;initial beginbegin#100;rst_n = 1;#1000;$finish;endendendmodule

仿真截图

仿真分析

在图示仿真可知,累加器功能正常,在din_valid信号拉低后第五拍可得到输出结果,功能正常。


http://www.ppmy.cn/news/50352.html

相关文章

【C++初阶】:指针空值nullptr

指针空值nullptr 一.空指针二.空指针nullptr 一.空指针 在良好的C/C编程习惯中&#xff0c;声明一个变量时最好给该变量一个合适的初始值&#xff0c;否则可能会出现不可预料的错误&#xff0c;比如未初始化的指针。如果一个指针没有合法的指向&#xff0c;我们基本都是按照如下…

5年测试经验,自动化都不会?月薪11K都难拿....

我接触了太多测试同行&#xff0c;由于多数同行之前一直做手工测试&#xff0c;现在很迫切希望做自动化测试&#xff0c;其中不乏工作5年以上的同行。 我从事软件自动化测试已经近十年&#xff0c;接触过底层服务端、API 、Web、APP、H5 等等&#xff0c;对自动化算是比较了解…

Maya - 后缀为xgen文件导出到虚幻引擎

Xgen是集成在Maya中的工具&#xff0c;可以在指定模型表面生成和控制大量物体的集成和离散&#xff1b;经常用于复杂的毛发制作&#xff0c;可以方便的用笔刷等控制曲线&#xff08;curves&#xff09;和导引线&#xff08;guides&#xff09;等线条来控制毛发的走向&#xff1…

JavaScript常用方法整理

文章目录 前言1.栈方法&#xff1a;push()、pop()2.队列方法&#xff1a;unshift()、shift()3.indexof()、lastIndexOf()、includes()4.操作方法&#xff1a;concat()、slice()、splice()5.Array.isArray()6.排序方法:sort()、reverse()7.转换方法&#xff1a;toString()、join…

倾斜摄影三维模型顶层合并技术及其实现方法

倾斜摄影三维模型顶层合并技术及其实现方法 倾斜摄影三维模型由于数据量大、结构复杂&#xff0c;常常需要进行顶层合并&#xff0c;以便更好地应用到城市规划、土地管理和文化遗产保护等领域。本文将介绍倾斜摄影三维模型顶层合并技术及其实现方法。 1、什么是顶层合并 倾斜…

DC-6靶机通关详解

信息收集 漏洞发现 发现无法访问web 加个hosts 这题类似那个dc2还是dc3,网站长的一样 wordPress5.1.1 上wpscan扫 enumrate一下user 看看能不能弱口令 测了wp给的那几个用户,都不能弱口令,dirsearch也没扫到什么有价值的路径 尝试ssh弱口令 没爆出来,回官网看了下描述 确实…

SpringBoot的AOP在开发中的实例、公共字段利用AOP实现自动填充

1. 公共字段自动填充 若要实现下述步骤&#xff0c;需掌握以下知识 **技术点&#xff1a;**枚举、注解、AOP、反射 1.1 问题分析 在我们开发时需要设置创建时间、创建人、修改时间、修改人等字段&#xff0c;比如编辑员工或者编辑分类时需要设置修改时间、修改人等字段。这些字…

MySQL运维30-基于主库搭建从库

文章目录 1、基于主库搭建从库的步骤2、总结 1、基于主库搭建从库的步骤 在主库上运行mysqldump导出逻辑转储文件&#xff1a; mysqldump --flush-logs --master-data2 --single-transaction --hex-blob -R -f --all-databases > databases.sql对以上命令&#xff0c;说明…