Verilog HDL初级入门

- 缩写

CPLD (complex programmable logic device)复杂可编程逻辑器件
FPGA   (field programmable gate array) 现场可编程门阵列
PLD  (programmable logic device)可编程逻辑器件
PAL  (programmable array logic)可编程阵列逻辑
ASIC (application specific integrated circuits)专用集成电路
PROM (programmable read only memony)只读存储器
MC (macro cell)可编程逻辑宏单元
SC  (standard cell)标准逻辑单元
RAM(Random Access Memory)随机存取存储器
SOPC  (system on a programmable chip)  片上可编程系统
PCB( Printed Circuit Board)印制电路板

- FPGA

FPGA是由存放在ram中的程序来设计工作状态的,工作时用户根据不同的配置方式采用不同的编程方式。加电时,FPGA将eprom中的数据读入片内编程ram中,配置完成后,FPGA进入工作状态,掉电后,FPGA恢复成白片,内部逻辑关系完全消失,所以FPGA能反复使用
FPGA设计流程:
电路设计与输入->功能仿真->综合优化->综合后仿真->布局->布线仿真->板级仿真验证->加载配置->在线调试

Verilog HDL

verilog模型可以是实际电路的不同级别的抽象分别是:
系统级–》
算法级–》
RTL级(register transfer level 数据在寄存器之间的流动以及如何处理数据)–》
门级(逻辑门以及其中之间的连接)–》
开关级别(模电领域)

模块框架(i/o声明 i/o说明 内部信号声明 功能)
1.i/o声明,说明
module 模块名(端口1,端口2,端口3….);
input in;
output out;
2.内部信号声明
reg [width-1:0] R变量1,R变量2….;
wire [width-1:0] R变量1,R变量2….;
3.功能定义
assign a =b&c; //声明语句
and and_list(q,a,b); //实例元件
always @(postdge clk or posedge clr)
begin
if(clr) q<=0;
else if(en) q<=d;
End
(always块中语句是顺序执行的)

行为型描述(语句/语句块 过程结构 时序控制 流控制)
1.语句块
begin….end 组合需要顺序执行的语句,称为串行块
fork….join 组合需要并行执行的语句,并行块
2.过程结构
initial/task/always/function
initial 模块只执行一次,是同时并行执行的,面向仿真,不可综合
always 仿真过程中是不断重复执行,没有时序控制会生成一个仿真死锁
只有寄存器类型的数据才可以在这两个模块中赋值<–initial和always语句
3.时序控制
(1)延迟控制 不可综合,用于仿真
(2)事件控制 可综合,通过always语句实现
4.流控制
assign赋值语句

- 基础语法

• Verilog区分大小写且关键字都是小写
• 常数的表示 : <位宽>’<进制><数值> eg: 4’b1010
b->二进制 d->十进制 十六进制 ->h 八进制 ->o 位宽:对应二进制的宽度
• module, endmodule定义一个基本模块,两个关键字间的语句是对该模块的描述,定义模块方便复用
• parameter关键字定义一个参数,增强模块的通用性 eg: parameter msb=7;
• output, input关键字指定输入输出,如果没有显示声明类型,默认为wire类型。如果需要reg类型以存储值,需要显示声明
• &q语句输出q每一位相与的结果,即&q=q[1]&q[2]&…&q[N]
• always @(posedge/negedge clk)语句,negedge下降沿 posedge上升沿,每当clk出现上升/下降沿时(clk都是自己定义的信号)就执行接下来的语句块(begin, end标志一个语句块)。这种语句构成时序逻辑,当前输出与上一个时刻的值有关。always语句块中的值改变只能发生在每一时刻(由@符号后的语句描述时刻)
•如果程序只用于仿真,那么几乎所有的语法和编程语句都可以使用,但是为了硬件实现,我们必须保证程序的可综合性,,即所编写的程序能被综合器转化为相应的电路结构

数据类型
表示数字电路硬件中的数据存储和传送元素
包括线网/寄存器类型
线网类型缺省值为高阻Z,寄存器为未知X
线网数据需要持续的驱动,寄存器保持最后一次的赋值
线网型 wire
表示直通,默认的输入输出信号类型,取值有1,0,x(不定值),z(高阻),相当于物理连线即输入有变化,输出马上无条件地反映(如与、非门的简单连接)。wire只能用组合逻辑,被assign连续赋值。wire 变量可以作任何方程式的输入,也可以用作“assign”语句或实例元件的输出

wire[7:0]  databus;       //定义20位宽wire向量数据总线
wire[7:0]  addrbus;        //定义20位宽wire向量地址总线
wire   data1;     //一个一比特位宽的线网
wire [n-1:0]  变量名1,2,,,,,i; //wire线网   共有i条总线,每天总线内有n条线路

ps:计算机三类系统总线是数据总线DB(Data Bus)、地址总线AB(Address Bus)和控制总线CB(Control Bus)

wire[7:0]a表示定义了一个wire型数据,该数据由8位的二进制数组成,该数据的
第1位表示为wire[7]
第2位表示为wire[6]
. .
第8位表示为wire[0]
同理,wire[8:1]a表示定义了一个wire型数据,该数据由8位的二进制数组成,该数据的
第1位表示为wire[8]
第2位表示为wire[7]
. .
第8位表示为wire[1]
•其他线网型:
tri 高阻态标准连线 & supply() 对低电平0建模 & supply1 对高电平1建模
是可综合的,其余只能用于仿真语句

寄存器型 reg
常用的寄存器型变量(触发器、寄存器等),表示一定要有触发,输出才会反映输入的状态,相当于存储单元。没有输入的时候可以保持原来的值,但不直接和实际的硬件电路对应。reg只能在initial和always中赋值, 用<=赋值,赋值符号左侧是寄存器,右侧是更新的值

reg a,b;
reg[8:1] data;   //定义了八位宽reg型向量
reg[7:0] mymem[1023:0]    //二维向量称为存储器变量,定义1k字节(8 bit)的存储器,前面定义宽度,后面定义深度

•字符串变量其实就是寄存器变量,字符串每个字符都是8位的二进制来表示,字符串由“开始,结束”
reg[198-1,0] a; 或者 reg[198,1] a;
•其他寄存器类型:
realtime 实数时间寄存器,memory类型即reg拓展
integer 整数寄存器包含整数值,整数不能作为位向量访问,截取位值的方法是将整数赋值给一般的reg类型变量

	integer a,b,c;    //三个整数型寄存器
	integer hist[3:6];   //一组四个寄存器

time

time events[0:31];    //时间值数组
time currtime;       

• 等于 ===
不等于 != 或 !==
信号的两种赋值方式
1.非阻塞 (当前语句的执行不会阻塞下一语句的执行)
块结束后才完成赋值操作,值不会立刻改变
非阻塞赋值语句(“<=”)
2.阻塞 (在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句)
赋值语句完全完成后变量立即改变,赋值语句完成后,块才结束
阻塞赋值语句(“=”)

• initial begin, end语句块指明初始化语句,这部分指令在系统上电后直接执行
• 'timescale 1ns/1ps指定测试的单位是1ns,精度是1ps
Timescale 编译器指令格式为 :` timescale time _unit / time _ precision ,time_unit 、time_precision 由值1、10、和100以及单位s、ms、us、ns、ps和fs组成。
• #100指令指明延时,单位由之前的代码指定
• $stop指令使仿真停止
• 时序逻辑:<=赋值;组合逻辑:-赋值

条件语句
If ……else 0,x,z都按照0“假”处理

case(条件表达式)
		<分支1>:<语句块1>
		<分支2>:<语句块2>
	...
	default:<语句块n>         //不缺省,在组合逻辑中会生成锁存器
endcase          //当语句跳转到某一分支后,控制指针将转移到endcase语句之后,其余分支不再比较,不同于c语言中不需要break语句

分支条件写完整,防治出现锁存器
条件语句必须在顺序执行块中使用。所谓顺序执行块是指由 initial 和always语句引导的执行语句集合。除了这两种语句引导的begin_end块中可以编写条件语句外,模块中的其他地方都不能编写
其中,if语句速度慢,但占用面积小,case语句速度快但占用面积大

循环语句
for/while/repeat/forever
repeat x/z循环次数按0处理
while x/z 不执行
• for(<变量赋值初始语句>;<条件表达式>;<变量增值语句>) 循环体;
• repeat(<循环次数表达>) 循环体;

赋值语句
连续赋值语句:assign语句
assign语句常用于对wire类型变量进行赋值,等式左边的wire变量随等式右边的值一起变化

过程赋值语句:always开头,@引导一个敏感列表
非阻塞语句在过程快结束时才完成赋值操作,多个非阻塞语句并行执行
在敏感信号表达式的位置写*,综合器会推断表达式。推断的主要依据是赋值语句的右侧值

• always里面赋值左边必须声明成reg,assign表达式左边必须声明成wire
• 如果是边沿触发的逻辑比如always @(posedge clk),里面一律用<=赋值,如果是电平触发的逻辑,一律用=赋值
•逻辑简单用assign语句;逻辑复杂用always语句

结构说明语句
initial
• initial过程块模拟上电之后的行为,不可综合,通常用于功能模拟的初始化,写进测试文件testbench
• 同一模块中的initial过程块,在上电时并行执行
• initial过程块不能嵌套

always
• always语句块不能嵌套
• 在敏感信号表达式前加posedge或negedge关键字可以指定上升沿或下降沿触发。否则每当表达式的值发生改变,就会执行语句块

always@(<敏感信号表达式>)
begin
…
end

task 任务
可以支持多种目的,能计算多个结果值,这些结果只能通过被调用的任务的输出或总线端口送出。能够启动其他任务或函数,可以没有或有多个任何类型的变量,没有返回值,任务仿真可以自己定义时间单位
1.任务定义

 task task_id;      //任务名
[declaration]          //端口声明和变量声明语句
procedural_statement;
endtask	

2.任务调用
task_id[(端口1,端口2….端口n)]; //参数列表给出传入任务的数据和接受返回结果的变量
任务应当有接受数据的输入端和返回数据的输出端
任务中可以调用其他任务或者函数,也可以调用自身,在定义结构中不可以出现initial/always过程快
任务调用语句只能出现在过程块内
可综合任务只能实现组合逻辑,也就是说调用可综合任务的时间为0,而在仿真任务中可以带有时序控制,面对仿真的调用时间不为0
任务没有返回值

task必须在always调用,也可以本身调用task,但是不可以调用module模块,只有采用和模块端口交互数据的方法达到调用的功能,task语句是可以综合的,但是不包括always语句,只能实现组合逻辑。时序设计无法处理,只能通过verilog层次化设计方法,封装成模块

function 函数
通过返回一个值来响应输入信号的值,一般将函数作为表达式中的操作符,这个操作的结果就是函数的返回值,不能启动任务,巫妖至少一个输入变量,有个一返回值,仿真只能和主模块共用一个仿真时间单位
1.函数定义
不允许输出端口说明,可以有多个输入端口

function[range]function_id;                 //参数指定函数返回值的
input_declaration;        //对函数各个输入端口的位宽和类型进行说明
other_declaration;
procedural_statement;
endfunction

函数定义只能在模块中完成,不能出现在过程块中
函数不能使用任何形式的时间控制语句/disable中止语句
函数内部可以调用函数不可以调用任务
函数调用可以在过程块中完成,也可以在assign这样的连续赋值语句中出现
函数中不能出现always/#这样的语句,保证函数的执行在零时间完成
函数向调用它的表达式返回一个值

编译预处理语句
define语句
include语句
timescale语句

• verilog不支持c语言中的++/–运算
• 硬件设计并不追求代码的短小,而是设计的时序和面积性能等特征
• 并行语句:同时进行,c语言代码由单个cpu执行,同一时刻只能做一件事;
而verilog代码综合适配到具体的fpga中,每一条并行语句对应着一块具体的电路

状态机
输出取决于过去输入部分和当前输入部分的时序逻辑电路
moore型 只和当前状态有关,可以看作是当前状态的函数 //具有一个周期的延时,具有较好的时序
mealy型 还和输入信号有关,可以看作是当前状态 //响应更快,状态少,具有较少的触发器
状态机的状态通过触发器的数量反应

常用编码
进制码/格雷码/独热码
• 二进制和格雷码转换:
(2->格雷码)从最右边一位起,依次和左边的一位异或,作为对应该位的值,最左边的一位不变

• 独热码 :当任何一个状态有且只有一个1,就是独热1码,有且只有一个0时,就是独热0码

• 二进制,格雷码使用较少的触发器,消耗较多的的组合逻辑,独热码相反,占用较多的位既消耗较多的触发器,在一定程度上简化译码逻辑,在状态比较时只需要比较一位,简化比较逻辑,减少毛刺的产生概率

你可能感兴趣的:(语言类)