September 03, 2011

Счетчик команд + внутренний стек

   Недавно возникла задача создать счетчик команд (instruction pointer, IP):

  Сигналы:
  1. I_CLK    -- сигнал синхросерии
  2. I_RST    -- сигнал сброса
  3. I_F      -- 3-х битная функция. Значения:        
            
    -- 000 : ожидание
             -- 001 : увеличение текущего адреса на 1
             -- 010 : текущий адрес+1 занести в стек
             --       установить текущий адрес равным
             --       I_ADDR
             -- 011 : взять текущее значение адреса из
             --       стека
             -- 100 : установить текущий адрес равным
             --       I_ADDR
             -- 101 : прибавить к текущему значению
             --       адреса значение смещения

  4. I_ADDR   -- входной 11-ти разрядный адрес перехода
  5. I_OFFSET -- входное 10-ти разрядное смещение
             -- старший бит отвечает за знак
  6. O_ADDR   -- выходной 11-ти разрядный адрес
    Структура счетчика без линий функции F выглядит так:


   Поначалу долго парился. Пытался как можно больше описать структурно. Получилось даже стек описать. Он даже правильно работал. Когда дошла очередь до управления стеком из счетчика команд, то начали тихонько плавиться мозги. Структурно связать несколько компонент не сложно. Сложно заставить это всё выдавать результат в течении одного цикла, а так же заставить одни компоненты управлять другими, когда все они имеют общий сигнал синхросерии. Наверно, не дорос я еще до такого. Короче, почувствовал себя УГ и решил описать с помощью поведенческой модели. Вот что вышло:

  1. ---------------------------------------------------------------------------------
  2. -- Instruction pointer with 32-depth stack
  3. -- F values:
  4. -- 000 : do nothing
  5. -- 001 : increment current address
  6. -- 010 : push current address+1 to stack. Set current address = I_ADDR
  7. -- 011 : pop value from stack to current address
  8. -- 100 : set current address = I_ADDR
  9. -- 101 : add to current address I_OFFSET value. I_OFFSET is signed
  10. ---------------------------------------------------------------------------------
  11. library IEEE;
  12. use IEEE.STD_LOGIC_1164.ALL;
  13. use IEEE.STD_LOGIC_ARITH.ALL;
  14. entity IP is
  15.     port (
  16.         I_CLK   :   in  STD_LOGIC;                      -- clock
  17.         I_RST   :   in  STD_LOGIC;                      -- reset
  18.         F       :   in  STD_LOGIC_VECTOR (2 downto 0);  -- function
  19.         I_ADDR  :   in  STD_LOGIC_VECTOR (10 downto 0); -- immediate address
  20.         I_OFFSET :  in  SIGNED (9 downto 0);            -- address' offset
  21.         O_ADDR  :   out STD_LOGIC_VECTOR (10 downto 0));-- output address
  22. end IP;
  23. architecture Behavioral of IP is
  24.    
  25.     type MATRIX32x11 is array(31 downto 0) of STD_LOGIC_VECTOR (10 downto 0);
  26.    
  27.     signal ST_body      : MATRIX32x11 := (others=> (others=>'0'));
  28.     signal ST_ptr       : integer range 0 to 31 := 0;
  29.    
  30.     signal L_addr       : STD_LOGIC_VECTOR (10 downto 0) := (others => '0');
  31.     signal L_addr_next  : STD_LOGIC_VECTOR (10 downto 0) := (others => '0');
  32. begin
  33.    
  34.     L_addr_proc: process(L_addr)
  35.     begin
  36.         L_addr_next <= conv_std_logic_vector(UNSIGNED(L_addr) + 1, 11);
  37.     end process;
  38.    
  39.     main: process(I_CLK, I_RST)
  40.     begin
  41.         if (I_RST='1') then
  42.             ST_ptr <= 0;
  43.             L_addr <= (others => '0');
  44.         elsif(I_CLK='1' and I_CLK'event) then
  45.             case f is
  46.                 when "001" => L_addr <= L_addr_next;
  47.                 when "010" =>
  48.                     ST_body(ST_ptr) <= L_addr_next;
  49.                     L_addr <= I_addr;
  50.                     ST_ptr <= ST_ptr + 1;
  51.                 when "011" =>
  52.                     L_addr <= ST_body(ST_ptr - 1);
  53.                     ST_ptr <= ST_ptr - 1;
  54.                 when "100" => L_addr <= I_addr;
  55.                 when "101" =>
  56.                     L_addr <= conv_std_logic_vector(SIGNED(L_addr) + I_OFFSET, 11);
  57.                 when others => NULL;
  58.             end case;
  59.         end if;
  60.     end process;
  61.    
  62.     O_addr <= L_addr;
  63. end Behavioral;

   Переполнение, опустошение стека, а так же выход за границы адресного пространства не учитываются. Результаты тестирования приведены ниже.


   Описание теста (по значениям управляющей функции):
  1. 0 : ожидание
  2. 1 : инкремент адреса
  3. 4 : установка адреса с I_ADDR (число 9)
  4. 1 : инкремент адреса
  5. 2 : запись следующего значения адреса в стек (число 14) и установка адреса с I_ADDR (число 9)
  6. 1 : инкремент адреса
  7. 3 : возврат адреса из стека (число 14)
  8. 1 : инкремент адреса
  9. 5 : прибавление к текущему абсолютному адресу смещение с I_OFFSET (число -4 в дополнительном коде, т.е. 1111111100)
  10. 1 : инкремент адреса
   Исходники можно забрать здесь.

No comments:

Post a Comment