2
\$\begingroup\$

I get a bunch of these errors on the following code:

(VERI-1100) procedural assignment to a non-register 'nextstate' is not permitted

The problem is mostly with the case statement.

I am genuinely confused. My design clearly cannot be implemented using clocked registers for these signals. I've tried several versions, with assign, with and without always and can't get it to compile.


// SPI Master in Mode 3

module SPIMode3(
    //external PHY interface
    cs,
    sclk,
    misoA,
    misoB,
    mosi,
    //internal interface
    spiclk,
    en,
    busy,
    misoA_pbus,
    misoB_pbus,
    mosi_pbus
    );
    
    //PARAMS
    parameter SPI_BITS = 16;
    parameter STATE_DONE = 2'd0;
    parameter STATE_RUNNING = 2'd1;
    
    //PORTS
    //external PHY
    output cs;
    output sclk;
    input misoA;
    input misoB;
    output mosi;
    //internal interface
    input spiclk; //would like for spiclk=sclk directly
    input en; //module is active when HIGH, rising edge loads the buffers
    output busy;
    output [(SPI_BITS-1):0] misoA_pbus;
    output [(SPI_BITS-1):0] misoB_pbus;
    input [(SPI_BITS-1):0] mosi_pbus;
    
    //REG/WIRE DECLARATIONS
    reg [1:0] state;
    wire [1:0] nextstate;
    
    reg [7:0] spi_counter;
    wire [7:0] spi_counter_in;
    
    reg [(SPI_BITS-1):0] misoA_reg;
    reg [(SPI_BITS-1):0] misoB_reg;
    reg [(SPI_BITS-1):0] mosi_reg; //technically this is redundant, could use one of the miso reg
    
    wire [(SPI_BITS-1):0] misoA_in;
    wire [(SPI_BITS-1):0] misoB_in;
    wire [(SPI_BITS-1):0] mosi_in;
    
    //REG INPUT ASSIGNMENTS
    always @ * begin
    case (state)
        STATE_DONE: begin
            nextstate = STATE_DONE; // in DONE state, everything just stops
            //REG ASSIGNMENTS
            spi_counter_in = spi_counter;
            misoA_in = misoA_reg;
            misoB_in = misoB_reg;
            mosi_in = mosi_reg;
            //OUTPUT ASSIGNMENTS
            cs = 1;
            sclk = 1;
            mosi = 1;
            busy = 0;
            misoA_pbus = misoA_reg;
            misoB_pbus = misoB_reg;
            end
            
        STATE_RUNNING: begin
            nextstate = (spi_counter < (SPI_BITS-1))? STATE_RUNNING : STATE_DONE;
            //REG ASSIGNMENTS
            spi_counter_in = spi_counter + 1;
            misoA_in = {misoA_reg[(SPI_BITS-2):0], misoA}; //left shifting
            misoB_in = {misoB_reg[(SPI_BITS-2):0], misoB}; //left shifting
            mosi_in = {mosi_reg[(SPI_BITS-2):0], 1'b0}; //left shifting
            //OUTPUT ASSIGNMENTS
            cs = 0;
            sclk = spiclk;
            mosi = mosi_reg[(SPI_BITS-1)]; //MSB out first;
            busy = 1;
            misoA_pbus = misoA_reg;
            misoB_pbus = misoB_reg;
            end
            
        default: begin
            nextstate = STATE_DONE; // in DONE state, everything just stops
            //REG ASSIGNMENTS
            spi_counter_in = spi_counter;
            misoA_in = misoA_reg;
            misoB_in = misoB_reg;
            mosi_in = mosi_reg;
            //OUTPUT ASSIGNMENTS
            cs = 1;
            sclk = 1;
            mosi = 1;
            busy = 0;
            misoA_pbus = misoA_reg;
            misoB_pbus = misoB_reg;
            end
    endcase
    end
    
    always @ (posedge spiclk, negedge en) begin
        if(!en) begin
            state <= STATE_DONE;
            spi_counter <= 0; //will this cause a BUGGGG???
            misoA_reg <= 0;
            misoB_reg <= 0;
            mosi_reg <= 0; //this may be suboptimal
        end
        else begin
            state <= nextstate;
            spi_counter <= spi_counter_in;
            misoA_reg <= misoA_in;
            misoB_reg <= misoB_in;
            mosi_reg <= mosi_in;
        end
    end

endmodule

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

You declared nextstate as type wire. It is illegal to make a procedural assignment (within an always block) to a wire. You need to declare the signal as logic:

logic [1:0] nextstate;

Do this for all signals which are assigned in the always block.

You must also do this for the output ports which are assigned in the always block. For example:

output logic cs;

These outputs did not explicitly use wire, but they default to a net type.

Note: You could have used reg instead of logic (since they are synonyms in SystemVerilog), but logic is recommended.

\$\endgroup\$
0
0
\$\begingroup\$

There are many lines in the code where something is declared a wire when it should be a reg. Contrary to their name, regs don't necessarily correspond to physical registers.

See this link
https://blogs.sw.siemens.com/verificationhorizons/2013/05/03/wire-vs-reg/
or just do an internet search on 'Verilog reg'.

SystemVerilog relieves this design choice by allowing the type 'logic' where the tool infers the correct kind (wire or reg). If you are using SystemVerilog, change all your wires and regs to logic, and let the tool do what it knows best.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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