Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Helo with Verilog FSM

Status
Not open for further replies.

Sink0

Full Member level 6
Joined
Nov 25, 2009
Messages
390
Helped
37
Reputation
74
Reaction score
30
Trophy points
1,308
Location
Sao Paulo, Brazil
Activity points
4,186
Hi, i have a very weird behavior on a Veriglog code and i need some help.

Just a fast exaplanation. It is a Wishbone master that should perform N reads, and the number N is defined by a number that i load on the r_counter.

The code is the following:

Code:
`include "network_controller_constants.v"

module NETWORK_CONTROLLER_WB_MASTER
(
	CLK_I,            
   RST_I,

	MINT_O,
	MADR_O,
	MDAT_O,
	MDAT_I,
	MSEL_O,
	MCYC_O,
	MSTB_O,
	MWE_O,
	MCAB_O,
	MACK_I,
	MRTY_I,
   MERR_I,
	 
	tx_b1_offset,
	tx_b2_offset,
	rx_b1_offset,
	rx_b2_offset,
	
	r_cnt_reg,
	r_cmnd_flag,
	
	tx_b_1_int,
	tx_b_2_int,
	rx_b_1_int,
	rx_b_2_int,
	
	tx_b_1_over,
	tx_b_2_over,
	rx_b_1_over,
	rx_b_2_over,
	
	r_counter_empty,
	counter_loaded,
	
	r_bus_data_in,
	data_sent,
	DATA_READY,
	
	leds,
	
	MEMORY
);


input			   	CLK_I;            
input             RST_I;

output				MINT_O;
output   [31:0]  	MADR_O;
input    [31:0]  	MDAT_I;
output   [31:0]  	MDAT_O;
output   [3:0]   	MSEL_O;
output            MCYC_O;
output            MSTB_O;
output            MWE_O;
output            MCAB_O;
input            	MACK_I;
input            	MRTY_I;
input            	MERR_I;

input		[31:0]	tx_b1_offset;
input		[31:0]	tx_b2_offset;
input		[31:0]	rx_b1_offset;
input		[31:0]	rx_b2_offset;

output				tx_b_1_over;
output				tx_b_2_over;
output				rx_b_1_over;
output				rx_b_2_over;

input		[31:0]	r_cnt_reg;
input					r_cmnd_flag;

input					tx_b_1_int;
input					tx_b_2_int;
input					rx_b_1_int;
input					rx_b_2_int;

output				r_counter_empty;

output	[31:0]	MEMORY;

input		[31:0]	r_bus_data_in;
output				data_sent;
input					DATA_READY;

output	[3:0]		leds;

output				counter_loaded;

parameter WB_IDLE	= 	  5'b00001;	
parameter WB_WRITING	= 5'b00010;
parameter WB_READING	= 5'b00100;
parameter WB_INT_ACK	= 5'b01000;
parameter WB_W_WAIT	= 5'b10000;

reg		[31:0]	MADR_O = 32'h40000000;
reg		[31:0]	MDAT_O;
wire		[31:0]	MDAT_I;
wire		[3:0]		MSEL_O;
reg					MCYC_O;
reg					MSTB_O;
wire					MWE_O;
reg					MCAB_O;
wire					MACK_I;
wire					MRTY_I;
wire					MINT_O;

reg		[31:0]	r_counter = 0;
reg		[4:0]		state_machine = WB_IDLE;
reg		[4:0]		next_state = WB_IDLE;
reg					int_ack_done = 0;
reg					write_done = 0;
reg					r_counter_empty = 1'b1;
wire					wb_int_gen;
wire					DATA_READY;

reg					tx_b_1_over = 0;
reg					tx_b_2_over = 0;
reg					rx_b_1_over = 0;
reg					rx_b_2_over = 0;

reg		[31:0]	MEMORY;
wire		[31:0]	r_bus_data_in;
reg					data_sent = 0;

reg		[29:0]	r_w_addr;

//###########################################################

reg 		[3:0]		MRTY_C = 0;
reg		[3:0]		MACK_C = 0;	
reg		[3:0]		leds;	

//###########################################################	

assign MSEL_O = 4'b1111;
assign MINT_O = wb_int_gen;
//assign DATA_READY = 1'b0;

assign	wb_int_gen = 	tx_b_1_int|
								tx_b_2_int| 
								rx_b_1_int|
								rx_b_2_int;

/*##################################################################################
############################ state_machine CONTROL #################################
##################################################################################*/

always@(state_machine or r_counter or tx_b_1_int or tx_b_2_int or write_done or int_ack_done or DATA_READY)
begin
	tx_b_1_over = 1'b0;
	tx_b_2_over = 1'b0;
	rx_b_1_over = 1'b0;
	rx_b_2_over = 1'b0;
	case (state_machine)
		WB_IDLE : 
			begin
				if(r_counter > 32'h00000000)
				begin
						next_state = WB_READING;
				end
			end
		WB_READING :
			begin
				if(r_counter == 32'h00000000)
				begin
					//next_state = WB_INT_ACK;
					next_state = WB_IDLE;
					rx_b_1_over = 1'b1;
				end
			end
		WB_WRITING :
			begin
				if(DATA_READY == 1'b0)
					next_state = WB_W_WAIT;
			end
		WB_INT_ACK : 
			begin
				if(int_ack_done)
					next_state = WB_IDLE;
			end
		WB_W_WAIT :
			begin
				if(write_done)
				begin
					next_state = WB_INT_ACK;
					tx_b_1_over = 1'b1;
				end
			end
		default:begin
				next_state = WB_IDLE ; 
            end 
	endcase
end

/*##################################################################################
############################ state_machine TIMING ##################################
##################################################################################*/

always@(posedge CLK_I)
begin
		state_machine = next_state;
end

/*##################################################################################
############################ int_ack_done CONTROL ##################################
##################################################################################*/

always@(posedge CLK_I)
begin
	int_ack_done = 1'b0;
	if(state_machine == WB_INT_ACK)
	begin
		if(MCYC_O && MACK_I)
			int_ack_done = 1'b1;
	end
end

/*##################################################################################
############################# write_done CONTROL ###################################
##################################################################################*/

always@(posedge CLK_I)
begin
	write_done = 1'b0;
	if(state_machine == WB_W_WAIT)
	begin
		if(MCYC_O && MACK_I)
			write_done = 1'b1;
	end
end

always@(posedge CLK_I)
begin
		case (next_state)
			WB_IDLE : begin
				if(r_cmnd_flag)
				begin
					r_counter <= r_cnt_reg;
					r_w_addr <= 30'h0;
				end
			end
			WB_READING : begin
				if(MCYC_O && MACK_I)
				begin
					if(r_counter > 0)
					begin
						r_counter <= r_counter - 32'h1;
						r_w_addr <= r_w_addr + 30'h4;
					end
				end
			end
			WB_WRITING : begin
				if(MCYC_O && MACK_I)
				begin
					r_w_addr <= r_w_addr + 29'h4;
					data_sent = ~data_sent;
				end
			end
		endcase
//	end
end

always@(negedge CLK_I)
begin
	case(next_state)
		WB_IDLE: begin
			MADR_O[30:0] <= r_w_addr + tx_b1_offset[30:0];
			MADR_O[31] <= 1'b0;
			MCAB_O <= 1;
			end
		WB_READING: begin
			MADR_O[30:0] <= r_w_addr + tx_b1_offset[30:0];
			MADR_O[31] <= 1'b0;
			MCAB_O <= 1;
			end
		WB_WRITING: begin
			MADR_O[30:0] <= r_w_addr + rx_b1_offset[30:0];
			MADR_O[31] <= 1'b1;
			MCAB_O <= 1;
			end
		WB_INT_ACK: begin
			MADR_O[30:0] <= `ACK_CYC_ADDR;
			MADR_O[31] <= 1'b0;
			MCAB_O <= 0;
			end
		WB_W_WAIT: begin
			MADR_O[30:0] <= tx_b1_offset[30:0] + `DUMMY_READ_ADDR;
			MADR_O[31] <= 1'b0;
			MCAB_O <= 0;
			end
		default: begin
			MADR_O[31:0] <= 0;
			MCAB_O <= 1;
			end
	endcase
end
 
always@(negedge CLK_I)
begin
	if(next_state == WB_IDLE)
	begin
		MSTB_O <= 1'b0;
		MCYC_O <= 1'b0;
	end
	else 
	begin
		MSTB_O <= 1'b1;
		MCYC_O <= 1'b1;
	end
end


always@(r_counter)
begin
	r_counter_empty = (r_counter > 0)? 1'b0 : 1'b1;
end

pulse_gen read_ld_pulse
(
	.Trigger				(r_counter_empty),
	.Pulse_Out			(counter_loaded),
	.Clock				(CLK_I)
);


endmodule
The simulation works ok... but when i implement that on a Spartan III i got a wird behavior on my FSM. For some reason the state keeps jumping from IDLE to READING, and from READING to IDLE, but the r_counter is not moving... so if i write 5 on r_counter.. it stay on 5 but the states keep moving. Any idea of what could couse that? As i do not have chipscope i am using 4 seven seg. display and 3 leds to debug. On the display i am looking to the counter, and at the leds on the first 3 elements of the next_state array, so i can see if it stay at IDLE or READING, but the result is that i can see that the the first and third led are ON, but not wih full power... as it was being driven by a PWM signal, so i could supose that the FSM keeps jumping between both states...

Any help please?

I will not give any further detail now becouse they are irrelevant as all teh rest looks ok, and i can see the r_counter value...

Thank you!
 

Code:
always@(posedge CLK_I)
begin
		state_machine = next_state;
end
You shouldn't do this, as it can break the simulation (but silently). notice that "state_machine" is in other processes also clocked by CLK_I. In this case there is no reason to believe these other blocks are using the correct value for "state_machine". the same goes for every other signal assigned within a clocked always block. you must use non-blocking logic if the signal is to be used outside of the always block. Remember, Verilog doesn't define an execution order for the always blocks -- the program might go from top to bottom, or might maintain a hash table, or might be multi-threaded. This means that the simulation might work once, but not after minor changes are made to the code. It's better to avoid this issue.

you should probably try to avoid making next_state a latch. currently, there are several cases where next_state isn't assigned and gets the default "next_state = next_state", instead of "next_state = state_machine" or "next_state = SOME_STATE".

You should take some time to build some better debug tools. eg, a basic FIFO+RS232. That way you can at least have better access to debugging information. failing that, an oscilloscope would be useful. I don't see any immediate things that would exactly explain your situation.
 
  • Like
Reactions: Sink0

    Sink0

    Points: 2
    Helpful Answer Positive Rating
Damn you are a genious... i forgot to assign a latch on my state machine!! Yea that is the reason for sure... so it always goes to an unknown state and get back to IDLE...

Yea i really should save a time to make a simple serial debug block.. i just dont want to loose time making a simple software to take a look at the data.. any advice on free software that i could digital data from a simple text file?

Hmmm .. about the blocking assignment, thats weird... i would expect that a single statement inside an always block would behave the same if it is blocking or not.. actually, i as was expecting taht it would be treated independently from others blocks.. so it is just considered "blocking inside that specific block"

Any way.. i lost like 2 days on that stupid mistake.. i got a lot of work untill i achieve a good knowhow haha.. thank you!
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top