2021-03-16

FPGA学习心得记录


在进行仿真时,所有过程块(always和initial)都是从0时刻开始并行进行的(这里能确定一个模块内的是同时进行,不能确定其是否所有模块都同时进行)



module 名字 #(
parameter LEN=256,DW=8


线网和变量


线网和变量是同级别的

线网: <线网类型>[[<数据类型>] [signed | unsigned] [位宽]] <标识符(或者说线网名)>[=<赋值>]{,<标识符>[=<赋值>]};
这里的线网类型一般为wire
这里必须写的是线网类型和线网名,若忽略数据类型,则默认为logic型;若忽略位宽,则为1bit
数据类型有除了reg的其他所有
值得一提的是,logic类型为4值,无符号,与reg一样,但logic还可作为wire型,且若无指定logic为wire或var,则其可根据代码上下文自动决定该对象是wire还是var

变量:[var] [<数据类型>] [signed | unsigned] [<位宽>]<标识符>[=<初值>] {, <标识符> [=<初值>]};
var关键字和数据类型至少有一个,若未指定数据类型,则默认为logic


参数和常量


参数包括以下类型:parameter,localparam,specparam
常量为:const

参数和常量定义的常用形式:<参数或常量类型> [<数据类型>] [signed | unsigned] [<位宽>] <标识符> [= <常数或常量表达式>] {, <标识符> = <常数或常量表达式>};


类型和位宽转换


隐式转换:从短数转换为长数,如果短数为有符号数,高位将填充符号位,否则填充0。
显示转换:$cast $signed $unsigned。系统函数是Verilog内置的函数,大部分不能综合成实际电路,主要用于编写仿真测试代码。


操作符和表达式P71



位选取操作符:用于选取多位数据中的一位或者多为


有两种方式可用:<操作数> [<MSB表达式>:<LSB表达式>]
MSB和LSB表达式必须为常量表达式

<操作数>[<M/LSB表达式>(+:|-😃 <位宽表达式>]
M/LSB表达式可以是变量表达式,而位宽表达式必须是常量表达式


位拼接和流运算符


位拼接运算符用于将多个数据拼接成更长的数据
{<重复次数>{<操作数1>{,<操作数2>}}}

流操作符
{(<<|>>) [<宽度>|<类型>] {<操作数1> {, <操作数2>} }}
能用于对一个数的任意位取反


与或非等运算


&与 |或 ^异或 ~&与非 ~|或非 ^和^为同或
当作用于两个数时,是两个数的每个位相作用
当作用域一个数时,时单个数的每个位依次作用
当位中含有x和z时,需要查表看一下


移位


移位分为逻辑移位和算数移位
不管左移还是右移,其总的位数不变,空出来的补零。
算数右移时,若为有符号数,则在高位补符号数


自增赋值


a++和++a
前者为先用后加,后者为先加后用


条件判断相关运算符


隐含运算(->):<操作数1> -> <操作数2>
等价于:(!<操作数1> || <操作数2>)

等价运算(<->): <操作数1><-><操作数2>
等价于((<操作数1>-><操作数2>)&&(<操作数2>-><操作数1>))

算数比较运算符(< <= >= >)直接根据字面意思理解,如果算数比较运算的操作数中含有x或z,则结果均为1’bx

在相等、不等中有x或z时,若由x和z使得结果不确定时,则结果为1’bx。(== !=)

在条件相等、条件不相等中,其x和z也作为比较的位,进行比较。(=== !==)

通配相等和通配不等运算中,右边操作数的x和z不参与比较。(==? !=?)


let语句


let<表达式名>(<端口1>{, <端口i>}) = <引用端口的表达式>;
有点像函数


结构和联合


结构可以整体赋值,也可以单个变量单独赋值
整体赋值:’{<成员1值>{, <成员i值>}}
单独赋值:结构名.变量名=a

紧凑型可对所有数据同时操作,如对两个相邻数的位同时操作。

联合与结构类似,但其中的成员共用 值保持单元。因此,可以使用带标签的类型,标记联合中的一个成员,使得只有被标记的成员能进行赋值,其他成员不能赋值。


数组


<类型>[i-1:0][j-1:0]<数组名>[m][n]
mn个元素,或者说数;一个数可以被分为ij份;例如先将一个32位的数,分成4*8份


赋值


赋值用来驱动线网或者变量
持续赋值:持续赋值使得线网持续接收右值,相当于直接连接到组合逻辑的输出
在线网定义时赋值和使用assign语句赋值。
assign<线网名1>=<表达式1>{, <线网名i>=<表达式i>}

过程赋值:在特定事件发生时更新变量的值
initial过程
always过程
always过程:可指定或不指定触发事件。
always_comb过程:专用于描述组合逻辑,在过程内的语句所依赖的任何一个值发生变化时执行,输出随着输入的变化而立即变化
always_ff过程,专用于描述触发器逻辑(ff时触发器flip-flop的缩写),当指定的线网或变量(即时钟)出现指定跳沿时执行。
final过程,在仿真结束时执行一次。
task过程,即任务。
function过程,即函数


程序进行过程


在程序一旦开始,各种过程和非过程的语句同时进行,过程内可能是从上到下,也可能是同时进行。非过程都是从上到下


foreach


foreach语句用于穷举数组中的元素,一般形式如下:
foreach(arr[i,j])arr[i][j] = i+j //将arr中的每个元素赋值为其中索引的和


always


always过程是Verilog中,特别是FPGA设计中最重要的语法元素

always<单一语句或块>
没有指定过程执行的触发条件,过程将不断重复执行

always@(<敏感值列表>)<单一语句或块>
当敏感值列表中的任何一个变量或线网发生值改变时,过程执行。当块内语句依赖的所有变量和线网都在敏感列表中列出来时,则always组成组合逻辑。
如果块内语句依赖的变量或线网只有部分列出,则always语句将构成锁存器逻辑

always@(*)<单一语句或块>
编译器将自动找出块内依赖的所有变量填充,主要用于实现组合逻辑

always@(<事件列表>)<单一语句或块>
事件的常用形式为 posedge <变量或线网>{(, | or) (posedge) <变量或线网>}

用作沿触发的变量和线网如果有多位,则只有最低位有效。

0->1、z、x均为上升沿
x、z->1 也为上升沿


always专用于组合逻辑和时序逻辑的式子


always_comb<单一语句或块>
启动时会执行一次,与真实组合逻辑电路的行为相符
不允许被驱动的变量在任何其他过程中驱动

always_ff@(posedge<时钟>iff<时钟使能条件>or posedge<异步复位>)
即得使能端作用,且有上升沿时,才执行过程
使能端在实际FPGA中推荐写在if里


阻塞和非阻塞赋值


除非阻塞赋值以外的所有赋值均为阻塞赋值

在顺序块中,阻塞赋值语句将“阻塞”后面语句的求值和赋值,即阻塞赋值语句是按书写次序逐条求值和赋值的;而非阻塞赋值语句不会“阻塞后面语句的求值和赋值,

“<=”在最后一个“=”前面时,“<=”和最后一个“=”同时赋值;当“<=”在最后一个“=”后面时,“=”赋值后,“<=”才赋值


使用阻塞型和非阻塞型语句的原则


描述触发器逻辑时,一律使用非阻塞赋值,这样每个被赋值的变量都形成触发器

描述组合逻辑时,一律使用阻塞赋值,这样可以确保不会出现触发器

测试代码中使用initial过程和不带敏感值/事件列表的always过程时使用阻塞赋值,以形成便于理解的时序。


input和output类型


input和inout端口只支持线网类型,output端口可以是线网也可以是变量(在fpga中)

在定义input和inout时,若没有指明为线网或者变量,则默认为线网;若数据类型也没有指定,则默认为logic型。

在定义ouput端口时,若没有指明为线网或者变量,则默认为变量;若数据类型也没有指定,则默认为logic类型的线网。


模块定义


当模块定义中包含parameter型的参数时,则module<模块名>#(

当模块定义中不包含parameter型参数时,则module<模块名>(


延时


5延时5个单位


$clog2()


$clog2(LEN)即log(LEN)


'{LEN{'0}}表达意思


logic [DW-1 : 0] m[LEN] = '{LEN{'0}};
即全部赋0


接口


当觉得在很多模块中写一摸一样的长长的端口定义很烦时,可使用接口


生成块


当觉得在模块中重复写类似的有规律的内容比较繁琐时,可使用生成块


任务和函数


ref作用:可将输入变量定义为ref型,使得在调用函数或任务时,传入的时指针,可方便操作数组的传入。值得注意的是,ref只用于自动存储的子程序中,即automatic。
当同时使用ref和const时,传入的数值不允许改变,只允许使用。

函数定义时,头部的数据类型符号位宽值的是输出的符号类型位宽。


typedef


将关键字进行替换


将结构体作为自变量传递至task和function


想要传递结构体类型的自变量,要先使用typedef定义为用户自定义数据类型的结构体。
在数据类型宽度那个位置,用结构体的定义来表示。

具体例子可在p102找到


系统任务和函数


系统任务和函数本身都是不能综合成实际电路的,主要用于仿真测试。但部分任务和函数会干预综合过程,影响综合结果,是可综合的代码中有用的内容,比如类型转换和存储器相关函数和任务。


文件操作


其多通道描述符是由 f o p e n 返 回 的 。 每 次 使 用 fopen返回的。每次使用 fopen使fopen,他返回的值会不同(也可以说通道不同),这不同的值就代表不同的文件。


reg和wire


wire为线性,物理上是直接一个线连接,赋值时不能在过程语句中(always和initial),只能使用assign赋值,且赋值后一直都有作用

reg为变量,物理上可以看作寄存器,赋值时一般在过程中,只有当语句执行时才生效,被赋值的变量的值才更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值