1
\$\begingroup\$

I am trying to write a Verilog module that generates a power-on reset signal for a few clock cycles. I am synthesizing using Lattice iCEcube2 + Synplify Pro targeting an iCE40 HX1K on the Nandland Go Board.

If I write the the module like this, it is getting optimized out:

`default_nettype none

module reset_generator #(
  parameter COUNT_WIDTH = 2
) (
  input wire    i_clk,
  output wire   o_rst
);

  reg [COUNT_WIDTH:0]   rst_count;
  assign o_rst = !rst_count[COUNT_WIDTH];

  always @(posedge i_clk) begin
    if (o_rst == 1) begin
      rst_count <= rst_count + 1;
    end
  end
endmodule

iCEcube2 outputs this warning:

...
@N:CL189 : reset_generator.v(13) | Register bit rst_count[4] is always 1.
@N:CL159 : reset_generator.v(6) | Input i_clk is unused.
...
@N:BN115 : ball_absolute_mv_vga_top.v(19) | Removing instance reset_gen (in view: work.ball_absolute_mv_vga_top(verilog)) of type view:work.reset_generator_4s(verilog) because it does not drive other instances.
...

And I can verify that the o_rst signal is indeed never set to 1. I thought all registers were initialized to 0, so I'm not sure why it thinks rst_count[4] is always 1.

However, if I explicitly set rst_count to 0, like this:

  reg [COUNT_WIDTH:0]   rst_count = 0;

Now it no longer is getting optimized out and works as expected, but iCEcube2 shows this warning:

@W:FX1039 : reset_generator.v(13) | User-specified initial value defined for instance reset_gen.rst_count[4:0] is being ignored. 

This warning also implies that initial values are 0. So why does the first version get optimized out? And why does adding an initial value that gets ignored change the behavior? Is this just a quirk of iCEcube2 and/or Synplify Pro?

EDIT 1: I'm using a power-on reset because Lattice can only initialize registers to zero, and I'd like some to start off with non-zero values.

The o_rst of this reset_generator component is hooked up to another component at a higher level like this:

  wire w_reset;
  reset_generator #(
    .COUNT_WIDTH(4)
  ) reset_gen (
    .i_clk(i_clk),
    .o_rst(w_reset)
  );

  ball_absolute ball_absolute (
    .clk(i_clk),
    .reset(w_reset),
    .vsync(o_vga_vsync),
    // ...
  );

The reason it does this is because ball_absolute has a pair of X/Y registers for the ball's position on the screen. I'd like the ball to start in the middle of the screen, not at (0, 0). And because Lattice can only initialize registers to 0, I want to use a power-on reset signal to set X/Y to non-zero values.

The full project is actually up on GitHub.

EDIT 2: I also understand that a PLL Lock signal could be used as a power-on reset, but unfortunately the HX1K does not have any PLLs. The Go Board uses an external crystal for the clock.

\$\endgroup\$
10
  • \$\begingroup\$ Your design approach is not good. Usually you will have an external reset input to reset/initialize internal registers of your reser generator logic. The logic can generate a multi-cycle synchronous reset from it to reset different modules in the system. \$\endgroup\$
    – Mitu Raj
    Aug 7, 2021 at 8:34
  • 7
    \$\begingroup\$ How does rst_count get reset? \$\endgroup\$
    – user253751
    Aug 7, 2021 at 10:12
  • 1
    \$\begingroup\$ You could check stackoverflow.com/a/38032139/9609830 - there is a lot of information which might solve your issue. \$\endgroup\$ Aug 7, 2021 at 12:15
  • \$\begingroup\$ @user253751: It doesn't. It starts at at 0 at power on, and counts up. Once o_rst goes low, rst_count stays at the same non-zero value forever. \$\endgroup\$ Aug 7, 2021 at 16:05
  • \$\begingroup\$ @ChristianB.: That link confirms what I am seeing. It says Lattice ignores the initialization value and initializes all FFs to zero. However, it does not explain why Lattice optimizes out the module when the initialization value is missing. Also, HX1K does not have a PLL, so using that to drive reset is not possible. \$\endgroup\$ Aug 7, 2021 at 16:10

1 Answer 1

4
\$\begingroup\$

This is probably a quirk in synplify. Synplify is intended for synthesizing designs for ASICs, not FPGAs, and as a result is rather opinionated. For ASICs, it's common to not initialize anything, ever, and instead use explicit resets. And as a result, synplify handles initial blocks and inline initializers differently from FPGA tools - specifically, it mostly ignores them, even if it causes strange, unexpected behavior. At any rate, all signals that are not explicitly initialized do not start at 0, they start at X (indeterminate logic level). And then the tools can pick whatever value they like during synthesis if it can simplify the logic. So, it seems that's what synplify is doing here... It notices that it can resolve that particular X to a 1, and as a result delete a bunch of logic. If you initialize that reg to 0, then synplify cannot make this optimization, but it warns you that the initializer is ignored because synplify does not understand how to actually initialize the registers as you can't do that on an ASIC. What you should do is keep the inline init to zero, but also add an external reset input that can also reset that register.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks very helpful! I think this explains what is going on. But why do you recommend an external reset input? I am using the power-on reset to initialize some registers to non-zero values, since Lattice is unable to do that. I don't think I need to reset after power on? \$\endgroup\$ Aug 7, 2021 at 20:31
  • \$\begingroup\$ Also, what do you mean by external reset? Like a physical button or something? The Go Board does have 4 push buttons, but I don't want to use one as a "reset" button, if I don't have to. I could do some button combo, but that seems like an unnecessary complication? \$\endgroup\$ Aug 7, 2021 at 20:32
  • 1
    \$\begingroup\$ Well, I guess it depends on what the intent is. I'll usually dedicate a button for reset, but on a lot of boards there is a dedicated "cpu_rst" button for that purpose. But also, there is almost invariably a PLL involved, so the internal reset will be derived from the PLL locked output, and the PLL reset would come from the external input. But if you don't have a PLL and you don't have a need for an external reset input, then I suppose it's not strictly necessary. \$\endgroup\$ Aug 7, 2021 at 21:53
  • \$\begingroup\$ Unfortunately, the HX1K does not have any PLLs. It uses an external clock as a crystal. The intent is to initialize some registers to non-zero values since iCEcube does not allow that. I think the right thing to do here is set rst_count = 0 and ignore the warning. \$\endgroup\$ Aug 7, 2021 at 23:25
  • 1
    \$\begingroup\$ Yep, sounds reasonable to me, if you don't want to dedicate a pushbutton to reset. \$\endgroup\$ Aug 7, 2021 at 23:27

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.