0

I have a VHDL stack machine which by having a push it has to reflect it at the following clock cycle, but it no reflects the value pushed, the outputs are the following:

Outputs

and the code is:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.defs.all;

entity stack is

  generic (
    size : natural := 1024);            
-- Maximum number of operands on stack

  port (
    clk       : in  std_logic;
    rst       : in  std_logic;
    value_in  : in  operand_t;
    push      : in  std_logic;
    pop       : in  std_logic;
    top       : out operand_t);

end entity stack;

architecture behavioural of stack is
    type mem_type is array (255 downto 0) of std_logic_vector(7 downto 0);
    signal stack_mem : mem_type := (others => (others => '0'));
    signal stack_ptr : integer := 255;
  -- Fill in type and signal declarations here.
begin  
-- architecture behavioural


    PUSH_POP : process(clk,push,rst)

    begin
        if (rst = '1' ) then
            top <= (OTHERS => '0');
        end if;

        if(rising_edge(clk)) then

        --push data, only if that is the signal and we do not reset
            if (rst = '0' and push = '1') then
                --Data pushed to the current address.
                stack_mem(stack_ptr) <= value_in; 

                if(stack_ptr /= 0) then
                    top <=  stack_mem(stack_ptr); 
                    stack_ptr <= stack_ptr - 1;
                end if; 

            end if;

        -- pop data only if that is the signal and we do not reset
            if (rst = '0' and pop = '1' ) then
        --Data has to be taken from the next highest address(empty descending type stack). 
                if(stack_ptr /= 255) then   
                    top <= stack_mem(stack_ptr+1); 
                    stack_ptr <= stack_ptr + 1;
                end if; 
            end if;

        end if; 

    end process;

end architecture behavioural;

and the test bench is here:

library ieee;
use ieee.std_logic_1164.all;
use work.defs.all;
use work.testutil.all;
-------------------------------------------------------------------------------

entity stack_tb is

end entity stack_tb;

-------------------------------------------------------------------------------

architecture behavioural of stack_tb is

  -- component generics
  constant size : natural := 1024;

  -- component ports
  signal rst      : std_logic := '0';
  signal value_in : operand_t := (others => '0');
  signal push     : std_logic := '0';
  signal pop      : std_logic := '0';
  signal top      : operand_t;

  -- clock
  constant clk_period : time := 20 ns;
  signal clk : std_logic := '1';

begin  -- architecture behavioural

  -- component instantiation
  DUT: entity work.stack
    generic map (
      size => size)
    port map (
      clk      => clk,
      rst      => rst,
      value_in => value_in,
      push     => push,
      pop      => pop,
      top      => top);

  -- clock generation
  clk <= not clk after clk_period/2;

  -- waveform generation
  WaveGen_Proc: process
  begin
    -- insert signal assignments here
    wait for clk_period/4;
    rst <= '1';
    wait for clk_period;
    rst <= '0';
    wait for clk_period;
    check(top = x"00", "Top value should be zero after reset");
    report "Test 1 passed" severity note;

    value_in <= x"EF";
    push <= '1';
    check(top = x"00",
          "Top value should not be updated immediately after push");
    report "Test 2 passed" severity note;
    wait for clk_period;
    push <= '0';
    check(top = x"EF", "Top value should be reflected one cycle after push");
    report "Test 3 passed" severity note;

pop <= '1';
check(top = x"EF", "Top value should not be updated immediately after pop");
report "Test 4 passed" severity note;

wait for clk_period;
pop <= '0';
check(top = x"00", "Top value should be reflected on cycle after pop");
report "Test 5 passed" severity note;

value_in <= x"ED";
push <= '1';
wait for clk_period;

value_in <= x"23";
wait for clk_period;
check(top = x"23", "push number 2 in a row should work");
report "Test 6 passed" severity note;

value_in <= x"67";
wait for clk_period;
check(top = x"67", "push number 3 in a row should work");
report "Test 7 passed" severity note;

value_in <= x"F4";
wait for clk_period;
check(top = x"F4", "push number 4 in a row should work");
report "Test 8 passed" severity note;

value_in <= x"AA";
wait for clk_period;
check(top = x"AA", "push number 5 in a row should work");
report "Test 9 passed" severity note;

push <= '0';
pop <= '1';
wait for clk_period;
check(top = x"F4", "pop number 1 in a row should work");
report "Test 10 passed" severity note;

wait for clk_period;
check(top = x"67", "pop number 2 in a row should work");
report "Test 11 passed" severity note;

wait for clk_period;
check(top = x"23", "pop number 3 in a row should work");
report "Test 12 passed" severity note;

wait for clk_period;
check(top = x"ED", "pop number 4 in a row should work");
report "Test 13 passed" severity note;

wait for clk_period;
check(top = x"00", "pop number 5 in a row should work");
report "Test 14 passed" severity note;

wait until clk = '1';
assert false report "TEST SUCCESS" severity failure;
  end process WaveGen_Proc;



end architecture behavioural;

-------------------------------------------------------------------------------

configuration stack_tb_behavioural_cfg of stack_tb is
  for behavioural
  end for;
end stack_tb_behavioural_cfg;

-------------------------------------------------------------------------------
Narry
  • 3
  • 4
  • And the testbench is where? –  Sep 17 '16 at 13:13
  • @BrianDrummond i have upload the test bench thanks – Narry Sep 17 '16 at 13:23
  • Your still missing the source for packages defs (type declaration for operand_t) and testutil (procedure check). Does this [waveform image](http://i.stack.imgur.com/1phRm.png) show the behavior you're after? –  Sep 18 '16 at 13:24

1 Answers1

1

Whats wrong

There appear to be two basic issues in your waveform:

waveform accompanying question

First, assuming this is a push down stack (and stack_ptr operates this way) top doesn't contain the 'top of the stack' value for each push onto the stack. You'll note when successive pops happen it does show each stack value once past the second problem described next. Fixing the first problem shows this clearly. Fixing the first problem impacts the solution to the second problem.

Second, There's a delay where the top value doesn't show the top of the stack during the first pop operation. This is caused by the first problem, and if you look during the next clock clock the current top of the stack value is displayed in the second clock. If you fix the first problem this would show that the top value is displayed for two successive pop operations.

The second problem comes about because the stack pointer is oriented to the next address to write during push operations, while during pop operations it's oriented to one higher. The stack pointer (and the top value) need to be oriented to the stack pointer - 2 for the first pop operation following a push (except when there is only one value on the stack).

Fixing the two problems

Your code in your question isn't quite a Minimal, Complete, and Verifiable example missing the source for package defs (the declaration for type operand_t, recoverable from reading your code and your waveform) and package testutil (the declaration and subprogram body for procedure check). These can be dummied up and your testbench run.

The changes

A single if statement is used for the reset and rising_edge clock to match among other things the recommended way of describing edge triggered sequential logic with an asynchronous reset. The rising edge test is now an elsif condition.

This also points out that push doesn't need to be in the sensitivity list, it's only evaluated inside the if statement condition rising_edge(clk). Additionally stack_ptr is reset to the top of stack memory. There's also some verbose conditions that were streamlined.

For every push operation top is loaded with value_in.

A new signal is added called push_last which is used to signal the first pop operation should use an offset of two instead of one. There's also a condition added to determine there's two values on the stack. Otherwise the pop operation or successive pop operation's stack and top are loaded with an offset toward the top of stack memory of only one.

    signal stack_ptr:  integer := 255;
    signal push_last:   std_logic;   -- signals need to adjust stack_ptr for pop
begin  

PUSH_POP:  
    process  (clk, rst) -- WAS (clk, push, rst) CHANGED
    begin
        if rst = '1' then
            top <= (others => '0');
            stack_ptr <= 255;        -- ADDED  
            push_last <= '0';        -- ADDED
        -- WAS end if;                  REMOVED
        elsif rising_edge(clk) then  -- CHANGED WAS if rising_edge
            if push = '1' then -- WAS rst = '0' and push = '1' then CHANGED
                push_last <= '1';    -- ADDED push_last FF
                stack_mem(stack_ptr) <= value_in; 
                if stack_ptr /= 0 then
                    -- top <=  stack_mem(stack_ptr);   -- CHANGED FROM
                    top <= value_in;    -- save to top register CHANGED TO
                    stack_ptr <= stack_ptr - 1;
                end if; 
            end if;
            if pop = '1' then -- WAS rst = '0' and pop = '1' then CHANGED
                push_last <= '0';
                if stack_ptr /= 255 then   
                    if push_last = '1' and stack_ptr /= 254 then -- ADDED
                        top <= stack_mem(stack_ptr + 2);         -- ADDED
                         stack_ptr <= stack_ptr + 2;             -- ADDED
                    else                                         -- CHANGED
                        top <= stack_mem(stack_ptr + 1);
                        stack_ptr <= stack_ptr + 1;
                    end if;                                      -- ADDED
                end if; 
            end if;                              
        end if; 
    end process;

Also note that your size generic is actually not used (as yet) in your model.

And this gives:

stack_tb_fix.png

Where Marker A shows the push_last inspired update of top and stack_ptr and Marker B shows that it doesn't occur when the stack is within two of stack_mem'high.

The simulator used allows and the waveform display supports peering into array values, and the stack_mem locations used in the simulation are displayed.

The impact of having three offset values for stack_ptr's next value should be fairly minimal.

You could note that without the actual procedure check changes to your testbench couldn't be recommended.

Community
  • 1
  • 1