Verilog语法_1(reg、wire、always语法)

https://blog.csdn.net/dengshuai_super/article/details/52557422

September 16, 2016 
作者:dengshuai_super 
出处:http://blog.csdn.net/dengshuai_super/article/details/52557422 
声明:转载请注明作者及出处。


可综合文件放到design文件夹下,testbench文件放到sim文件夹下(文件夹名可自定义)

//ex_module.v
module ex_module(
                input   wire                 sclk,
                input   wire             rst_n,
                input   wire  [7:0]  d,//声明模块的时候,输入一定是wire变量
                output  reg   [7:0]  q//声明模块的时候,输出可以是wire变量也可以是reg;reg变量必须在always块里面赋值
);//接口列表
//异步的D触发器
always @(posedge sclk or negedge rst_n)    //括号里面是敏感列表,可以包括电平触发或者沿触发
                                  //寄存器发生变化或翻转就是由CLK(让D触发器翻转)或CLR(复位端让寄存器清零)
        if(rst_n == 1'b0) //if后面的括号里是条件表,这里是组合逻辑。"=="声明一个比较器,"1"指的是1比特、""用来区分阿拉伯数字和进制,"b"代表的进制binary,“0”是一个比特的0
              q<=8'h00;            //10'b00000_00000  10'd10  10'hff,沿触发的逻辑里边一定都用<=非阻塞赋值。
        else
              q<=d;

////同步
//always @(posedge sclk)//同步的时候sclk在上升沿的时候,检测到低电平;异步的时候,当rst_n出现下降沿的时候,寄存器复位
//        if(rst_n == 1'b0)
//              q<=8'h00;
//        else
//              q<=d;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

//ex_wire.v
module ex_wire(
    input  wire sel,
    input  wire a,
    input  wire b,
    output wire c
);//always 对reg赋值,assign语句(连续赋值)对wire赋值
//wire 变量一定用assign连续赋值语句赋值,而且必须是用阻塞赋值
assign c=(sel == 1'b1)?a:b;//(条件)?条件为1:条件为0
/*
            if(sel == 1'b1)
                c =a;
            else
              c =b;
*/
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

//ex_cnt.v
module ex_cnt(
        input wire sclk,//模拟晶振产生时钟震荡
        input wire rst_n,//模拟外部复位电平testbench
      output wire [9:0] cnt
);
reg [9:0] cnt_r;//定义一个寄存器变量"r"代表reg

always @ (posedge sclk or negedge rst_n)
            if(rst_n == 1'b0)
                    cnt_r <= 10'd0;//"'d0"直接返回32位的0,截取低10位给cnt_r,1023+1=1024
            else
                cnt_r <= cnt_r + 1'b1;//0---1023-0---1023
assign cnt =cnt_r;          
//仿真工具modelsim    
//链接:http://pan.baidu.com/s/1qW5IhhM 密码:n28z          
endmodule



//请参考verilog数据常量
//数字表达式:<位宽><进制><数字>
//'b:二进制    //eg.4'b1110  表示4位二进制数1110
//'h:十六进制 //eg  8'hef、4’ha等
//'d:十进制    //eg   2'd3、4‘d15(不能写16,4位宽最大15)等
//
//所以10’d0表示10位宽的数值0,0000000000
//加入10‘d15,则表示十进制15 ,0000001111

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
//tb_ex_cnt.v

//声明延时单位,1ns指的是单位,100ps(0.1ns)指的是时标的精度。
//例如:#10.11--->10.10(最后的10ps精度被忽略)
`timescale 1ns/100ps   

module tb_ex_cnt;//这是完整的顶层,没有输入输出接口
            reg  tb_sclk,tb_rst_n;
            wire [9:0]  tb_cnt;

            initial//一上电只被执行一次,在initial这个块里面只能被寄存器变量赋值
            begin//在testbench里面begin、and是顺序执行的;在可综合模块里面begin、and就是一个括号
                    tb_sclk <=0;
                    tb_rst_n<=0;//它俩有先后顺序,先是tb_sclk被赋值然后再是tb_rst_n被赋值。但是之间的延迟是0。
                    #200.1
                    tb_rst_n<=1;
            end
always #10 tb_sclk <= ~tb_sclk;//例如初始状态是0,过了10ns变成1,又保持10ns变成0,周而复始的进行翻转。于是产生了时钟和复位信号

//例化的方法
//原始模块名字 例化的名字(可以自定义)
ex_cnt ex_cnt_inst(
        .sclk  (tb_sclk),//模拟晶振产生时钟震荡
        .rst_n (tb_rst_n),//模拟外部复位电平testbench;例化模块的时候如果原始模块是输入信号,那么括号内可以是wire变量也可以是reg变量
      .cnt   (tb_cnt) //例化模块的时候如果原始模块是输出信号,那么括号内必须是wire变量(正好和可综合模块相反)
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

例化时,变量的赋值应该遵循下图(按照自己理解画的,不一定正确,欢迎指正): 
Design中的模块输出的时候可以作为寄存器,它相当于把输出寄存器的Q端直接连接到输出口了,就把中间那根线给省略了; 
Testbench中输出变量必须是wire类型,因为芯片画PCB时,输出的管脚都用线连。 
这里写图片描述

打开ModelSim--->File--->new--->Project--->Project Name:ex_cnt(自定义,别写中文);路径:D:\VivadoProjects\FPGA_From_e_to_c\ex_1\sim(根据你文件的路径写)
--->在Project标签页下右键--->Add to Project--->Existing File--->将ex_cnt.v,tb_ex_cnt.v加进来--->Compile All--->数据编译到Library标签页的work下
--->右键tb_ex_cnt--->Simulation without Optimization--->右键ex_cnt_inst,Add Wave--->
  • 1
  • 2
  • 3
  • 4

如图所示: 
这里写图片描述

在Wave 页面下,如果左侧信号栏变量名带路径,可以在Tools--->Window Preferences--->Display Signal Path改为1即可。
然后在Wave页面设置运行时间:这里设置100us--->点击Run--->在左侧右击变量--->Radix--->选择显示的进制。
  • 1
  • 2
  • 3

Verilog中wire与reg类型的区别: 
http://blog.csdn.net/changhaizhang/article/details/6933806


来源: 
https://ke.qq.com/user/index/index.html#cid=66019&term_id=100056181

版权声明:自由转载,请声明出处。 https://blog.csdn.net/dengshuai_super/article/details/52557422
文章标签:  Verilog
个人分类:  FPGA

===========================================


wire表示直通,即输入有变化,输出马上无条件地反映(如与、非门的简单连接)。

reg表示一定要有触发,输出才会反映输入的状态。

reg相当于存储单元,wire相当于物理连线。reg表示一定要有触发,没有输入的时候可以保持原来的值,但不直接实际的硬件电路对应。

      两者的区别是:寄存器型数据保持最后一次的赋值,而线型数据需要持续的驱动。wire使用在连续赋值语句中,而reg使用在过程赋值语句(initial ,always)中。wire若无驱动器连接,其值为z,reg默认初始值为不定值 x 。

      在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑

      对组合逻辑输出变量,可以直接用assign。即如果不指定为reg类型,那么就默认为1位wire类型,故无需指定1位wire类型的变量。当然专门指定出wire类型,可能是多位或为使程序易读。wire只能被assign连续赋值,reg只能在initial和always中赋值。

      输入端口可以由wire/reg驱动,但输入端口只能是wire;输出端口可以是wire/reg类型,输出端口只能驱动wire;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型(wire/tri)。用关键词inout声明一个双向端口, inout端口不能声明为reg类型,只能是wire类型。

      默认信号是wire类型,reg类型要申明。这里所说的默认是指输出信号申明成output时为wire。如果是模块内部信号,必须申明成wire或者reg.

      对于always语句而言,赋值要申明成reg,连续赋值assign的时候要用wire。

模块调用时 信号类型确定方法总结如下:

信号可以分为端口信号内部信号。出现在端口列表中的信号是端口信号,其它的信号为内部信号。

对于端口信号,输入端口只能是net类型。输出端口可以是net类型,也可以是register类型。若输出端口在过程块中赋值则为register类型;若在过程块外赋值(包括实例化语句),则为net类型。

内部信号类型与输出端口相同,可以是netregister类型。判断方法也与输出端口相同。若在过程块中赋值,则为register类型;若在过程块外赋值,则为net类型。

若信号既需要在过程块中赋值,又需要在过程块外赋值。这种情况是有可能出现的,如决断信号。这时需要一个中间信号转换

下面所列是常出的错误及相应的错误信息(error message)

用过程语句给一个net类型的或忘记声明类型的信号赋值。

           信息:illegal …… assignment.

将实例的输出连接到声明为register类型的信号上。

           信息:<name> has illegal output port specification.

将模块的输入信号声明为register类型。

           信息:incompatible declaration, <signal name> ……

分类:  fpga

=========================================


这是事转载的一篇文章,觉得不错,虽然中间有点小错误。

wire与reg类型的区别:

wire型数据常用来表示以assign关键字指定的组合逻辑信号。模块的输入输出端口类型都默认为wire型。默认初始值是z

reg型表示的寄存器类型。always模块内被赋值的信号,必须定义为reg型,代表触发器。

默认初始值是x。

reg相当于存储单元,wire相当于物理连线

Verilog 中变量的物理数据分为线型和寄存器型。这两种类型的变量在定义时要设置位宽,缺省为1位。变量的每一位可以是0,1,X,Z。其中x代表一个未被预置初始状态的变量或者是由于由两个或多个驱动装置试图将之设定为不同的值而引起的冲突型线型变量。z代表高阻状态或浮空量。

线型数据包括wire,wand,wor等几种类型在被一个以上激励源驱动时,不同的线型数据有各自决定其最终值的分辨办法。

两者的区别是:寄存器型数据保持最后一次的赋值,而线型数据需要持续的驱动

 

输入端口可以由net/reg驱动,但输入端口只能是net,如a = b & c,输入端口a 只能是net型,但其驱动b,c可以是net/reg型;输出端口可以使net/reg类型,输出端口只能驱动net,如a = b & c,模块的输出端口b,c可以是net/reg型,但它们驱动的a必须是net型;若输出端口在过程块(always/initial)中赋值则为reg型,若在过程块外赋值则为net型。用关键词inout声明一个双向端口, inout端口不能声明为寄存器类型,只能是net类型。

 

wire表示直通,即只要输入有变化,输出马上无条件地反映;reg表示一定要有触发,输出才会反映输入。

不指定就默认为1位wire类型。专门指定出wire类型,可能是多位或为使程序易读。wire只能被assign连续赋值,reg只能在initial和always中赋值。wire使用在连续赋值语句中,而reg使用在过程赋值语句中。

在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑。

wire型的变量综合出来一般是一根导线;

reg变量在always块中有两种情况:    always后的敏感表中是(a or b or c)形式的,也就是不带时钟边沿的,综合出来还是组合逻辑   always后的敏感表中是(posedge clk)形式的,也就是带边沿的,综合出来一般是时序逻辑,会包含触发器(Flip-Flop)

在设计中,输入信号一般来说你是不知道上一级是寄存器输出还是组合逻辑输出,那么对于本级来说就是一根导线,也就是wire型。而输出信号则由你自己来决定是寄存器输出还是组合逻辑输出,wire型、reg型都可以。但一般的,整个设计的外部输出(即最顶层模块的输出),要求是寄存器输出,较稳定、扇出能力也较好。

 

Notes:七七八八的也看不太懂,总之wire赋值用assign,reg在always内使用。


猜你喜欢

转载自blog.csdn.net/kebu12345678/article/details/80585078
今日推荐