1

我无法理解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

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

大多数指南都声明永远不要混合阻塞和非阻塞分配。有没有更好的方法来表示这样的事情?考虑到它在一个always_ff块中,现在在 SystemVerilog 设计中可以混合两种类型的分配吗?

4

2 回答 2

6

您永远不应该将阻塞和非阻塞分配混合到同一个变量。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

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

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

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

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

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

完全同意@jonathan 的回答。

您应该始终在 always_comb 块中拆分逻辑元素,在 always_ff 块中拆分顺序元素。

  • 如果您编写的代码紧密缝合在一起(同一块中的组合元素和顺序元素),即使它是正确的并且符合系统 verilog 规范,一些旧版本的模拟器或正在开发的新模拟器可能会以错误的方式推断它。

  • 您的代码对其他人来说不会是干净和可理解的。

  • 同样,通过以上述方式编写,您只是在压缩代码行,即使逻辑保持不变。如果它妨碍了代码的可读性,那么编写紧凑的代码是没有意义的。

现在就阻塞和非阻塞语句的使用而言,我认为辩论现在已经结束。现在,在 always_comb 块中使用阻塞语句,在 always_ff 块中使用非阻塞语句,现在更像是一种规则而不是指南。

但是,您所有问题的答案都在Clifford E Cummings 的 Verilog Synthesis 中的非阻塞分配、杀死的编码风格的这篇精彩论文中得到了解释。

如果您是 Verilog/系统 Verilog 设计的新手,我建议您阅读他们所有的论文,它们非常有用,为 RTL 设计工程师奠定了良好的基础。

此外,这里要说的可能太多了,但是如果您正在寻找如何在组合和顺序块中分离代码,您可以查看bluespec生成的代码

信号名称很难一口气理解,但如果仔细观察,代码逻辑上非常简洁,不会留下任何模拟和综合工具的奇思妙想。

于 2020-10-17T06:13:09.270 回答