Запись файла реестра в VHDL

Я пытаюсь записать регистровый файл на VHDL. Файл содержит 16 64-битных регистров. В каждом цикле считываются два регистра и записывается один регистр (при условии, что запись разрешена). Должен быть обход данных (пересылка), чтобы только что записанное значение направлялось непосредственно на выход, если мы читаем и записываем в / из одного и того же регистра за один цикл.

Моя идея заключалась в том, чтобы писать по переднему фронту и читать по заднему фронту часов, чтобы завершить это за один цикл. Однако мой дизайн не работает (не то, чтобы я ожидал этого, поскольку я не верю, что проверка спадающего фронта в блоке if, который проверяет нарастающий фронт, будет работать должным образом).

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity register_file is   
    port
    (
    outA          : out std_logic_vector(63 downto 0);
    outB          : out std_logic_vector(63 downto 0);
    input         : in  std_logic_vector(63 downto 0);
    writeEnable   : in std_logic;
    regASel       : in std_logic_vector(5 downto 0);
    regBSel       : in std_logic_vector(5 downto 0);
    writeRegSel   : in std_logic_vector(5 downto 0);
    clk           : in std_logic
    );
end register_file;

architecture behavioral of register_file is
type registerFile is array(0 to 15) of std_logic_vector(63 downto 0);
signal registers : registerFile;
begin

    regFile: process(clk)
    begin
        if rising_edge(clk) then 
            if(writeEnable = '1') then
                registers(to_integer(unsigned(writeRegSel))) <= input;
            end if;
            if falling_edge(clk) then
                outA <= registers(to_integer(unsigned(regASel)));
                outB <= registers(to_integer(unsigned(regBSel)));
            end if;
        end if;
        if falling_edge(clk) then
                outA <= registers(to_integer(unsigned(regASel)));
                outB <= registers(to_integer(unsigned(regBSel)));
        end if;
    end process;
end behavioral;

Любая помощь будет оценена по достоинству.


person audiFanatic    schedule 12.11.2013    source источник
comment
Если вам нужно только 16 (2 ^ 4) регистров, тогда почему у вас есть 6-битная адресная строка, дающая вам 64 (2 ^ 6) возможных комбинаций?   -  person Daniel Kamil Kozar    schedule 13.11.2013
comment
да, ты прав. Я думаю, что сделал это просто по привычке из работы с MIPS   -  person audiFanatic    schedule 13.11.2013


Ответы (2)


Представленный код VHDL имеет конструкцию:

...
if rising_edge(clk) then
  ...
  if falling_edge(clk) then
  ...

Это оставит мертвый код, поскольку и rising_edge, и falling_edge не могут быть истинными одновременно. Кроме того, идея использования как нарастающего, так и спадающего фронта часто вызывает проблемы при проектировании и синтезе.

Для лучшей синхронизации и простоты проектирования и синтеза я предлагаю использовать только нарастающий фронт, если только использование как нарастающего, так и спадающего фронта не является обязательным.

При обходе записи данных для чтения A и B в одном цикле регистровый файл может выглядеть так:

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

entity register_file is
  port(
    outA        : out std_logic_vector(63 downto 0);
    outB        : out std_logic_vector(63 downto 0);
    input       : in  std_logic_vector(63 downto 0);
    writeEnable : in  std_logic;
    regASel     : in  std_logic_vector(3 downto 0);
    regBSel     : in  std_logic_vector(3 downto 0);
    writeRegSel : in  std_logic_vector(3 downto 0);
    clk         : in  std_logic
    );
end register_file;


architecture behavioral of register_file is
  type registerFile is array(0 to 15) of std_logic_vector(63 downto 0);
  signal registers : registerFile;
begin
  regFile : process (clk) is
  begin
    if rising_edge(clk) then
      -- Read A and B before bypass
      outA <= registers(to_integer(unsigned(regASel)));
      outB <= registers(to_integer(unsigned(regBSel)));
      -- Write and bypass
      if writeEnable = '1' then
        registers(to_integer(unsigned(writeRegSel))) <= input;  -- Write
        if regASel = writeRegSel then  -- Bypass for read A
          outA <= input;
        end if;
        if regBSel = writeRegSel then  -- Bypass for read B
          outB <= input;
        end if;
      end if;
    end if;
  end process;
end behavioral;

Обратите внимание, что «адрес» в * Sel уменьшен только до 4 бит, чтобы соответствовать 16 обязательным записям в регистровом файле, как также указывает Даниэль Камил Козар.

При моделировании нет проверки значений X, но при необходимости ее можно добавить с помощью функции Is_X.

person Morten Zilmer    schedule 13.11.2013

В подавляющем большинстве случаев у вас не может быть ни нарастающего, ни спадающего фронта процесса, так как в (большинстве) устройств, на которые вы нацеливаетесь, нет элементов, которые могли бы реагировать на обоих фронтах. (Единственным исключением являются триггеры ввода-вывода в устройствах, которые поддерживают ввод-вывод с двойной скоростью передачи данных).

Если вы хотите иметь обход, то закодируйте его явно в рамках обычного процесса нарастающего фронта:

outa <= registers(to_integer(...etc));
if write_enable = '1' and regAsel = writeregsel then 
   outa <= input;
end if;
-- similar for regb  

Кроме того, почему бы не сделать ваши входные данные regsel типа integer или, по крайней мере, unsigned - учитывая, что они определенно представляют собой число (а не просто произвольный пакет битов, как в случае ваших векторов ввода-вывода данных)?

person Martin Thompson    schedule 14.11.2013
comment
Использование integer в качестве типа для regsel устранит возможность неопределенных (X) значений в моделировании с риском скрытия проблем с неопределенными значениями, которые в противном случае могут быть замечены во время моделирования. Использование unsigned допускает неопределенные значения, но вопрос в том, считают ли модули, которые создают экземпляр регистрового файла, regsel чем-нибудь, кроме мешка битов. Таким образом, использование std_logic_vector - это общий подход, который откладывает преобразование до определенного контекста. - person Morten Zilmer; 15.11.2013
comment
@MortenZdk - вы указываете на правильный подход к дизайну. Мне нравится делать вещи максимально конкретными, начиная с максимально возможной высоты. Я не могу представить себе дизайн, в котором что-то, выбирающее регистр лично, было бы отличным от числа, но каждый свое :) Педант во мне также вынужден указать, что X не является неопределенным, это конфликтующий < / i> драйвер (который завершился бы ошибкой во время разработки, если бы использовался integer). U - неопределенное (или технически неинициализированное) значение - я уверен, вы это знали, но я укажу на это будущим читателям :) - person Martin Thompson; 15.11.2013
comment
Спасибо за ваши комментарии :-) - person Morten Zilmer; 15.11.2013