Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17049 Discussions

state machine not holding variable value outside state

Altera_Forum
Honored Contributor II
2,135 Views

I'm trying to build a RAM function that will write data to RAM then take the average of the array for N samples. 

 

My current problem is that (in simulation) I cannot get variables to hold their value outside the states where their value is explicitly stated (i.e. sum := 0). This is causing an issue with the sum variable as I cannot calculate the sum of the array.  

 

I suspect that this issue is the result of the way I have my state machine setup.  

 

I'm also having issues with zero time oscillations when i use the statement sum := sum + ram_data. I can see how this would cause the osculations however i have seen this method used to increment a variable so I'm confused as to why it cannot be used to add something other than a constant to a variable.  

 

I apologize for portions of the code being awkward. I've been beating my head and trying different things for a while.  

 

 

library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.Numeric_Std.all; entity WriteAverage is port( Dready, Sclk, reset: in std_logic; Data: in std_logic_vector (15 downto 0); RDataIn: in std_logic_vector (15 downto 0); Nsamples: in std_logic_vector (7 downto 0); Raddr: out std_logic_vector (7 downto 0); Rdata: out std_logic_vector (15 downto 0); Average: out std_logic_vector (15 downto 0); Rclk, We, AvgDone: out std_logic; state: out std_logic_vector (3 downto 0); test2, sum_temp_out:out std_logic_vector (15 downto 0); test: out std_logic_vector (7 downto 0) ); end; architecture state of WriteAverage is signal Next_state : integer range 0 to 15; signal Current_state : integer range 0 to 15; begin state <= (std_logic_vector(to_unsigned(current_state, 4))); PROCESS (Sclk, Next_state) BEGIN IF (reset = '0') THEN -- if we get a reset input from the blue push button, return to the idle state at any time Current_state <= 0; ELSIF (rising_edge (Sclk)) THEN Current_state <= Next_state; END IF; END PROCESS; PROCESS(Sclk, Dready, Data, NSamples, RDataIn) variable Waddress :integer range 0 to 255; --write addr location variable Waddress_temp :integer range 0 to 255; variable Raddress :integer range 0 to 255; --read addr location variable Raddress_temp :integer range 0 to 255; variable Nsamples_int :integer range 0 to 255; variable sum :integer range 0 to 16777215; variable sum_temp1, sum_temp2 :integer range 0 to 16777215; variable avg :integer range 0 to 16777215; Begin Next_state <= Current_state; Nsamples_int := 2; --to_integer(unsigned(Nsamples)); test <= RDataIn (7 downto 0); test2 <= (std_logic_vector(to_unsigned(sum, 16))); sum_temp_out <= (std_logic_vector(to_unsigned(sum_temp1, 16))); Rclk <= '0'; if (current_state = 0) then --reset state machine waddress := 0; --reset write address Next_state <= 1; elsif (Current_state = 1)then --idle We <= '1'; --enable RAM write Raddress := 0; --set initial read addr = 0 Raddress_temp := 0; avg := 0; --reset average sum := 0; --reset sum of array AvgDone <= '0'; if (Dready ='0') then --for testing, was 1 Next_state <= 2; end if; elsif (Current_state =2) then Rdata <= Data; --ram data = data input if (Waddress = Nsamples_int) then --if write addres = max address... Waddress := 0; --loop to top of array end if; Raddr <= (std_logic_vector(to_unsigned(Waddress, 8))); --ram addr = write address Next_state <= 3; elsif (Current_state = 3) then Rclk <= '1'; --clk ram Waddress_temp := Waddress; --part 1 incrimenting write address, trying to prevent zero time oscilation Next_state <= 4; elsif (Current_state = 4) then We <= '0'; --enable ram read waddress := Waddress_temp + 1; --part 2 incriment write address Next_state <= 5; elsif (Current_state = 5) then --doing nothing ATM Next_state <= 6; elsif (Current_state = 6) then --if (Raddress = Nsamples_int) then --comented out for testing -- Next_state <= 10; --if read address = aray siize finish sum of array --else Next_state <= 7; --end if; elsif (Current_state = 7) then Raddr <= (std_logic_vector(to_unsigned(Raddress, 8))); --ram addr = next array location to be read Next_state <= 8; elsif (Current_state = 8) then Rclk <= '1'; --clk ram Raddress_temp := raddress; --part 1 readd addr incriment, trying to prevent z-time osc sum_temp2 := sum; --trying to add ram data to sum of array sum_temp1 := to_integer(unsigned(RDataIn)); --trying to add ram data to sum Next_state <= 9; elsif (Current_state = 9) then sum := sum_temp2 + sum_temp1; --trying to add ram data to sum Raddress := Raddress_temp + 1; --go to next ram address Next_state <= 6; elsif (Current_state = 10) then avg := sum / Nsamples_int; --average sum of array Average <= std_logic_vector(to_unsigned(sum, 16)); --output avg AvgDone <= '1'; Next_state <= 11; elsif (Current_state = 11) then --wait for Dready = 0 before idle if (Dready = '1') then --for testing, was 0 Next_state <= 1; --go to idle end if; end if; END PROCESS; END;
0 Kudos
3 Replies
Altera_Forum
Honored Contributor II
870 Views

Following the behavior of your code is difficult (for me at least) due to your use of a large collection of signals in the sensitivity list. Try working with just one process using the following framework: 

PROCESS (Sclk, reset ) --do not add items here BEGIN IF (reset = '0') THEN --put everything you want to initialize/re-initialize here ELSIF (rising_edge (Sclk)) THEN --put ALL of your other code here END IF; END PROCESS; 

 

Using this framework, your debugging should go much smoother. As a side note, I normally don't use variables if I can help it. It makes the logic much easier to follow for me.
0 Kudos
Altera_Forum
Honored Contributor II
870 Views

the problem is all of your outputs are in the asynchronous process, and as such you will create latches which are frownd upon, and things like counters should never be in an asynchronous process. 

 

Id go with what Kosh says - go with the single process state machine format - forget the old fashioned tutorials that show the 2 state machine process - its a little old hat.
0 Kudos
Altera_Forum
Honored Contributor II
870 Views

I beg to differ: there is nothing wrong using the 2-process state machine approach nor with using variables. You just have to be careful. 

 

The 2-process state machine, maybe be old but certainly not out of fashion. It allows you to generate both combinatorial and synchronous outputs. If you use the 1-process synchronous approach and you need combinatorial outputs, e.g. a master state machine controlling a number of slave state machines or stimulating an external device, you still have to create a second combinatorial process where you have to decode the same conditions as in the synchronous process. I do agree that we may not need combinatorial signals that often. 

 

Variables, local to the process, are fine but you must of course be fully aware of the behaviour of a variable in VHDL. You could compare it to the variable in a C function, which doesn't hold its value between calls. If that is necessary you have to use either a global variable (a signal in VHDL) or the 'static' attribute (no matching VHDL construct) to preserve the value until the next call. In VHDL a process is activated for every change in the sensitivity list, which is kind of analogous to calling a C-function. If you need persistence e.g. a counter you cannot use a variable but resort to a signal (declared outside the process).
0 Kudos
Reply