tag 标签: 非阻塞

相关博文
  • 热度 21
    2013-2-14 16:41
    1958 次阅读|
    0 个评论
         这里有一个数组:Data 、Data 、Data 和Data ,它们都是4比特的数据。我们需要在它们当中找到一个最小的数据,同时将该数据的索引输出到LidMin中,这个算法有点类似于“冒泡排序”的过程,而且需要在一个时钟周期内完成。例如,如果这4个数据中 Data 最小,那么LidMin的值则为2。    module Bubble_Up(                     Rst_n,                     Clk,                     Data,                     Lid_Min                     );     input Rst_n;     input Clk;     input   Data  ;     output   Lid_Min;     reg   Lid_Min;      always @(posedge Clk or negedge Rst_n)     begin         if (~Rst_n)         begin              Lid_Min = 2'd0;         end         else            begin                if (Data  = Data )    //"="表示小于等于                begin                    Lid_Min = 2'd0;    //"="表示非阻塞赋值                end                if (Data  = Data )                begin                    Lid_Min = 2'd1;                end                                          if (Data  = Data )                 begin                     Lid_Min = 2'd2;                 end                 if (Data  = Data )                 begin                     Lid_Min = 2'd3;                 end             end         end     endmodule   我们的原意是首先将Lid_Min设置为一个初始值(任意值都可以),然后将Data ~Data 与Data 进行比较,每比较一个数,就将较小的索引暂存在Lid_Min中,然后再进行下一次比较。当4组数据比较完成之后,最小的数据索引就会保留在Lid_Min 中。   我们在以上代码中使用了非阻塞赋值,结果发现,仿真波形根本不是我们所需要的功能,如图所示,图中的Data ~Data 分别为 11、3、10和12,Lid_Min的初始值为0。按道理来说,Lid_Min的计算结果应该为1,因为Data 最小,但仿真波形却为2。 为什么会得出这样的结果呢?   在时钟上升沿到来以后,且Rst_n信号无效时开始执行以下4个语句,假设这时候的Lid_Min是0,Data ~Data 分别为11、3、10和12:              if (Data  = Data )    //"="表示小于等于               begin                    Lid_Min = 2'd0;    //"="表示非阻塞赋值                end                if (Data  = Data )                begin                    Lid_Min = 2'd1;                end                                          if (Data  = Data )                 begin                     Lid_Min = 2'd2;                 end                 if (Data  = Data )                 begin                     Lid_Min = 2'd3;                 end   第一句的if为真,因此执行Lid_Min = 2’d0,而这时候,Lid_Min并没有立刻被赋值,而是调度到事件队列中等待执行,这是非阻塞赋值的特点。   第二句的if为真,因此执行Lid_Min = 2’d1,这是Lid_Min也没有立刻被赋值为1,而是调度到事件队列中等待执行。当前的Lid_Min还是0,没有发生任何变化。   同样,第三句的if也为真,因此执行Lid_Min = 2’d2,将更新事件调度到事件队列中等待执行。当前的Lid_Min还是0。   而第四句的if为假,因此直接跳过Lid_Min = 2’d3,这时跳出always语句,等待下一个时钟上升沿。   在以上的always语句执行完成以后,仿真时间没有前进。这时存在于事件队列中当前仿真时间上的3个被调度的非阻塞更新事件开始执行,它们分别将Lid_Min更新为0、1和2。   按照Verilog语言的规范,这3个更新事件属于同一仿真时间内的事件,它们之间的执行顺序随机,这就产生了不确定性。一般的仿真器在实现的时候是根据它们被调度的先后顺序执行的,事件队列就像一个存放事件的FIFO,它是分层事件队列的一部分,如图所示:   这3个事件在同一仿真时间被一一执行,而真正起作用的时最后一个更新事件,因此在仿真的时候得到的最终结果时Lid_Min为2。   然后我们想要得到的结果是,在每个if语句判断并执行完成以后,Lid_Min先暂存这个中间值,再进行下一次比较,也就是说在进行下一次比较之前,这个Lid_Min必须被更新,而这一点也正是阻塞赋值的特点,因此我们将代码作如下更改:     module Bubble_Up(                     Rst_n,                     Clk,                     Data,                     Lid_Min                     );     input Rst_n;     input Clk;     input   Data  ;     output   Lid_Min;     reg   Lid_Min;      always @(posedge Clk or negedge Rst_n)     begin         if (~Rst_n)         begin              Lid_Min = 2'd0;         end         else            begin                if (Data  = Data )    //"="表示小于等于                begin                    Lid_Min = 2'd0;    //"="表示非阻塞赋值                end                if (Data  = Data )                begin                    Lid_Min = 2'd1;                end                                          if (Data  = Data )                 begin                     Lid_Min = 2'd2;                 end                 if (Data  = Data )                 begin                     Lid_Min = 2'd3;                 end             end         end     endmodule   其仿真波形如图所示:   在代码仿真过程中,第二句的if为真,执行Lid_Min = 2'd1,根据阻塞赋值的特点,Lid_Min被立刻赋值为1。在执行第三句if的时候,if (Data  = Data )为假,直接跳过Lid_Min = 2'd2不执行,同样也跳过Lid_Min = 2'd3不执行。Lid_Min被最终赋值为1,这正是我们想要的结果。         另外,为了使代码看起来更简洁,我们使用for语句改写了代码:      module Bubble_Up(                      Rst_n,                      Clk,                      Data,                      Lid_Min                      );       input Rst_n;       input Clk;       input   Data  ;       output   Lid_Min;       reg   Lid_Min;       integer i;       always @(posedge Clk or negedge Rst_n)       begin           if (~Rst_n)           begin               Lid_Min = 2'd0;           end           else           begin               for (i = 2'd0; i = 2'd3; i = i + 2'd1)               begin                   if (Data  = Data )                   begin                         Lid_Min = i;                   end               end           end        end      endmodule   这种写法与前面展开的写法完全等效,功能完全一致。今后大家在读代码时发现带有for语句的电路功能比较难理解,可以将这些语句展开,增强代码的可读性。  
相关资源