- 为模块定义原型:
extern module counter
#(
parameter N = 15
)(
output logic [N:0] cnt ,
input wire [N;0] d ,
input wire clock ,
load ,
resetN
);
module counter(.*);
always @(posedge clock, negedge resetN)
begin
if(!resetN) cnt <= 0;
else if(load) cnt <= d;
else cnt <= cnt + 1;
end
endmodule
- 命名的代码块结尾:
module: <module_name>
endmodule: <module_name>
interface: <interface_name>
endinterface: <interface_name>
task: <task_name>
endtask: <task_name>
function: <function_name>
endfunction: <function_name>
begin: <block_name>
end: <block_name>
- Verilog语言中提供了两种连接模块实例的代码风格:按端口次序和按端口名称连接。在按照端口次序连接中,每个端口的名称无关紧要,关键是端口所处的位置。在按照端口名称连接中,不需要保持模块实例的端口次序。
// 端口次序风格
dff d1 (out, /*not used*/, in, clock, reset);
- SystemVerilog提供了一种简洁的端口连接方式.name。使用Verilog的端口名称连接方式时,为了将线网与端口连接上,需要对一个名称重复两次。例如:.data(data)。SystemVerilog简化了这种端口名称连接的语法,只需要指出端口名称即可。当只给出端口名称后,SystemVerilog会自动地将与该名称一致的线网或变量连接到端口上,也就是说.data(data)可以简化为.data。
// 使用.name端口连接的模块实例,会自动在模块里寻找与端口名相同的信号
pc_stack pcs(
.program_counter,
.program_address,
...
);
- SystemVerilog还提供了一种简化大型网表端口连接的方式.*。表示模块实例中所有名称相同的端口和线网是自动连接在一起的。
// 使用.*端口连接的模块实例
pc_stack pcs(
.*
);
- SystemVerilog新增了一个alias语句,表示两个不同名称对同一个线网的引用。定义线网的别名不是将一个线网的值复制给另一个线网。下面的代码,线网clk就是clock的别名,clock也是clk的别名。clk不是clock的复制值,而就是clock,只是用了不同的名称表达而已。clock值的任何变化会反映在clk上,clk值的任何变化也会反映在clock上。alias和assign语句不一样,assign右边值的变化会反映给左边值,但是左边值的变化不会反映给右边。但是alias是双向的过程,这是因为别名实际上是一个线网有两个不同名字而已。多个线网可以同时进行别名化,任何一个线网的变化都会反映到所有一起被别名化的线网上。只有线网类型才可以使用alias别名化,并且左右线网的位宽要相同。
wire clock;
wire clk;
alias clk = clock;
wire reset,rst,resetN,rstN;
alias reset = rst;
alias reset = resetN;
alias resetN = rstN;
// 上面的语句等同于下面的语句
alias reset = rst = resetN = rstN;
-
隐式线网:当一个未声明的标识符与模块或原语实例的端口连接时自动推断出这个标识符是线网类型,并且线网的位宽和端口定义的相同。
-
Verilog中只有线网类型才可以作为模块的输入信号,只有线网类型,reg和integer类型才可以作为模块的输出信号,通过端口传递real类型是不合法的。SystemVerilog基本取消了所有关于什么类型的数据能在模块端口间传递的限制。任何类型包括实数都可以在端口间传递,压缩和非压缩的数组,结构体和联合体都可以在端口间传递。但是SystemVerilog规定端口两边的非压缩类型在结构上必须完全匹配,数组的维数和位数都要一样,结构体和联合体都要求是同一个用户自定义类型。
-
SystemVerilog指定了端口的默认方向是inout,如果端口列表中的下一个端口定义了类型,但是没有指定方向,那么默认端口的方向与前一个端口的方向一样。如果端口指定了方向没有指定类型,则默认是wire类型。
module accum(
// data指定了类型但是没指定方向,因此是默认的inout
wire [31:0] data,
//
output reg [31:0] result,
// co有类型但是没有方向,所以是前面端口的方向output
reg co,
// a,b有方向但是没有类型,所以是默认的类型wire
input [31:0] a,b,
// ci指定了类型但是没有方向,所以是前面端口的方向input
tri1 ci
);
...
endmodule
- 为了与Verilog保持完全向后兼容,SystemVerilog规定第一个端口同时没有方向和类型,那么就使用Verilog-1995的语法规则,其他端口也不能有方向和类型。
// Verilog-1995的语法规则
module accum(data, result, ...);
- Verilog能够使用parameter和localparam来定义常量,然后使用这些常量来计算模块端口或其他声明的向量位宽。SystemVerilog中,模块的线网和变量类型可以参数化。参数化的类型可以使用一对关键字parameter type进行声明。
module adder #(
parameter type ADDERTYPE = shortint
) (
input ADDERTYPE a,b, // 默认是shortint类型,在例化的时候可以传递其他类型
output ADDERTYPE sum, // 默认是shortint类型,在例化的时候可以传递其他类型
output logic carry
);
ADDERTYPE temp; // 可重新定义类型的局部变量
endmodule