您的位置:首页 > 编程语言 > PHP开发

FPGA学习笔记3-verilog HDL

2012-01-19 14:48 337 查看
Verilog HDL基础

不是软件编程语言,是一种可以硬件仿真的硬件描述语言

常用术语

HDL-Hardware Description Language 

RTL-Register Transfer Level

行为建模-由输入输出关系描述的组件

结构化建模-由底层互联组成和原语描述的组件

综合-将HDL译成电路,然后对表征电路进行优化

模块-是verilog HDL中基本设计单元

行为建模

只有电路功能,没有结构

没有专门的硬件目标

由于综合以及仿真目的

可面向任意技术的通用代码

结构化建模

电路功能和结构

要求明确的硬件实现

处于综合以及仿真目的

可以是通用或者器件专用,也可以同时兼用

RTL综合

语句-译成-优化

模块结构

Verilog基本模型结构
moudle moudle_name(port_list);
    端口声明
    数据类型声明
    电路功能
    时序规范

end moudle 

case敏感

所有关键字为小写

空白用于提高可读性

分好是声明结束符

单行注释://

多好注释:/* */

时序规范用于仿真

端口

端口列表

-端口名称列表,例如:moudle mult_acc(out,ina,inb,clk,clr)

端口类型

-input(输入端口)

-output(输出端口)

-inout(双向端口)

端口声明

-<port_type><port_name>

-例如:input[7:0] ina,inb;

             input clk,clr;

             output[15:0] out;

数据类型

网数据类型(NET)-表示进程之间的物理连接

寄存器类型-表示暂时存储数据的变量,并不一定表示硬件中寄存器

NET数据类型

wire-表示一个节点或者连接

tri-表示一个三态节点

supply0,逻辑0,

supply1,逻辑1

寄存器数据类型

寄存器可以是:整数,实数,时间,实时

只能在进程声明,任务或者功能中赋值reg类型变量

不能是逻辑门输出,或者是assign语句的输出

输入输出规则表

variable_typeinputoutput inout
netYESYESYES
register NOYESNO
赋值-数字

sized或者Unsized
<size>'<base format><number>

size例子:3'b010 = 3位宽二进制数字,前缀3表示数字位宽

unsize例子:123 = 默认的32位宽十进制数字

PS.默认-没有指定的<base format>,默认为decimal,没有指定的<size>,默认为32位宽数字

基本格式

-十进制   ('d或者'D)16'd255 = 16位宽十进制数字

-十六进制 ('h或者'H)8'h9a = 8位十六进制数字

-二进制   ('b或者'B)'b1010 = 32位宽二进制数字

-八进制   ('o或者'O)'o21 = 32位宽八进制数字

数字

负数-在<size>前加上负号表示

-合法:-8'd3 = 8位负数,存储为2'的补码3

-非法:4'd-2 = Error!

特殊数字字符

-'_'(下划线):用于可读性

例子:32'h21_65_bc_fe = 32位16进制数字

-'x'或者'X'(未知值)

例子:12'h12x = 12位16进制数字:LSB位置

-'z'或者'Z'(高阻抗值)

例子:1'bz = 一位高阻抗数字

算子

算子符号执行的计算 例子(ain=5,bin=10,cin=2'b01,din=2'b0Z)
+加法bin + cin = 11
-减法,取负bin - cin = 9 , -bin = -10
*乘法ain * bin = 50
/除法bin / ain = 2
%取模bin % ain = 0,PS:取模支持的比较有限
1.把矢量整体作为一个数值

2.如果任一操作数为Z或者X,那么结果未知。例:ain + din = unknow

3.如果结果和操作数大小相同,则进位丢失

4.负数以2的补码格式存储,但是当用在表达式中时,解释为无符号值

位算子                            

算子符号执行的计算例子(ain=3'b101,bin=3'b110,cin=3'b01X)
~每位取反~ain = 3'b010
&每位andain&bin = 3'b100 , bin&cin = 3'b010
|每位orain|bin = 3'b111
^每位Xor  ain^bin = 3'b011
^~或者~^每位Xnorain^~bin = 3'b100
1.对操作数的每一位进行运算

2.结果是最大操作数的大小

3.如果位宽不同,以零向左扩展

缩位算子                           

算子符号执行的计算例子(ain=5'b10101,bin=4'b0011,cin=3'bZ00,din=3'bX011)
&and所有位&ain = 1'b0 , &din = 1'b0
~&nand所有位~&ain = 1'b1
|or所有位|ain = 1'b1 , |cin = 1'bX
~|nor所有位~|ain = 1'b0
^Xor所有位 ^ain = 1'b1
~^或者^~Xnor所有位~^ain = 1'b0
1.将矢量减为单比特

2.X或者Z被认为未知,但是结果可能是确定值,例:&din = 1'b0

关系算子                         

算子符号执行的计算 例子(ain=3'b010,bin=3'b100,cin=3'b111,din=3'b01z,ein=3'b01x)
>大于ain>bin = 1'b0
<小于  ain<bin = 1'b1
>=大于等于 ain>=din = 1'bX
<=小于等于ain<=ein = 1'bX
1.用于对比数值

2.返回一位标量值,布尔真(1)/假(0)

3.如果任一操作数是Z或者X,那么结果未知

相等算子                     

算子符号执行的计算  例子(ain=3'b010,bin=3'b100,cin=3'b111,din=3'b01z,ein=3'b01x)
==相等ain==cin = 1'b0
!=不等ein!=ein = 1'bX
===条件相等ein===ein = 1'b1
!==条件不等ein!==din = 1'b1
1.用于对比数值

2.返回一位标量值,布尔真(1)/假(0)

3.如果任一操作数是Z或者X,那么结果未知

4.条件相等和不等包括X和Z

PS:相等只支持已知的数值,不支持z,x,条件相等支持所有的数值,1,0,x,z

逻辑算子                  

算子符号执行的计算例子(ain=3'b101,bin=3'b000)
非真!ain = 1'b0
&&所有表达式真ain&&bin = 1'b0
|| 一个或所有都真ain||bin = 1'b1
1.返回一位标量值,布尔真(1)/假(0)

2.如果任一操作数是Z或者X,那么结果未知

移位算子                                           

算子符号执行的计算例子(ain=1'b1010,bin=4'b10X0)
>>右移bin>>1 = 4'b010X
<<左移ain<<2 = 4'b1000
1.矢量向左或者向右移动一定比特

2.填充零

3.移出比特丢失

其他算子        

算子符号执行的计算例子
?:条件(condition)?true_val:false_val;  sig_out = (sel==2'b01)?A:B;
{}连接ain=3'b010,bin=4'b1100;   {ain,bin} = 7'b0101100;
{{}} 复制 {3{2'b10}} = 6'b101010
算子优先级

算子默认优先级

 +,-,!,~(unary)

 +,-(Binary)

 <<,>>

 <,>,<=,>= 

 ==,!=

 & 

 ^,^~ or ~^

 |

 &&

 ||

 ?:(ternary)

()可以优于默认优先级

赋值语句

连续赋值声明

使用算子,对组合逻辑进行建模
wire adder_out = mult_out + out

等价于
wire adder_out

assign adder_out = mult_out + out

assign #5 adder_out = mult_out + out 延迟5个tip

1.左手侧(LHS)必须是net数据类型

2.保持主动:当一个右手侧(RHS)操作数变化时,评估表达式,立即更新LHSnet

3.RHS可以是net,寄存器或者函数调用

4.延迟值可以赋值给模型逻辑门延迟

进程赋值模块

inital模块-用于初始化仿真的行为声明(被综合器忽略)

always模块-使用行为声明,用于描述电路功能

1.每个always和inital模块代表不同的进程

2.进程并行运行,在仿真时间0开始

3.而进程中的声明顺序执行

4.always和inital模块不能嵌套

inital模块

由行为声明构成

用于初始化,监视,波形和其他进程,在仿真中只能执行一次

-一个inital模块在时间0启动,在仿真中只执行一次,然后不再执行

-inital模块中的行为声明顺序执行

-因此,声明的顺序并不重要

综合不支持(例如,被综合器忽略)

always模块

由行为声明构成

如果有多个always模块,同时执行每个模块

用于对数字电路中不断重复的进程进行建模

-一个always模块在时间0启动,以循环的仿真连续执行行为声明

-初始模块中的行为声明顺序执行

-因此,声明的顺序并不重要

-如果有多个声明,必须使用关键词begin和end组合在一起

两类进程赋值

阻塞赋值(=):按顺序模块中指定的次序执行

非阻塞赋值(<=):不对顺序模块后的声明进行阻塞赋值,支持对赋值的调度,时间步长的最后进行

驻留在进程模块中

左手侧,更新reg,integer,real,time或者realtime变量值

PS:实际上感觉非阻塞赋值即是不考虑赋值顺序中其上存在延迟赋值,即所有的赋值延迟参考点为赋值段开始的时候,

而阻塞赋值则是为上一个赋值结束为下一个阻塞起始参考点

使用进程模块的电路类型

组合电路-对组合逻辑中使用的所有输入敏感

例子:always @(a or b or sel)  敏感事件列表包括组合逻辑使用的所有输入

时钟电路-对时钟以及控制信号敏感

例子:always @(posedge clk or negedge clr)  敏感事件列表不包含输入,只有时钟以及控制信号

行为声明

-IF-ELSE声明

对条件按照从上到下的顺序进行评估

优先级

-CASE声明

立即对条件进行评估

没有优先级

循环声明

用于重复计算

PS:
必须用于always或者initial模块中

这些行为声明也可以用在时钟进程中

IF-ELSE声明(逐个检查条件)
if (<conitional 1>)
sequence of statement(s)

else 

if (<conitional 2>)
sequence of statement(s)
.
.

else
sequence of statement(s)

CASE声明(立即检查条件,不过条件不可有交叠,效率比if高)
case (expression)
<condition 1>:
sequence of statement(s)
<condition 2>:
sequence of statement(s)
.
.
sequence of statement(s)
defalut:
sequence of statement(s)

endcase

两种其他形式的CASE声明

casez

-认为case条件下的所有'z'值不重要,不是逻辑值

-所有'z'值也可以表示为'?'

casex

-认为case条件下所有'x'和'z'值不重要,不是逻辑值

永远和重复循环

forever循环-不断执行

例:
inital
begin
clk = 0;
forever #25 clk = ~clk;
end

repeat循环-执行一定次数

例:
if(rotate == 1)

   repeat(8)
begin
  tmp = data[15];
  data = {data<<1,temp};
end

while循环-如果表达式为真,则执行

例:(从0到100计数,101退出循环)
inital

   begin
count = 0;
while(count<101)
 begin(count<101)
    $display("Count =%d",count);
    count = count + 1;
 end

   end

for循环-循环开始时立即执行一次,如果表达式为真,则继续执行

例:
integer i; //declare the index for the FOR LOOP

always @(inp or cnt)

   begin
result[7:4] = 0;
result[3:0] = inp;
if(cnt == 1)
 begin
    for(i=4;i<=7;i=i+1)
begin
 result[i] = result[i-4];
end
    result[3:0]=0;
 end

   end

Verilog HDL函数和任务

-函数和任务是子程序

-用于可重复代码

-增加模块可读性

-函数

--根据输入返回一个值

--产生组合逻辑

--用在表达式中:assign mult_out = mult(ina,inb);

-任务

--与其他语言的程序相似

--可以使组合或者寄存

--以声明形式调用任务:stm_out(nxt,first,sel,filter);

函数定义例:
function [15:0]mult;
//函数名字,也是返回变量

  input[7:0] a,b;

  reg[15:0] r;

  integer i;

  begin

    if(a[0]==1)

       r=b;

    else 

       r=0;

    for(i=1;i<=7;i=i+1)

      begin

        if(a[i]==1)

   r=r+(b<<i);

      end

  mult=r;

  end

endfunction

任务实例:
task add;     //task definition

  input a,b;  //two input argument ports

  output c;   //one output argument port

  begin
c=a+b;

  end

endtask

函数和任务的不同

函数任务
可以使能其他函数,但不是其他任务可以使能其他任务和函数
不能包括任何延迟,时间或者时序控制声明可以含有延迟,事件或者时序控制声明
至少要有一个输入变量可以由零或者更多的输入,输出或者inout变量
总能返回一个数值返回零或者更多的数值
不能有output或者inout变量
 
PS:实际上感觉函数就是有返回值的,任务就是没有返回值的函数,应该说是没有返回赋值。

函数调用时表达式为

assign mult_out = mult(ina,inb);

ina,inb为输入量,而函数定义中的r作为输出量,返回给mult,然后赋值给mult_out,每次能够只能返回一个变量

任务调用表达式为

add(1,0,p); p声明为reg

这里按照数值出现顺序进行传递,1,0为input,而p作为output输出,这里直接返回给p,没有通过内部中继,可以一次性返回多个变量

函数可以调用另外一个函数,但是不可以调用另外一个任务

而任务可以调用另外一个任务,也可以调用函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息