Verilog基础:模块端口(port)定义的语法(1995)

相关阅读

Verilog基础icon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482


        Verilog中的端口定义有两种风格,一种是Verilog Standard 1995风格,一种是Verilog Standard 2001风格,本文将对Verilog Standard 1995风格进行详细阐述。

        首先来看一下模块定义的BNF范式(语法),有关BNF范式相关内容,可以参考之前的文章。BNF范式icon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/article/details/132567389?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172377821516800178519242%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=172377821516800178519242&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132567389-null-null.nonecase&utm_term=BNF&spm=1018.2226.3001.4450

图1 模块定义的BNF范式

        从上图可以看出,module_declaration有两种形式,由符号|分隔:前一种使用list_of_ports形式的是Verilog Standard 1995风格;后一种使用list_of_port_declarations形式的是Verilog Standard 2001风格,这是一种ANSI C风格的形式。

        图2将图1中与端口定义有关的语法单独列出来了。

图2 端口定义的BNF范式 

        下面将对Verilog Standard 1995风格端口定义的格式进行逐步分析。

list_of_ports

        list_of_ports是用小括号包围的一个或多个port(如有多个,用逗号分隔)。

        port是一个可选的port_expression或者是.port_identifier加上可选的port_expression(这有些奇怪,一般这个形式是在模块例化时用于命令端口连接的,但事实上,他也可以在模块端口定义时使用)。

        port_expression是一个port_reference或port_expression的拼接(使用拼接运算符{})。

        而最底层的port_reference,其实就是一个port_identifier,如果其为一个向量,还可以使用向量的常量位选或常量域选(见图中的constant_range_expression)。

        下面列出了一些合法的list_of_ports,但其实只有第一种情况是最常用的(说实话,在看标准前,我没遇见过其他情况)。

module test1(a, b, c, d);   // most common used
module test2(a, , b, c, d);  
module test3(a[1:0], {b, c}, a[2], d);  
module test4(.aa(a[1:0]), .bb({b, c}), .cc(a[2]), d, .ee()); 

        上面的test4模块中,使用了一种特殊的port形式,即.port_identifier加上可选的port_expression,可以将其称呼为显式端口。而一般情况下的port_expression,可以将其称呼为隐式端口。

        使用显式端口的目的,是为了方便进行命名端口连接,我们首先来隐式端口的命名端口连接。

test1 test1_i(.a(a1), .b(b1), .c(c1), .d(d1)) 

        这很自然,因为a, b, c, d是简单标识符,但如果出现port_expression不是一个简单的标识符的情况,这时应该如何命名端口连接呢?下面的形式合法吗?

test3 test3_i(.a[1:0](a1), .{b, c}(b1), .a[2](c1), .d(d1));  // error 

        很不幸,这是不合法的,至少对于前三个端口,这是不合法的。那我是否能前三个端口使用位置端口连接,最后一个端口使用命名端口连接呢?这也是不合法的,因为不能混合使用命名端口连接和位置端口连接。

test3 test3_i(a1, b1, c1, .d(d1));  // error

        可以解决这个问题,如果使用了显式端口,则可以使用port_identifier作为命名端口连接的替换,如下所示。

test4 test4_i(.aa(aa1), .bb(bb1), .cc(cc1), .d(d1), .ee(ee1));  // no error

        以上,我们已经学习了端口列表相关的内容,但其实我们还未描述端口的详细信息:输入or输出or双向?向量or标量?有符号or无符号?类型?这些由模块体中的port_declaration完成。也就是说,如果使用了Verilog Standard 1995风格,则模块体中必须存在相应的port_declaration。

port_declaration

        有三个类型的port declaration:输入端口声明、输出端口声明和双向端口声明,它们的BNF范式如图3所示。

图3 端口声明的BNF范式

        port declaration用于描述port_expression中的port_identifier的详细信息(注意,显式声明.port_identifier中的port_identifier并不需要声明,它只是为了方便命名连接而存在的)。

        从图3中我们可以看出,输入端口和输出端口有可选的net_type,这是因为输入端口的连接就像是一个assign连续赋值,作为等号左边的信号自然得是net大类(图4所示),其中wire类型最常用。

图4 net大类

        输出端口则没有这些限制,所以它可以是net大类,也可以是variable大类中的reg,integer和time类型。

        即使在port declaration时,可以用net_type,reg,signed,range,描述一个信号的信息,但仍然可以使用net declaration或variable declaration对其再次进行声明(可以用于补充更多信息,但需注意如果是向量,则位宽需要一致),后面我们统称为additional declaration。如果在port declaration时,指定了net_type,reg,integer或time,则这个端口声明视为一个对信号的完整描述,则不可以再使用additional declaration对其再次进行声明。

module test1(a, b, c, d);
// port declaration
output signed [2:0]a;  
output b;
input wire [2:0]c; // unable to use additional declaration
input [2:0]d;


// additional declaration
reg [2:0]a;
wire signed b; 
// wire [1:0]d; error   
.....
endmodule

        注意:如果在port declaration时一个信号不存在类型信息,且其没有使用additional declaration补充说明其类型,则其默认为wire类型,如上例中的信号d。一个信号如果在port declaration或additional declaration中的任意一个指定了signed,则其为有符号,否则为无符号。

        根据这个规则,信号a是输出的,reg类型的,有符号的3位向量信号;信号b是输出的,wire类型的,有符号的标量信号;信号c是输入的,wire类型的,无符号的3位向量信号;信号d是输入的,wire类型的,无符号的3位向量信号。

一个良好的编程习惯

        因为Verilog标准对端口定义提供了相当高的自由度,所以一个公司内常常需要统一编码风格,例如下面就是,使用Verilog Standard 1995风格,只在port declaration中声明端口方向和位宽(如需要),在additional declaration中指定其他信息(注意,最好显式指定wire类型,而不是利用默认wire特性),下面是一个好的编码风格。

module DecoderS1 (

    // Common AHB signals
    HCLK,
    HRESETn,

    // Signals from the Input stage
    HREADYS,
    sel_dec,
    decode_addr_dec,
    trans_dec,

    // Bus-switch output 0
    active_dec0,
    readyout_dec0,
    resp_dec0,
    rdata_dec0,
    ruser_dec0,

    // Bus-switch output 1
    active_dec1,
    readyout_dec1,
    resp_dec1,
    rdata_dec1,
    ruser_dec1,

    // Bus-switch output 2
    active_dec2,
    readyout_dec2,
    resp_dec2,
    rdata_dec2,
    ruser_dec2,

    // Bus-switch output 3
    active_dec3,
    readyout_dec3,
    resp_dec3,
    rdata_dec3,
    ruser_dec3,

    // Output port selection signals
    sel_dec0,
    sel_dec1,
    sel_dec2,
    sel_dec3,

    // Selected Output port data and control signals
    active_dec,
    HREADYOUTS,
    HRESPS,
    HRUSERS,
    HRDATAS

    );


// -----------------------------------------------------------------------------
// Input and Output declarations
// -----------------------------------------------------------------------------

    // Common AHB signals
    input         HCLK;           // AHB System Clock
    input         HRESETn;        // AHB System Reset

    // Signals from the Input stage
    input         HREADYS;        // Transfer done
    input         sel_dec;            // HSEL input
    input [31:10] decode_addr_dec;     // HADDR decoder input
    input   [1:0] trans_dec;          // Input port HTRANS signal

    // Bus-switch output MI0
    input         active_dec0;        // Output stage MI0 active_dec signal
    input         readyout_dec0;      // HREADYOUT input
    input   [1:0] resp_dec0;          // HRESP input
    input  [31:0] rdata_dec0;         // HRDATA input
    input  [31:0] ruser_dec0;         // HRUSER input

    // Bus-switch output MI1
    input         active_dec1;        // Output stage MI1 active_dec signal
    input         readyout_dec1;      // HREADYOUT input
    input   [1:0] resp_dec1;          // HRESP input
    input  [31:0] rdata_dec1;         // HRDATA input
    input  [31:0] ruser_dec1;         // HRUSER input

    // Bus-switch output MI2
    input         active_dec2;        // Output stage MI2 active_dec signal
    input         readyout_dec2;      // HREADYOUT input
    input   [1:0] resp_dec2;          // HRESP input
    input  [31:0] rdata_dec2;         // HRDATA input
    input  [31:0] ruser_dec2;         // HRUSER input

    // Bus-switch output MI3
    input         active_dec3;        // Output stage MI3 active_dec signal
    input         readyout_dec3;      // HREADYOUT input
    input   [1:0] resp_dec3;          // HRESP input
    input  [31:0] rdata_dec3;         // HRDATA input
    input  [31:0] ruser_dec3;         // HRUSER input

    // Output port selection signals
    output        sel_dec0;           // HSEL output
    output        sel_dec1;           // HSEL output
    output        sel_dec2;           // HSEL output
    output        sel_dec3;           // HSEL output

    // Selected Output port data and control signals
    output        active_dec;         // Combinatorial active_dec O/P
    output        HREADYOUTS;     // HREADY feedback output
    output  [1:0] HRESPS;         // Transfer response
    output [31:0] HRUSERS;        // User read Data
    output [31:0] HRDATAS;        // Read Data


// -----------------------------------------------------------------------------
// Wire declarations
// -----------------------------------------------------------------------------

    // Common AHB signals
    wire          HCLK;            // AHB System Clock
    wire          HRESETn;         // AHB System Reset

    // Signals from the Input stage
    wire          HREADYS;         // Transfer done
    wire          sel_dec;             // HSEL input
    wire  [31:10] decode_addr_dec;      // HADDR input
    wire    [1:0] trans_dec;           // Input port HTRANS signal

    // Bus-switch output MI0
    wire          active_dec0;         // active_dec signal
    wire          readyout_dec0;       // HREADYOUT input
    wire    [1:0] resp_dec0;           // HRESP input
    wire   [31:0] rdata_dec0;          // HRDATA input
    wire   [31:0] ruser_dec0;          // HRUSER input
    reg           sel_dec0;            // HSEL output

    // Bus-switch output MI1
    wire          active_dec1;         // active_dec signal
    wire          readyout_dec1;       // HREADYOUT input
    wire    [1:0] resp_dec1;           // HRESP input
    wire   [31:0] rdata_dec1;          // HRDATA input
    wire   [31:0] ruser_dec1;          // HRUSER input
    reg           sel_dec1;            // HSEL output

    // Bus-switch output MI2
    wire          active_dec2;         // active_dec signal
    wire          readyout_dec2;       // HREADYOUT input
    wire    [1:0] resp_dec2;           // HRESP input
    wire   [31:0] rdata_dec2;          // HRDATA input
    wire   [31:0] ruser_dec2;          // HRUSER input
    reg           sel_dec2;            // HSEL output

    // Bus-switch output MI3
    wire          active_dec3;         // active_dec signal
    wire          readyout_dec3;       // HREADYOUT input
    wire    [1:0] resp_dec3;           // HRESP input
    wire   [31:0] rdata_dec3;          // HRDATA input
    wire   [31:0] ruser_dec3;          // HRUSER input
    reg           sel_dec3;            // HSEL output

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日晨难再

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值