热度 18
2012-11-4 03:04
4059 次阅读|
0 个评论
wire 和reg才是精干 虽说变量数据类型可以变出很多,但是领导群雄的只有两大门派,一个是wire型,另一个就是reg型,他们才是精干,和他们打交道的机会也是最多的。任何时候,结识一个群体的核心是比较重要的。接下我们就着重就说说这两大门派。 wire型 我该如何声明wire型 wire型数据该如何表示呢?wire型信号的声明是有一定的格式的。 其格式为: 数据类型标示符(wire) 位宽 数据名列表; 如果一次定义多个数据,数据名之间用逗号隔开,声明语句最后要用分号表示语句结束。例如: wire a,b,c; 或者 wire a,b,c; //定义了三个n位宽的信号a,b,c wire是wire型数据的标示符; 和 代表该数据的位宽n;a,b,c是数据的名字。 若信号声明时为位宽缺省,其位宽默认为1位。如: wire a; //定义了一个1位的wire型数据a 该如何使用wire型 1.wire型信号可以用于任何方程式的输入,也可作为用做“assign“语句的或者实例元件(如门)的输出;如 wire ain; wire bout; reg cout; assign bout = ~ ain;// bout作为“assign“语句输出,ain作为输入 always @(posedge clk) begin cout= bout+ ain; // ain 和bout求和方程式的输入 end 又如: wire ain; wire bout; not uuu(bout,ain);// bout作为非门元件的输出,ain作为输入 2.在verilog HDL程序模块中,输入信号须定义为wire型,同时输入,输出信号若未定义,则默认定义为 wire 类型。 reg型 我该如何声明reg型数据 reg型的变量与wire的声明格式很相似的,可以一次定义多个reg型数据,格式如下: 数据类型标示符(reg) 位宽 数据名列表; 比如: reg a,b,c; //定义了3个名为a,b,c的reg型数据; “always“的常客 reg型数据常用来表示“always“模块内的制定信号,常代表触发器,同时在“always“模块中被赋值的每一个信号都必须定义成reg型,他是“always“模块中的常客。如 module sum(ain,bin,cout,dout) input ain,bin; output cout; reg bout; always @( ain or bin or cout) begin cout= ain+bin; // bout必须定义成reg型 dout= cout+ ain; //reg型数据(如 cout)也可以作为运算式的输入 end endmodule 从例子可以知道,reg型在“always“模块可以作为运算式的输入,也可作为运算式的输出,但运算式的输出(即等号左边)必须为reg型。 reg型的赋值问题 reg型数据可以赋正值,也可赋负值,但是当reg型作为一个表达式中操作数时,其内部数值会被作为无符号数(也就是正值)处理。如何进行转化呢?reg型变量的数值的进行取反,再加1。比如 reg b= -5; 那么b中的无符号数值为多少呢?按照上面的方法,5对应的四位宽的二进制数为0101,将其取反就是1010,再加1,就是1011,也就是10进制的11。 另外,reg型数据的缺省的初始值为不定值x。在顶层测试仿真文件中,初始的信号要定义成reg型,比如:clk,rst。模块间的连接信号和模块的输出信号要定义为wire型。 不要以为reg我就是触发器 reg型信号常常是寄存器或触发器的输出,但不能以为reg我就是触发器; 比如: module or_test( ain, bin, cout ); input ain,bin; output cout; reg cout; always @ (ain or bin or cout) begin cout = ain | bin; end endmodule 综合后的RTL级电路如下: 这是用“always”块实现的or门电路的模块,reg型cout信号并不是触发器的输出。 memory其实也是reg memory型可以看做reg型变量的数组,是二维的reg,可以用来描述RAM型或ROM型的存储器。memory型数据类型是通过扩展reg型数据的地址范围来生成的。 我该怎么声明memory型变量? memory型有特定的表示格式: reg 存储器名 ; reg 定义了存储器中每一个单元的大小,也就是存储单元的位宽; 定义了存储器中有多少个存储单元,地址范围从0到m-1。地址索引的表达式必须为常数表达式,表达式中可以含有参数常量。如: parameter memorysize; reg memory_a ; 例子中定义了名字为memory_a,有memorysize个16位宽的存储单元的存储器。地址从0到memorysize-1。 memory型和reg型数据可以在一起定义,如 reg memory_a ,reg_b,reg_c; 我该怎么对memory型变量赋值? 对memory型数据不能像reg型数据一样在一条赋值语句里赋值。如 reg reg_a, memory_b ; reg_a=0; //合法赋值 memory_b=0; //非法赋值 要想对一个memory型的数据赋值或者进行读写操作,必须通过指定数据变量的地址分别对每个存储单元进行操作。如: memory_b =0; //将memory_b地址为5的存储单元赋值为0 我们应该如何对一个memory型变量所有的单元进行访问或操作?那么我们可以通过访问memory型变量的地址索引来访问该变量的每个单元。 例如: module test_memory_assignment; reg clk; //时钟 reg mema ; //memory型变量 reg add_mema; //地址索引寄存器 reg over; //赋值结束信号 always #1 clk=~clk; //产生仿真时钟 //地址控制模块 always @(posedge clk) begin if(add_mema==7over==0) begin mema =0; end else if(over==0) begin add_mema=add_mema+1; mema =0; end else ; end initial begin //初始化 clk = 1; over = 0; add_mema =0; #20; $stop; //仿真结束函数 end endmodule 仿真结果如下: 上面的仿真是通过地址索引对memory型变量的单元依次进行初始化。 inout该怎么定义类型 第六章已经讲过模块的端口定义分为input,output和inout是三类。那么inout型的如何使用呢,该怎么定义变量数据类型?前面讲过input只能定义为net型数据, inout型端口也可以作为输入,也同样只能定义为net型数据,一般定义为wire型。 因为inout型变量是输入又是输出,那我们可以用“assign“语句作为inout型变量的驱动源,通过定义一个寄存器io_link作为选择inout口方向,若将io_link置1,则代表为output,若io_link置为0则代表input口。 还是举个例子吧: inout io_data; //inout口 reg out_data; //需要输出的数据 reg io_link; //inout口方向控制,1为输出,0为输入 assign io_data = io_link ? out_data:1'bz; //这个是关键,没用是一定要拉三态 切记:在没有作为输出时,一定要把它置为高阻态z,别“占着茅坑不拉屎”,只有这样才可以把inout口当作平常的input口用了。