FSM is double incrementing - verilog

I have a newbie FSM Verilog question. In the below code, around line 96, I am incrementing led_num with the non blocking led_num <= led_num+1; However, because of the way my code is setup I have a non blocking curr_state <= next_state at line 82, and then I am doing a next_state <= "NEXT STATE" in every one of my case statements. This is causing me to be in each state 2 clocks and is causing my led_num <= led_num+1 to execute twice, and I want just a single time.
How do I go about fixing this so I am in each state a single clock or how do I prevent the led_num being incremented by two each time? I had one person tell me to non blocking all of the time, but some examples mix them and I am pretty sure I need to move my nextState to use a blocking assignment but I have tried several things so far and I keep messing it up.
`timescale 1ns / 1ps
module ws2812_b(clk, rst, send_the_data, led_data_out);
input clk;
input rst;
input send_the_data;
output reg led_data_out;
parameter NUMBER_LEDS = 5;
parameter ADDRESS_BITS =8;
parameter NUM_BITS = 24;
parameter STATE_BITS = 4;
parameter T0_HIGH_0_COUNT = 6; // .35us (System clock = 12Mhz, 83.3 ns/cycle.
parameter T0_HIGH_1_COUNT = 16; // .9us
parameter CYCLE_COUNT = (T0_HIGH_0_COUNT+T0_HIGH_1_COUNT); //.9+.35
parameter RESET_COUNT = 1500; // 50us
localparam ST_IDLE = 4'd0,
ST_GET_WORD = 4'd1,
ST_SEND_START = 4'd2,
ST_UPDATE_WORD = 4'd3,
ST_DELAY_0 = 4'd4,
ST_DRIVE_0 = 4'd5,
ST_DELAY_1 = 4'd6,
ST_CHECK_WORD_DONE = 4'd7,
ST_SEND_RESET = 4'd8,
ST_NDEF_9 = 4'd9,
ST_NDEF_10 = 4'd10,
ST_NDEF_11 = 4'd11,
ST_DELAY_1S = 4'd12,
ST_NDEF_13 = 4'd13,
ST_NDEF_14 = 4'd14,
ST_NDEF_15 = 4'd15;
reg [STATE_BITS-1:0]currState;
reg [STATE_BITS-1:0]nextState;
reg [14:0] delay_value;
reg [NUM_BITS-1:0] led_word;
reg [5:0] bit_num;
reg [13:0] delay0, delay1;
reg [8:0] led_num;
`define rundelay currState <= ST_DELAY_1S
`define returndelay currState <= nextState
always #(posedge clk, posedge rst)
begin
if (rst) begin
currState <= ST_IDLE;
nextState <= ST_IDLE;
led_data_out <=0;
led_word <= 0;
bit_num <= 0;
delay0 <= 0;
delay1 <=0;
delay_value <=0;
led_num <= 0;
end
else
begin
currState <= nextState;
case (currState)
ST_IDLE: //0
begin
led_data_out <= 0;
nextState <= ST_GET_WORD;
led_num <= 0;
end
ST_GET_WORD: //1
begin
led_word <= 24'h335599;
bit_num <= 0;
nextState <= ST_SEND_START;
led_num <= led_num + 1 ; // ***** DOUBLE INCREMENTS ****
end
ST_SEND_START: //2
begin
led_data_out <= 1;
if (led_word[0]==1)
begin
delay0 <= T0_HIGH_1_COUNT;
delay1 <= (CYCLE_COUNT - T0_HIGH_1_COUNT + 1);
end else
begin
delay0 <= T0_HIGH_0_COUNT;
delay1 <= (CYCLE_COUNT - T0_HIGH_0_COUNT + 1);
end
nextState <= ST_UPDATE_WORD;
end
ST_UPDATE_WORD: //3
begin
led_word[23:0] <= {1'b0,led_word[23:1]};
bit_num <= bit_num+1;
nextState <= ST_DRIVE_0;
delay_value <= delay0;
`rundelay;
end
ST_DRIVE_0: //5
begin
led_data_out <= 0;
nextState <= ST_CHECK_WORD_DONE;
delay_value <= delay1;
`rundelay;
end
ST_CHECK_WORD_DONE: //4
begin
if (bit_num<24)
begin
nextState <= ST_SEND_START;
end else
begin
if (led_num<3)
begin
nextState <= ST_GET_WORD;
end else
begin
nextState <= ST_SEND_RESET;
end
end
end
ST_SEND_RESET:
begin
led_data_out <= 0;
nextState <= ST_IDLE;
delay_value <= 2000;
`rundelay;
end
ST_DELAY_1S: // Delay of ~1sec. Note that the total delay is one clock cycle more because of the state transition.
begin
if (delay_value)
begin
delay_value <= delay_value -1; // as long as delay_value is larger than zero ( bitwise or)
// decrement (decrementing counters synthesize smaller than
// incrementing counters as no comparator is needed, only a
// zero check which is a bitwise or.
currState <= currState;
end
else
begin
//currState <= nextState; // if it hits zero ; throw the target state into currentstate.
`returndelay;
end
end
default:
begin
currState <= ST_IDLE;
end
endcase
end
end
endmodule

As Greg pointed out, FSMs are implemented one of two ways:
Single always block (like you've implemented) In this case, every clock runs through the "always block" once and you only need one "State" variable. All variables are "non-blocking" ("<=" symbol) which implies that all statements are executed in parallel.
Double always blocks. In this case, the first always block is purely combinational, which is fully "blocking" assigns so that you can have sequential arithmetic to calcuate your final value. The second always block behaves like a set of registers to let the whole state-machine "step" to the next state on the clock edge. This setup requires "currState" and "nextState". The first combinational always block calculates "nextState" from "currState". The second (sequential) always block simply transfers nextState to currState on a clock edge.
In your case, it looks like you're trying to jump to a "delay" state for a certain number of cycles and then jump back to the next state in the sequence like a subroutine in C code that delays.
While I haven't run it, I think the following is closer to what you're trying to do. When you jump to ST_DELAY_1S, you need to save the state you want to return to in a separate variable (I used afterDelayState) so that you can spin in the delay state and then return (much like the instruction pointer on the stack) to the proper place.
`timescale 1ns / 1ps
module ws2812_b(clk, rst, send_the_data, led_data_out);
input clk;
input rst;
input send_the_data;
output reg led_data_out;
parameter NUMBER_LEDS = 5;
parameter ADDRESS_BITS =8;
parameter NUM_BITS = 24;
parameter STATE_BITS = 4;
parameter T0_HIGH_0_COUNT = 6; // .35us (System clock = 12Mhz, 83.3 ns/cycle.
parameter T0_HIGH_1_COUNT = 16; // .9us
parameter CYCLE_COUNT = (T0_HIGH_0_COUNT+T0_HIGH_1_COUNT); //.9+.35
parameter RESET_COUNT = 1500; // 50us
localparam ST_IDLE = 4'd0,
ST_GET_WORD = 4'd1,
ST_SEND_START = 4'd2,
ST_UPDATE_WORD = 4'd3,
ST_DELAY_0 = 4'd4,
ST_DRIVE_0 = 4'd5,
ST_DELAY_1 = 4'd6,
ST_CHECK_WORD_DONE = 4'd7,
ST_SEND_RESET = 4'd8,
ST_NDEF_9 = 4'd9,
ST_NDEF_10 = 4'd10,
ST_NDEF_11 = 4'd11,
ST_DELAY_1S = 4'd12,
ST_NDEF_13 = 4'd13,
ST_NDEF_14 = 4'd14,
ST_NDEF_15 = 4'd15;
reg [STATE_BITS-1:0] State;
reg [STATE_BITS-1:0] afterDelayState;
reg [14:0] delay_value;
reg [NUM_BITS-1:0] led_word;
reg [5:0] bit_num;
reg [13:0] delay0, delay1;
reg [8:0] led_num;
//`define rundelay currState <= ST_DELAY_1S
//`define returndelay currState <= nextState
always #(posedge clk, posedge rst)
begin
if (rst) begin
State <= ST_IDLE;
afterDelayState <= ST_IDLE;
led_data_out <=0;
led_word <= 0;
bit_num <= 0;
delay0 <= 0;
delay1 <=0;
delay_value <=0;
led_num <= 0;
end
else
begin
case (State)
ST_IDLE: //0
begin
led_data_out <= 0;
State <= ST_GET_WORD;
led_num <= 0;
end
ST_GET_WORD: //1
begin
led_word <= 24'h335599;
bit_num <= 0;
State <= ST_SEND_START;
led_num <= led_num + 1 ; // ***** DOUBLE INCREMENTS ****
end
ST_SEND_START: //2
begin
led_data_out <= 1;
if (led_word[0]==1)
begin
delay0 <= T0_HIGH_1_COUNT;
delay1 <= (CYCLE_COUNT - T0_HIGH_1_COUNT + 1);
end else
begin
delay0 <= T0_HIGH_0_COUNT;
delay1 <= (CYCLE_COUNT - T0_HIGH_0_COUNT + 1);
end
State <= ST_UPDATE_WORD;
end
ST_UPDATE_WORD: //3
begin
led_word[23:0] <= {1'b0,led_word[23:1]};
bit_num <= bit_num+1;
State <= ST_DRIVE_0;
delay_value <= delay0;
// delay "delay0" cycles and then jump to ST_DRIVE_0
delay_value <= delay0;
State <= ST_DELAY_1S;
afterDelayState <= ST_DRIVE_0;
end
ST_DRIVE_0: //5
begin
led_data_out <= 0;
// delay "delay1" cycles and then jump to ST_CHECK_WORD_DONE
delay_value <= delay1;
State <= ST_DELAY_1S;
afterDelayState <= ST_CHECK_WORD_DONE;
end
ST_CHECK_WORD_DONE: //4
begin
if (bit_num<24)
begin
State <= ST_SEND_START;
end else
begin
if (led_num<3)
begin
State <= ST_GET_WORD;
end else
begin
State <= ST_SEND_RESET;
end
end
end
ST_SEND_RESET:
begin
led_data_out <= 0;
// delay 2000 cycles and then jump to ST_IDLE
delay_value <= 2000;
State <= ST_DELAY_1S;
afterDelayState <= ST_IDLE;
end
// This is a special "delay" loop that jumps to a specified "afterDelayState" when the delay_value runs to zero
ST_DELAY_1S: // Delay of ~1sec. Note that the total delay is one clock cycle more because of the state transition.
begin
if (delay_value)
begin
// every clock cycle stay in the ST_DELAY_1S state until the "delay_value" runs to zero
delay_value <= delay_value -1; // as long as delay_value is larger than zero ( bitwise or)
// decrement (decrementing counters synthesize smaller than
// incrementing counters as no comparator is needed, only a
// zero check which is a bitwise or.
//
// no change in State, so we stay here
// State <= State
end
else
begin
//after it hits zero, jump to the state we stored in afterDelayState
State <= afterDelayState;
end
end
default:
begin
State <= ST_IDLE;
end
endcase
end
end
endmodule
In the code above, each state has only one State <= (new state) command.
We only assign the afterDelayState variable when jumping to the ST_DELAY_1S "subroutine" so we know where to go back to.
I took out the `defines to make all assignments more explicit.
One side recommendation is to install VSCode and iverilog so that you can do syntax checking, auto-formatting and compile checking inside the editor. This quickly helped me clean things up.

Related

How to get outputs/pulses when counter reaches two particular values?

I have created a counter that counts up to 30. I have an output signal out. At two particular counts, i.e., when counter reaches 10 (first) and when counter reaches 15 (second), I want the output to become low. Somehow I'm missing a basic logic here as only at one particular count (either at 10 or 15) I'm able to make the output zero.
Here is the code
module user_def_pulse(
output integer counter,
output reg out,
input clk, reset
);
parameter no_of_counts = 30;
parameter first = 10;
parameter second = 15;
initial
begin
counter = 0;
out = 1'b0;
end
always #(posedge clk)
begin
if (reset)
begin
counter <= 1'b0;
end
else if (counter == no_of_counts)
begin
counter <= 1'b0;
out <= 1'b0;
end
else
begin
if ((counter == first) || (counter == second))
out <= 1'b0;
else
begin
counter <= counter + 1;
out <= 1'b1;
$display($time," The value of counter is %d", counter);
end
end
end
endmodule
Here is the test bench
module user_def_pulse_tb(
);
parameter time_period = 10;
wire [31:0] COUNTER;
wire OUT;
reg CLK, RESET;
user_def_pulse udp1 (.counter(COUNTER), .out(OUT), .clk(CLK), .reset(RESET));
initial
begin
CLK = 1'b0;
RESET = 1'b1;
#20 RESET = 1'b0;
end
always
#time_period CLK = ~CLK;
endmodule
Here is the output waveform.
The problem with your code is that is stops incrementing the counter as soon as it hits the first value. You need to keep incrementing the counter. I moved the increment outside of the if ((counter == first) || ... clause.
always #(posedge clk) begin
if (reset) begin
counter <= 1'b0;
end else if (counter == no_of_counts) begin
counter <= 1'b0;
out <= 1'b0;
end else begin
counter <= counter + 1;
$display($time," The value of counter is %d", counter);
if ((counter == first) || (counter == second)) begin
out <= 1'b0;
end else begin
out <= 1'b1;
end
end
end

vivado simulation error: Iteration limit 10000 is reached

While I was trying to run the simulation in vivado, I got:
ERROR: Iteration limit 10000 is reached. Possible zero delay
oscillation detected where simulation time can not advance. Please
check your source code. Note that the iteration limit can be changed
using switch -maxdeltaid. Time: 10 ns Iteration: 10000
I don't have any initial statement in my module being tested.
Could anybody point out where the problem could be?
`timescale 1ns / 1ps
module mulp(
input clk,
input rst,
input start,
input [4:0] mplier, // -13
input [4:0] mplcant, // -9
output reg done,
output [9:0] product
);
parameter N = 6;
parameter Idle = 2'b00;
parameter Load = 2'b01;
parameter Oper = 2'b10;
parameter Finish = 2'b11;
reg done_r;
reg [N-1:0] A, A_r, B, B_r;
reg [1:0] state, state_r;
reg [2:0] count, count_r;
wire [N-2:0] C, C_comp;
reg [N-2:0] C_r;
assign C = mplcant; assign C_comp = {~C + 1};
assign product = {A_r[N-2:0], B_r[N-2:0]};
always #(posedge clk) begin
if (rst) begin
state_r <= Idle;
count_r <= 0;
done_r <= 0;
A_r <= 0;
B_r <= 0;
end else begin
state_r <= state;
count_r <= count;
done_r <= done;
A_r <= A;
B_r <= B;
end // if
end // always
always #(*) begin
state = state_r;
count = count_r - 1; // count: 6
done = done_r;
A = A_r;
B = B_r;
case (state)
Idle: begin
if (start) begin
state <= Load;
end // if
end
Load: begin
A = 0; B = {mplier, 1'b0}; count = N; // start at 6
state = Oper;
end
Oper: begin
if (count == 0)
state = Finish;
else begin
case (B[1:0])
2'b01: begin
// add C to A
A = A_r + {C[N-2], C[N-2:0]};
// shift A and B
A = {A_r[N-1], A_r[N-1:1]};
B = {A_r[0], B_r[N-1:1]};
end
2'b10: begin
A = A_r + {C_comp[N-2], C_comp[N-2:0]};
A = {A_r[N-1], A[N-1:1]};
B = {A_r[0], B_r[N-1:1]};
end
(2'b00 | 2'b11): begin
A = {A_r[N-1], A[N-1:1]};
B = {A_r[0], B_r[N-1:1]};
end
default: begin
state = Idle; done = 1'bx; // error
end
endcase
end // else
end // Oper
Finish: begin
done = 1;
state = Idle;
end // Finish
default: begin
done = 1'bx;
state = Idle;
end
endcase
end // always
endmodule
You have a combinational loop. You are sampling and driving the state signal in the combinational always block. Typically, you sample the registered state variable (state_r in your code) in an FSM. Change:
case (state)
to:
case (state_r)
Unrelated, but you should use all blocking assignments in the combo block (not a mixture). Change:
state <= Load;
to:
state = Load;

Place 30-574 Poor placement for routing between an IO pin and BUFG

`timescale 1ns / 1ps
module stopwatch(
input clock,
input reset,
input increment,
input start,
output [6:0] seg,
output dp,
output [3:0] an
);
reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
reg [22:0] ticker;
wire click;
//the mod 1kHz clock to generate a tick ever 0.001 second
always # (posedge (clock) or posedge (reset))
begin
if(reset)
begin
ticker <= 0;
end
else
begin
if (start)
begin
if(ticker == (100000 - 1)) //if it reaches the desired max value reset it
ticker <= 0;
else if (increment)
ticker <= ticker;
else
ticker <= ticker + 1;
end
end
end
//increment a second everytime rising edge of down button
reg [3:0] inc_temp;
always # (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
assign click = ((ticker == (100000 - 1))?1'b1:1'b0); //click to be assigned high every 0.001 second
//update data start from here
always # (posedge (clock) or posedge (reset))
begin
if(reset)
begin
reg_d0 <= 0;
reg_d1 <= 0;
reg_d2 <= 0;
reg_d3 <= 0;
end
else
begin
if (increment)
begin
reg_d3 <= inc_temp;
reg_d0 <= reg_d0;
reg_d1 <= reg_d1;
reg_d2 <= reg_d2;
end
else if (click) //increment at every click
begin
if(reg_d0 == 9) //xxx9 - 1th milisecond
begin
reg_d0 <= 0;
if (reg_d1 == 9) //xx99 - 10th milisecond
begin
reg_d1 <= 0;
if (reg_d2 == 9) //x999 - 100th milisecond
begin
reg_d2 <= 0;
if(reg_d3 == 9) //9999 - The second digit
reg_d3 <= 0;
else
reg_d3 <= reg_d3 + 1;
end
else
reg_d2 <= reg_d2 + 1;
end
else
reg_d1 <= reg_d1 + 1;
end
else
reg_d0 <= reg_d0 + 1;
end
else
begin
reg_d3 <= reg_d3;
reg_d0 <= reg_d0;
reg_d1 <= reg_d1;
reg_d2 <= reg_d2;
end
end
end
//Mux for display 4 7segs LEDs
localparam N = 18;
reg [N-1:0]count;
always # (posedge clock or posedge reset)
begin
if (reset)
count <= 0;
else
count <= count + 1;
end
reg [6:0]sseg;
reg [3:0]an_temp;
reg reg_dp;
always # (*)
begin
case(count[N-1:N-2])
2'b00 :
begin
sseg = reg_d0;
an_temp = 4'b1110;
reg_dp = 1'b1;
end
2'b01:
begin
sseg = reg_d1;
an_temp = 4'b1101;
reg_dp = 1'b0;
end
2'b10:
begin
sseg = reg_d2;
an_temp = 4'b1011;
reg_dp = 1'b1;
end
2'b11:
begin
sseg = reg_d3;
an_temp = 4'b0111;
reg_dp = 1'b0;
end
endcase
end
assign an = an_temp;
//update the data to display to LEDs
reg [6:0] sseg_temp;
always # (*)
begin
case(sseg)
4'd0 : sseg_temp = 7'b1000000;
4'd1 : sseg_temp = 7'b1111001;
4'd2 : sseg_temp = 7'b0100100;
4'd3 : sseg_temp = 7'b0110000;
4'd4 : sseg_temp = 7'b0011001;
4'd5 : sseg_temp = 7'b0010010;
4'd6 : sseg_temp = 7'b0000010;
4'd7 : sseg_temp = 7'b1111000;
4'd8 : sseg_temp = 7'b0000000;
4'd9 : sseg_temp = 7'b0010000;
default : sseg_temp = 7'b0111111; //dash
endcase
end
assign seg = sseg_temp;
assign dp = reg_dp;
endmodule
I'm trying to design a stop watch, but I'm stuck at the increment thing. The intent is when I press increment(a button), the reg_d3 will increment by one and hold its state until the button is released. I'm able to make the clock stop when the button is pressed, but I can't update the reg_d3. I always receive
[Place 30-574] Poor placement for routing between an IO pin and BUFG
I don't know why; I use increment in the clkdivider just find.
I think the problem is related to this part of your code:
always # (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
You are basically using an input signal as a clock, and that is completely discouraged when designing for a FPGA. The P&R tries to re-route an IO pin to a BUFG (global buffer) inside the FPGA so it can be used as a clock.
For FPGA design, you should use one clock signal for all your always #(posedge...) constructions, and use input signals to conditionally load/update the register.
To do that, you have first to synchronize your increment signal to your clk, so avoiding metastability issues:
reg incr1=1'b0, incr2=1'b0;
always #(posedge clk) begin
incr1 <= increment;
incr2 <= incr1;
end
wire increment_synched = incr2;
Then, deglitch increment_synched and detect a rising edge in it:
reg [15:0] incrhistory = 16'h0000;
reg incr_detected = 1'b0;
always #(posedge clk) begin
incrhistory <= { incrhistory[14:0] , increment_synched };
if (incrhistory == 16'b0011111111111111)
incr_detected <= 1'b1;
else
incr_detected <= 1'b0;
end
To detect a valid rising edge, we store a history of the last 16 values of increment_synched. When a valid steady change from 0 to 1 is produced, the history pattern will match the pattern 0011111111111111. Then, and only then, we signal it by raising incr_detected to 1. The next clock cycle, the history pattern won't match the above sequence, and incr_detected will go down to 0 again.
Prior to that, multiple bounces in the push button increment is connected to would cause many transitions, leading to many increments. Using a pattern matching like that eliminates those glitches caused by multiple bounces. With 1Khz clock as you seem to use, this pattern should be enough.
Now you can use incr_detected in your original code, incr_detected wil be 1 for just a single clk cycle.
always # (posedge clk) begin
if (incr_detected) begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
end
You can test these additions using the following simulation:
http://www.edaplayground.com/x/AQY
What you will see there is a module that takes your increment input signal from the outside, and generate a glitch-free one-cycle pulse when the input signal makes a final transition from low to high level.
Actually, I've written two versions. The second one tries to mimic the behaviour of a monostable, so the input won't be sampled for a specific period of time after the first low to high transition is detected.
You will see that the second version produces a pulse much sooner than the first version, but it's also prone to take a glitch as valid rising edge, as showed in the simulation. I'd stick with the first version then.

ERROR: HDLCompiler:806 ... Syntax error near "end"

I'm trying to make an I2C protocol on Verilog, and I was typing what this guy was typing (a video on YouTube that explains how to make a I2C BUS protocol)
module step1(
input wire clk,
input wire reset,
output reg i2c_sda,
output reg i2c_scl
);
//goal is to write to device addres 0x50, 0xaa
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_STOP = 6;
localparam STATE_WACK2 = 7;
reg [7:0] state;
reg [6:0] addr;
reg [7:0] data;
reg [7:0] count;
always #(posedge clk) begin
if (reset == 1) begin
state <= 0;
i2c_sda <= 1;
i2c_scl <= 1;
addr <= 7'h50;
count <= 8'd0;
data <= 8'haa;
end
else begin
case(state)
STATE_IDLE: begin //idle
i2c_sda <= 1;
state <= STATE_START;
end // end state idle
STATE_START: begin //start
i2c_sda <= 1;
state <= STATE_ADDR;
count <= 6;
end // end of state start
STATE_ADDR: begin // fisrt addres bit or the most significant adress bit
i2c_sda <= addr[count];
if (count == 0) state <= STATE_RW;
else count <= count - 1;
end // end of state ADDR
STATE_RW: begin // Read or Write opperation
i2c_sda <= 1;
state <= STATE_WACK;
end // end state RW
STATE_WACK: begin
state <= STATE_DATA;
count <= 7;
end // end of state WACK
STATE_DATA: begin
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK2;
else count <= count-1;
end // end of state DATA
STATE_WACK2: begin
state <= STATE_STOP;
end // end state WACK2
STATE_STOP: begin
i2c_sda <= 1;
state <= STATE_IDLE;
end // end of state STOP
end// end of case
end // end of the else
end // end of if
endmodule
But, when I try to compile, the following error pops out. I really don't understand why, because all end are correct (at least for me):
ERROR:HDLCompiler:806 - "/home/yunta23/Documentos/Digital1/VideosYou/primero/step1/step1.v" Line 97: Syntax error near "end".
A case statement requires the endcase keyword, not an end keyword. Change:
end// end of case
to:
endcase

Behavioral algorithms (GCD) in Verilog - possible?

I want to write a module for GCD computing, using extended Euclidean algorithm. But the main problem is that I completely don't know how to do that without getting to the lowest (RTL) level. What I mean is to have FSM with three states:
IDLE (waiting for input)
COMPUTING (as many clock cycles as needed)
FINISHED (ready to read output).
However, when I try to separate FSM & computations into separate processes, like this:
module modinv(clk, reset, number, prime, finished, gcd, inverse_fail, inverse);
input [31:0] number, prime;
input wire clk, reset;
output integer gcd, inverse;
output reg finished, inverse_fail;
parameter [2:0] IDLE = 3'b001, COMPUTING = 3'b010, END = 3'b100;
reg [2:0] state, state_next;
integer a, b, c, q, p, r;
always # (posedge clk, posedge reset)
begin
if (reset == 1)
begin
state <= IDLE;
end
else
begin
state <= state_next;
end
end
always #(state or b)
begin
finished <= 0;
inverse_fail <= 0;
case (state)
IDLE:
begin
a <= number;
b <= prime;
p <= 1;
r <= 0;
state_next <= COMPUTING;
end
COMPUTING:
begin
c = a % b;
q = a / b;
a = b;
b = c;
r = p - q * r;
p = r;
if (b == 0)
begin
state_next <= END;
end
else
begin
state_next <= COMPUTING;
end
end
END:
begin
gcd <= a;
inverse <= p;
finished <= 1;
if (gcd != 1)
begin
inverse_fail <= 1;
end
end
endcase
end
endmodule
And when I try to put computation in the second process, in COMPUTING state case, it only works once - what is correct in means of verilog, because until computing is done, state doesn't change, so the process isn't called again.
However, when I put computation in the first process, there isn't any non-ugly way to limit the computations only to correct STATE, which results in wrong output (as soon as FSM is in FINISHED state, the output is already incorrect - one step further).
So, my question is - how to do it correctly without using FSM + datapath (low-level RTL) solution?
My current waveform:
You seem to be missing some clocked elements in your design.
From what I understand of your design, you seem to expect once the state goes to COMPUTING, it should keep iterating the values of a and b until b reaches 0. But the only thing you're actually clocking on a clock edge is the state variable, so there's no memory of a and b from one state to the next. If you want variables like a and b to have memory from one clock cycle to the next, then you need to latch these variables as well:
I made some modifications to your program, it might not be 100% correct, but you should see what I'm getting at. See if this makes sense how you do the combinational logic in the second block, but you register the values on the posedge so that you can use them at the start of the next clock cycle.
module modinv(clk, reset, number, prime, finished, gcd, inverse_fail, inverse);
input [31:0] number, prime;
input wire clk, reset;
output integer gcd, inverse;
output reg finished, inverse_fail;
parameter [2:0] IDLE = 3'b001, COMPUTING = 3'b010, END = 3'b100;
reg [2:0] state, state_next;
integer a, b, c, q, p, r;
integer a_next, b_next, p_next, r_next;
always # (posedge clk, posedge reset)
begin
if (reset == 1)
begin
state <= IDLE;
a <= 0;
b <= 0;
p <= 0;
r <= 0;
end
else
begin
state <= state_next;
a <= a_next;
b <= b_next;
p <= p_next;
r <= r_next;
end
end
always #* //just use the auto-triggered '#*' operator
begin
finished <= 0;
inverse_fail <= 0;
case (state)
IDLE:
begin
a_next <= number;
b_next <= prime;
p_next <= 1;
r_next <= 0;
state_next <= COMPUTING;
end
COMPUTING:
begin
c = a % b;
q = a / b;
a_next = b;
b_next = c;
r_next = p - q * r;
p_next = r;
if (b == 0)
begin
state_next <= END;
end
else
begin
state_next <= COMPUTING;
end
end
END:
begin
gcd <= a;
inverse <= p;
finished <= 1;
if (gcd != 1)
begin
inverse_fail <= 1;
end
end
endcase
end
endmodule

Resources