FPGA开发笔记-Verilog入门

目录

一、3种描述方式

1、结构描述(类似原理图输入)

2、数据流描述(布尔代数)

3、行为描述(描述电路的功能或行为)

二、经典组合电路、时序电路代码示例

1、组合电路

2、时序电路

(1)同步复位的D触发器

(2)异步复位的D触发器

3、过程中的两类赋值语句


注意元件的命名规范:同一层次内不能重名,不同层次之间也不能重名!


一、3种描述方式

1、结构描述(类似原理图输入)

即直接描述硬件的端口连接情况,以2选1数据选择器为例,代码如下:

module mux21(a,b,c,y);    //模块名以及端口列表
    input a,b,c;    //输入、输出端口声明
    output y;
    //模块功能的描述
    wire x1,x2,x3;    //变量数据类型(常用的有寄存器型reg和网线型wire)

    and U1(x1,a,x3);
    not U2(x3,c);
    and U3(x2,c,b);
    or U4(y,x1,x2);

endmodule    //模块以module和endmodule为引导(作用类似C语言中的花括号)

2、数据流描述(布尔代数)

不解释,仍以mux21为例,直接看示例代码:

//mux21的逻辑:y=ac'+bc

module mux21(
    input a,b,c,
    output y);    //可以在声明端口的时候直接指明输入/输出

    assign y=(a&~c)|(b&c);    //assign引导连续赋值语句(不作特殊声明,则默认是wire型)
    //另一种表达:
    //assign y=(c?b:a);    //与C语言中的含义一致

endmodule

注:(1)按位逻辑运算符:~非;|或;&与;^异或;~^(^~)同或
(2)逻辑运算符:!非;||或;&&与


3、行为描述(描述电路的功能或行为)

个人认为结构描述是口述搭电路的过程,数据流描述是在做数电作业(无意冒犯),而行为描述才真正是verilog的魅力所在(也是debug时让人血压持续走高的根源)。仍以mux21为例,代码如下:

module mux21(
    input a,b,c,
    output y);

    reg y;    //寄存器型变量,与之相对的是wire型变量

    always@(a or b or c)
    begin
        case (c)
        1'b0:y<=a;    //1位二进制(binary)的0
        1'b1:y<=b;
        //default:y<=a;
        endcase
    end

    //另一种always结构描述
    always@(a,b,c)
    begin
        if(c==0) y<=a;
        else y<=b;
    end

endmodule

注:
(1)always@引导过程语句结构
(2)括号中为敏感表,敏感信号之间用“or”或“,”连接
(3)always引导的顺序语句中,变量必须是reg型
(4)多路分支语句case-endcase,类似真值表表达方式的描述
(5)若case/if-else不能覆盖全部情况,必须加default语句!
(6)等式运算符:==等于;!=不等于;===全等;!==不全等


二、经典组合电路、时序电路代码示例

1、组合电路

首先实现mux41,代码如下:

module mux41(
    input d0,d1,d2,d3,a0,a1,
    output reg y);

    always @ (d0,d1,d2,d3,a0,a1)
    begin
        case({a1,a0})	//拼接运算符{}
        2'b00:y<=d0;	//2位二进制(binary)的00
        2'b01:y<=d1;
        2'b10:y<=d2;
        2'b11:y<=d3;
        endcase
    end
endmodule

举一反三,实现4位的二选一数据选择器:

module mux4_21(
    input [3:0] A,B,
    input S,
    output reg [3:0] Y);
    //可以按照C语言中的数组来理解
    //Y[0],Y[1],Y[2],Y[3]是相互独立的4个端口
    always @ (A,B,S)
    begin
        if(S==0) Y<=A;
        else Y<=B;
    end
endmodule

2、时序电路

(1)同步复位的D触发器

代码如下:

module dff_syn(
    input clk,d,rst,
    output reg q);

//边沿敏感信号clk必须出现在敏感表中,always过程结构中clk不再出现
    always @ (posedge clk)
    begin
        if(!rst) q<=0;
        else q<=d;
    end
endmodule

注:
(1)上升沿-posedge,下降沿-negedge
(2)rst不出现在敏感表中,说明rst是时钟同步信号


(2)异步复位的D触发器

代码如下:

module dff_asyn(
    input clk,d,rst,en,
    output reg q);

//异步控制信号rst必须出现在敏感表中
    always @ (posedge clk or negedge rst)
    begin
        if(!rst) q<=0;
        else if(en) q<=d;
    end
endmodule

注:
(1)在always过程结构中必须表述其逻辑行为,且两种表述必须相匹配(下降沿有效-低电平有效;上升沿有效-高电平有效)
(3)敏感表中出现边沿敏感的表述,则其他类型的敏感信号不能放置,如always@(posedge clk, rst)是错误的!(原因:不特殊声明,变量默认为reg型,因此rst被判断为reg型;敏感表中已经有了posedge clk,不能再放reg rst)


3、过程中的两类赋值语句

(1)阻塞式(一般用于组合电路)

结合代码进行讲解:

always@(a,b)
begin
    x=a;
    y=b&x;
    z=x|y;
end
//阻塞式赋值:当前语句进行完才会开始后续语句
//因此上述语句的作用等价于:
//x=a, y=b&a, z=a|(b&a)

(2)非阻塞式(一般用于时序电路)

always@(posedge clk)
begin
    q1<=d;
    q2<=q1;
end
//非阻塞式赋值:各个赋值语句并行
//或理解为所有赋值语句分两步执行:
//1.所有语句一起计算各自等号右边的值
//2.同时将计算的值赋给各自等号左边的变量
//因此上述语句的结果将是q1=d,q2=d

注:同一always过程结构中,两者千万不要混用!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值