Оба края Clk в кодировании синтеза VHDL

Стили кодирования синтеза будут реализованы в будущем? Или стандарт IEEE-1076.6-200X теперь позволяет упростить и расширить возможности кодирования синтеза VHDL?

--Multiple Edge Registers
--Copyright © 2004 SynthWorks Design Inc. All Rights Reserved.
DualEdgeFF : process( nReset, Clk1, Clk2)
begin
  if (nReset = '0') then
    Q <= '0' ;
  elsif rising_edge(Clk1) then -- Functional Clock
    Q <= D ;
  elsif rising_edge(Clk2) then -- Scan Clock
    Q <= SD ;
  end if ;
  -- RTL_SYNTHESIS OFF
  if rising_edge(Clk1) and rising_edge(Clk2) then
    report "Warning: . . ." severity warning ;
    Q <= 'X' ;
  end if ;
-- RTL_SYNTHESIS ON
end process;

--Register Using Both Edges of Clk
DualEdge_Proc: process (Clk, Reset) is
begin
  if Reset = '1' then
    Q <= (others => '0');
  elsif rising_edge(Clk) then
    Q <= D4Rise;
  elsif falling_edge(Clk) then
    Q <= D4Fall;
  end if;
end process DualEdge_Proc;

person user2599152    schedule 08.01.2019    source источник
comment
Это не имеет ничего общего со стандартами VHDL, а скорее с тем, существует ли технология, в которой есть регистры, использующие двойные края. Насколько я знаю, в настоящее время нет технологии, которая бы использовала оба фронта тактовых импульсов.   -  person Tricky    schedule 08.01.2019
comment
Как вы думаете, что имел в виду автор, когда публиковал шаблоны с помощью Register Using Both Edges of Clk?   -  person user2599152    schedule 08.01.2019
comment
Это совершенно логичный шаблон, который будет отображаться на флип-флоп с двойным краем. Но в настоящее время их не существует.   -  person Tricky    schedule 08.01.2019
comment
В то время, я думаю, были библиотеки ASIC, в которых часы сканирования BIST были отделены от функциональных часов. Следовательно, это стиль кодирования, который рабочая группа предложила для решения этой проблемы - конечно, если технология не реализует его, разумно ожидать, что код не будет синтезируемым. У меня больше нет ни электронных писем рабочей группы, ни книг данных, поэтому на данный момент у меня уйдет много времени на исследования.   -  person Jim Lewis    schedule 08.01.2019
comment
OTOH, нет никаких оправданий тому, почему поставщики не внедрили стиль кодирования DDR.   -  person Jim Lewis    schedule 08.01.2019
comment
@Сложный. Как насчет двухпортовой оперативной памяти? Смотри ниже   -  person Jim Lewis    schedule 08.01.2019


Ответы (2)


if (nReset = '0') then Q <= '0' ; elsif rising_edge(Clk1) then -- Functional Clock Q <= D ; elsif rising_edge(Clk2) then -- Scan Clock Q <= SD ; end if ;

Это никогда не может сопоставляться ни с чем разумным в реальном мире. Это недопустимый дизайн для синтеза.

if Reset = '1' then Q <= (others => '0'); elsif rising_edge(Clk) then Q <= D4Rise; elsif falling_edge(Clk) then Q <= D4Fall; end if;

Это может сопоставляться с выходным регистром ввода-вывода DDR. У FPGA есть такая возможность, но сегодня инструменты не способны синтезировать этот код. Они могут поддерживать что-то подобное в будущем. Также есть некоторые проблемы, например, D4Fall должен быть перезапущен из домена восходящего края.

В настоящее время вы должны явно создавать экземпляры ячеек DDR для конкретных технологий.

person Timmy Brolin    schedule 08.01.2019
comment
С кодом, который вы отмечаете как недопустимый дизайн для синтеза, если вы удаляете сброс, его можно использовать для двухпортовой оперативной памяти. - person Jim Lewis; 08.01.2019
comment
Я предполагаю, что какой-нибудь инструмент мог бы распознать это как двухпортовую ОЗУ... Но обычный способ моделирования двухпортовой ОЗУ таков: закончить, если; если восходящий_край(Clk2), то Q ‹= SD; закончить, если; - person Timmy Brolin; 27.02.2019
comment
Из семантики инструмента синтеза единственное, что меняется, — это порядок подразумеваемого приоритета. WIth If then else, первая ветвь if имеет приоритет. С if-end if выигрывает последнее присваивание, следовательно, второй оператор if имеет приоритет. - person Jim Lewis; 27.02.2019

Рабочая группа предоставила шаблоны и правила для создания стилей кодирования. В приведенных выше примерах показаны некоторые возможные варианты использования. Конечно, я недавно не видел первый стиль кодирования, хотя, как я уже говорил, я думаю, что в то время я смог найти такой регистр в библиотеке ASIC, которая использовала его для логики сканирования.

Однако сегодня, если мы немного изменим показанный шаблон кода (но все еще совместимый с 1076.6-2004), мы получим кое-что полезное. Примечание. Я заменил «elsif» на «конец, если» и отдельное «если», что является моим предпочтительным способом кодирования.

MemProc : process (ClkA, ClkB)
  type MemType is array (0 to 1023) of std_logic_vector(7 downto 0) ;
  variable Mem : MemType ;
begin
  if rising_edge(ClkA) then
    DataOutA <= Mem(to_integer(unsigned(AddrA))) ;
    if WriteA = '1' then
      Mem(to_integer(unsigned(AddrA))) := DataInA ;
    end if ;
  end if ;
  if rising_edge(ClkB) then
    DataOutB <= Mem(to_integer(unsigned(AddrB))) ;
    if WriteB = '1' then
      Mem(to_integer(unsigned(AddrB))) := DataInB ;
    end if ;
  end if ;
end process ;

Вы также можете подумать, что стиль кодирования, который требуют некоторые поставщики FPGA, не является допустимым для языка. Тип общей переменной должен быть защищенным. Общие переменные с обычными типами были временно разрешены в VHDL-93, но, как отмечено в VHDL-93, это было исправлено в следующей версии VHDL-2000/2002.

Если поставщики FPGA хотят сделать что-то эффективное и легальное для языка, они могут заменить свой незаконный код кодом OSVVM MemoryPkg, чтобы реализовать модели памяти как надлежащий защищенный тип. Причина, по которой я говорю, что это эффективно, заключается в том, что MemoryPkg реализует структуру данных, которая реализует память только по мере ее использования. Вы можете найти OSVVM на github и osvvm.org.

library OSVVM;
use OSVVM.MemoryPkg.all;

architecture ...
  shared variable ptRam : MemoryPType ;
begin
  ptRam.MemInit(
AddrWidth => Address'length, DataWidth => Data'length
) ;

MemAProc : process (ClkA)
begin
  if rising_edge(ClkA) then
    DataOutA <= ptRam.MemRead(AddrA) ; ;
    if WriteA = '1' then
      ptRam.MemWrite(AddrA, DataInA) ;
    end if ;
  end if ;
end process ;

MemBProc : process (ClkB)
begin
  if rising_edge(ClkB) then
    DataOutB <= ptRam.MemRead(AddrB) ; ;
    if WriteB = '1' then
      ptRam.MemWrite(AddrB, DataInB) ;
    end if ;
  end if ;
end process ;

Вы можете сказать, что синтезировать защищенный тип слишком сложно. Простой ответ: вам не нужно. Вы не можете синтезировать большую часть кода ни в std_logic_1164, ни в numeric_std — не верьте мне, попробуйте взять код изrising_edge и использовать все это в операторе if для создания триггера.

person Jim Lewis    schedule 08.01.2019
comment
Afaik, поставщики принимают сигнал вместо общей переменной для вывода ОЗУ. Общая переменная полезна только для определения записи перед чтением ОЗУ. Altera всегда использовала сигнал в своем примере (Xilinx использует общую переменную). Проблема в том, что это законно с VHDL 93 года. Кроме того, в некоторых симуляторах (на самом деле) поведение по умолчанию заключается в том, что отсутствие защищенного типа является лишь предупреждением для обеспечения надлежащей обратной совместимости по умолчанию. Строгий режим необходим для принудительного применения ошибки. - person Tricky; 08.01.2019
comment
Мне повезло с сигналами - может это была Altera, не помню. Однако для этого требуется одна форма процесса. Если вы используете сигналы с несколькими процессами, то это неправильный двойной порт (то есть: запись и чтение с любого порта). - person Jim Lewis; 08.01.2019