Question

I am trying to wrap my head around a mix of combinational and behavioral logic. I've got small FPGA with 4 LEDs and a 66 MHz clock input. The idea was to make two of them glowing (one rising, one falling) and another two blinking. So I came up with the following code:

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

I did not want to use a vendor specific DCM, and so simple bit adders with 66MHz clock works out the magic. Perhaps the whole design is wrong in a first place (for instance, I could have used two clock dividers and simply flip a bit of two registers to achieve (almost) the same thing), but I ran into this situation which made me wondering...

From a regular software developer's point of view, there are some parts in continuous assignments that seem redundant. For example, an extra register can be used and so it would seem that less work is performed. For instance:

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

I was trying to dig into synthesizer report differences for two approaches above and look at HDL schematics, but it way too complex for such an inexperienced guy like me.

No doubt synthesis tool optimizes the combinational logic very well, but assuming the the right hand side expressions are very complicated to be one-liners etc, is there a way to say something like this?

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

Or does it even make sense to do so? If not, does it make sense to introduce registers in such cases to simplify the behavioral part? I am sure there are some rules or thumb at least. Any help is appreciated.

Was it helpful?

Solution

Your question is a bit verbose, but I think I understand what you're getting at (correct me if I'm wrong).

You wish to know if there is a way to break up long assign statements to use if/else logic, similar to regs in an always block?

Verilog always seemed slightly funny to me in this way, but just because you declare something a 'reg' datatype does not mean that it gets synthesized to a register. It only actually creates a register if there is some state to store. Having said that, the following two statements should synthesize to exactly the same thing:

Case 1:

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

Case 2:

reg a;
wire b;

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

Both of these should create the exact same logic (simply, an inverter with a = !b). Even in the second case where you have declared a reg, it doesn't actually instance a register, because there's nothing to remember (all of the inputs are in the sensitivity list).

Because of this, you are free to write complex if/else logic to simplify your code, and this doesn't mean you're paying a penalty of synthesizing extra registers. So feel free to write it which ever way is most comfortable for you. (If you do use an always block, make sure to have an assignment for all possible cases, or you will infer a latch which you probably don't want).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top