2
\$\begingroup\$

I've been struggling with a very simple Verilog program. It's a 4 bit shift register that gets rotated at every clock cycle and drives four LEDs. (As you can tell I'm new to FPAGs and HDLs.)

The problem: Below code synthesises without warnings and is successfully programmed into the FPGA. Then, upon start, nothing happens, the LEDs stay dark. The i_Switch_1 input was added to make something happen at all and indeed when I push the switch the LEDs start rotating.

Here's the Verilog code:

Version 1 (fail)

module top
   (input i_Clk, 
    input i_Switch_1,
    output o_LED_1,
    output o_LED_2,
    output o_LED_3,
    output o_LED_4
   );

     reg [3:0]shift_reg;

     initial
         shift_reg = 4'b0001;   // has no effect

     always @(posedge i_Clk)
     begin
         shift_reg <= i_Switch_1 ? 4'b0001 : {shift_reg[2:0], shift_reg[3]};
     end

     assign o_LED_1 = shift_reg[0];
     assign o_LED_2 = shift_reg[1];
     assign o_LED_3 = shift_reg[2];
     assign o_LED_4 = shift_reg[3];

 endmodule

Assessment: My conclusion so far is that shift_reg is not initialised to 1. The RTL view below shows that no initialisation is synthesized. shift register

I read in many places that the initial block is synthesizable, so I'm really puzzled, now.

Question 1: Is my assessment correct?

Question 2: Assuming my assessment is correct, what is the remedy? I've tried various things and none of them work:

  • Route in the reset pin, but that doesn't seem to be allowed.
  • Use a shift_reg==0 comparison (version 2 below)
  • Use a is_init flag (version 3 below)

I'm beginning to believe that I'm getting something fundamentally wrong. What is going on??

Version 2 (fail)

shift_reg <= (shift_reg==0 || i_Switch_1) ? 1 : {shift_reg[2:0], shift_reg[3]}

Version 3 (fail)

reg is_init; 
initial
    is_init = 0;   // Must have this or else the is_init gets optimized out!

always @(posedge i_Clk)
begin
    if(~is_init || i_Switch_1) begin
        is_init <= 1;
        shift_reg <= 4'b0001;
    end
    else begin
        is_init <= 1;
        shift_reg <= {shift_reg[2:0], shift_reg[3]};
    end
end

Setup: LatticeSemi iCE40HX1K (nandland go board) using iCEcube2, synthesis tool is Synplify Pro.

--

Update

This here works:

Version 4 (success)

reg [3:0]shift_reg = 0;

always @(posedge i_Clk)
begin
    case(shift_reg)
    1: shift_reg <= 2;
    2: shift_reg <= 4;
    4: shift_reg <= 8;
    8: shift_reg <= 1;
    default: 
        shift_reg <= 1;
    endcase
end

But the synthesis result is somewhat bloated: properly initialised shift register via case statement

\$\endgroup\$
  • \$\begingroup\$ Why cant you use reset? \$\endgroup\$ – Prakash Darji Apr 18 '16 at 3:49
3
\$\begingroup\$

In many cases FPGAs don't support power-on initial values of anything but 0. I know that all the Altera FPGAs I've worked with don't. In fact according to the datasheet for your FPGA, this is indeed the case:

Each DFF also connects to a global reset signal that is automatically asserted immediately following device configuration.

Global reset suggests 0, it would be set if it resulted in a 1.

To get around this what some synthesis tools do is something called bubble pushing - anything that should be initialised to 1 is instead initialised to 0 and a not gate is added to the output. However it seems like in your case that the synthesis tool is not correctly doing this. You can actually try it manually if you want:

...
shift_reg <= {shift_reg[2:1], !shift_reg[0], shift_reg[3]};
...
assign o_LED_1 = !shift_reg[0];

Although that is not particularly useful in the long run.

You can also try the alternative way of specifying the initial value and see if the synthesis tool does a better job:

reg [3:0] shift_reg = 4'b0001;

--

At any rate, generally we don't tend to rely on an initial value for registers and logic. Instead we have a global reset signal and reset clauses in the logic. This allows us to be able to set all registers to a known state at any point in time without having to do a power cycle.

In your example with the switch it seems like your code with the switch in it has correctly inferred a reset signal (R_PAT I presume) which is driven as expected by i_Switch_1. Typically however, we use a somewhat different format for reset signals:

always @ (posedge clock) begin
    if (reset) begin
        // Do stuff here when in reset
    end else begin
        // Do stuff here when not in reset
    end
end
\$\endgroup\$
  • \$\begingroup\$ I've been fiddling endlessly with this and my conclusion still is that the lattice synthesis tools (Lattice's own one and 'Synplify') assume that all DFFs are initialised as 'b0 at startup. That's consistent with what the datasheet says - as you point out. What's irritating to me is that a reg [3:0] r = 1'b1 gets silently substituted by reg r = 1'b0. No message of any kind warns me of this. \$\endgroup\$ – mcmayer Apr 26 '16 at 8:18
2
\$\begingroup\$

The structured procedural statement 'initial' is not synthesizable. To initialize the value when your fpga powers on, you can give initiate the value of the register by giving the value at the time of declaration. eg.

reg [3:0]shift_reg= 4'b0000;

\$\endgroup\$
  • \$\begingroup\$ I tried that and but the synthesis tools at my disposal (Lattice and "Synplify") effectively ignore any explicit or implicit initial statement. It seems to me that initialisation of registers (DFFs) cannot be synthesised like that. Instead I have to build a FSM that works correctly with DFFs that are initialised as 1'b0 at power-up. \$\endgroup\$ – mcmayer Apr 26 '16 at 8:13
  • \$\begingroup\$ I agree with Hesham. That is the reason why your case statement works. Assignment at the time of declaration is part of systemverilog. Maybe check the compile messages to see if it is being ignored by the compiler. You could try the place and route constraints that would let you set the power on state of the register. \$\endgroup\$ – shparekh Apr 29 '16 at 5:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.