Verilog中的assign

(一)

assign 用于描述组合逻辑,用阻塞赋值,但assign语句是并行执行,(说明:阻塞赋值串行操作是局限于在behavior structual 描述内部,也就是指在initial and always block内部。)

所有的assign和always是并行执行的。

对assign之后不能加块,实现组合逻辑只能用逐句的使用assign 组合逻辑,如果不考虑门的延时的话当然可以理解为瞬时执行的,因此没有并行和顺序之分,并行和顺序是针对时序逻辑来说的。值得注意的是所有的时序块都是并行执行的。initial块只在信号进入模块后执行1次而always块是由敏感事件作为中断来触发执行的。

assign 用于连续赋值语句,if-else用于RTL级描述中,被赋值的变量都是reg类型。reg类型赋值分blocked和nonblocked,即=和<=,不需要再使用assign。

(二)

一、引入语法的概念

 1、只有寄存器类型的信号才可以在always和initial 语句中进行赋值,类型定义通过reg语句实现。
  2、always 语句是一直重复执行,由敏感表(always 语句括号内的变量)中的变量触发。
  3、always 语句从0 时刻开始。
  4、在begin 和end 之间的语句是顺序执行,属于串行语句。

二、总结下几种assign用法:

1.作为信号量输出,通过寄存器连续赋值

output [3:0]oLED;

//internal signal

reg [3:0]sr_LED; //用独热码表示LED亮灯位置。

assign  oLED[3:0] = ~ sr_LED[3:0]; //向LED灯接口输出信号。

2.作为信号量输出,通过寄存器拼接数据位实现。

output [15: 0] oSI_DATA;

//internal signal

reg [ 3: 0] s_HEX;

reg [ 7: 0] s_SEGBINARY; // s_SEGBINARY[2] should be the DOT

reg [ 3: 0] s_SEG_SEL;

assign oSI_DATA = {iLED_SEL,s_SEG_SEL,s_SEGBINARY};

3.作为信号量输出,通过判断条件,赋值给信号

output[ 1: 0] oSEG_STATE;

output        oCP_PLUSE;

wire s_CNTEQCYCLE;

parameter PARAM_7SEG_CYCLE = 32‘d2500000;

reg [ 1: 0] sr_SEG_STATE;

reg [31: 0] sr_cnt;

reg         sr_cp_pluse;

assign oSEG_STATE = sr_SEG_STATE;

assign oCP_PLUSE = sr_cp_pluse;

assign s_CNTEQCYCLE = ( sr_cnt == PARAM_7SEG_CYCLE ) ? 1 : 0;

4.作为输出信号量,通过输入信号量赋值给输出,同样可以输入信号量和寄存器组合逻辑,赋值给输出信号量。

input        iCLK50M;

input        iCP_PULSE;

input[15:0]  iSI_DATA;

output       oSI;

output       oCP;

reg [ 3: 0] sr_cnt;

reg [15: 0] sr_si_data;

reg sr_cp;

reg sr_en;

assign oSI = sr_si_data[15];

assign oCP = sr_en & iCLK50M;

三、对比输出寄存器变量和信号量

下面是功能相同但写法不同的两段代码:

第一段A

module assign_test_a (
                       clk,
                       lhold,
                       lholda
);

input clk;
input lhold;
output lholda;

reg lholda;

always @(posedge clk)
if (lhold)
 lholda<=lhold;
else
 lholda<=0;

endmodule

第二段B
module assign_test_b (
                       clk,
                       lhold,
                       lholda
);
input clk;
input lhold;
output lholda;

reg lholda_r;
  always @(posedge clk)
  if (lhold)
     lholda_r<=lhold;
  else
     lholda_r<=0;

 assign  lholda=lholda_r;
endmodule

两端代码生成的电路时一样的,没有区别,只是在应用上有区别

第一段A分析

第二段B的分析

Quartus RTL图

加入assign风格的综合结果

Xillinx RTL图

分析:

1. 从代码角度来看。 A是直接把内部reg信号做为输出,因此相对外部来说,外部信号引脚lholda没有选择的连接到reg输出信号。 这里其实暗含了用根导线直接把reg的输出与lholda连接起来。因此B代码就是把这个暗含的明显化。因此他们的RTL没有多大区别。
2. 从实用角度来说,这里的意义比较大。当内部有多个信号需要输出,可是输出引脚只有一个,那么这时就可以进行选择。如下:
assign  lholda= (条件)? (lholda_ra): lholda_rb;  可以嵌套使用。
   或者在这种情况下也非常有用。
     Lholda 与 内部的reg输出lholda_ra, lholda_rb,…., 存在逻辑函数关系

时间: 2024-11-09 00:47:11

Verilog中的assign的相关文章

关于Verilog 中的for语句的探讨

在C语言中,经常用到for循环语句,但在硬件描述语言中for语句的使用较C语言等软件描述语言有较大的区别. 在Verilog中除了在Testbench(仿真测试激励)中使用for循环语句外,在Testbench中for语句在生成激励信号等方面使用较普遍,但在RTL级编码中却很少使用for循环语句.主要原因就是for循环会被综合器展开为所有变量情况的执行语句,每个变量独立占用寄存器资源,每条执行语句并不能有效地复用硬件逻辑资源,造成巨大的资源浪费.简单的说就是:for语句循环几次,就是将相同的电路

Verilog中generate语句的用法

在Verilog-2001中新增了语句generate,通过generate循环,可以产生一个对象(比如一个元件或者是一个模块)的多次例化,为可变尺度的设计提供了方便,generate语句一般在循环和条件语句中使用,为此,Verilog-2001增加了四个关键字generate,endgenerate, genvar, localparam,genvar是一个新增的数据类型,用在generate的循环中的标尺变量必须定义为gnevar类型. 首先设计一个1bit位宽的buffer_1,这里有几点

verilog中的latch到底是个啥??简直快疯了!!!!!

在很多地方都能看到,verilog中if与case语句必须完整,即if要加上else,case后要加上default语句,以防止锁存器的发生,接下来就来说说其中原因. 一,什么是锁存器?锁存器与触发器的区别. 锁存器与触发器最大的区别在于,锁存器是电平触发,而触发器是边沿触发.锁存器在不锁存数据时,输出随输入变化:但一旦数据锁存时,输入对输出不产生任何影响. 二,为什么语句的不完整会导致锁存器的产生? 语句不完整即有某些情况的输入对输出无任何影响,根据锁存器的特征,反映到硬件电路即会产生锁存器.

verilog中defparam的用法 (verilog调用底层模块(只改变)参数的传递)

当一个模块引用另外一个模块时,高层模块可以改变低层模块用parameter定义的参数值,改变低层模块的参数值可采用以下两种方式: 1)defparam 重定义参数 语法:defparam path_name = value ; 低层模块的参数可以通过层次路径名重新定义,如下例: module top ( .....)input....;output....;defparam U1 . Para1 = 10 ;M1 U1 (..........);endmodulemodule M1(....);

verilog中defparam的用法

有机会看下defparam的语法了:如下: 当一个模块引用另外一个模块时,高层模块可以改变低层模块用parameter定义的参数值,改变低层模块的参数值可采用以下两种方式: 1)defparam 重定义参数 语法:defparam path_name = value ; 低层模块的参数可以通过层次路径名重新定义,如下例: module top ( .....)input....;output....;defparam U1 . Para1 = 10 ;M1 U1 (..........);end

Verilog中变量位宽注意

Verilog中,变量定义方式可以为:reg[位宽-1:0] 数据名:reg[位宽:1] 数据名.其他变量也类似. 以reg变量cnt为例,当cnt位宽为4时,可定义为reg[3:0] cnt,或者定义为reg[4:1] cnt 当cnt赋值为3时,reg[3:0] cnt:cnt=3 等效为 cnt[3]=0,cnt[2]=0,cnt[1]=1,cnt[0]=1; reg[4:1] cnt:cnt=3 等效为 cnt[4]=0,cnt[3]=0,cnt[2]=1,cnt[1]=1; 当cnt被

一段比较有意思的代码——介绍system verilog中的新增幅值语句

system verilog中新加了很多幅值语句,虽然都只适用于阻塞幅值,但是在某些场合中非常实用. 下面是一段有意思的代码,覆盖了一些用法. 1 package definitions; 2 typedef enum logic [2:0] {ADD,SUB,MULT,DIV,SL,SR} opcode_t; 3 typedef enum logic {UNSIGNED, SIGNED} operand_type_t; 4 typedef union packed { 5 logic [23:

verilog中signed的使用

1.在verilog中有时会用signed修饰符来修饰定义的数据,运算的时候也会用$signed()任务来强制转换数据,那么signed的修饰是为什么呢,是为了区分有符号数和无符号数的加法和乘法吗?其实不是的,因为有符号数和无符号数据的加法强结果和乘法器结构是一样的,signed的真正作用是决定如何对操作数扩位的问题. 2.verilog中的加法和乘法操作前,会先对操作数据扩位成结果相同的位宽,然后进行加法或者乘法处理.比如a/b都为4位数据,c为5位数据,c = a + b,这个运算的时候会先

verilog中assign和[email&#160;protected](*)的区别和值得注意

verilog描述组合逻辑一般常用的有两种:assign赋值语句和[email protected](*)语句.两者之间的差别有: 1. 被assign赋值的信号定义为wire型,被[email protected](*)结构块下的信号定义为reg型,值得注意的是,这里的reg并不是一个真正的触发器,只有敏感列表为上升沿触发的写法才会综合为触发器,在仿真时才具有触发器的特性. 2. 另外一个区别则是更细微的差别:举个例子, wire a; reg b; assign a = 1'b0; [ema