目录
1.verilog端口
1.1 verilog端口声明
module count ( inout wire[31:0] data,
output reg[31:0] result,
output reg co,
input [31:0] a,b
iput tril ci);
...
endmodule
//verilog里端口的名称,方向,位数和类型都可以在端口列表声明
//也可以在端口列表只声明端口名称,在module内声明方向,位宽和类型
//若没有显式声明端口类型,则默认wire类型;默认位宽为类型的默认位宽
//上例中,a,b默认类型为wire,co的位宽为1
//为避免诸多不必要的麻烦,声明端口时,尽量名称+方向+位宽+类型一并声明
一些限制:所有端口必须显式声明方向;必须重新指定端口方向,才能改变后面端口类型;必须重新指定端口方向和类型,才能改变后面的端口位宽。
1.2 verilog端口的连接
//位置对应方式连接
module and_1( a,b,c);
input a,b;
output c;
assign c=a&b;
endmodule
module logic(in1,in2,q);
inpu in1,in2;
output q;
and_1 U1 (in1,in2,q); //按顺序,a连in1,b连in2,c连q
endmodule
//端口对应方式连接
module and_1( ..)
..
endmodule
module logic(..);
..
and_1 U1(.a(in1),.b(in2),.c(q)); //按位置,a连in1,b连in2,c连q
//.选择底层模块的端口,后面()里是连接的顶层模块端口
endmodule //用这种方法可以不按顺序写
2. sv端口
sv的端口在verilog端口基础上做了一些延伸扩展:
指定了缺省方向为inout;端口列表中下一个端口定义了类型但没有方向,则方向参照前一个端口。
需要注意:如果第一个端口既没有方向也没有类型,那么后面的所有端口都不能有方向和类型。
可以理解为此时端口列表只声明端口名称,方向和类型都在模块内声明。
3.sv接口和modport
3.1 sv接口总结
以上图为例,如果要完成这样一个结构的连接,可以预想到的是,main_bus中的信号需要分别在六个模块中声明,然后再与六个模块相连接,同样的信号需要被重复声明和连接六次,这样代码量十分冗余。
sv中引入接口,接口可以允许许多信号合成一组由一个端口表示,即接口类型的端口。
上例中,使用verilog编写的测试生成器代码如下:
模块定义:
模块例化连接连接:
可以看出,main_bus在模块中要声明一次,连接时又要声明一次。
sv接口中,将main_bus信号包裹在interface和endinterface中,集中声明然后重复使用。
interface声明如下:
用sv接口来简化后的测试生成器代码如下:
模块定义:
模块例化连接:
模块定义中的main_bus bus,bus是接口类型的端口main_bus的名称,模块例化连接中的.bus(bus)里的(bus)是在顶层模块中例化的main_bus的实例名。具体理解见下
//显式声明一个接口类型的端口
interface chip_bus;
...
endinterface
module ram (chip_bus pins, input clock);
//在verilog学习后,刚接触sv接口总是想写成“方向+类型+名称”,比如 input logic[3:0] abc;
//这里,chip_bus已经是一个interface类型,
//且interface类型本身就可以具有input,output或者inout方向
//可以理解成chip_bus本身已经包括方向+类型,而pins就是变量名称
..
endmodule
//隐式声明一个接口类型端口
interface chip_bus;
...
endinterface
module arm (interface pins, input clock);
//参照上例,“方向+类型+名称”,明显没有声明“方向+类型”,而是用interface代替,名字为pins;
//这里只是举例隐式声明的方法,但个人来看,在实际应用中,interface的定义不止一个,
//如果都用隐式声明,个人理解会有不妥,所以实际编写代码,应该显式声明最稳妥
3.2 modport的定义和使用
3.2.1 modport定义
接口中的信号并未规定方向,对于不同的模块来说,接口中的信号方向会有不同。modport就定义了从不同的模块角度来看接口中信号的方向。
可以看出,modport中只需要定义信号对于不同模块的方向,而类型和位宽在接口中声明即可。
3.2.2 modport的使用
//在例化时选择modport
interface chip_bus(input logic clock,restn);
modport master (); //接口中相对于master的信号及方向
modport slave (); //接口中相对于slave的信号及方向
endinterface
module primary (chip_bus pins);
..
endmodule
module secondary (chip_bus pins);
..
endmodule
module chip (input logic clock,restn);
chip_bus bus (clock,resetn); //连接接口前一定要例化接口
primary i1 (bus.master); //例化primary时选择连接bus中的modport master
secondary i2 (bus.slave); //例化secondary时选择连接bus中的modport slave
endmodule
定义端口时就选择连接的modport
//端口定义时就选择连接的modport
interface chip_bus (input logic clock,resetn);
modport master (..);
modport slave (..);
endinterface
module primary (chip_bus.master); //这里有点像是用例化的名称去索引包含的对象,但从后面来看
//chip_bus此时并没例化,而且例化名称是bus
//这里就记为接口中modport使用的一个专门用法
..
endmodule
module secondary (chip_bus.slave);
..
endmodule
module chip (input logic clock,resetn);
chip_bus bus (clock,resetn);
primary i1 (bus); //会连接到bus中的master
secondary i2 (bus); //会连接到bus中的slave
endmodule
一些个人理解和总结:
interface my_intf (..);
..
endinterface
module abc (my_intf intf);//接口类型端口,名称为intf
..
endmodule
module top (..);
my_intf intf (..);//例化名称为intf
abc U1 (.*)
..
endmodule
//此时例化名称和模块内端口名称相同,连接时可用.*自动连接
//如果不同,则用.索引端口再连接
注意:
1.如果一个模块端口列表中有接口类型的端口,那么这个端口必须被连接到接口实例或者其它接口类型端口
2.显式声明的接口类型端口,必须连接到同一类型接口实例
3.隐式声明的接口类型端口,可以连接到任何类型接口实例