I have a bunch of (System) Verilog code that uses initialization statements. This is code for an Altera FPGA. I test the code using automated testbenches in the version of modelsim that ships with quartus, and it all works fine. However, I have been trying to move some of our test benches to the cadence simulator, and it is complaining. A simple example of code that fails is this:

reg [15:0] counter = 0;

always_ff @(posedge clk) begin
    counter = counter + 1'b1;
    display("counter: %4X", counter);
end

This give an error in the cadence simulator that it is not allowed for counter to have multiple drivers because it is used in an always_ff block.

Is this error correct? Two tools say that code is OK, and one fails. The rules I have found for always_ff state that "a variable assigned in an always_ff, always_comb, or always_latch may not be assigned in by any other process". This makes sense, but it seems strange that the initial value would be considered a process, and in any case would make those language features mutually incompatible.

So is there a correct way to use initializers along side system verilog new style always_* processes? Does this behavior depend on the version of the system verilog standard such that I might be able to tell my tools which one to use? Or are my choices to use explicit reset lines only, or stick to old style always blocks?

The LRM is not very clear about initializers as a process. Since you could call a function in an initialization, that could be be considered a process.

The purpose of the always_ff construct was strictly for design code not testbenches. Their purpose is to declare the intent of an always_* process up front in simulation so there are no surprises when you get to synthesis. However, the rules for what is synthesizable is a moving target.

If this code is indeed for a testbench, I would change the data types to bit instead of reg, then the default value becomes 0 anyways. Otherwise, I would use a simple always block.

  • I updated the question to make it clear I am concerned about code targeting the FPGA when run from the testbench, not specifically the testbench code itself. I guess I thought the purpose of the always_* restriction on multiple assignments was to avoid race conditions where it isn't clear which order the processes execute. But as I understand it, there can't be a race condition between an initializer and a regular process block. – Evan Jul 18 '16 at 3:57
  • Most synthesis tools to not accept variable declarations with initializer that only execute once at time 0. Real hardware comes up in a random state and needs a reset signal to get to a known "good" state. – dave_59 Jul 18 '16 at 4:46
  • FPGAs, at least Xilinx and Altera FPGAs support and even encourage use of initializers, either instead of or in addition to reset nets, but I guess I should just not do that, or use a different simulator. – Evan Jul 19 '16 at 15:31

Looks like the code infers logic for fpga. Instead of initializing the register during declaration, you should use a reset signal. That models the hardware more accurately.

In fpgas, the POR is implicit but you still should bring in external or internal reset into the logic. E.g. PLL locked output, etc.

reg [15:0] counter;
reg rst;

always_ff @(posedge clk or posedge rst)        
begin
   if(rst)
     counter <= '0;
   else
     begin
     counter <= counter + 1'b1;
     'ifdef SIM
        display("counter: %4X", counter);
      'endif 
      end
end

If you do not want to generate the reset internally, the fpga compilers have a default setting that sets the power up state of the registers. You can override this to any value.

  • Using compiler flags to set the initial values would make the simulation results wrong, so that isn't really an option. If sounds like adding a reset line is the only option. – Evan Jul 18 '16 at 3:58

I see that Cadence and Synopsys both produce an error for this code. I also see that Mentor and Aldec both allow driving initialized variables in always_ff blocks. This suggests that the correct behavior is not properly defined in the LRM.

Relying on power-up values for FPGA designs is perfectly viable. Altera's recommended coding guideline is to use always @(posedge clock), so I would suggest that you do this as a workaround. Alternatively you can use a different simulator.

Cadence's behavior arguably makes sense for ASIC designs, where you can't rely on initialization of registers. Adding an initialization value for a variable by mistake could hide missing reset bugs in simulation.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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