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

news2024/11/15 12:25:11

前言

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

设计需求

题目来源:

【数字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)begin
    if(rst_n == 'd0)begin
      sum <= 'd0;
      out <= 'd0;
    end
    else begin
      sum <= a_in + b_in;
      out <= sum;
    end
  end
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)begin
    if(rst_n == 'd0)begin
      din_r0 <= 'd0;
    end
    else if(din_valid==1'B1)begin
      din_r0<= din;
    end
    else begin
      din_r0<='d0;
    end
  end

  //adder0_valid信号
  reg adder0_valid;
  always @(posedge clk or negedge rst_n)begin
    if(rst_n == 'd0)begin
      adder0_valid <= 'd0;
    end
    else if(din_valid==1'B1)begin
      adder0_valid<=!adder0_valid;
    end
    else begin
      adder0_valid<='d0;
    end
  end

  wire[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 ) begin
      adder0_valid_dly<={adder0_valid_dly[0],adder0_valid};
  end

  wire [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 ) begin
    adder1_valid_dly<={adder1_valid_dly[0],ab_sum_valid};
  end
  //输出
  always @(posedge clk ) begin
    din_valid_r0<={din_valid_r0[2:0],(din_valid || adder0_valid)};
  end
  always @(posedge clk or negedge rst_n) begin
    if(rst_n == 'd0)begin
      dout <= 'd0;
      dout_valid <= 'd0;
    end
    else if(adder1_outvld == 1 && (din_valid_r0[3]==1 && din_valid_r0[2]==0))begin
      dout <= sum_in ;
      dout_valid <= 'd1;
    end
    else begin
      dout <= dout ;
      dout_valid <= 'd0;
    end
  end

endmodule

代码架构设计

  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;

  // Parameters
  localparam  DATA_WIDTH = 8;
  localparam  DATA_LEN = 5;
  // Ports
  reg 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)begin
    if(rst_n == 'd0)begin
            din <= 'd0;
      din_valid <= 'd0;
    end
    else if(dout_valid == 1)begin
      din <= 'd0;
      din_valid <= 'd1;
    end
    else if(din == DATA_LEN)begin
      din <= din;
      din_valid <= 'd0;
    end
    else if(din != DATA_LEN)begin
      din <= din + 1;
      din_valid <= 'd1;
    end
    else begin
      din <= din;
      din_valid <= 'd0;
    end
  end

  always #5  clk = ! clk ;
  initial begin
    begin
      #100;
      rst_n = 1;
      #1000;
      $finish;
    end
  end

 
endmodule

仿真截图

仿真分析

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/449170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚幻图文笔记:如何清理Character Creator角色的垃圾数据

书接上文《虚幻图文笔记&#xff1a;Character Creator 4角色通过AutoSetup For Unreal Engine插件导入UE5.1的过程笔记》 在一个项目中我按照上文的步骤导入UE5&#xff0c;但是产生了一些莫名其妙的文件&#xff0c;下面还原一下发现和解决问题的过程。 1. 使用Character Cr…

【C++入门必备知识】

【C入门必备知识】 ①.【命名空间】1.命名空间定义Ⅰ.正常定义命名空间Ⅱ.嵌套定义命名空间Ⅲ.合并命名空间 2.命名空间的使用Ⅰ.命名空间名称及域作用限定符Ⅱ.using成员引入Ⅲ.using namespace名称全部引入 3.注意事项Ⅰ.概念1.全缺省参数2.半缺省参数3.使用规则4.应用场景再…

Baumer工业相机堡盟工业相机如何通过BGAPISDK的软触发实现两相机的同步采集(C#)

Baumer工业相机堡盟工业相机如何通过BGAPISDK的软触发实现两相机的同步采集&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的高速同步采集的技术背景Baumer工业相机通过BGAPI SDK在回调函数里同步保存图像工业相机在回调函数BufferEvent保存工业相机使用软触发进行同…

#Chrome扩展程序开发教程--04:权限申请

#Chrome扩展程序开发教程--04&#xff1a;权限申请 引言1、基本介绍2、权限相关属性2.1、permissions2.2、optional_permissions2.3、host_permissions2.4、optional_host_permissions 3、申请权限4、检查权限5、移除权限 引言 本系列博客旨在带来最新的Chrome扩展程序开发入门…

C语言函数大全-- m 开头的函数

C语言函数大全 本篇介绍C语言函数大全-- m 开头的函数 1. malloc 1.1 函数说明 函数声明函数功能void *malloc(size_t size);用于动态分配内存 参数&#xff1a; size &#xff1a; 需要分配的内存大小&#xff08;以字节为单位&#xff09; 返回值&#xff1a; 如果分配成…

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

目录 一、属性注入&#xff08;Autowired&#xff09; 1.1 优点分析 1.2 缺点分析 1.2.1 无法实现final修饰的变量注入。 1.2.2 兼容性不好 1.2.3 &#xff08;可能违背&#xff09;设计原则问题 1.2.4 代码举例&#xff1a; 1.2.5 出现循环依赖该怎么办&#xff1f; 二…

自然语言模型的哲学小谈

近期&#xff0c;以chatGPT为代表的大语言模型表现非常惊艳。“In Context Learning”、“Instruct”1&#xff0c;以及推理能力&#xff0c;很难不让我们期待未来人工智能的发展&#xff0c;同时冷静思考一下为什么自然语言模型能够取得巨大进步。 文章目录 1 放空大脑从0开始…

Ngiinx反向代理和负载均衡

系列文章目录 目录 系列文章目录一、Nginx的反向代理1.代理含义2.反向代理配置模块 二、1.动静分离2.负载均衡实验 总结 一、Nginx的反向代理 1.代理含义 正向代理 正向代理&#xff0c;指的是通过代理服务器 代理浏览器/客户端去重定向请求访问到目标服务器 的一种代理服务…

ARP协议详解

ARP协议详解 文章目录 ARP协议详解ARP协议介绍ARP抓包ARP包解析 ARP协议介绍 ARP&#xff08;Address Resolution Protocol&#xff09;是一种用于将网络层地址&#xff08;如IP地址&#xff09;转换为数据链路层地址&#xff08;如MAC地址&#xff09;的协议&#xff0c;当一…

软件测试概念篇(下)|开发模型与测试模型

作者&#xff1a;爱塔居 专栏&#xff1a;软件测试 作者简介&#xff1a;大三学生&#xff0c;希望同大家一起进步&#xff01; 文章简介&#xff1a;主要介绍软件生命周期、瀑布模型和螺旋模型两个开发模型&#xff0c;V模型和W模型两个测试模型 文章目录 目录 文章目录 一、软…

【Go】五、网络编程

文章目录 网络编程1、互联网协议介绍2、Socket编程2.1、socket图解2.2、TCP编程2.3、UDP编程2.4、粘包&#xff08;❌没有详细看代码&#xff0c;但是大概知道怎么实现&#xff09; 3、Http编程4、WebSocket编程 网络编程 1、互联网协议介绍 2、Socket编程 2.1、socket图解 1…

这家工作室为网飞、亚马逊、迪士尼都制作过特效

过去的十年里&#xff0c;CGEV工作室通过为电影、电视剧以及Netflix、Amazon、Disney等平台制作大量内容&#xff0c;建立了坚不可摧的声誉。我们采访了CGEV团队&#xff0c;了解他们如何在每一个环节都依赖于ftrack Studio。 CGEV全称Compagnie Gnrale des Effets Visuels&…

C++缺省参数

目录 什么是缺省参数缺省参数分类全缺省参数半缺省参数 缺省参数函数的声明缺省参数的使用 什么是缺省参数 缺省参数是声明或定义函数时,为函数的参数指定一个缺省值。 在调用该函数时&#xff0c;如果没有指定实参&#xff0c;那么形参就会采用缺省值&#xff0c;如果指定了实…

【C语言】基础语法5:数组和指针

上一篇&#xff1a;函数和递归 下一篇&#xff1a;字符串和字符处理 ❤️‍&#x1f525;前情提要❤️‍&#x1f525;   欢迎来到C语言基本语法教程   在本专栏结束后会将所有内容整理成思维导图&#xff08;结束换链接&#xff09;并免费提供给大家学习&#xff0c;希望…

C#串口通信从入门到精通(4)——串口调试助手的使用

前言: 关于本文中使用到的串口助手工具,订阅专栏后,加入vip群,即可在群文件免费下载 1、认识串口助手 串口助手主要的功能有以下六个模块,功能介绍分别如下: 1.1 打开、关闭串口、清除接收区数据按钮区 这些按钮用于打开串口、关闭串口、清除接收数据区的数据 1.2 …

IIC协议——同步半双工串行通信方式

文章目录 前言一、简要介绍1、优点2、缺点 二、信号线和连接方式1、信号线2、连接方式2.1 单主设备&#xff0c;单从设备2.2 单主设备&#xff0c;多从设备2.3 多主设备&#xff0c;多从设备 三、数据传输格式1、数据传输过程 二、SPI配置1、传输模式2、地址位宽3、仲裁机制3.1…

【Linux】Linux基本指令(1)

一.前言 从这篇文章开始&#xff0c;博主就开启了Linux学习之路了&#xff0c;本篇文章也是博主的第一篇Linux的文章&#xff0c;今后也会持续不断更新的。 二.理解文件 1.文件 文件文件数据文件属性&#xff08;所以一个建好的文件就算没有数据&#xff0c;也占用存储空间&am…

[RoarCTF 2019]Easy Calc、攻防世界 ics07、[极客大挑战 2019]EasySQL

[RoarCTF 2019]Easy Calc 进入题目是一个计算器的功能 检查网页源码发现这样一个重要信息 这题有WAF计算功能是通过calc.php这里面的代码执行的&#xff0c;我们去访问一下得到源码 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str…

传统机器学习(二)逻辑回归算法(二)

传统机器学习(二)逻辑回归算法(二) 之前在传统机器学习(二)逻辑回归算法(一)中介绍了逻辑回归的原理、公式推导、手动python实现及sklearn工具包的使用详解等内容。继续对逻辑回归的使用细节进行介绍。 一、如何得到逻辑回归模型系数 1.1、一个简单的逻辑回归例子 已采集15…

广州蓝景分享—6 个ES13 中非常实用的新 JavaScript 特性

首先作为前端最重要的编程语言JavaScript&#xff0c;每年都在不断发展&#xff0c;让该语言都会通过新功能变得更强大。今天由小蓝跟大家分享6 个ES13 中非常实用的新 JavaScript 特性。 接下来让我们开始&#xff1a; 1.at 当我们想要获取数组的第 N 个元素时&#xff0c;…