Increment case state automatically in verilog - verilog

I want to write a synthesizable state machine that read/write wishbone commands in an ordered sequence.
Currently I defined some verilog macros :
`define WB_READ(READ_ADDR) \
begin \
wb_addr_o <= UART_DIV;\
wb_stb_o <= 1'b1; wb_cyc_o <= 1'b1; wb_we_o <= 1'b0; end
`define WB_WRITE(WR_ADDR, WVALUE) \
begin \
wb_addr_o <= WR_ADDR;\
wb_wdat_o <= WVALUE;\
wb_stb_o <= 1'b1; wb_cyc_o <= 1'b1; wb_we_o <= 1'b1; end\
`define WB_NOPE \
begin\
wb_stb_o <= 1'b0; wb_cyc_o <= 1'b0; wb_we_o <= 1'b0; end
And used in in my FSM process :
always #(posedge clk or posedge rst)
if(rst) begin
count <= 8'h00;
wb_addr_o <= 8'h00;
wb_wdat_o <= 8'h00;
wb_stb_o <= 1'b0;
wb_cyc_o <= 1'b0;
wb_we_o <= 1'b0;
end
else begin
case(count)
{7'h01, 1'b1}: `WB_READ(UARD_DIV)
{7'h02, 1'b1}: `WB_READ(UARD_DIV)
{7'h03, 1'b1}: `WB_WRITE(UART_LCR, 8'h60)
{7'h04, 1'b1}: `WB_WRITE(UART_DIV, 8'h01)
{7'h05, 1'b1}: `WB_WRITE(UART_THR, 8'h55)
default: `WB_NOPE
endcase
if (count < {7'h06, 1'b1})
count <= count + 1;
end
Each time count is even, WB_NOPE state is «executed» and each time it's odd, the command given is executed.
That works in simulation but if I want to add a command in the middle of state machine, I have to re-indent all {7'hxx, 1'b1} states. and increment the if(count < ...) at the end.
Is somebody know how to improve this (with macro ?) to avoid it ?

You can just use an integer value in the case statements, and increment it for each step. Here's a slightly stripped back version of your code that does what you want (or at least something close enough that you can fix it :-) )
module testcase (input logic clk,input logic rst);
enum logic [1:0] { READ,WRITE,NOP } op;
logic [7:0] count;
`define WB_READ begin op <= READ; end
`define WB_WRITE begin op <= WRITE; end
`define WB_NOPE begin op <= NOP; end
logic [6:0] fsm_step_number;
always #(posedge clk or posedge rst)
if(rst) begin
count <= 8'h00;
op <= NOP;
end
else begin
fsm_step_number=1;
case(count)
{(fsm_step_number++), 1'b1}: `WB_READ
{(fsm_step_number++), 1'b1}: `WB_READ
{(fsm_step_number++), 1'b1}: `WB_WRITE
{(fsm_step_number++), 1'b1}: `WB_WRITE
{(fsm_step_number++), 1'b1}: `WB_WRITE
default: `WB_NOPE
endcase
if (count < {(fsm_step_number), 1'b1})
count <= count + 1;
end
assert
endmodule

Related

Verilog program is not terminating

I am trying to create a four element direct mapped cache with 4-bit memory address. After creating a cache, I am reading the values from the file to figure out hits or misses on cache. But, somehow, my program is not terminating. Can someone please help me with this? I expect the simulation to end when the program has read the file. Here is the code with the testbench.
module cache_memory_direct_mapped(input clk,
input reset,
input [3:0]read_addr,
output reg hit,
output reg miss);
reg [1:0]c1[3:0];
reg [7:0]hit_count =8'h00;
reg [7:0]miss_count = 8'h00;
always #(posedge clk, posedge reset)
begin
if(reset)
begin
c1[0] <= 2'hx;
c1[1] <= 2'hx;
c1[2] <= 2'hx;
c1[3] <= 2'hx;
end
else
begin
if(read_addr[3:2] == c1[0])
//if(read_addr[3:2] == c1[0] || read_addr[3:2] == c1[1] || read_addr[3:2] == c1[2] ||
//read_addr[3:2] == c1[3])
begin
hit <= 1;
hit_count <= hit_count + 1;
miss <= 0;
end
else
begin
hit <= 0;
miss <= 1;
miss_count <= miss_count + 1;
if(read_addr[1:0] == 0 )
c1[0] <= read_addr[3:2];
else if(read_addr[1:0] == 1 )
c1[1] <= read_addr[3:2];
else if(read_addr[1:0] == 2 )
c1[2] <= read_addr[3:2];
else if(read_addr[1:0] == 3 )
c1[3] <= read_addr[3:2];
end
end
end
endmodule
module Tb_direct_mapped;
// Inputs
reg clk;
reg reset;
reg [3:0] read_addr;
// Outputs
wire hit;
wire miss;
integer data_file ; // file handler
integer scan_file ; // file handler
reg [4:0]captured_data;
// Instantiate the Unit Under Test (UUT)
cache_memory_direct_mapped uut (
.clk(clk),
.reset(reset),
.read_addr(read_addr),
.hit(hit),
.miss(miss)
);
initial begin
// Initialize Inputs
clk = 0;
reset = 0;
data_file = $fopen("data_file.txt", "r");
end
always
#10 clk= ~clk;
always #(posedge clk) begin
scan_file = $fscanf(data_file, "%h\n", captured_data);
if (!$feof(data_file)) begin
read_addr <= captured_data;
end
end
endmodule
The simulation does not terminate because you did not specify when it should end.
always
#10 clk= ~clk;
The code above instructs the simulator to add a new event every 10 time units. It continues to add new events indefinitely, which is why the simulation does not end. One common way to stop a simulation is to use the $finish system task:
initial #100 $finish;
You should change 100 to be something more meaningful to your testbench.
Or, if you want to end the simulation after the file is read:
always #(posedge clk) begin
scan_file = $fscanf(data_file, "%h\n", captured_data);
if (!$feof(data_file)) begin
read_addr <= captured_data;
end else begin
$finish;
end
end

"Illegal reference to memory" in Verilog switch case

I am trying to write a Finite State Machine for an assignment. However, I don't understand what is wrong with my module code. I get the error:
ERROR VCP5221 "Illegal reference to memory: st." "design.sv" 77 5
when I try to synthesize. I think I've either misunderstood how switch-case is used in Verilog or I've attempted to make an illegal assignment inside the switch-case but I don't know how to find it.
//Code here
module MooreFSM(
input clk,
input in,
output out
);
reg state[2:0];
reg sel[2:0];
reg o;
assign out = o;
initial begin
state <= 3'b000;
o <= 1'b0;
end
always#(negedge clk) begin
state <= sel;
end
always#(posedge clk) begin
case(state)
3'b000: begin
if(in == 1'b0) begin
sel <= 3'b010;
o <= 1'b0;
end
else if(in == 1'b1) begin
sel <= 3'b001;
o <= 1'b0;
end
end
3'b001: begin
if(in == 1'b0) begin
sel <= 3'b000;
o <= 1'b0;
end
else if(in == 1'b1) begin
state <= 3'b011;
o <= 1'b0;
end
end
3'b010: begin
if(in == 1'b0) begin
sel <= 3'b100;
o <= 1'b0;
end
else if(in == 1'b1) begin
sel <= 3'b000;
o <= 1'b0;
end
end
3'b011: begin
if(in == 1'b0) begin
sel <= 3'b000;
o <= 1'b1;
end
else if(in == 1'b1) begin
sel <= 3'b011;
o <= 1'b1;
end
end
3'b100: begin
if(in == 1'b0) begin
sel <= 3'b100;
o <= 1'b1;
end
else if(in == 1'b1) begin
sel <= 3'b000;
o <= 1'b1;
end
end
default: begin
sel <= 3'b000;
o <= 1'b0;
end
endcase
end
endmodule
Please help me identify the problem, or if I need to use a different method to synthesize a mux.
I think when you put
else if(in == 1'b1) begin
state <= 3'b011;
o <= 1'b0;
end
you might have meant to write
else if(in == 1'b1) begin
sel <= 3'b011;
o <= 1'b0;
end
By putting state as something being assigned in just one case of this switch statement, you're implicitly asking for it to be latched back to in every other case, which conflicts with you explicitly making it a flop above.

Increment integer under case state in verilog with yosys

I don't know if it's in Verilog-2005 standard but I managed to compile following code with «synplify pro» and «icarus verilog».
integer fsm_step_number;
always #(posedge clk or posedge rst)
if(rst) begin
pc <= 8'h00;
wb_addr_o <= 8'h00;
wb_wdat_o <= 8'h00;
wb_stb_o <= 1'b0;
wb_cyc_o <= 1'b0;
wb_we_o <= 1'b0;
temt <= 1;
end
else begin
fsm_step_number=1;
case(pc)
fsm_step_number++: begin
wb_addr_o <= UART_LSR;
wb_stb_o <= 1'b1;
wb_cyc_o <= 1'b1;
wb_we_o <= 1'b0;
end
fsm_step_number++: begin
temt <= wb_rdat_i[6];
wb_stb_o <= 1'b0;
wb_cyc_o <= 1'b0;
wb_we_o <= 1'b0;
end
[...]
endcase
end
The incrementation of fsm_step_number integer doesn't works with lattice synthesis program (LSE) neither Yosys.
I have a syntax error with yosys :
yosys> read_verilog uart_ctrl_pre.v
1. Executing Verilog-2005 frontend.
Parsing Verilog input from `uart_ctrl_pre.v' to AST representation.
ERROR: Parser error in line uart_ctrl_pre.v:74: syntax error, unexpected TOK_INCREMENT
Do you know if it's possible to do a think like that with Yosys (increment integer into case state) ?
The ++ operator is in SystemVerilog, not Verilog.
And I think that synthesis tools require that the either the case(expression) or list of item: expressions be a constant, but do not allow both to be non-constant expressions.

Verilog Error in all assignings

Verilog Error
I am trying to learn verilog . This code is made for seven segment led using counter. But I am not able to assign value to nr it gives error. I made a state machine and wish to get next number on seven segment led after each positive clock.
/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/
module LED ( nr,clk);
input clk;
output [6:0]nr; //output led seven bit number
reg [6:0]nr;
reg [2:0]state;
always #(posedge clk);
begin
state <= 3'b000; // assigning at each clock
case (state)
3'b000:
begin
nr <= 7'b0000001;
state <= 3'b001;
end
3'b001:
begin
nr <= 7'b0011111;
state <= 3'b010;
end
3'b010:
begin
nr <= 7'b0100101;
state <= 3'b011;
end
3'b011:
begin
nr <= 7'b0001100;
state <= 3'b100;
end
3'b100:
begin
nr <= 7'b1011010;
state <= 3'b101;
end
3'b101:
begin
nr <= 7'b1001000;
state <= 3'b110;
end
3'b110:
begin
nr <= 7'b1000000;
state <= 3'b111;
end
3'b111:
begin
nr <= 7'b0011101;
state <= 3'b000;
end
end
endmodule
always #(posedge clk) no semicolon!

Why wont Xilinx ISE accept this statement in a state machine?

So i am currently doing a little project involving a hd44780 display. But since i want to write my own init sequence i decided to use a state machine. I am quite new to FPGAs an their programming coming from a Java background.
This is my State machine Block.
I this state it works and the IDE doesnt show any errors.
always #(posedge reset)
begin
en_timeout <= 2'b00;
timeout <= 14'b00000000000000;
init <= 4'b000;
data <= 8'b00000000;
en <= 1'b1; //active low
rs <= 1'b0;
rw <= 1'b0;
state <= 4'b0000;
next_state <= 4'b0000;
debug <= 1'b0;
end
if(timeout == 0)
begin //Begin of Initiation state machine
case(state)
s0:
begin
end
s1:
begin
end
s2:
begin
end
s3:
begin
end
s4:
begin
end
s5:
begin
end
s6:
begin
end
s7:
begin
end
s8:
begin
end
s9:
begin
end
s10:
begin
end
normal:
begin
end
endcase
end //End of Initiation state machine
But if i add any assignment between the begin and end of one of the states it shows me "Line n: Syntax error near "<="."
for example:
case(state)
s0:
begin
state <= s1;
end
Full code of my DisplayDriver so far:
module DisplayDriver(
output reg [8:0] data,
output reg en,
output reg rs,
output reg rw,
output reg debug,
input clk,
input reset
);
parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5,s6=6,s7=7,s8=8,s9=9,s10=10,normal = 11;
reg [3:0] state; // 4 bit for max 11 combinations s0-s10 and normal
reg [3:0] state; // 4 bit for max 11 combinations s0-s10 and normal [next State]
reg [1:0] en_timeout; // 2 bit for en high to low to high cylce
reg [13:0] timeout; // 14 bit
initial
// begin init
begin
en_timeout <= 2'b00;
timeout <= 14'b00000000000000;
init <= 4'b000;
data <= 8'b00000000;
en <= 1'b1; //active low
rs <= 1'b0;
rw <= 1'b0;
state <= 4'b0000;
next_state <= 4'b0000;
debug <= 1'b0;
end
// end of init
always #(posedge clk)
//begin of everything that needs the clock
begin
if(en_timeout > 0) //begin timeout stack
begin
en_timeout <= en_timeout -1;
en <= ~en;// if en_timeout = 2 -> en = 0; if en_timeout = 1 -> en = 1;
end
else if (timeout > 0) timeout <= timeout -1; //end timeout stack
if(timeout == 0)state <= next_state;
end //end of everything that needs the clock
always #(posedge reset)
begin
en_timeout <= 2'b00;
timeout <= 14'b00000000000000;
init <= 4'b000;
data <= 8'b00000000;
en <= 1'b1; //active low
rs <= 1'b0;
rw <= 1'b0;
state <= 4'b0000;
next_state <= 4'b0000;
debug <= 1'b0;
end
if(timeout == 0)
begin //Begin of Initiation state machine
case(state)
s0:
begin
end
s1:
begin
end
s2:
begin
end
s3:
begin
end
s4:
begin
end
s5:
begin
end
s6:
begin
end
s7:
begin
end
s8:
begin
end
s9:
begin
end
s10:
begin
end
normal:
begin
end
endcase
end //End of Initiation state machine
endmodule
Does anyone have an idea why it behaves this way?
I assume that you are trying to synthesize a register for "state", in which case the update "<=" needs to be inside always (#posedge clk).

Resources