Verilog基础:语法、建模与案例,FPGA入门竟如此简单?


作者:Mr.Winter

简介:主攻机器人与人工智能领域的理论研究和工程应用,业余丰富各种技术栈。主要涉足:【机器人(ROS)】【机器学习】【深度学习】【计算机视觉】


目录

  • 第一章·语法
    • 1 数值
    • 2 字符串
    • 3 标识符
    • 4 关键字
    • 5 任务和函数
    • 6 编译引导语句
    • 7 基本数据类型
  • 第二章·建模
    • 1 结构建模
    • 2 数据流建模
    • 3 行为建模
    • 4 FSM建模
  • 第三章·案例
    • 1 循环彩灯控制器
    • 2 红外入侵传感器

第一章·语法

1 数值

verilog中数值有以下表示方法
(1) 逻辑值
Verilog基础:语法、建模与案例,FPGA入门竟如此简单?_第1张图片
(2) 整数

整数可以标明位数也可不标明位数,通用表示方法为:

位数 ′ 基数数值 \text{位数}'\text{基数} \text{数值} 位数基数数值

其中位数表明该数用二进制的几位来表示;基数为数值使用的码制——可以是二(b)、八(o)、十(d)或十六(h)进制;数值可以是所选基数的任何合法值包括不定值 X X X和高阻态 Z Z Z

例如:8’b11010001、32’H080A_FFFF、48

(3) 位扩展

对于所有小于位宽的数值,在其位区间内用0填充高位;除非该数值为不定值 X X X或高阻态 Z Z Z,此时高位用相应的 X X X Z Z Z扩展。所谓位区间就是基数码制中,一个数占用的比特数,例如二进制位区间为1,十六进制为4。

Verilog基础:语法、建模与案例,FPGA入门竟如此简单?_第2张图片

2 字符串

字符串常用于系统测试时,表示命令内需要显示的信息;通常不用于硬件建模。

字符串是用“”括起来的一行字符,其内可以用C语言中的各种格式控制符(转义符),如“\n”、“\t”等;也可以用C语言中的各种数值型控制符,如:%b、%o、%d、%h、%t、%s等。

3 标识符

所谓标识别符就是用户为程序描述中的Verilog对象——如模块名、端口名、实例名等,所起的名字。标识符必须以英文字母或下划线起头,最长可以达到1023个字符。此外,Verilog语言是大小写敏感的。

4 关键字

关键字是Verilog语言中预设的用于描述架构的词,所有关键字都是小写字母,如:module、endmodule、always、reg、wire、if、else等。

5 任务和函数

任务和函数具备将程序中反复调用的语句结构聚合起来的能力,因其可在过程块中被调用(而模块不行),因此可以有效的简化程序结构。利用任务和函数可以把一个大的程序模块分解成多个小的任务和函数,利于调试。

任务和函数的共同点是:语句中不能出现过程引导的语句,且其中无法描述时序电路,只能描述组合电路。

  • 任务结构

基本格式

task <任务名>;
     端口及数据类型声明语句;
     过程语句;
endtask

调用格式

<任务名> (端口1,端口2,…,端口N)
  • 函数结构

基本格式

function <位宽范围声明> 函数名;
     输入端口及数据类型声明语句;
     过程语句;
     函数名= ***;
//该句是作为函数的返回值,不可缺
endfunction

调用格式

X = <函数名> (端口1,端口2,…,端口N)
任务与函数的不同点在于:

(a) 函数只能与主模块共用同一个仿真时间,而任务可以定义自己的仿真时间;
(b) 函数不能调用任务,但任务能调用其他任务和函数;
(c) 函数至少要有一个输入变量,而任务可以没有或有多个输入变量;
(d) 函数显式返回一个值,而任务则隐式返回值——或理解为处理值;
(e) 任务需要定义输入和输出,而函数只需定义输入,函数名就是输出

下面给出两个实例:

module TASKDEMO (S,D,C1,D1,C2,D2);
input S;
input[3:0] C1,D1,C2,D2;
output [3:0] D;
reg[3:0] out1,out2;

task CMP;                            //任务定义,任务名CMP
    input [3:0] A,B;
    output[3:0] DOUT;
    begin
      if(A>B)  DOUT=A;
   end
endtask

always @(C1)
   begin
      CMP(C1,D1,out1);    		//一次调用任务
      CMP(C2,D2,out2);   		//二次调用任务
endmodule

module CN(
    input [3:0]A,
    output [2:0]OUT
);
    function[2:0] GP;
        input[3:0] M;
        reg [2:0]CNT,N;
        begin
            CNT = 0;
            for(N=0;N<=3;N=N+1)
                if(M[N]==1) CNT=CNT+1;
            GP = CNT;
        end
     endfunction
     
     assign OUT = (~|A) ? 0:GP(A);

endmodule

此外还有一系列系统任务和函数,以符号$起头。

系统任务/函数 含义
$time 找到当前的仿真时间
$display、$monitor 显示和监视信号值的变化
$stop 暂停仿真
$finish 结束仿真

6 编译引导语句

编译引导语句用主键盘左上角小写键`起头,用于指导仿真编译器在编译时采取一些特殊处理,编译引导语句一直保持有效,直到被取消或重写。编译引导语句不会生成硬件电路。

常用编译引导 含义
`define 用于宏定义
`include 用于包含其它模块,便于层次化系统设计
`timescale 用于说明程序中的时间单位和仿真精度,必须放在模块边界前面。例如:`timescale 1ns/100ps表示下面模块中所有的时间单位都是1ns的整数倍。尽可能使仿真精度与时间单位接近,前者是由所有参加仿真模块中由`timescale指定的精度最高(即时间最短)的决定。特殊符号“#”常用来表示延迟,其延迟单位由时间单位决定。如上例中指定的模块若有# 10,则表示延迟10ns
`uselib 用于定义仿真器到哪里去找库元件
`resetall 用于把所有设置的编译引导恢复到缺省状态

7 基本数据类型

(1) Nets(网络连接)
Verilog基础:语法、建模与案例,FPGA入门竟如此简单?_第3张图片
表示器件之间的物理连接

  • wire(缺省)、tri:对应于标准的互连线
  • supply1supply2:对应于电源线或接地线
  • wortrior:对应于有多个驱动源的线或逻辑连接
  • wandtriand:对应于有多个驱动源的线与逻辑连接
  • trireg:对应于有电容存在能暂时存储电平的连接
  • tri1tri0:对应于需要上拉或下拉的连接

(2) Register(寄存器/变量)
在这里插入图片描述
表示抽象的储存单元

  • reg:无符号整数变量,可以选择不同位宽
  • integer:有符号32位宽整数变量,算术运算可产生2的补码
  • real:有符号双精度浮点数
  • time:无符号64位宽整数变量(Verilog-XL仿真工具用64位正数记录仿真时刻)

(3) Parameters(参数)

常用参数来声明运行时的常数,参数是本地的,其定义只在本模块内有效 可用字符串表示的任何地方,都可以用定义的参数来代替。

第二章·建模

1 结构建模

描述系统的具体结构组成、由哪些子模块组合而成以及如何互连。具体而言,采用模块互相调用、组合的方式进行建模。

2 数据流建模

描述系统中信号/数据在线路中的流向,即一个或几个信号、数据如何从一个线路传递到另一个线路上。具体而言,采用assign连续赋值方式建模。

3 行为建模

按高级语言的思路对一个系统的功能或工作行为过程进行描述。具体而言,采用always或initial引导过程块方式建模。
Verilog基础:语法、建模与案例,FPGA入门竟如此简单?_第4张图片

4 FSM建模

在Verilog中引入FSM建模的优势在于:

(a) FSM是高效的顺序控制模型——克服了纯硬件数字系统顺序方式控制不灵活的缺点;
(b) 容易利用现成的EDA优化工具;
(c) 性能稳定。状态机容易构成性能良好的同步时序逻辑模块;
(d) 设计实现效率高。状态机的HDL表述丰富多样、程序层次分明、易读易懂;
(e) 高速性能及高可靠性。

第三章·案例

1 循环彩灯控制器

问题描述:设计一个循环彩灯控制器。要求控制红、绿、黄发光管循环发亮。红发光管亮2秒,绿发光管亮3秒,黄发光管亮1秒。设系统时钟为10MHz。

//@ Attention:时钟频率10MHz
module circle_lights(
    input clk,
    input rst,
    output reg [1:0] lights
    );
/******************* 变量定义区 **********************/
reg [1:0] state;
reg [1:0] next_state;
reg [25:0] cnt;

`define S_red       2'b00           //红灯
`define S_green     2'b01           //绿灯
`define S_yellow    2'b10           //黄灯
`define sec_2       26'd2000_0000   //2s
`define sec_5       26'd5000_0000   //5s
`define sec_6       26'd6000_0000   //6s
/***************************************************/

//state register block
always @ (posedge clk)
begin
    if(!rst||(cnt==`sec_6))         
    begin
         state<=`S_red;
         cnt<=0;
    end
    else
    begin
        state <= next_state;
        cnt <= cnt+1;
    end
end

//next state logic
always @(state or cnt)
begin
    case(state)
    `S_red:
            begin
                 if(cnt==`sec_2) next_state = `S_green;      //持续2s
                 else            next_state = `S_red;
            end
    `S_green:
            begin
                 if(cnt==`sec_5) next_state = `S_yellow;    //持续3s
                 else            next_state = `S_green;
            end
    `S_yellow:  
            begin
                 if(cnt==`sec_6) next_state = `S_red;      //持续1s
                 else            next_state = `S_yellow;
            end
    endcase
end

//output logic
always@(state or cnt)
begin
    case(state)
    `S_red:     lights = 2'b00;
    `S_green:   lights = 2'b01;
    `S_yellow:  lights = 2'b10;
    endcase
end
endmodule

Verilog基础:语法、建模与案例,FPGA入门竟如此简单?_第5张图片

(0表示红灯,1表示绿灯,2表示黄灯)

2 红外入侵传感器

用FSM设计一个入侵警报系统 Verilog 代码:
启用键,进入防护状态
解除键,从其他状态返回到解除防护状态
测试键,进入测试状态,报警
当传感器输出为“1”持续5秒,警报器报警。

//@ Attention:时钟频率10MHz
module alarm(
    input clk,
    input [3:0] btn, 
    //0->进入防护状态 1->解除防护 2->报警 3->复位
    //one_hot编码
    output reg beep
    );
/******************* 变量定义区 **********************/
reg [1:0] state;
reg [1:0] next_state;
reg [25:0] cnt;

`define S_init      2'b00           //解除防护状态
`define S_defence   2'b01           //防护状态
`define S_alarm     2'b10           //报警状态
`define sec_5       26'd5000_0000   //5s
/***************************************************/

//state register block
always @ (posedge clk)
begin
    if(btn == 4'b1000)         
    begin
         state<=`S_init;
         cnt<=0;
    end
    else
    begin
        state <= next_state;
        cnt <= cnt+1;
    end
end

//next state logic
always @(state or btn)
begin
    if(btn == 4'b0001)      next_state = `S_defence;
    else if(btn == 4'b0100)
    begin
        next_state = `S_alarm;
        cnt = 0;                    //开始5s计时
    end
    else                    next_state = `S_init;                       
end

//output logic
always@(state or btn)
begin
    if(state == `S_alarm)
    begin
        if(cnt == `sec_5)
        begin
            beep = 0;
            next_state = `S_defence;
        end
        else    beep = 1;
    end
    else    beep = 0;
end
endmodule

测试模块代码:
module test_alarm(
    );
reg clk;
reg [3:0] btn;
wire beep;

alarm my_test(clk,btn,beep);

always #50 clk <= ~clk;

initial
begin
    clk = 1'b0;
    btn <= 4'b1000;
    #55
    btn <= 4'b0001;
end
endmodule

更多精彩专栏

  • 《机器人原理与技术》
  • 《计算机视觉教程》
  • 《机器学习》
  • 《嵌入式系统》
  • 《数值优化方法》

欢迎加入社区和更多志同道合的朋友交流:AI 技术社

配套代码 · 优质体验 · 系统知识 请关注

你可能感兴趣的:(嵌入式系统,fpga开发,verilog,嵌入式,硬件)