Author Topic: Getting back into verilog and the synth tool vomits cryptic "warnings."  (Read 3999 times)

0 Members and 1 Guest are viewing this topic.

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
Eleven years ago, I did Verilog work and had a good time of it. Life happened and I didn't do any FPGA work since then. I have a project in which I'm getting back into FPGAs and have had a few tries getting some code to work. With a few failures, I've determined that warnings are errors with the modern synthesis engines.  I have, since, started from scratch with something which should be pretty straight forward (a simple SPI engine). It is 100% state machine.

The precise question for where I stand right now is at the bottom. Here is the process I've been through:

I get 3 identical errors:
1. Bit 7 of register intState_FSM is stuck at zero (this is, of course, after the synthesizer converts my states to a one-hot design, in which the MSB [bit 7] becomes 1 in the last state).
2. Register intState_FSM_i1 is stuck at zero.
3. Register rdy_54 is stuck at zero.

Now, if it reported everything being stuck at zero, that would tell me I screwed up with my reset signalling. But, as you will see below, it's quite literally if(reset) {} else {bulk of code}
If bit 7 is "stuck at zero" that tells me that either something is wiring it to zero (which should generate blocking vs. non-blocking errors) or I never reach there. Problem is, the state before it does 1 thing and goes to the next state.
As for the ready signal always being zero, the only way I can see this happening is if the state machine never reaches the state which sets the ready flag to 1.

I noted that having a "default: ..." catch in the case statement seems to be a possible source of the problem, as it doesn't exist in the one-hot list. I removed it, and then I get down to two errors:
WARNING - d:/projects/spi_eng.v(100): Bit 0 of Register intState is stuck at Zero. VDB-5010
and later
2. WARNING - logical net 'GND_net' has no load.

My text books are pretty much useless for this. If I switch to the Synplify synthesis, I get completely different synthesis errors (default engine I'm using is Lattice Synthesis Engine). Does anyone have any suggestions? Any help is appreciated. Cheers!



Code: [Select]
module spi_engine(clk, rst, load, rdy, clr, ext_cs, ext_sdo, ext_sdi, ext_clk, inWord, outWord);
input clk, rst, load,clr;
output rdy;

output ext_cs, ext_sdo, ext_clk;
input ext_sdi;

input [23:0] inWord;
output [23:0] outWord;

reg [7:0] intState;
// 0h00 - powerup
// 0h00 - idle, waiting for load to be triggered.
// 0h02 - triggered system.
// 0h03 - setup chip select and the shifter

/// large valued registers
reg [23:0] wordStorage;
reg [23:0] outWord;
reg [7:0]  bitCounter;

// Control Signals
reg rdy;
reg ext_sdo, ext_cs, ext_clk;

wire clr; // wire for the clear signal

always @(posedge clk)
if(1==rst)
begin
// do reset stuff here
intState<=8'h00;
rdy<=0; // not yet ready with a new word.
ext_sdo<=0;
ext_cs<=1;
ext_clk<=0;
bitCounter<=0;
end
else
case(intState) // state machine business

8'h00: begin
wordStorage<=0;
intState<=8'h01;
bitCounter<=0;
   end
8'h01: // idle state. Wait for the load pin to be asserted.
if(1==load)
begin
// load pin is high, this is the start of a transaction.
wordStorage<=inWord; // copy the word appearing on the input pins.
intState<=8'h02; // next state.
end
// do nothing if we haven't hit the load assertion.

8'h02: // triggered state. Now we begin the whole business.
begin
// start by setting up chip-select.
ext_cs<=0;
bitCounter<=0; // clear the counter
intState<=8'h03; // jump to the next state
end
8'h03: begin // put the MSB onto the bus
ext_sdo<=wordStorage[23]; // make the serial-data-output bit equal to the MSB of the word-storage reg
intState<=8'h04;
end
8'h04: begin
ext_clk<=1;
intState<=8'h05;
outWord[0]<=ext_sdi;
end
8'h05: begin
ext_clk<=0;
wordStorage<=wordStorage<<1; // shift all the bits in wordStorage left 1.
outWord<=outWord<<1;  // shift all the bits in OutWord left 1
intState<=8'h06;
end
8'h06: begin // determine how many bits are left to count...
if(23==bitCounter)
// we're good.
intState<=8'h07;
// still shifting.
bitCounter<=bitCounter+1;
intState<=8'h03;
end
8'h07: begin // do some cleanup.
ext_cs<=1; // indicate we're finished to the device.
intState<=8'h08;
end
8'h08: begin
rdy<=1; // indicate we're done with the transaction.
intState<=8'h0F;
end
8'h09:  if(1==clr)
begin
rdy<=0;
intState<=8'h01;
end

endcase

endmodule
 

Offline Muxr

  • Super Contributor
  • ***
  • Posts: 1369
  • Country: us
The first step would be to validate your case and why your state counter isn't being incremented. I would recommend using the `case default` block for non matched cases, you can use it instead of your 8'h00 case.

I am sorta new to Verilog as well, but one suggestion from reading other people's code, instead of the else block, I would just start a new `always @(posedge clk) if(rst != 1)..` for your state machine.

The other issue you might be having is the clock. Perhaps add another counter that's always incrementing in its own always block as a test.

I've been using the Lattice's MachX02 and I have to initialize its internal clock like this. (not sure if it matters in a synth tool). I've only used it briefly, I tend to just push the code to the dev board, since I can't be bothered writing test harnesses.

Code: [Select]
//// Internal Oscillator
defparam OSCH_inst.NOM_FREQ = "133.00";
OSCH OSCH_inst
(
.STDBY(1'b0), // 0=Enabled, 1=Disabled also Disabled with Bandgap=OFF
.OSC(osc_clk),
.SEDSTDBY()      // this signal is not required if not using SED
);


//// counter with no flag control
always @ (posedge osc_clk)

Here is a full example: https://eewiki.net/display/LOGIC/Lattice+Diamond+and+MachXO2+Breakout+Board+Tutorial+%28with+Verilog%29
« Last Edit: June 02, 2015, 06:30:39 am by Muxr »
 

Offline 6thimage

  • Regular Contributor
  • *
  • Posts: 181
  • Country: gb
First of all, have you run this in a simulator at all? The problem should be very obvious when you have the waveforms in front of you.

The issue you are having is due to:
Code: [Select]
8'h06:
begin // determine how many bits are left to count...
if(23==bitCounter)
// we're good.
intState<=8'h07;
// still shifting.
bitCounter<=bitCounter+1;
intState<=8'h03;
end

The setting of intState to 3 is overriding the end condition - you either need an else statement or to move the if statement.

The important thing to remember is that the synthesiser converts your code, optimises it and then reports the errors. So the errors it gives will most likely be cryptic - the best I've seen is when xilinx's synthesiser reports that states are unreachable (which it would do in this case), then reports about unused register bits. I'm not sure if Altera's or Lattice's synthesisers report the same thing.

You have also written the logic in quite a fast way (large number of states with little logic in each), but you won't get a 50% duty cycle (you'll have 25% high, 75% low), which might cause issues with some SPI devices. I wrote a SPI master a couple of years ago, which I've attached (in code block below) in case you want to have a look. It's a little over-complicated in places, but is designed to give a square sclk.

Code: [Select]
module spi_master(
/* clock */
 input           clk,
/* external connections */
output reg       sclk,      /* serial clock */
output reg       mosi,      /* master out, slave in */
 input           miso,      /* master in, slave out */
/* internal connections */
 input           reset,     /* reset - active low */
 input           enable,    /* enable / start - starts a spi transaction - active high */
 input     [7:0] clock_div, /* clock divider  - spi clock has a maximum of clk/2, this is
                                                to reduce it futher */
 input           cpol,      /* sclk polarity  - 0 for start low, 1 for start high */
 input           cpha,      /* sclk phase     - if 0, the first bit is transmitted with the
                                                falling edge of sclk, if 1 the first bit is
                                                delayed to the first sclk */
 input     [7:0] tx_data,   /* data to transmit */
output reg [7:0] rx_data,   /* received data  - updated when not busy */
output reg       busy       /* busy flag      - is 1 during a transaction, 0 otherwise */
);

initial
begin
    busy=1'b0;
    sclk=1'b1;
    mosi=1'b1;
end

/* internal data buffers */
reg [7:0] tx_data_int;
reg [7:0] rx_data_int=8'hff;

/* internal config buffers */
reg [7:0] clock_div_int;
reg cpol_int, cpha_int;
wire cpol_eq_cpha;
assign cpol_eq_cpha=(cpol_int==cpha_int);

/* serial clock - for dividing the main clock down */
reg [7:0] clock_counter;
wire clock_counter_hit;
assign clock_counter_hit=(clock_counter==clock_div_int);

/* bit counter */
reg [3:0] bit_counter; /* number of bits sent */

/* clock edges
                sclk state      edge
                read    write   read    write
   cpha=0
       cpol=0   0       1       rising  falling
       cpol=1   1       0       falling rising
   cpha=1
       cpol=0   1       0       falling rising
       cpol=1   0       1       rising  falling
   
   as far as clock edges are concerned, there are two situations
   that determine which edge is used for reading and writing
       cpol==cpha
       cpol!=cpha
 */
wire sclk_receive_edge, sclk_transmit_edge;
assign sclk_receive_edge=(cpol_eq_cpha)?(sclk==1'b0):(sclk==1'b1);
assign sclk_transmit_edge=(cpol_eq_cpha)?(sclk==1'b1):(sclk==1'b0);

always @(posedge clk or negedge reset)
begin
    if(!reset)
    begin
        /* reset to defaults */
        busy <= 1'b0;
        sclk <= 1'b1;
        mosi <= 1'b1;
        rx_data_int <= 8'hff;
    end
    else
    begin
        /* detect start */
        if(enable && !busy)
        begin
            /* reset counters */
            clock_counter <= 8'h0;
            /* set bit counter to 0 */
            bit_counter <= 4'h0;
           
            /* update config */
            clock_div_int <= clock_div;
            cpol_int <= cpol;
            cpha_int <= cpha;
           
            /* start transaction */
            busy <= 1'b1;
            sclk <= cpol;
           
            /* send first bit if cpha=0 */
            mosi <= tx_data[7];
            if(!cpha)
            begin
                /* shift tx data accordingly */
                tx_data_int <= {tx_data[6:0],1'b0};
            end
            else
                tx_data_int <= tx_data;
           
        end
        /* manage data transaction */
        else if(busy)
        begin
            if(clock_counter_hit)
            begin
                /* reset counter */
                clock_counter <= 8'h0;
               
                /* update clock */
                if(bit_counter!=4'h8)
                    sclk <= ~sclk; /* toggle clock */
               
                /* update bit counter */
                if(sclk!=cpol_int)
                    bit_counter <= bit_counter+1'b1;
               
                if(bit_counter!=4'h8)
                begin
                    if(sclk_transmit_edge)
                        {mosi, tx_data_int} <= {tx_data_int, tx_data_int[7]};
                    else if(sclk_receive_edge)
                        rx_data_int <= {rx_data_int[6:0], miso};
                end
                else
                begin
                    /* disable transmission */
                    busy <= 1'b0;
                   
                    /* output received data */
                    rx_data <= rx_data_int;
                end
            end
            else
                /* increment counter */
                clock_counter <= clock_counter+1'b1;
        end
    end
end
endmodule
« Last Edit: June 02, 2015, 04:10:28 pm by 6thimage »
 

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
Aha! Many thanks!

I'm working out the simulator issue right now (that is, getting one I can use).

With respect to the duty cycle, at the moment I'm not particularly concerned - it was "test an idea and see if it will compile." I'll make the fixes when I get home!

 

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
As a dumb update, that fixed that set of errors. I got setup with IcarusVerilog and have written some test benches. Now, though, it's bellyaching about the MSB of a register being stuck at zero, so I'm looking at everything which drives that bit. iVerilog, however, has no problems at all and produces expected results.

Edit 3/6/2015: I changed the "reset" values to make the "stuck at zero" registers all 1s, and the synthesizer stopped its bellyaching.
« Last Edit: June 03, 2015, 01:04:35 pm by XFDDesign »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf