当前位置: 首页 > news >正文

Verilog实现组合逻辑电路

在verilog 中可以实现的数字电路主要分为两类----组合逻辑电路和时序逻辑电路。

组合逻辑电路比较简单,仅由基本逻辑门组成---如与门、或门和非门等。当电路的输入发生变化时,输出几乎(信号在电路中传递时会有一小段延迟)立即就发生变化。

相反,时序逻辑电路使用时钟且必须要触发器等存储元件,所以其输出变化与电路时钟同步,不是即时变化的。

这篇文章将讨论如何使用 assign 关键字在 verilog 中实现连续赋值(continuous assignment),以及使用连续赋值语句实现基本逻辑门和多路选择器。

1、Verilog 中的连续赋值(Continuous Assignment

设计者可以使用连续赋值语句将数据驱动到设计中的net类型中。因此,连续赋值语句经常被用来实现组合逻辑电路。

实际上可以使用两种不同的方法在verilog中实现连续赋值。第一个被称为显式(explicit)连续赋值,这是verilog中最常用的连续赋值方法;此外还可以使用隐式(implicit)连续赋值,或者叫:net声明赋值。这种方法不太常见,但它要写的代码更少。

1.1、显式连续赋值(Explicit Continuous Assignment

使用assign关键字进行连续赋值的方法被称为显式连续赋值。下面的 verilog 代码展示了使用 assign 关键字进行连续赋值的一般语法。

assign <variable> = <value>;

<variable> 是要为其分配数据的信号的名称,只能使用连续赋值的方式来给net类型的变量赋值。

<value> 可以是一个固定值或者是某个表达式,在此表达式中可以使用变量或net类型。

使用连续赋值时,只要 <value> 中的一个信号改变状态,<variable> 值就会立即发生改变。

下面的代码片段展示了一个最基本的 verilog 连续赋值示例。在该示例中,只要 b 信号改变状态,a 的值就会立即更新,使其等于 b。

assign a = b;

1.2、线网声明赋值(Net Declaration Assignment

设计者还可以在 verilog 设计中使用隐式连续赋值,这种方法通常也被称为线网(net)声明赋值。使用线网声明赋值时,只需要在声明信号的语句中写一条连续赋值语句,这可以减少代码行数。

在 verilog 中使用线网声明赋值时,需要在声明信号时使用 = 符号为信号赋值。下面的代码片段展示了线网声明赋值的一般语法。

<type> <variable> = <value>;

<variable>和<value>使用方法与显式连续赋值中一致。

下面的 verilog 代码展示了如何使用线网声明赋值将 b 的值赋给信号 a。

wire a = b;

2、 在Verilog 中实现组合逻辑电路

使用连续赋值语句和运算符,即可实现基本的组合逻辑电路。

下图是一个3输入与门的示例:

为了在 verilog 中实现该电路,可以使用 assign 关键字将数据驱动到 and_out 输出。这意味着 and_out 信号必须声明为net(线网)类型,例如wire ,然后可以使用按位与运算符 (&) 来实现基本的与门。

下面的代码片段展示了如何实现这个3输入与门。

assign and_out = a & b & c;

这个例子展示了在 verilog 中设计基本的组合逻辑电路是多么的简单。如果设计者需要更改逻辑门的功能,只需要使用不同的verilog运算符即可。又或者设计者需要构建更复杂的组合逻辑电路,那么也可以混合使用不同的位运算符。为了证明这一点,将以下面的电路作为示例。

要在 verilog 中实现电路,需要混合使用按位与 (&) 运算符按位或 (|) 运算符。下面的代码片段展示了如何在 verilog 中实现这一点。

assign logic_out = (a & b) | c;

这段代码同样不难理解。但是设计者需要确保使用了括号来实现复杂的逻辑电路。这不仅可以确保电路正常运行,还可以让代码更易于阅读和维护。

2.1、在 Verilog 中实现多路选择器(Multiplexors

多路选择器是组合逻辑电路中一个常用的组件。在 verilog 中,设计者可以通过多种方式实现这些组件,其中一种方法使用称为always块(always block)的结构,此语法通常被用来实现时序逻辑电路,但同时也可以实现组合逻辑电路。

2.1.1、Verilog 条件运算符

verilog中有一个与C语言等编程语言类似功能的条件运算符。要使用条件运算符,需要在 ? 表达式前写一个逻辑表达式,然后判断它是真还是假。根据表达式的真假,将两个值中的某一个赋值给输出。

下面的 verilog 代码展示了条件运算符使用的一般语法。

output = <expression> ? <value if true> : <value if false>;

接下来看一个简单的 2选1的多路选择器的例子,如下面的电路图所示。

下面的代码片段清楚地展示了如何使用条件运算符在 verilog 中实现上图中的多路选择器。

assign q = addr ? b : a;

2.1.2、嵌套的条件运算符(Nested Conditional Operators

虽然这并不常见,但设计者也可以使用嵌套的条件运算符(Nested Conditional Operators)来编写代码,以实现更大的多路选择器。

接下来将以一个4选1多路选择器为例进行说明,如下图电路所示。

为了使用条件运算符在 verilog 中实现此电路,可以将该多路选择器视为一对2选1的多路选择器。这意味着其中一个多路选择器将在输入 A 和 B 之间进行选择,而另一个多路选择器则在输入 C 和 D 之间进行选择。这两个多路选择器都使用地址信号的 LSB 作为地址引脚。

assign mux1 = addr[0] ? b : a;
assign mux2 = addr[0] ? d : c;

要实现完整的4选1多路选择器,还需要另一个多路选择器。这个多路选择器将前两个多路选择器的输出作为输入,并使用地址信号的 MSB 在它们之间进行选择。

下面的代码片段展示了实现该功能的方法。

assign q = addr[1] ? mux2 : mux1;

此代码使用了在上一个示例中定义的信号 mux1 和 mux2,但其实设计者也可以从此代码中删除 mux1 和 mux2 信号,作为替代使用嵌套的条件运算符,这可以有效地减少代码行数。

下面的代码片段展示了如何做到这一点。

assign q = addr[1] ? (addr[0] ? d : c) : (addr[0] ? b : a);

从这个例子也可以看出,使用条件运算符在 verilog 中实现多路选择器时,代码会变得难以阅读和理解。因此,设计者最好只使用这种方法来实现小型的多路选择器。

2.1.3、用数组(Arrays)作为多路选择器

设计者也可以使用verilog中的数组来构建简单的多路选择器。为此,可以将所有多路选择器的输入组合成一个数组,并使用地址指向数组中的元素。

为了更好地了解它是如何在实践中运用的,仍然以一个4选1的多路选择器为例。

首先需要将输入信号组合成一个数组,有两种方式可以做到这一点。第一种:先声明一个数组,然后给数组中的每一位赋值,如下面的 verilog 代码所示。

assign in_vec[0] = a;
assign in_vec[1] = b;
assign in_vec[2] = c;
assign in_vec[3] = d;

第二种:可以使用verilog中的拼接运算符 { },这样就可以在一行代码中对整个数组赋值----使用一对花括号 { } 并在其中列出希望包含在数组中的所有元素。在使用拼接运算符时,如果是使用的net类型,那么也可以在一条语句中声明和赋值。

下面的 verilog 代码展示了如何使用拼接运算符来对数组赋值。

assign in_vec = {d, c, b, a};        //赋值
wire [3:0] in_vec = {d, c, b, a};    //声明+赋值

由于 verilog 是一种弱类型(Loosely Typed Language)语言,所以也可以使用两位地址信号,就好像它是一个integer类型一样,然后该信号将被用作确定选择4个元素中的哪一个的指针。

下面的代码片段展示了如何实现这种方法。由于多路选择器的输出是wire类型,所以必须在这种情况下使用连续赋值。

assign mux_out = in_vec[addr];

  • 📣您有任何问题,都可以在评论区和我交流📃!

  • 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net

  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!


相关文章:

  • Qt——通过一个简单的程序例程熟悉使用Qt Creator软件进行项目搭建的基本流程(新建项目、项目的文件组成、修改ui文件、编译运行与调试)
  • 一文带你吃透操作系统
  • 07从零开始学Java之如何正确的编写Java代码?
  • 如何保证Redis缓存和数据库一致性?
  • 2023年网络安全比赛--attack(新)数据包分析中职组(超详细)
  • 【Android -- 软技能】聊聊程序员的软技能
  • STM32F1硬件SPI驱动nRF24L01通过按键控制数据收发带状态反馈
  • 2022济南大学acm新生赛题解
  • ES+Redis+MySQL,这个高可用架构设计太顶了!
  • js逆向爬取某音乐网站某歌手的歌曲
  • Python打包成exe,文件太大问题解决办法(比保姆级还保姆级)
  • 【小白】git是什么?gitee和git和github的关系?
  • 如何用Python求解微分方程组
  • 初识C++需要了解的一些东西(2)
  • 【面试题】面试官:如果后端给你 1w 条数据,你如何做展示?
  • docker python 配置
  • JavaScript设计模式系列一:工厂模式
  • Material Design
  • react 代码优化(一) ——事件处理
  • vue-loader 源码解析系列之 selector
  • vue的全局变量和全局拦截请求器
  • windows-nginx-https-本地配置
  • windows下mongoDB的环境配置
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 记录一下第一次使用npm
  • 简单基于spring的redis配置(单机和集群模式)
  • 码农张的Bug人生 - 初来乍到
  • 判断客户端类型,Android,iOS,PC
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 主流的CSS水平和垂直居中技术大全
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • ()、[]、{}、(())、[[]]命令替换
  • (0)Nginx 功能特性
  • (C语言)fgets与fputs函数详解
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (pytorch进阶之路)扩散概率模型
  • (二)PySpark3:SparkSQL编程
  • (三)终结任务
  • (一)SpringBoot3---尚硅谷总结
  • ***通过什么方式***网吧
  • . Flume面试题
  • .aanva
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .Net6使用WebSocket与前端进行通信
  • .Net小白的大学四年,内含面经
  • .sdf和.msp文件读取
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • @SpringBootApplication 包含的三个注解及其含义