Stack Notes

These notes are to help understand the inside mechanics of a writable computer part, a stack. The stack acts like a deep dual input register (DIR). You write to it and read from it like a register with the difference that values can be pushed into it and then popped out of it in the order that they went in. Hence the nick-name "push-down stack". The block diagram illustrates what the architecture could be, but it is not how it might be when the VHDL code for the part is compiled.

The purple lines are the control lines. The blue lines are the data flow lines. The orange lines are internal control flow for the index into the register array. The DIR, index, register array and flip flop are all clocked on the positive edge.

The push and pop control whether the index into the register array increments, decrements or stays the same. The push signal is captured in the flip flop to write to the register array and select the proper source for the data output. The push signal must be delayed to synchronize it with the data in the DIR and the address in the index register which are also clocked. The delayed push signal selects the output data to be from the DIR and writes the DIR to the register array. The push signal is used to write to the DIR.

If the number of registers in the register array is set to zero, then all the support blocks are not needed, the stack reduces to a DIR and the pop signal is not connected. In the VHDL code, this optimization is done when the generic value for the stack depth is set to zero.


An alternative stateless, implementation for the stack:

In this diagram, the push signal is not delayed since the data and index are not delayed. This implementation has one less flip flop for the push signal but the four to one mux has to pass all the bits in the index register. Comparing it to the previous implementation, only 0, 1 or -1 had to pass through the mux where theoretically only two bits should be required to pass through the mux. The appeal of this implementation is that it is stateless, the data is written to the register array immediately. To allow for one of two locations to be written to (store goes to the current location; push goes to the next location) two addresses must be calculated and the proper one chosen through the mux. Because of this, the register array can't feed the data_out signal directly because it may change locations part way through a cycle when a push or pop signal is applied, so the register array output must be captured in a latch. To allow for reading and writing to the register array, the data must be captured on the same clock edge that it is written to the register array so this requires a mux before the output latch. While this circuit has one less flip flop than the previous one, there are two arithmetic circuits instead of one. The first circuit should be less hardware.


With synchronous RAM, a lot of the design can be absorbed into it.


--------------------------------------------------------------------------	
-- Stack for stack processor  Rob Chapman  Mar 2, 1998
-- Values are pushed onto the stack and popped off when needed.  If push
-- and pop are asserted, then a store is performed.

Library IEEE;
use IEEE.STD_Logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity Stack is

  generic ( width : positive := 8;
            widthad : positive := 3;
			depth : positive := 8 );

  port ( clock, push, pop, d1_d2 : in  std_logic;
         din1, din2              : in  std_logic_vector( width-1 downto 0 );
		 reset 					 : in std_logic;
--		 addressout				 : out std_logic_vector( widthad-1 downto 0 );
         dout                    : out std_logic_vector( width-1 downto 0 ));

end;


architecture behaviour of Stack is

	subtype stackcell is std_logic_vector(width-1 downto 0);

	type  Stack  is array ( depth-1 downto 0 ) of stackcell;    -- basic stack


 -- internal signals

	signal din : stackcell;  -- data input to RAM
	signal index : std_logic_vector(widthad-1 downto 0);
	signal address : std_logic_vector(widthad-1 downto 0);
	signal pushpop : std_logic_vector(1 downto 0);  -- for push&pop
	constant addresszero : std_logic_vector(widthad - 1 downto 0) := (others => '0');

	signal next_out : stackcell;

begin

	-- OUTPUT --
	stack_ram : process(address, din, push, clock ) is
		variable stack_file : Stack;
	begin
		if rising_edge(clock) then
			if push = '1' then
					stack_file(conv_integer(index)) := din;
					next_out <= din;
            else
				next_out <= stack_file(conv_integer(index));
			end if;
		end if;
	end process;

	send_on_falling : process(clock) is
	begin
		if falling_edge(clock) then
			dout <= next_out;
       end if;
  end process;

  -- select the input data --
  process(d1_d2, din1, din2)
  begin

    if  d1_d2 = '0'  then
      din <= din1;
    else
      din <= din2;
    end if;

  end process;


  -- assign push and pop as a control vector
  pushpop(1) <= push;
  pushpop(0) <= pop;


  -- RAM address calculation
  next_address : process(clock, reset) is
  begin
		if reset = '1' then
			address <= addresszero;
		else 
	
	    case pushpop is
	
	      when "10" =>          -- push
	
	        address <= index - 1;  -- subtract one to change the index
	
	      when "01" =>          -- pop
	
	        address <= index + 1;  -- add one to change the index
	
	      when others =>        -- do nothing
	
	        address <= index;
	
	    end case;
	end if;

  end process;


  -- stack address becomes index
  set_index : process(clock, reset) is
  begin
	if reset = '1' then
		index <= addresszero;
	else
	 	if falling_edge(clock) then --   wait until clock = '1';	
		    index <= address;	
		end if;
	end if;

  end process;

end;


This information has been assembled by Rob Chapman for EE552.