
基于FPGA的SOC在嵌入式系统应用越来越广了,往往一个复杂系统使用一个单芯片基于FPGA的SOC就搞定了。比较流行的方案主要有Altera/xilinx两家的方案。要用这样的方案,首要需要掌握的是硬件描述语言。最为流行的硬件描述语言有两种Verilog HDL/VHDL,均为IEEE标准。Verilog HDL具有C语言基础就很容易上手,而VHDL语言则需要Ada编程基础。另外Verilog HDL语言具有大量成熟的模块,从某种角度说Verilog HDL更具生命力。本文整理了一下Verilog HDL语言技术要点,并分享给大家。如发现有错误,欢迎留言指正。 Verilog HDL能干啥? Verilog HDL的特点:
在学习Verilog HDL之前,先明确一下FPGA的设计抽象层次: ![]() module module_name(port_list) //声明各种变量、信号 reg //寄存器 wire //线网 parameter //参数 input //输入信号 output //输出信号 inout //输入输出信号 function //函数 task //任务 .... //程序代码 initial assignment always assignment module assignment gate assignment UDP assignment continous assignment endmodule 启示:描述的是模块,其本质是数字电路:
变量名类似C语言,以一组字母、数字、下划线和$符号的组合,且首字符须为字母或者下划线。如 input ctrl_1;数据类型 将四种基本数据类型整理成一张导图: ![]() 其中须注意的是,对于memory型存储单元进行读写,须指定地址,如: reg[15:0] addr; //定义addr为16位位宽的存储器变量addr = 1; //ok reg addr[15:0]; //定义addr为1位位宽的16个存储器变量 addr = 1; //错误 addr[0] = 1; //正确 //又如: reg[15:0] addr[3:1]; //定义3个位宽为16位存储器 addr[1] = 16'h0 //16'指定位宽,h 表示16进制,0 addr[2] = 16'b011 //b表示二进制 对于parameter变量的实用价值可读性比较好理解,那么可维护性怎么体现呢? 熟悉C语言编程的,联想一下宏,如果宏变了,有宏的地方全替换,这里parameter变量作用类似,如: module Decode(A,F);parameter Width=1, Polarity=1; …………… endmodule module Top; wire[3:0] A4; wire[4:0] A5; wire[15:0] F16; wire[31:0] F32; Decode #(4,0) D1(A4,F16); Decode #(5) D2(A5,F32); Endmodule 常量 parameter定义常量,那么对于常数,整型常量即整常数有以下四种进制表示形式:
数字表达方式有以下三种:
在数字电路中,x代表不定值,z代表高阻值。不确定是啥?高阻又是啥?记住verilog描述的数字电路,那么对于一个模块的I/O就有可能是高阻,或者状态不确定。 负数:一个数字可以被定义为负数,只需在位宽表达式前加一个减号,减号必须写在数字定义表达式的最前面。注意减号不可以放在位宽和进制之间也不可以放在进制和具体的数之间。 -8'd7 //-号直接放在最前面8'd-7 //这样则不正确 实数 实数可用十进制方式表述或者科学计数法描述,如: //十进制表示1.0 20.234 //科学计数法表示 6e-4 模块端口
学习硬件描述语言,一定要时刻记住,这是描述的是电路,风格类C,但不是C! 表达式及运算符和C语言类似,运算符也有三种:
对于运算符,整理了一张导图: ![]() 大部分与C语言类似,除了等式运算符、位拼接运算符、缩减运算符,这里放点例子方便理解: //缩减运算符reg [3:0] B; reg C; C = &B; //相当于: C =( (B[0]&B[1]) & B[2] ) & B[3]; //位拼接运算符 {a,b[3:0],w,3’b101} //相当于: {a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1} 运算符优先级: ![]()
块语句有两种,一种是begin_end语句,通常用来标识顺序执行的语句,用它来标识的块称为顺序块。一种是 fork_join语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。 顺序块
语句1; 语句2; ...... 语句n; end 并行块
语句1; 语句2; ....... 语句n; join 流控语句 ![]() 流控语句风格与C语言类似,仅仅需要注意的有下面几点:
Verilog语言中的任何过程模块都从属于以下四种结构的说明语句:
![]() 对于task/function的不同点,使用时需要注意:
在Verilog HDL语言中每个系统函数和任务前面都用一个标识符$来加以确认,有这些系统函数和任务。 rtoi, setup, skew, setuphold, strobe, time, timefoemat, width, write, $recovery,按字面意思理解,需要用到时查询手册即可。 编译预处理宏定义 `define用法: `define 标识符(宏名) 字符串(宏内容) 如: //类似C宏替换`define signal hello 与C语言宏类似,除了关键字不一样,也支持嵌套。组成宏内容的字符串不能够被以下的语句记号分隔开的,下面几点需要注意:
用法:`include “文件名” 四点说明:
`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用`timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。用法: `timescale<时间单位>/<时间精度> ![]() //1ns/ps:1纳秒/脉冲 `timescale 1ns/1ps 注意:如果在同一个设计里,多个模块中用到的时间单位不同,需要用到以下的时间结构:
`ifdef、`else、`endif 这与C语言用法类似,这里就不赘述了。 总结一下Verilog HDL的语法与C语言的语法类似,但是一定要意识到Verilog HDL描述的是电路,光有代码还不够,器件可能运行的结果并不是代码想要的效果。另外要注意理解并行的概念,这里的并行是硬件在时钟驱动真的同时按照所设计的逻辑运行。一些重要的概念:
那么最好的学习办法是什么呢?写代码、仿真、综合、优化布局布线,挖坑、踩坑、填坑,在错误中总结,渐进明晰、不断实践总结。 |
希望楼主多多分享,赠人玫瑰,手有余香,念念不忘,必有回响;.