通过混合组合和行为逻辑来优化连续分配?

时间:2012-04-23 00:26:21

标签: optimization verilog led digital-logic clockrates

我试图围绕组合和行为逻辑的混合。我有一个带有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

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

1 个答案:

答案 0 :(得分:2)

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

你想知道是否有办法打破长期分配语句使用if / else逻辑,类似于一个始终阻止的reg?

通过这种方式,Verilog对我来说似乎总是有点滑稽,但仅仅因为你宣称'reg'数据类型并不意味着它被合成到寄存器。如果存在某种状态,它实际上只创建一个寄存器。话虽如此,以下两个陈述应该合成完全相同的事情:

案例1:

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

案例2:

reg a;
wire b;

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

这两者都应该创建完全相同的逻辑(简单地说,一个带有=!b的逆变器)。即使在你声明了reg的第二种情况下,它实际上并不是一个寄存器实例,因为没有什么可记住的(所有输入都在灵敏度列表中)。

因此,您可以自由编写复杂的if / else逻辑来简化代码,这并不意味着您需要支付合成额外寄存器的代价。因此,随意编写它对您来说最舒适。 (如果确实使用了始终阻止,请确保为所有可能的情况分配,或者您将推断出您可能不想要的锁存器)。