tag 标签: fpga教程

相关博文
  • 热度 16
    2012-11-4 03:00
    2683 次阅读|
    0 个评论
    拿下变量数据类型          在上一讲中,我们讲了常量数据类型的语法介绍,从如何表达一个整数,x和z的意义,参数(parameter)型常量的使用到常量一些默认的规律。常量数据类型在verilog HDL是很重要的,那么变量数据类型呢? 答案是肯定的,变量数据类型甚至更重要。 其实是可以变很多的 什么是变量呢?在程序运行过程中可以改变的量就是变量。既然是变量,那肯定是可以变出很多数据类型啊,总体来说有两大派系,一是网络(net)连接类型,另一个是寄存器(Register)类型变量。 我们怎么区分这两大派系呢?网络(net)连接类型不能存储数据,就好比家家户户的普通的连接管;而寄存器(Register)类型变量可以存储数据,直至被赋予新值,好比带源头的管子。后面的具体的门派好比管子又有很多,比如自来水管、下水道管,通风管、北方的暖气管等 下面我们来细说这两大派系。 1.网络(net)连接类型 网络(net)连接类型变量是用于结构实体之间的物理连接,它不能存储数值,必须要有驱动器(例如:模块或门驱动,连续赋值语句)的驱动,驱动器信号的改变其驱动变量的数值,若没有驱动器的驱动其变量的就是高阻的,其值为z;在多驱动源的情况下,逻辑值会发生冲突,产生不确定的值。 那么派系有什么具体的门派呢?其主要的有wire型, tri型,supply0型, supply1型,wor型,trior型,wand型, triand型,trireg型,tri1型,tri0型等。 各个门派都是有什么绝技的呢? wire, tri 型 此类变量主要用于连接单元的连线,是最常见的net类型变量。wire型变量通常用来表示单个驱动源驱动的net型变量,而tri型(用于建模仿真)变量通常用来表示多驱动器驱动的网络型数据。在不同的场合用不同的net类型,只是为了区分用的场合而已,而wire型与tri型语法和语义一致,可以相互替换。我们还是看个多驱动源的例子吧。 模块程序如下: module or_test(          ain,          bin,          cout          ); input ain; input bin; output cout; tri  cout; assign cout=bin; assign cout=ain; endmodule 上面的双驱动模块不可综合,但可以仿真,仿真结果想如下: 综合以后会有以下语法错误。   对上面的双驱动模块进行仿真,程序如下: module testbench;                   reg ain,bin; // Inputs          wire cout; //实例化模块 or_test uuu (     .ain(ain),     .bin(bin),     .cout(cout)     ); initial begin                    ain = 0;                    bin = 0;                    #10;                    ain = 0;                    bin = 1;                    #10;                    ain = 0;                    bin = 1'bx;                    #10;                    ain = 0;                    bin = 1'bz;                    #10;                    ain = 1;                    bin = 0;                    #10;                    ain = 1;                    bin = 1'bx;                    #10;                    ain = 1;                    bin = 1'bz;                    #10;                    ain =1'b x;                    bin = 1'bx;                    #10;                    ain = 1'bx;                    bin =          1'bz;                    #10;                    ain = 1'bz;                    bin = 1'bz;                    #10;                     $stop;          end endmodule   下面仿真的结果   根据上面的仿真可以得出多驱动源时的真值表:   wire,tri 0 1 X Z 0 0 X X 0 1 X 1 X 1 X X X X X Z 0 1 X Z       supply1, supply0型 supply0型变量用于对“地”建模,即低电平0;supply1型变量用于对电源建模,即高电平1。这类变量是可以综合的。例如: module or_test(          cout,dout          ); output cout; output dout; supply0 ain; // supply0对应的地 supply1 bin;      // supply1对应的地 assign dout=bin; assign cout=ain; endmodule 下图为综合出来的电路图,,supply1对应的是电源。   wor,  trior型 此类型数据对应于有多个驱动源的线或逻辑连接,综合出来的结果相当于或门。当有多个驱动源驱动线或(wor)和三态线或(trior)数据时,就会产生线或结构。线或(wor)和三态线或(trior)如果某个驱动源为1,这类变量的值也为1。 举个例子吧。          module wor_test(    ain,     bin,  cin,   din, //in          cout,         dout            //out          ); input ain,bin,cin,din; output cout,dout; wor  cout;         //wor 类型声明 trior dout;                           //trior类型声明   assign cout=bin;   assign cout=ain;    //wor 类型多驱动源   assign dout=cin; assign dout=din;                //trior类型多驱动源   endmodule 上面是一个用两个驱动源驱动一个wor型和tri型的变量,其综合出来的电路如下,从图可以看出,他就是一个双输入的或门电路。            大家可以仿照wire和tri型仿真程序进行仿真,根据仿真结果(大家可以自己做一下,篇幅有限,不在重复),同样可以得出多驱动源时的真值表:   wor,trior 0 1 X Z 0 0 1 X 0 1 1 1 1 1 X X 1 X X Z 0 1 X Z   wand, triand型 此类型数据对应于有多个驱动源的线与逻辑连接,综合出来的结果相当于与门。当有多个驱动源驱动线或(wand)和三态线或(triand)数据时,就会产生线与结构。线与(wand)和三态线与(triand)如果某个驱动源为0,这类变量的值也为0。比如: module wand_triand_test(    ain,     bin,  cin,   din, //in          cout,         dout            //out          ); input ain,bin,cin,din; output cout,dout; wand  cout;         //wand 类型声明 triand dout;                        //triand类型声明   assign cout=bin;   assign cout=ain;    //wand 类型多驱动源   assign dout=cin; assign dout=din;                //triand类型多驱动源   endmodule        
  • 热度 22
    2012-11-4 02:37
    2898 次阅读|
    7 个评论
    第9章拿下运算符(1)           万丈高楼平地起,我们有了常量和变量的基础,也就知道在Verilog中怎么表示我们需要的数据,可是想要达到我们的目的,只有数据是远远不够的,还需要将这些数据按照一定的运算组合起来,才能会当凌绝顶,一览众山小,实现我们需要的功能。那么,在Verilog中,都有些什么运算符呢?它们又到底是怎么工作的呢?其实,这些运算符对于有过编程经历的人来说是很熟悉的,它跟C语言中的很类似,但有许多地方则是完全不同的,比如缩减运算符、位拼接运算符、阻塞非阻塞赋值运算等等。下面我们就一起来看看这些大大小小的运算符吧。   9.1林林总总的运算符 9.1.1逻辑运算符    一说到逻辑运算符,立马就能想到是逻辑与、逻辑或、逻辑非。BINGGO!确实如此。 逻辑与: 逻辑或:|| 逻辑非:! 上述三种运算符的真值表如下表所示。 表逻辑运算符   a 真 真 假 假 b 假 真 假 真 !a 假 假 真 真 !b 真 假 真 假 ab 假 真 假 假 a||b 真 真 假 真   表中,各种真真假假不期而遇,令人眼花缭乱。大家看到这种逻辑运算符,第一反应就是各种真假条件之间的运算关系,而真假逻辑容易让我们想到数字电路中的“1”和“0”,但在实际情况中有可能并不是简简单单的“1”和“0”,我们还是通过实际的例子来鉴定一下真真假假的运算关系吧。 modulelogicmode{                                      clk,                                      rst,                                      dataout };          inputclk;          inputrst;          outputregdataout;                   reg temp1=4’b0010;         // 逻辑值为1          reg temp2=4’b0000;         // 逻辑值为0          reg temp3=4’b1ZX0;         // 逻辑值为1          reg temp4=4’b00XZ;         // 逻辑值为X          reg data1,data2,data3,data4; always @(posedgeclk) begin          if(rst)                    dataout=0;          else                    begin                             data1=(!temp1);                    //  data1=0                             data2=(temp1 temp2);           //   data2=0                             data3=(temp2 || temp3);            //   data3=1                             data4=(temp2 || temp4);            //   data4=X                             dataout=((!data2) (temp3));       //   dataout=1                    end end endmodule   在Modelsim中仿真结果如下所示:   如图中蓝色线圈中信号所示,data1=0,data2=0,data3=1,data4=X,dataout=1。 从上例可以看出以下几点: (1)逻辑运算符和||是双目运算符,需要两个操作数参与运算,逻辑运算符!是单目运算符,只需要一个操作数; (2)逻辑运算符只对逻辑值进行操作,若操作数中全为0,则该操作数代表逻辑值0,若操作数中有一位1时,则该操作数代表逻辑值1,若操作数中只包含0、X、Z,则该操作数代表逻辑值X; (3)逻辑运算符的运算结果为1位:0、1、X。   特别说明:在不清楚运算符优先级的情况下,建议还是带上括号吧,避免由于优先级的问题而导致程序运算结果的错误。不要着急,在熟悉了各种运算符之后我们再给它们排个座。   9.1.2按位运算符 上面的逻辑运算符是对逻辑值进行操作的,按位运算符,顾名思义就是对数据中对应的每一位即每bit进行操作,很多人在不经意间就搞混了。 按位与: 按位或:| 按位非:~   真值表如下所示。   按位与() 0 1 X Z 0 0 0 0 0 1 0 1 X X X 0 X X X Z 0 X X X     按位或(|) 0 1 X Z 0 0 1 X X 1 1 1 1 1 X X 1 X X Z X 1 X X     按位非(~) 0 1 X Z   1 0 X X   其实,看似复杂的真值表,小结一下就很简单: 任何逻辑值(0、1、X、Z)和“1”进行“或”操作,得到的结果都是1; 任何逻辑值(0、1、X、Z)和“0”进行“与”操作,得到的结果都是0; 有逻辑值“Z”参与的运算只能得到逻辑值0、1、X; 除了(1)(2)两种情况外,只要有X或Z参与的逻辑运算,结果都为X。 例如: reg a=6’b011101; reg b=6’b101X00; reg c=6’b10011Z; reg d=4’b1101;   result1=(ab);     // result1=6’b001X00 result2=(b|c);     // result2=6’b10111X result3=(~c);      // result3=6’b01100X result4=(c|d);     // result4=6’b101111   上述运算的仿真结果如图所示:     上例中,result4是对两个位数不同的操作数进行运算,结果的位数与c的位数相同(6位),我们从仿真结果中也可以看出,在运算过程中,先把d扩展到6位(图中红线所圈),再按位或,得到的结果为6位(图中蓝线所圈),即当两个操作数位数不同时,位数少的操作数0扩展到相同的位数,也就是我们常说的少数服从多数嘛,而运算结果的位数与位数多的操作数相同。 所以,我们可要睁大眼睛看清楚咯,按位运算符是对数据中所有位进行操作,而逻辑运算符是对整个数或者表达式的逻辑值进行操作,比如逻辑非(!)的结果为一位(0、1、X),但是按位非(~)的结果却与操作数的位数相同,不一定是一位。  9.1.3 缩减运算符 缩减运算符也叫一元归约操作符,其符号和上面介绍的按位运算符相同: 与: 或:| 异或:^ 与非:~ 或非:~| 异或非:^~或者~^ 虽然缩减运算符是对数据中每位进行操作,不同的是,它是单目运算符,只有一个操作数,是对操作数中每位与相邻的下一位进行运算,即先把最高位与次高位进行与、或等操作,再将结果与次高位的下一位进行与、或等运算,依次类推,最终得到结果,这个结果是一位的,和按位运算符有着明显的差别。上述缩减运算符中常用的有与()、或(|)、异或(^),例如:   reg num=4’b0110;          reg    out;            out1=num;  //相当于进行(((num num )num )num ),out=0;     out2=~num;  //相当于进行(~(((num num )num )num )),out=1;   从上例中可知,缩减运算符是对数据内部的位进行操作,只涉及到一个操作数,并且没有“非”运算,与按位运算符有着本质的区别,不要混淆咯。大家如果对缩减运算符感兴趣,可以自己下去做做仿真,说不定还能挖出宝藏,哈哈。   
相关资源