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
2 Answers 2
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.
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.