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.
EDIT 3: Clarification on the PLL. Some HX1Ks do have a PLL, but not all of them. From the Notes on page 8 of the iCE40 LP/HX Family Data Sheet: "No PLL available on the 16 WLCSP, 36 ucBGA, 81 csBGA, 84 QFN, and 100 VQFP packages". The Go Board has a 100 VQFP package, so it does not have a PLL.
2 Answers 2
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.
-
\$\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\$Dave Dribin– Dave Dribin2021年08月07日 20:31:05 +00:00Commented 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\$Dave Dribin– Dave Dribin2021年08月07日 20:32:47 +00:00Commented 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\$alex.forencich– alex.forencich2021年08月07日 21:53:40 +00:00Commented 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\$Dave Dribin– Dave Dribin2021年08月07日 23:25:57 +00:00Commented 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\$alex.forencich– alex.forencich2021年08月07日 23:27:19 +00:00Commented Aug 7, 2021 at 23:27
Apologies for thread-revival, but the HX1K has a single PLL. I actually stumbled on this thread with a random google for including the IceCube2-generated PLL module into a vhdl project.
-
1\$\begingroup\$ Not all HX1Ks have a PLL. From the Notes on page 8 of the iCE40 LP/HX Family Data Sheet: "No PLL available on the 16 WLCSP, 36 ucBGA, 81 csBGA, 84 QFN, and 100 VQFP packages". The Go Board has a 100 VQFP package, so it does not have a PLL. \$\endgroup\$Dave Dribin– Dave Dribin2023年10月31日 18:00:35 +00:00Commented Oct 31, 2023 at 18:00
-
1\$\begingroup\$ Dave - THANK YOU!!, I missed that bit - I'd been using an ICE Stick with a 144p-TQFP, which would probably be the device (or the 4k) that I'd spin a board for, but I hadn't noticed the notes. Once seen, can't be unseen - but truly appreciate the heads-ups on this. \$\endgroup\$Doddy– Doddy2023年11月01日 19:19:56 +00:00Commented Nov 1, 2023 at 19:19
0
at power on, and counts up. Onceo_rst
goes low,rst_count
stays at the same non-zero value forever. \$\endgroup\$