1. 对端口的准确理解
module test11 (clk, testin, testout);
input clk;
input testin;
output testout;
reg testout;
...
endmodule
说明:端口中的名称都是线型的。在实例化子模块时常容易犯的一个错误是:把寄存器当变量往子模块里送,并将子模块的对应端口申明为寄存器输出,企图从中获得什么反馈。其实把“寄存器”往里送并不是绝对不可以,问题是你送进去的寄存器禁止被赋值。也就是说,子模块无权修改父模块内寄存器的内容。
结合开头的例子,做个更精确的解释:例子中的testout实质是两个东西,一个是wire,一个是reg。它们是缺省相关的,因为名称一样。而当以变量形式将testout往子模块里送时,你送进去的“寄存器"并不是reg,而是wire。为便于理解,上述例子实质内涵是如下形式:
module test12 (clk, testin, testout);
input clk;
input testin;
output testout;
reg testreg;
assign testout = testreg; //这句是关键, 类似“output reg testout;”的语句中
//其实隐含有 assign testout = testout;
//若分为两句写, “output testout;”这句才是真正的端口说明,
//而“reg testout;”这句只是因为写程序中要用到寄存器,而且
//这个寄存器跟testout紧密相关,所以不妨就用testout, 重名而已.
...
endmodule
2. 数据总线读写的语法
数据总线是可读可写的,是三态的。(但在对端口申明时,不必刻意在端口申明中加tri字样)。读写三态总线有其规范格式,否则综合时反复出错。标准例程格式可以到www.altera.com上下载。
module test21 (A, D, CLK, nRESET, nOE, TESTin, TESTout);
input [15:0] A;
inout [7:0] D;
input nOE;
input [7:0] TESTin;
output [7:0] TESTout;
assign TESTout = D; //读总线上的数据与读一般端口、寄存器、线型网点一样, 没有任何区别;
assign D = (~nOE)? TESTin : 8'bzzzzzzzz; //这是写总线的标准、经典格式,永远别企图改变. |