Verilog 基础知识(一) Verilog 基础语法与注意事项

基础知识

0.1 模块(Module)

Verilog中的module可以看成一个具有输入输出端口的黑盒子,该黑盒子有输入和输出接口(信号),通过把输入在盒子中执行某些操作来实现某项功能。(类似于C语言中的函数)

Verilog 基础知识(一) Verilog 基础语法与注意事项

图1 模块示意图

0.1.1 模块描述

图1 所示的顶层模块(top_module)结构用Verilog语言可描述为:

module  top_module(
    input a,
    input b,
    output out
);

   .......

endmodule
  • 模块以module 开始,endmodule结束
  • top_module 为模块名
  • input : 为输入端口
  • output: 为输出端口
  • 所有代码必须处于module模块中!

同理,图1 所示的次级模块(mod_a)结构用Verilog语言可描述为:

module  top_module(
    input in1,
    input in2,
    output out
);

   .......

endmodule

注意事项每个模应单独块处于一个.v文件中,模块名即为文件名(规范代码!)

0.1.2 模块输入输出信号

  • 输出: output
  • 输入: input

模块的输入输出端口都可看出模块的信号,若不写信号类型则默认为wire类型信号!

// 以下这两个语句本质是一直的
input a;

input wire a;

除了wire型信号,还有reg型信号,具体详见1.4节!

0.1.3 模块实例化

如图1所示,top_module的两个输入端口连接到次级模块(mod_a)的输入端口,那如何在top_module模块模块中使用mod_a模块的功能呢?这就需要通过模块实例化,可以把top_module看成C语言中的主函数,次级模块mod_a看成普通函数,这样就可以在主函数中调用其他函数来完成相应的功能!

在top_module中实例化mod_a的方式为:

模块实例化语法: 模块名 实例名(定义连接port的信号);

module  top_module(
    input a,
    input b,
    output out
);

    mod_a instance2 (.in1(a), .in2(b), .out(out));

endmodule
  • 按mod_a定义的端口顺序实例化: mod_a instance1 (a, b, out);
  • 按mod_a端口名实例化: mod_a instance2 (.in1(a), .in2(b), .out(out)); (推荐此种写法)

0.2 逻辑块(always、generate)

0.2.1 always逻辑块

always块可构建 组合逻辑块 和 时序逻辑块,复杂的逻辑操作都需要处于该逻辑块中,如if、case、for等

(1) 组合逻辑块

module top_module();

    always @(*) begin
        ....

    end

endmodule
  • always逻辑块中任意信号变化时立即触发,执行begin – end之间的语句
  • begin – end用于将多条语句组成一个代码块,只有一条语句时可省略

(1) 时序逻辑电路

module top_module();

    always @(posedge clk) begin
        ....

    end

endmodule
  • clk信号的上升沿触发
  • posedge: 上升沿
  • negedge: 下降沿

0.2.2 generate逻辑块

generate主要结合for循环使用,主要用途有:

  • 对向量中的多个位进行重复操作
  • 对同一个模块进行多次重复实例化(主要用途)

(1) 操作向量

module top_module(input [7:0] in,  output [7:0] out);
    genvar i;        // genvar i; 也可以定义在generate内部
    generate
        for(i=0; i<8; i++) begin: bit assign out[i]="^in[8-1:i];" end endgenerate endmodule< code></8;>

(2) 模块重复多次实例化

module  top_module(
    input a,
    input b,
    output out
);
    genvar i;
    generate
        for(i=0; i<8; i++) begin: gen_mod_a 为每个begin_end的结构的名称 mod_a instance2 (.in1(a), .in2(b), .out(out)); end endgenerate endmodule< code></8;>
  • 注意:模块多次实例化时必须写每个begin_end结构的名称(gen_mod_a)
  • 仿真器会通过gen_mod_a来标识生成结构: gen_mod_a[0],gen_mod_a[1]….

0.2.3 initial块

initial块可以理解为一个初始化块,在initial的起始位置的语句在0时刻即开始执行,之后如果遇到延时,则延时之后执行接下来的语句。

初始块是不可综合的,因此不能将其转化为带有数字元素的硬件原理图。因此初始块除了在仿真中使用外,并没有太大的作用。

[En]

The initial block is not synthesizable, so it cannot be converted into a hardware schematic with digital elements. Therefore, the initial block is not very useful except for being used in the simulation.

如:在仿真文件中初始化各种参数:

initial
begin
    sys_clk    = 1'b1;
    sys_rst_n  = 1'b0;
    #50
    sys_rst_n  = 1'b1;
end

注意:

  • initial 块在电路中不可综合,故一般不出现在RTL代码中
  • initial 一般只在仿真文件中使用

若需要在RTL代码中初始化参数,需要用always块,用initial块会导致错误!

如下所示,在RTL代码中初始化存储器的方式为:

reg [255:0]char_data[4:0];

always@(posedge clk)
    begin
        char_data[0]     <= 256'h0000000000000000000000000000000000000000000000000000000000000000; char_data[1] <="256'h0000000000000000000000000000000000000000000000000000000000000000;" char_data[2] char_data[3] char_data[4] end< code></=>

0.3 赋值方式

Verilog 中赋值方式有三种: 连续赋值、阻塞赋值、非阻塞赋值

0.3.1 连续赋值(assign)

assign x = y;
  • 该语句表示把x和y两个信号进行连接,真实的物理连接!
  • 不能在always块中使用

0.3.2 阻塞赋值(=)

// &#x7EC4;&#x5408;&#x5757;
always @(*)  begin
    out1 = a ;
    a = b ;
    out2 = a ;
end
  • 组合always块中用阻塞式赋值
  • 执行顺序:按照begin_end语句块中的顺序依次执行,上述输出结果为:out1 = a ,out2 = b

0.3.3 非阻塞赋值(

Original: https://blog.csdn.net/jac_chao/article/details/123744724
Author: Triumph++
Title: Verilog 基础知识(一) Verilog 基础语法与注意事项

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/93592/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

发表回复

登录后才能评论
免费咨询
免费咨询
扫码关注
扫码关注
联系站长

站长Johngo!

大数据和算法重度研究者!

持续产出大数据、算法、LeetCode干货,以及业界好资源!

2022012703491714

微信来撩,免费咨询:xiaozhu_tec

分享本页
返回顶部