相关阅读
Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482
Verilog中的端口定义有两种风格,一种是Verilog Standard 1995风格,一种是Verilog Standard 2001风格,本文将对Verilog Standard 1995风格进行详细阐述。
图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_reference的拼接(使用拼接运算符{})。
而最底层的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所示,除了trireg类型),其中wire类型最常用。
图4 net大类
输出端口则没有这些限制,所以它可以是net大类(除了trireg类型),也可以是variable大类中的reg,integer和time类型。
即使在使用port declaration时,可以用net_type,reg,signed,range,描述一个信号的信息,但仍然可以使用net declaration或variable declaration对其再次进行声明(可以用于补充更多信息,但需注意如果是向量,则位宽需要一致,否则是一个未定义的行为),后面我们统称为additional declaration,如图5和图6所示。
如果在port declaration时,指定了net_type,reg,integer或time,则这个端口声明视为一个对信号的完整描述,则不可以再使用additional declaration对其再次进行声明。
图5 net声明的BNF范式
图6 variable声明的BNF范式
下面进行举例说明。
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, e;
// additional declaration
reg [2:0]a;
wire signed b;
// wire [1:0]d; error
.....
endmodule
从图5和图6可以看出additional declaration可以描述port declaration除端口方向外的所有信息,除此之外还能使用[delay3]可选项和线网声明赋值(尽管这很少见),如下所示。
module examlpe(a, b);
// port declaration
input a;
input [1:0] b;
// additional declaration
wire a=1'b1; // 线网声明赋值
wire [1:0] #1 b; // [delay3]
endmodule
注意:如果在port declaration时一个信号不存在类型信息,且其没有使用additional declaration补充说明其类型,则其默认为wire类型,如上例中的信号d。一个信号如果在port declaration或additional declaration中的任意一个指定了signed,则其为有符号,否则为无符号。
根据这个规则,信号a是输出的,reg类型的,有符号的3位向量信号;信号b是输出的,wire类型的,有符号的标量信号;信号c是输入的,wire类型的,无符号的3位向量信号;信号d和信号e拥有相同的属性,是输入的,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