0

我试图将我的头脑围绕在组合逻辑和行为逻辑的混合中。我有带有 4 个 LED 和 66 MHz 时钟输入的小型 FPGA。这个想法是让其中两个发光(一个上升,一个下降),另外两个闪烁。所以我想出了以下代码:

module ledflash(input wire CLK,
        input wire USER_RESET,
        output wire LED[3:0]);

   reg [26:0]           cnt;
   reg [4:0]            pwm;

   wire             led_enable = ~USER_RESET;

   always @(posedge CLK)
     begin
    if (led_enable)
      begin
         cnt <= cnt + 1;
         pwm <= pwm[3:0] + (cnt[26] ? cnt[25:22] : ~cnt[25:22]);
      end
    else
      begin
         cnt <= 0;
         pwm <= 0;
      end
   end

   assign LED[0] = led_enable ? (cnt[26] ? pwm[4] : ~pwm[4]) : 0;
   assign LED[1] = led_enable ? (cnt[26] ? ~pwm[4] : pwm[4]) : 0;

   assign LED[2] = led_enable ? cnt[25] : 0;
   assign LED[3] = led_enable ? ~cnt[25] : 0;

endmodule

我不想使用供应商特定的 DCM,因此具有 66MHz 时钟的简单位加法器可以发挥作用。也许整个设计首先是错误的(例如,我可以使用两个时钟分频器并简单地翻转两个寄存器来实现(几乎)相同的事情),但我遇到了这种让我想知道的情况。 ..

从普通软件开发人员的角度来看,连续分配中的某些部分似乎是多余的。例如,可以使用一个额外的寄存器,因此看起来执行的工作更少。例如:

module ledglow(input wire CLK,
        input wire USER_RESET,
        output wire LED[3:0]);

   reg [26:0]           cnt;
   reg [4:0]            pwm;
   reg              led_pair1;
   reg              led_pair2;

   wire             led_enable = ~USER_RESET;

   always @(posedge CLK)
     begin
    if (led_enable)
      begin
         cnt <= cnt + 1;
         pwm <= pwm[3:0] + (cnt[26] ? cnt[25:22] : ~cnt[25:22]);
      end
    else
      begin
         cnt <= 0;
         pwm <= 0;
      end
    led_pair1 <= cnt[26] ? pwm[4] : ~pwm[4];
    led_pair2 <= cnt[25];
     end

   assign LED[0] = led_enable ? led_pair1 : 0;
   assign LED[1] = led_enable ? ~led_pair1 : 0;

   assign LED[2] = led_enable ? led_pair2 : 0;
   assign LED[3] = led_enable ? ~led_pair2: 0;

endmodule

我试图深入研究上述两种方法的合成器报告差异并查看 HDL 原理图,但对于像我这样没有经验的人来说,它太复杂了。

毫无疑问,综合工具很好地优化了组合逻辑,但假设右手边的表达式非常复杂,成为单行等,有没有办法说这样的话?

   if (some_reg_var) begin
       assign net0 = 1;
       assign net1 = 0;
    end
   else
    begin
       assign net0 = 0;
       assign net1 = 1;
    end

或者这样做是否有意义?如果不是,在这种情况下引入寄存器以简化行为部分是否有意义?我相信至少有一些规则或经验。任何帮助表示赞赏。

4

1 回答 1

2

你的问题有点冗长,但我想我理解你的意思(如果我错了,请纠正我)。

您想知道是否有一种方法可以分解长分配语句以使用 if/else 逻辑,类似于 always 块中的 regs?

以这种方式,Verilog 对我来说总是有点好笑,但仅仅因为你声明了一个 'reg' 数据类型并不意味着它会被合成到一个 register。如果有一些状态要存储,它实际上只会创建一个寄存器。话虽如此,以下两个语句应该合成完全相同的东西:

情况1:

wire a;
wire b;
assign a = b ? 0 : 1; 

案例二:

reg a;
wire b;

always @(b)
   if(b)
       a <= 0;
   else
       a <= 1;

这两个都应该创建完全相同的逻辑(简单地说,a = !b 的反相器)。即使在您声明了一个 reg 的第二种情况下,它实际上也没有实例化一个寄存器,因为没有什么要记住的(所有输入都在敏感度列表中)。

因此,您可以自由编写复杂的 if/else 逻辑来简化代码,这并不意味着您要为合成额外的寄存器付出代价。因此,请随意编写最适合您的方式。(如果您确实使用了 always 块,请确保对所有可能的情况进行分配,否则您将推断出您可能不想要的锁存器)。

于 2012-04-23T01:28:12.430 回答