Verilog基本语法
- 1 模块结构
- 端口: module 模块名(端口1, 端口2, 端口3)
- 内容:
- I/O说明:
input 端口名; output 端口名;
- 内部信号:
reg [width-1:0] r变量1,r变量2; wire [width-1:0] w变量1,w变量2;
- 功能定义:
- a. assign 连线
- 功能定义:
assign a = b&c;
- b. 实例化其他元件
and and_inst(q, a, b);
- c. always模块
always @(posedge clk or posedge clr) begin if(clr) q <= 0; else if(en) q <= d; end
- 2.数据类型 常量 变量
- 常量:
- 整数:<位宽 num'><进制 b|o|d|h><数字>,例如 4'b1010
- 常量:
x值(不定值)和z值(高阻值,也可用?代替) x和z可以标识某一位或者某一个数字 4'b10x0,4'bx,4'b101z,4'bz,4'b?
- 负数:整数最前面加-
- 下划线:分割数字部分,更加易读(8'b1000_1000)
- 参数:parameter
parameter 参数名=表达式; 表达式只能是数字或者定义过的参数
- 变量:
- wire型:wire [n-1:0] 数据名;
- 变量:
wire表示信号,常用来表示assign关键字指定的组合逻辑信号 wire型信号可以用作输入,输出
- reg型:reg [n-1:0] 数据名;
对存储单元的抽象 常用来表示always模块内的指定信号,常代表触发器 always块内被赋值的每一个信号都必须定义为reg型
- memory型:reg [n-1:0] 存储器名[m-1:0];
reg [n-1:0]表示基本存储单元的大小 存储器名[m-1:0]表示基本存储单元的个数,存储空间的容量 对存储器进行地址索引的表达式必须是常数表达式 一个n位寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器不行
- 运算符及表达式:
- 基本运算符:+ - * / %
- 位运算符:~ & | ^ ^~
- 逻辑运算符:&& || !
- 关系运算符:< > <= >=
- 等式运算符:== != (不管x、z,结果可能是不定值)
- 运算符及表达式:
=== !==(对参数的x、z都进行比较)
- 移位运算符:<< >>
- 位拼接运算符:{ },将几个信号拼接起来,例如{a,b[3:0],w,3'b100}
- 缩减运算符:C =&B;C =|B;C =^B;
- 优先级别:和c语言差不多,加括号
- 赋值语句:
- 1)非阻塞赋值方式(b <= a)
- a.块结束才完成赋值
- b.b的值不是立刻就改变的
- c.在可综合的模块中常用
- 2)阻塞赋值方式(b = a)
- a.赋值语句执行完成后,块才结束
- b.b的值在赋值语句执行后立刻改变
- c.可能会产生意想不到的结果
- 简单理解:
- 1)非阻塞赋值方式(b <= a)
非阻塞赋值用了多个触发器,每次时钟到达,所有触发器都触发一次 阻塞赋值连到同一个触发器上,时钟到达,导致所有寄存器被赋值
- 块语句:
- 顺序块:
- 1)块内顺序执行
- 2)每条语句的延迟是相对于前一条语句的仿真时间(语句前#num)
- 3)直到最后一句执行完,流程控制才跳出该块
- begin
- 语句1;
- ...
- 语句n;
- end
- 或
- begin:块名:
- 块内声明;
- 语句1;
- ...
- 语句n;
- end
- 并行块:
- 1)块内是同时执行的
- 2)语句的延迟是相对于程序流程控制进入块内时的仿真时间
- 3)延迟时间是用来给赋值语句提供时序的
- 4)时序最后的语句执行完,或者disable语句执行时,跳出程序块
- fork
- 语句1;
- ...
- 语句n;
- join
- 或
- fork:块名:
- 块内声明;
- 语句1;
- ...
- 语句n;
- join
- 顺序块:
- 块名:可以给每一块取名,将名字加在begin和fork之后
- 1)可以在块内定义局部变量
- 2)可以被其他语句调用
- 3)在verilog中,所有变量静态(都有唯一地址)
- 起始时间和结束时间:
- 并行块和顺序块中有起始时间和结束时间
- 条件语句:
- 1)if...else 语句
- if(表达式)
- 语句|语句块
- else
- 语句|语句块
- 2)case语句
- case|casez(case?)|casex,最常用的casez
- case(控制表达式)
- 分支表达式1:语句|语句块
- ...
- 分支表达式n:语句|语句块
- default: 语句
- endcase
- 分支表达式的值的位宽必须相等,需要指明位宽
- 使用if时,最好也要使用else
- 使用case时,最好用上default
- 块语句:
- 循环语句:
- 1)forever 连续的执行语句
- forever
- begin
- 多条语句
- end
- 常用来生成周期型波形,用来作为仿真测试信号
- 不能独立写在程序中,必须写在initial块中
- 2)repeat 执行一条语句n次
- repeat(常量表达式)
- begin
- 多条语句
- end
- 3)while:执行一条语句直到某个条件不满足(如果一开始条件不满足,则一次也不执行)
- while(表达式)
- begin
- 多条语句
- end
- 4)for
- a) 循环次数变量初始值
- b) 循环表达式判断
- c) 执行语句修正循环次数变量
- 使用方法和c语言基本一致
- for(表达式1;表达式2;表达式3)
- begin
- 多条语句
- end
- 循环语句:
- 结构说明:
- initial语句:
- 结构说明:
initial在仿真一开始就执行,但是只执行一次
- initial
- begin
- 多条语句
- end
- always语句:
- always <控制时序> <语句>
- always 在仿真一开始就执行,always语句会不断重复执行,所以需要时序的控制
- 不加时序控制,会不停重复执行,形成仿真死锁
- //边沿触发
- always @(postedge clock or postedge reset)
- begin
- 多条语句
- end
- //电平触发
- always @(postedge clock or postedge reset)
- begin
- 多条语句
- end
- 边沿触发的always块常常用来描述时序逻辑
- 一个模块中可以有多个always块,他们并行执行
- task语句:
- 任务定义:
- task <任务名>;
- <端口及数据类型声明语句>
- <语句1>
- ...
- <语句n>
- endtask
- 任务调用:
- <任务名> (端口1,...端口n)
- 例子:
- //定义
- task mytask;
- input a,b;
- inout c;
- output d,e;
- ...
- <语句> //执行任务工作相应的语句
- ...
- c=foo1;
- d=foo2;
- e=foo3;
- endtask
- //调用
- mytask(v,w,x,y,z);
- function语句:
- function定义:
- function <返回值的类型或范围> (函数名);
- <端口说明语句>
- <变量类型说明语句>
- begin
- 多条语句;
- end
- endfunction
- 函数调用:
- <函数名> (<表达式1>,...,<表达式n>)
- 函数的使用规则:
- 1)函数定义中不能包含有任何的时间控制语句
- 2)函数不能启动任务
- 3)定义函数时至少有一个输入参数
- 4)在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值
- 该函数变量具有和函数名相同的名字
- 例子:
- //函数定义
- function [7:0] getbyte;
- input [15:0] address;
- begin
- <说明语句>
- getbyte = result_expression;
- end
- endfunction
- //函数调用:
- word = control ? {getbyte(mybyte),getbyte(mybyte)} : 0;