【FPGA入门】第一篇、Verilog基本语法常识

news2024/11/20 20:20:38

目录

第一部分、不同的变量类型

1、wire和reg的区别

 2、如何对变量进行赋值呢?

3、什么是阻塞?什么是非阻塞?

第二部分、变量位宽的定义

1、各种系统默认情况

2、变量位宽声明方式

3、表明位宽的情况下,赋值方式

4、两个模块之间例化,不定义变量直接用的方式

5、常用的变量定义为参数

第三部分、赋值语句

1、assign和always赋值语句的区别

2、assign和always赋值语句的例子

3、inital语句

4、reg类型变量的初始值问题

第四部分、运算符号

1、算数运算符(+,-,*,/,%)

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

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

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

5、三目/条件运算符((x)?x:x)

6、赋值运算符(= 、<=)

7、移位运算符(>>、<<)

8、位拼接运算符({})

第五部分、条件判断语句

1、if else语句的注意事项

2、begin end问题

3、case endcase语句的注意事项

第六部分、赋值分隔符问题

第七部分、编写测试代码时常用的语句

1、随机数产生代码

2、初始化代码模块

3、时钟产生代码

4、延时代码

第八部分、总结


第一部分、不同的变量类型

1、wire和reg的区别

verilog中的变量类型有wire类型和reg类型。

在实际的电路中wire类型对应的就是一根导线,只存在传输的作用。而reg类型在实际电路中表示寄存器,可用来存储数据的。

如下图:

 2、如何对变量进行赋值呢?

  • 学习C语言可以知道赋值就是用=号,int a = 15;//将15赋值给a;
  • 然而在verilog语法中也有 =(阻塞赋值) 这种赋值方式,当然除了这种方式还有 <=(非阻塞赋值)这种方式;
  • 阻塞赋值 = (例如 a = b;):b的值在赋值语句执行完后立刻就改变的,用在组合逻辑;
  • 非阻塞赋值 <= (例如 a <= b ;):b的值想要发生变化,必须要在时钟的上升沿/下降沿,用在时序逻辑;

3、什么是阻塞?什么是非阻塞?

阻塞:假设信号pi_a在导线上传输的时间为5ns,pi_b在导线上传输的时间是10ns,而po_c的值因为pi_b晚到5ns而被阻塞。

非阻塞:假设信号pi_a在导线上传输的时间为5ns,pi_b在导线上传输的时间是10ns,虽然po_c存在阻塞问题,但是Q端输出的结果只取决于clk上升沿/下降沿到来时D端的瞬时结果,因次Q输出不存在阻塞。

总结:

  • 你想要在时钟的上升沿到来时才想要输出变化那就用非阻塞,你想要输出变化之取决与输入,输入变化,输出就变换那就用非阻塞。
  • 组合逻辑只能用阻塞赋值,时序逻辑只能用非阻塞赋值。

第二部分、变量位宽的定义

1、各种系统默认情况

不注明位宽的情况下,默认位宽为1。

input a;//默认为wire类型,位宽为1位

reg clk;
reg key1,key2;

2、变量位宽声明方式

wire [高位:低位]变量名;
reg  [高位:低位]变量名;

wire [高位:低位]变量名[denth:0];//表示数据深度
reg  [高位:低位]变量名[denth:0];//表示数据深度
//上面这种定义调用时
变量名[i];  默认认为是第几个数据,而不是该数据的第几位,除非再加一个括号,才表示第几位

3、表明位宽的情况下,赋值方式

//wire类型的变量
wire [7:0] value;

assign value = 8'd255 = 8'hff = 8'b1111_1111 = 'd255;//你是几位,那么赋值就一定要带上那个位数,不管你赋的什么值
assign value = 255;//系统默认255为32位的十进制数据,然后截取低8位数据到value中。

//reg类型的变量
reg [7:0] value;
assign@ (posedge clk) begin
value <= 8'd255;
value <= 8'hff;
value <= 8'b1111_1111;
value <= 'd255;
end

4、两个模块之间例化,不定义变量直接用的方式

一位位宽的wire类型变量在不输入也不输出的情况下,可以不声明,但是这种做法不推荐,容易翻车,写的代码别人看不懂。

5、常用的变量定义为参数

注意:parameter后面的参数建议定义成大写字符

一般情况下,变量定义为小写字母,参数定义为大写字母。

parameter LEN 100;//相当于C语言中的#define LEN 100

第三部分、赋值语句

1、assign和always赋值语句的区别

1、assign赋值语句:

  • assign只能实现组合逻辑;
  • assign语句后面只能跟一条语句;
  • wire型变量,必须在assign中进行赋值。
assign 表达式;

2、always赋值语句:

  • always赋值语句不但能实现时序逻辑,还能实现组合逻辑;
  • reg型变量,必须在always中进行赋值;
  • always敏感信号可分为边沿触发和电平触发;
    • 电平触发时always@(*) = always@(a or b) = always@(a ,b);
    • 电平触发:敏感列表触发电平信号不全会导致锁存器的产生;
  • always@(边沿触发):非阻塞赋值语句,对应时序逻辑电路。
  • always@(电平触发):阻塞赋值语句,对应组合逻辑电路。

注意:一个变量只能在一个always语句块中被赋值,不能在两个语句块中赋值,因为always语句块是并行执行的,会产生冲突。

always@(敏感信号)begin
    语句;
end

2、assign和always赋值语句的例子

module variable_assignment(
    input wire clk,
    input wire a,
    input wire b,

    output wire c,
    output reg  c1,
    output reg  c2
    );

//assign combinatorial logic
assign c = a & b;

//always combinatorial logic
always@(*)begin
    c1 = a & b;
end
always@(a,b)begin//equivalence
     c1 = a & b;
end
always@(a or b)begin//equivalence
     c1 = a & b;
end

//sequential logic
always @(posedge clk)begin
    c2 <= a & b;
end 
endmodule

3、inital语句

  • inital语句是初始化语句,但是不能写在可综合模块中,因为有些综合软件无法综合inital语句。
  • inital语句中被赋值的变量必须是reg类型。
//举例子
initial begin
    clk = 0;
    a = 0;
    b = 0;
end

4、reg类型变量的初始值问题

  • reg类型的变量是可以赋初始值,但是有个条件就是这个reg类型的变量不能在后面的语句中被综合为了组合逻辑,只有reg是时序逻辑才可以在fpga里赋值初始值。(最好是这样,记住就可以)
  • reg变量既可以生成时序逻辑,也可以生成组合逻辑。
  • reg赋初始值时要用阻塞赋值。

第四部分、运算符号

1、算数运算符(+,-,*,/,%)

注意:在功能模块中尽量减少使用*,/,%这三种运算。

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

注意:小于等于(<=),在条件判断语句中和非阻塞赋值有点像,所以一定要注意,不要犯错!!

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

返回的值要么为真,要么为假。

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

5、三目/条件运算符((x)?x:x)

6、赋值运算符(= 、<=)

7、移位运算符(>>、<<)

多次左移,会使数据溢出,例如0001,在左移4次后会变为0000,丢失一位数据,回到0。这在循环右移的代码中就会节约一个选择器

8、位拼接运算符({})

一个非常巧妙的利用位拼接符实现循环左移的方法。

妙蛙种子吃了妙脆角妙进米奇妙妙屋,秒到家的移位操作!!!!!!

 示例如下:

module operational_sign_homework(
    input wire clk,
    input wire rst,
    output reg [7:0]po_a = 1'b0//give an initial value
    );
//循环左移的方式
always@(posedge clk) begin
        if(rst == 1'b1)    //这里采用同步复位的方式
            po_a <= 8'd1;
        else if(po_a == 8'b1000_0000)//多消耗一个寄存器
            po_a <= 8'b0000_0001;
        else 
            po_a <= po_a << 1;


//通过位拼接操作符来实现循环左移(太刁了,比上面的方法好)
always@(posedge clk) begin
        if(rst == 1'b1)
            po_a <= 8'd1;
        else 
            po_a <= {po_a[6:0],po_a[7]};//每来一次上升沿,我就搬移一次,就形成了循环
    end    
endmodule

第五部分、条件判断语句

        条件判断语句有if else 和 case endcase这两种,这两种语句的赋值都必须放在always语句中。

1、if else语句的注意事项

1.1、if else语句叠加不能太多,老师的经验是不能大于8级,因为if else是串行执行的语句,如果太多就会导致线路的延时太多,进而导致时序违例

1.2、if else语句书写的时候要考虑优先级。

1.3、if else语句结尾尽量以else结尾,这样可以避免锁存器的产生。

什么是时序违例?

也就是说:当前时钟上升沿我把信号给了当前的电路模块,因为当前个电路模块时延很严重,经过一个时钟周期后,到了下一个时钟的上升沿,正常情况下你这个模块就应该输出处理好的输出信号,结果因为时延,我在输出端口检测不到输出信号。

通常表现上是:建立时间不满足要求通常是因为组合逻辑处理时间太长、保持时间不满足要求通常是因为组合逻辑处理时间太短。

2、begin end问题

        begin end就是括号等价于C语言中{}。

always@(posedge clk) begin
    if(rst == 1'b1)
        po_a <= 8'd1;
    else 
        po_a <= 8'd0;
  end
//需要注意的是,加begin end和不加begin end都是对的!!!!
always@(posedge clk) 
    if(rst == 1'b1)
        po_a <= 8'd1;
    else 
        po_a <= 8'd0;

3、case endcase语句的注意事项

  • case语句结尾必须时endcase。
  • case语句是并行执行,(多路选择器)所以多种条件时使用case endcase语句比使用if else速度要快,但是case endcase也不能非常多。
  • case的条件在没有完全列清楚的情况下,要用default语句。
//可以带上begin end
always@(posedge clk)
    case(po_a)
    1:    po_a <= 8'd1;
    2:    po_a <= 8'd2;
    default: po_a <= 8'd0;
    endcase
//带上begin end
   always@(posedge clk)
    case(po_a)
    1:begin    
        po_a <= 8'd1;
    end    
    2:    po_a <= 8'd2;
    default: po_a <= 8'd0;
    endcase 

第六部分、赋值分隔符问题

当在数值前面声明了位宽以及进制,这种表达方式可以放数值的分隔符。

下面两种表达方式都可以,这两条语句完全等价:

parameter END_COUNT = 'd49_999_999;
parameter END_COUNT = 26'd49_999_999;//这两条语句完全等价

当数值前面没有带位宽以及进制,系统默认为32位的十进制数据,这个时候无法再对数据放置分隔符。

错误的表达方式:

parameter END_COUNT = 49_999_999;//错误的表达方式

第七部分、编写测试代码时常用的语句

1、随机数产生代码

a = {$random}%256;//产生0~255的随机数据

2、初始化代码模块

initial begin
    clk = 0;
    rst_n = 0;
    #100;
    rst_n = 1;
end

3、时钟产生代码

always #20 clk = ~clk;

4、延时代码

#200;//延时200ns

第八部分、总结

        这些都是我在使用过程的一些总结,希望能够对你帮助🤓🤓🤓。

        然后这篇文章将给大家带来一个新的系列那就是【FPGA入门】,我会在这个系列中记录一些有趣的实验和心得,虽然之前也写过FPGA的相关内容,但是那部分内容主要是学习Altera中的Nios II中的IP核。

        而这个系列是我正式入门FPGA学习的过程,所以我会尽量保证接下来每一篇文章的质量,当然我也是一个比较笨的人,写博客的过程中总有一些错误,希望读者发现后及时告诉我,我们一起进步。

        最后,希望大家可以继续关注后面的文章。冲!

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

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

相关文章

来自一个敲了5年代码的网络安全工程师的自述(目前薪资30K)

本人是一名敲了5年半代码的网络安全工程师&#xff0c;目前在杭州工作&#xff0c;月薪目前是在30.6K左右&#xff0c;经历过两次跳槽&#xff0c;第一次跳槽拿到了12K的offer&#xff0c;第二次跳槽拿到18K的offer。一直到目前为止的30K左右。 说到这里再给大家提个醒&#x…

SpringBoot整合定时任务技术Quartz

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ RequestMapping注解 &#x1f680;Quartz应用场…

好消息!PMP证书还没过期的宝子,可以增持免考CSPM-2证书

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

如何使用hexo next主题,新建一个专栏

文章目录 backgroundIntroHow to do that&#xff1f;&#x1f388; background 今天突发奇想&#xff0c;想要在自己的博客中增加一个新的专栏&#xff0c;记录自己的一些随想。起因是不想让博客成为一个纯粹记录技术成长的网站&#xff0c;&#xff08;毕竟如果真的有人要看…

PostgreSQL(八)锁的相关操作

目录 一、锁存在的意义二、表级锁1.ACCESS SHARE2.ROW SHARE3.ROW EXCLUSIVE4.SHARE UPDATE EXCLUSIVE5.SHARE6.SHARE ROW EXCLUSIVE7.EXCLUSIVE8.ACCESS EXCLUSIVE9.表级锁模式冲突表10.示例一11.示例二 三、行级锁1.FOR UPDATE2.FOR NO KEY UPDATE3.FOR SHARE4.FOR KEY SHARE…

那个准点下班的人,比我先升职了...

前言 二黑最近心态很崩。 和他同期一道进公司的陈琪又升了一级&#xff0c;可是明明大家在进公司时&#xff0c;喜子不论是学历还是工作经验&#xff0c;样样都不如自己&#xff0c;眼下不过短短的两年时间便一跃在自己的职级之上&#xff0c;这着实让他有几分不甘心。 二黑…

Unity 安装负责音频的 wwise

很多游戏的音频用的是 wwise 先下载 https://www.audiokinetic.com/zh/download 安装的时候要选sdk 就是20g的那个 然后运行 选择unity 可以看到这个界面 好&#xff0c;现在开始要安装离线包 直接项目里点 第二个 装好后 他会提示你 无法找到unity安装的地址 1 打开你的 …

干货 | 电路中为何需要串联小电阻?

电路中串联小电阻是电路设计中常见的一种技术手段&#xff0c;它可以在电路中起到多种作用。在本文中&#xff0c;我将从不同的角度分析串联小电阻的作用&#xff0c;深入探讨为何需要在电路中串联小电阻。 一、串联小电阻的概念和作用 串联小电阻是指在电路中串联一个电阻&am…

使用hutool实现entity转map、map转entity,以及entity转entity

前言 在项目开发中&#xff0c;entity的数据结构一般用来传参以及结果响应&#xff0c;但是在某些场景下&#xff0c;map可以实现list无法实现的效果。 比如&#xff1a;实现根据不同等级的用户&#xff0c;可以看到的数据的数量不一样。等级低的用户看到的某些字段是经过加密…

Redis入门 - 发布订阅

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis入门 - 发布订阅 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-pub-sub.html Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收…

基于Java Web的墓地管理系统的设计与实现+第五稿+文档

博主介绍&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 项目名称 基于Java Web的墓地管理系统的设计与实现第五稿文档 视频演示 视频去哪了呢&#xff1f;_哔哩哔哩_bilibili 系统介绍 3.3 角色分析 本系统一共分为…

微信小程序9大方面测试点全方位总结

微信小程序无需下载安装&#xff0c;用户在微信扫一扫或搜索即可使用&#xff0c;小程序版本类型可分为&#xff1a;开发版、体验版、正式版。 开发版、体验版无需审核&#xff0c;只需要给微信号权限&#xff0c;经过扫小程序的二维码就能访问&#xff0c;正式版本需要经过微…

计网期末复习篇

五层协议 协议字段数据单元 PDU 典型协议 (协议字段) 网络连接设备 寻址方式 物理层 比特流 以太网协议 232、485、449、x25、以串口方式、网卡 物理层不寻址 数据链路层 帧 ppp协议 broadcast协议 网桥、网络交换机(特点有题) MAC地址(48bit) 网络层 (重点) 网络分…

Spark SQL 内置函数

文章目录 一、Spark SQL内置函数&#xff08;一&#xff09;内置函数概述1、10类内置函数2、两种使用方式 &#xff08;二&#xff09;内置函数演示1、通过编程方式使用内置函数upper()2、通过SQL语句的方式使用内置函数upper()3、演示其它内置函数的使用 二、自定义函数&#…

离散数学题目收集整理练习(期末过关进度30%)

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 ✨博主的其他文章&#xff1a;点击…

软件 安全,处理威胁STRIDE模型

微软威胁分析工具&#xff1a; https://www.microsoft.com/en-us/securityengineering/sdl/threatmodeling?azure-portaltrue STRIDE 是微软定义的6中威胁 身份假冒&#xff08;Spoofing&#xff09; 身份假冒&#xff0c;即伪装成某对象或某人。例如&#xff0c;我们通过伪…

校园旧物商城系统

一、项目说明 校园旧物回收商城&#xff0c;使用SpringbootVue2.x开发,使用了JWT、MybatisPlus、JWT、ElementUI 项目已经开源在https://github.com/astudent2020/Campus_waste_recycling 文章目录 一、项目说明一、说明书1、用户主页&#xff1a;2、登录注册页面3、后台页面…

在Maya、ZBrush和UE中制作龙香炉

大家好&#xff0c;今天云渲染小编给大家带来的分享是来自印尼的CG艺术家Stephen Herman“龙香炉”道具分解幕后花絮。 介绍 大家好&#xff01;我叫 Stephen Herman&#xff0c;是来自印度尼西亚雅加达的 3D 艺术家。 目前&#xff0c;我在 Bandai Namco Studios Malaysia …

数字电路基础---时序逻辑

时序逻辑 通过前面的组合逻辑的学习&#xff0c;我们知道了组合逻辑电路是没有记忆功能的&#xff0c;也就是说在任何时刻产生的输出信号都仅仅取决于该时刻电路的输入信号&#xff0c;而与它以前的输入信号是无关的。下来我们来学习下什么是时序逻辑。 1、简介 时序电路是有…

C语言实现顺序表

绪论 从本章开始就是开始数据结构的开端&#xff0c;本章将会写出数据结构中的顺序表的代码实现&#xff0c;多会以注释的方法来描述一些细节&#xff08;注释是我们程序员必须常用的工具&#xff09;。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看&#xf…