FPGA_学习_04_Verilog基础语法和Modelsem仿真

news2024/12/23 4:19:29

前言:对于以前学过C/C++/C#的作者来讲,Verilog的基础语法算是特别简单的。本文主要介绍Verilog的基础语法和Modelsem仿真。

Verilog的基础语法

1 模块声明

FPGA开发是以模块为基础的,每个可综合的.v文件都是一个模块,模块由moduleendmodule来声明。在这两个关键字的内部,完成模块功能的实现。

在Vivado的一个空项目中,新建一个.v源文件,会自动生成以下代码(我把多余的注释删除了)

`timescale 1ns / 1ps	// 这行以后代码经常会见,表示时间单位是1ns,精度是1ps    


module verilog_base(	// module 模块名(
	...		            // 定义模块的输入输出接口
);			            // );
endmodule		        // endmodule

 下面以一个与门为例,进一步演示如何声明一个模块。

`timescale 1ns / 1ps	        // 这行以后代码经常会见,表示时间单位是1ns,精度是1ps    


module verilog_base(
	input		wire		a,	// input表示这是模块的输入接口  wire是变量类型 a是变量名,除最后一个变量定义外,都以‘,’结束
	input		wire		b,
	output		wire		c	// output表示这是模块的输出接口 wire是变量类型 c是变量名,最后一个变量定义,不以‘,’结束
);

assign c = a & b;				// 完成与门的组合逻辑幅值

endmodule

 

2 变量类型

在Verilog开发中有两种数据类型,一种是wire (线),一种是reg (寄存器)。在数字电路中信号只有两种形态,一种是传输,一种是存储。传输是通过连接线,存储是用寄存器,因此也就清楚了在Verilog中常用了wire和reg变量了。wire和reg变量模型如下图所示:

 

wire型变量在物理结构上只是一根线,在Verilog描述时,对线型变量赋值用assign即可,相对简单。

C语言赋值我直接 a = b;   Verilog赋值得在前面加关键字。  assign a = b;

reg型变量左端有一个输入端口D,右端有一个输出端口Q,并且reg型存储数据需要在clk(时钟)沿的控制下完成。 clk也即是我们常说的方波,它由晶振产生,是我们描述数字电路是最基本的时间单元,它周期固定,占空比一般为50%(高电平占整个周期的比例)。clk的低电平用数字0表示,高电平用1表示,从低电平转变到高电平的过程叫做上升沿,从高电平转变到低电平的过程叫做下降沿。

 

 在对reg型变量赋值时,必须在always块内完成,可以选择用时钟上升沿,也可以选择时钟下降沿,具体用上升沿还是下降沿可以根据需要定。下面尝试把第一节给出的与门例子的输出定义成reg型,实现两个输入相与之后将结果传输给寄存器的功能。即

 Verilog代码如下:

`timescale 1ns / 1ps	// 这行以后代码经常会见,表示时间单位是1ns,精度是1ps    


module verilog_base(
	input		wire		clk,	// 系统时钟输入,由晶振提供
	input		wire		a,
	input		wire		b,
	output		reg		    c	    // 将输出的类型改成reg
);

// reg型变量的赋值必须要在always块里面,注意:赋值符号不是'=',而是 '<='。
always @(posedge clk) begin
	c <= a & b;
end

endmodule

在always块中,@(posedge clk)表示的是,每当遇到clk的上升沿时,执行always块中的语句。

c <= a & b;中的'<='表示的是非阻塞赋值。Verilog中有两种赋值方式:

        1  '<=' 非阻塞赋值 适用于给reg变量赋值,always块 - 时序逻辑

        2  ‘=’ 阻塞赋值 适用于给wire变量赋值,assign块 – 组合逻辑

阻塞赋值时,输入改变输出是同时改变,在非阻塞赋值中,只有在时钟变化的时候,输出才会发生变化。

begin-end其作用与C C++ C#中的{}是一样的,在Verilog中,就可以视begin-end为{}

3 多位宽数据表示

在数字电路中,所有数据最终都是以二进制形式呈现的,二进制和十进制都只是一种数据的表达方式,同一个数据无论用二进制还是十进制来表达,本质上代表的值是一样的。十进制数据是0到9组成,二进制是0,1组成。 比如5,它的二进制是3’b101,十进制是’d5。二进制的每一个0/1叫做1位,若想知道数据是多少位。可以用计算器看。

 

如果我要表示53698745这个数,就需要26个位。 那么在定义的时候就要像下面这样定义

wire [25:0] data;
reg [25:0] data;
wire [26:1] data;
reg [26:1] data;

一般推荐最低位都是从0开始,也就是[25:0]这种写法。

4 赋值语句

前面第二小节已讲了一些相关内容。assign 和 always分别用于组合逻辑的赋值 和 时序逻辑的赋值。 还有一种initial,一般仅用于仿真文件中。

initial 语句是初始化语句,会在上电(电路刚刚运行时)执行一次,不会循环执行。在电路中只有可以存储数据的寄存器才有初始化的必要,所以initial 语句中被赋值的变量也必须为reg。 某些第三方综合软件认为initial 是不可以被综合的,也就是说不可以被写到功能文件中的,所以为了代码的兼容性,我们尽量只在测试文件中写initial 语句。示例代码如下所示。

reg	clk;
initial begin
	clk = 0;
	forever #(5) clk = ~clk;    // forever和always的区别是 forever仅用于仿真
end

示例代码产生的是周期为10ns的时钟信号。

5 运算符

5.1 关系运算符(< 、<= 、== 、>= 、> 、!=)

C语言中可以用if(2<a<6),但Verilog只能用if(a>2 && a<6),其余一致

5.2 逻辑运算符(&& 、||、 !)

逻辑运算符与C 语言中一致:对于&& 只有参与运算的两个数据都为真时,结果才为真,对于|| 只要参与运算的两个数据由一个为真,结果就为真。(!)进行的时逻辑取反。

5.3 位运算符(& 、|、 ~)

位运算是对二进制的运算,运算时,需要将数据都转换位二进制后才能进行计算。当位宽不一样时,位宽少的在高位补0。

5.4 条件运算符

如:assign a = (b>6)?1’b1:1’b0;

当b 大于6 时,a 等于1,否则a 等于0;

5.5 赋值运算符

前面已经介绍过Verilog 中的赋值运算符,<= 和=,其中<= 是非阻塞赋值,用于时序逻辑,=是阻塞赋值,用于组合逻辑。

5.6 移位运算符(<< >>)

>>为向右移位,每次右移一位,数据高位补零,向下溢出的数据丢弃。<<与之相反。

5.7 位拼接运算符({}

位拼接运算符,可以将不同数据的位拼接成一个新的数据。

reg[3:0] a = 4'b0110;
reg[4:0] b = 5'b10110;
reg[4:0] c;

always@(posedge clk) begin
	c <= {b[1],a[1:0],b[3],b[1]};
end

拼接完成后,c = 5’b11001;

6 条件判断

同一个变量可以在不同的情况下获得不同的值,不同的情况需要判断语句来描述。Verilog HDL 中经常使用的判断语句有if else 语句和case endcase 语句,两种判断语句必须写在always 语句中,不能写在assign 中。

6.1 If-else

if-else 语句与C 语言当中的使用方法类似。

always@(posedge clk)begin
	if(a==1) begin
		b <= 1;
	end
	else if(a==2) begin
		b <= 2;
	end		
	else if(a==3) begin
		b <= 3;
	end
	else if(a==4) begin
		b <= 4;
 	end
 	else if(a==5) begin
 		b <= 5;
 	end
 end

if else 叠加不易过多,不然可能造成线路的延时过多。每一个if else 语句都会生成一选择器,当if else 过多时,选择器链路就会很长,而每两级选择器之间都会有线路的延时,当链路过多时,造成的延时就会很多,这样对于描述的电路的时序影响会很大,时序出问题时,就算是功能仿真正确,下板后电路也是不正确的。

使用if-else 语句时需要考虑优先级的顺序,优先执行的条件放在上方,优先级较低的条件放在后方。最好还是用case吧。

6.2 Case 语句

Verilog的case语句和C语言的switch case类似,在if-else 级数过多的情况下,也可以使用case 语句,case 语句生成的是多路器

 

always@(posedge clk) begin
	case(a)
		0: 
			b <= 0;
		1: 
			b <= 1;
		2: 
			b <= 2;
		default:
			b <= 0;
	endcase
end

Case 语句以case 开始,以endcase 结尾,在其之间,列出要判断的条件,根据条件的值,执行对应的代码。

Modelsem仿真

1 编写仿真程序

新建一个空白的项目的流程在上一篇博客中已经讲过了,这里不在赘述。 按照下面的操作流程,新建一个仿真文件。

 

 

 

 Sublime Text (编辑软件)可以利用 源文件 自动生成 仿真文件。

 

 

 

仿真程序输入要用reg型输出要用wire型
 

 再次强调initial语句也常用在仿真文件,请尽量不要在实际的功能模块中使用。

 

`timescale 1ns/1ps
module tb_verilog_base (); /* this is automatically generated */

    reg  a;
    reg  b;
    wire  c;

    verilog_base inst_verilog_base (.a(a), .b(b), .c(c));


    initial begin
        a = 0;
        b = 0;

        #100; // 延时100ns

        a = 1;
        b = 0;

        #100; 

        a = 0;
        b = 1;

        #100;
        a = 1;
        b = 1;
    end
endmodule

2 Vivado仿真流程

 

 

 

 

 从仿真中我们可以看到,assign赋值是立即生效的。

3 Modelsem仿真流程

Modelsem软件安装及编译相关的库文件等操作,请参考Vivado:【1】Vivado 2018.3 配置ModelSim仿真_Alex-YiWang的博客-CSDN博客

 

 

 

 

 

正常人都能看出来Modelsem的原始界面是比vivado丑的,但Modelsem的界面是可以配置的,可自行查找相关资料。

4 时序逻辑仿真

源文件

`timescale 1ns / 1ps	// 这行以后代码经常会见,表示时间单位是1ns,精度是1ps    


module verilog_base(
	input		wire		clk,	// 系统时钟输入
	input		wire		a,
	input		wire		b,
	output		reg		    c	    // 将输出的类型改成reg
);


// reg型变量的赋值必须要在always块里面,注意:赋值符号不是'=',而是 '<='。
always @(posedge clk) begin
	c <= a & b;
end

endmodule

仿真文件

`timescale 1ns/1ps
module tb_verilog_base (); /* this is automatically generated */

    reg  clk;
    reg  a;
    reg  b;
    wire  c;

    verilog_base inst_verilog_base (
        .clk(clk), 
        .a(a), 
        .b(b), 
        .c(c)
    );

    initial begin
        clk = 0;
        forever #(5) clk = ~clk;
    end


    initial begin
        a = 0;
        b = 0;

        #100; // 延时100ns

        a = 1;
        b = 0;

        #100; 

        a = 0;
        b = 1;

        #100;
        a = 1;
        b = 1;
    end

endmodule

仿真结果

时序逻辑赋值,并不是立即生效,而是在相应的“沿”信号处执行。

把源文件的always块修改成下降沿触发  always @(negedge clk) begin

把仿真文件的最后一个#100改成#33。

 把仿真文件的 #33 改回 #100。

 

5 Modelsem小技巧

打开以下这个文件

 

 

你修改源文件或者修改仿真文件保存后,可以不用重新在vivado点击仿真。 可以在Modelsem的命令行执行以下三个命令。

        1 do tb_verilog_base_compile.do 重新编译一遍

        2 restart 有弹窗没关系,直接回车键默认Ok

        3 run 运行仿真

这样可以快速修改代码,高效率仿真。

最后愿我们共同进步! 感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

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

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

相关文章

华为云——代码托管的使用

一、打开前后端项目 登录华为云&#xff0c;点击页面右上角的用户名——点击个人设置 2.点击代码托管的HTTPS密码管理&#xff0c;设置自己的密码 3.回到代码仓库&#xff0c;复制HTTP地址 4.打开GitHubDesktop&#xff0c;点击左上角进行仓库克隆 &#xff08;我这里已经cl…

Redis 介绍相关知识,常用五大数据结构

1.Redis 介绍相关知识 Redis 是单线程多路 IO 复用技术 多路复用是指使用一个线程来检查多个文件描述符&#xff08;Socket&#xff09;的就绪状态&#xff0c;比如调用select 和 poll 函数&#xff0c;传入多个文件描述符&#xff0c;如果有一个文件描述符就绪&#xff0c;则…

1米挂幅「社交泛娱乐出海作战地图」预定火爆,免费抢领纸质版

移步【融云全球互联网通信云】回复“地图”免费领 家人们&#xff01; 融云自制《社交泛娱乐出海作战地图》 首开大捷&#xff01; 预约已超 300 出海必备实战手册 移步公众号报名 泰火辣~ 已预约进入排队的朋友请耐心等待 后期我们将按照报名顺序依次派送 另外&#…

终于通过啦! 我拿到了阿里云【通义千问】大模型AI测试体验资格啦!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

Jmeter的十大组件

1.Jmeter的十大组件以及执行顺序 1.十大组件 测试计划线程组配置元件前置处理器定时器取样器后置处理器断言监听器 2.执行顺序为从测试计划到监听器依次执行 测试计划> 线程组>配置元件>前置处理器>定时器> 取样器> 后置处理器>断言>监听器 3.作用…

leetcode 2130. Maximum Twin Sum of a Linked List(链表的最大孪生和)

给出一个单向链表&#xff0c;第i 个node 和 第(n-1-i)个node称为twin. 0 < i < n/2 - 1 求所有twin的最大和。 链表长度为偶数。 思路&#xff1a; 链表长度为偶数&#xff0c;就省了不少步骤&#xff0c;不用再考虑奇数时中间那个node单独计算了。 直觉上来看&#x…

Servlet编程---Day 06

一、会话技术概述 &#xff08;一&#xff09;什么是会话技术 类似两个人谈话&#xff0c;会话其实就是服务器和客户端的多次请求和响应 一次会话&#xff1a;多次请求和响应 组成了一次会话。从第一次发送请求建立会话&#xff0c;直到一端断开连接 http协议&#xff1a;…

web前端开发需要哪些技术?学前端顺序千万千万不要搞错啦!

宝子们&#xff0c;下午好&#xff0c;之前给大家分享了前端岗位的前景规划&#xff0c;小源看的出来&#xff0c;还是有不少宝子想入行前端的&#xff01; 那除了会面试&#xff0c;还要有充足丰富的知识储备&#xff0c;需要什么技术&#xff0c;怎么样做才能找到高薪工作呢&…

Oracle Profile详解

Profile的作用主要表现在三个方面 1、密码策略 2、对用户所能使用的资源进行管理 3、profile存放在数据字典里面&#xff0c;默认有一个名字为default的profile set linesize 160 set pagesize 30 select resource_name,resource_type,limit from dba_profiles where profile‘…

Node.js 学习系列(四)—— 回调函数

Node.js 异步编程的直接体现就是回调。 异步编程依托于回调来实现&#xff0c;但不能说使用了回调后程序就异步化了。 回调函数在任务完成后就会被调用&#xff0c;Node 使用了大量的回调函数&#xff0c;Node 的所有 API 都支持回调函数。 例如&#xff0c;我们可以一边读取…

ubuntu22.10 ffmpeg-webrtc推拉流srs环境搭建

一、编译ffmpeg-webrtc 二、openssl&#xff0c;opus&#xff0c;x264配置 三、编译srs 四、测试 4.1推流端 4.2拉流端 五、交互与sdp 最近看到杨大佬发的动态&#xff0c;尝鲜体验一下。 一、编译ffmpeg-webrtc ffmpeg-webrtc官网&#xff1a;https://github.com/ossrs/ffmp…

Linux---相关介绍、相关下载、连接Linux系统、虚拟机快照

1. Linux系统相关 内核提供了Linux系统的主要功能&#xff0c;如硬件调度管理的能力。 Linux内核是免费开源的&#xff0c;是由林纳斯托瓦兹在1991年创立并发展至今成为服务器操作系统领域的 核心系统。 内核无法被用户直接使用&#xff0c;需要配合应用程序才能被用户使用…

C++层次遍历(队列结构)

#include <stdio.h> #include <malloc.h> typedef struct ok //树结构 { int data; struct ok *lchild; struct ok *rchild; }bittree; //队列结构 typedef struct d { int head; //头 int tail; //尾 bittree **data; //数组 …

安全狗入选中国网络安全市场全景图多个细项

5月16日&#xff0c;数说安全正式发布《2023年中国网络安全市场全景图》&#xff08;以下简称全景图&#xff09;。作为国内云原生安全领导厂商&#xff0c;安全狗凭借综合且全面的产品与安全实力入选全景图。 数说安全采用科学、遵循市场发展规律且符合客户采购习惯的分类方法…

功能测试4年,5月份被辞退,2023年的功能真的没有出路了

在测试行业摸爬滚打5年&#xff0c;以前经常听到开发对我说&#xff0c;天天的点点点有意思没&#xff1f; 和IT圈外的同学、朋友聊起自己的工作&#xff0c;往往一说自己是测试&#xff0c;无形中也会被大家轻视&#xff0c;总有人会问你&#xff0c;为啥干测试啊&#xff0c…

纯python统计基于orthofinder得到的系统发育树的关注点位置的树型结构

对于某一个物种或某类物种在整个系统发育树中的位置存在一定争议的情况&#xff0c;使用直系同源基因构建单基因树&#xff0c;并对该物种或该类物种所在结构进行统计是可以对争议起到一定的解决作用的&#xff0c;在此留下全套流程和大家交流。 主要分为几步&#xff1a; 使…

260道网络安全常见面试题汇总(附答案解析+配套资料)

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;所有的资料都整理成了PDF&#xff0c;面试题和答案将会持续更新&#xff0c;因为无论如何也不可能覆盖所有的面试题。 目录 一、渗透测试…

从内网护卫到零信任尖兵:腾讯iOA炼成记

腾讯既是企业产品的服务商又是使用者&#xff0c;很多产品最原始的出发点最早只是为了解决腾讯自身某一个需求&#xff0c;经过不断地发展完善和业务场景锤炼&#xff0c;最终进化成一个成熟的企服产品。本系列文章讲述的是这样一组Made in Tencent故事&#xff0c;这是系列的第…

广西高等教育学会高校教育技术委员会莅临瑞云科技考察交流

2023年3月18日上午11点整&#xff0c;广西高等教育学会高校教育技术专业委员会组织了一批来自广西各院校的专家老师&#xff0c;来到深圳市瑞云科技股份有限公司&#xff08;以下简称瑞云科技&#xff09;参观考察。瑞云科技是一家专注为视觉行业提供垂直云计算服务的公司&…

手敲MyBatis(十一章)-支持注解配置执行SQL

1.前言 这一章节从题目中也看出来我们要支持注解版的增删改查&#xff0c;可以在Mapper层的接口类的方法上写Sql语句&#xff0c;如&#xff1a;Insert&#xff0c;Update&#xff0c;Delete&#xff0c;Select的这几个基础Sql&#xff0c;如下图&#xff0c;这样就不用在Xml里…