在仲裁器的 always_ff 块中混合非阻塞和阻塞分配

edc*_*edc 1 synthesis fsm round-robin system-verilog

我无法理解Stuart Sutherland(和他的同事)所著SystemVerilog For Design书中的示例 10-3 。

见第 232 行:

https://code.google.com/p/vak-opensource/source/browse/trunk/hardware/systemverilog/utopia-example/squat.sv?r=185

这是代码片段。我的问题将随之而来。

  bit [0:NumRx-1] RoundRobin;

  always_ff @(posedge clk, posedge reset) begin: FSM
    bit breakVar;
    if (reset) begin: reset_logic
      Rxready <= '1;
      Txvalid <= '0;
      Txsel_out <= '0;
      SquatState <= wait_rx_valid;
      forward <= 0;
      RoundRobin = 1;
    end: reset_logic
    else begin: FSM_sequencer
      unique case (SquatState)

        wait_rx_valid: begin: rx_valid_state
          Rxready <= '1;
          breakVar = 1;
          for (int j=0; j<NumRx; j+=1) begin: loop1
            for (int i=0; i<NumRx; i+=1) begin: loop2
              if (Rxvalid[i] && RoundRobin[i] && breakVar)
                begin: match
                  ATMcell <= RxATMcell[i];
                  Rxready[i] <= 0;
                  SquatState <= wait_rx_not_valid;
                  breakVar = 0;
                end: match
            end: loop2
            if (breakVar)
              RoundRobin={RoundRobin[1:$bits(RoundRobin)-1],
                          RoundRobin[0]};
          end: loop1
        end: rx_valid_state
Run Code Online (Sandbox Code Playgroud)

具体来说,我的问题是关于阻塞分配breakVarRoundRobin。我在某处读到变量是本地评估的,但我无法想象逻辑是如何合成的。是否RoundRobin被合成到状态寄存器?

大多数指导方针声明永远不要混合阻塞和非阻塞分配。有没有更好的方法来表示这样的东西?鉴于它在一个always_ff块中,现在在 SystemVerilog 设计中可以混合两种类型的赋值吗?

dav*_*_59 5

永远不要将阻塞和非阻塞赋值混合到同一个变量。breakVar是一个临时变量,将被合成为组合逻辑,因为它总是先写入,然后再读取。没有要保存的状态RoundRobin是一个局部变量,同时用作中间变量和状态变量。但是因为它只能从always_ff块内访问,所以不存在竞争条件的危险。


临时变量只是表示方程的一种象征方式。这是一个不同但更简单的例子:

always_ff @(posedge clock)
   begin
   full = (counter == 10);
   brimming = (counter > 7);
   hold <= brimming && !full;
   if (full) 
      counter <= counter + 1;
   else 
      counter < = 0;
end
Run Code Online (Sandbox Code Playgroud)

这相当于编写以下内容(但可能更难理解)

always_ff @(posedge clock)
   begin
   hold <= (counter > 7) && !(counter == 10);
   if (counter == 10) 
      counter <= counter + 1;
   else 
      counter < = 0;
end
Run Code Online (Sandbox Code Playgroud)

在上面的两个例子中,counter总是被综合为一个寄存器,因为它是先读后写。无论我们使用阻塞赋值还是非阻塞赋值都没有关系,因为我们counter在写入之后从不读取。always_ff使用阻塞赋值的块内没有竞争条件,但如果有另一个always_ff块试图读取它,则可能存在竞争条件。由于fullbrimming是在读取之前写入的,因此不必注册。

总而言之,如果这些条件中的任何一个为真,则变量将被合成为寄存器

  1. 变量写入同一个 always 块之前被读取。请注意,即使非阻塞赋值语句首先出现,读取也会首先发生,因为写入被安排在稍后发生。
  2. 由于条件或循环语句,有时会读取变量而不写入
  3. 变量写入always_ff块中并在块外读取。