首页 > 代码库 > Verilog中的assign

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 = http://www.mamicode.com/{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,…., 存在逻辑函数关系

Verilog中的assign