Verilog "optimizes" my code to run slower
The software is Lattice's ispLever Classic, as I said, version 2.0 (the latest). That is a software suite, and the component doing this "optimization" is the fitter.

Clock enable is the issue, as the clock enable must be valid before the clock, while the data input needs to be valid at the clock. Looking at the post-fit equations in the "Fitter Report" shows that the clock enable is being used, and the "Timing Report" shows Fmax=185MHz with the limiting path involving the clock enables.

I kept playing with it, and found that the presence of seemingly unrelated wires can generate different answers, sometimes differing significantly in Fmax. Replacing the last line in the always block with this still uses the clock enable and gives FMax=185MHz:

if(latchEnable) latch = counter;


But if I also add a new wire "dummy" to the module command and add these lines, I get Fmax=210MHz:

output dummy;
wire [19:0] latchSelect = (latchEn1 &amp; !latchEn2) ? counter : latch;
assign dummy = latchSelect[0] | latchSelect[1] | latchSelect[2] | 
    latchSelect[3] | latchSelect[4] | latchSelect[5] | latchSelect[6] | 
    latchSelect[7] | latchSelect[8] | latchSelect[9] | latchSelect[10] | 
    latchSelect[11] | latchSelect[12] | latchSelect[13] | latchSelect[14] | 
    latchSelect[15] | latchSelect[16] | latchSelect[17] | latchSelect[18] | 
    latchSelect[19];


Note this new latchSelect is used ONLY to set dummy, which is an output pin (a real output is needed to prevent it being optimized away). But its presence changes the code used to set the latch. Now it uses the D input, not the clock enable; Fmax=210MHz. (Making dummy be a 20-bit bus slows it down.)

I can now replace the last line in the always block with this, and get FMax=208MHz (yes, slower than previous);

latch = latchSelect;


But if I remove dummy the latchSelect gets optimized away, it uses the clock enable, and Fmax=185MHz.

Another poor "optimization" I found is that if I connect a FF output like latchEn1 to an output pin, it also slows the circuit down, because wherever that signal is used, it uses the output pin, not the FF output (look at the post-fit equations). I connect important signals to output pins so my logic analyzer can see them for debugging -- it's OK if those output pins run somewhat slower, but reducing the counter/latch Fmax means I must remove those assignments once the circuit works.

Bottom line: fitting verilog equations to a device is complicated and subtle. Small changes in the code can make important changes in circuit performance. I do have code that meets my requirements with 5% margin (Fmax=210MHz, requirement is 200 MHz). Of course I still need to install the circuit and test it with real signals....