Перейти к содержанию
    

При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно.

При объявлении массива указываю атрибут:

attribute syn_ramstyle : string;

attribute syn_ramstyle of data_array_1 : signal is "block_ram";--"no_rw_check";

 

При этом Synplify Pro 8.4 в отчете выдает следующее сообщение:

Could not implement Block RAM. Is the read address registered using the same clock as the RAM?

 

Код примерно следующий:

 

entity name is

clock : in std_logic;

din : in signed( 15 downto 0 );

write : in std_logic;

dout : out signed( 15 downto 0 );

...

end name;

 

architecture name_body of name is

 

subtype data_type is signed( 15 downto 0 );

type data_array_type is array( 0 to 7 ) of data_type;

signal data_array_1 : data_array_type := ( others => to_signed( 0, data_type'length ) );

signal data_array_2 : data_array_type := ...;

attribute syn_ramstyle : string;

attribute syn_ramstyle of data_array_1 : signal is "block_ram";--"no_rw_check";

attribute syn_ramstyle of data_array_2 : signal is "block_ram";--"no_rw_check";

 

signal rd1_addr, wr1_addr : unsigned( 2 downto 0 ) := to_unsigned( 0, 4 );

signal rd2_addr, wr2_addr : unsigned( 2 downto 0 ) := to_unsigned( 0, 4 );

signal A, C : data_type := to_signed( 0, data_type'length );

 

body

 

A <= data_array_1( to_integer( rd1_addr ) );

C <= data_array_2( to_integer( rd2_addr ) );

 

process( reset, clock )

begin

if reset = '1' then

A <= to_signed( 0, data_type'length );

C <= to_signed( 0, data_type'length );

rd1_addr <= ...;

wr1_addr <= ...;

rd2_addr <= ...;

wr2_addr <= ...;

...

elsif rising_edge( clock ) then

dout <= A * C;

if write = '1' then

data_array_1( to_integer( wr1_addr ) ) <= din;

end if;

rd1_addr <= rd1_addr + 1;

wr1_addr <= wr1_addr + 1;

rd2_addr <= rd2_addr + 1;

end if;

end process;

 

end name_body;

 

Как нужно описывать RAM в виде массива, чтобы Synplify сделал из него BlockRAM?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно.

При объявлении массива указываю атрибут:

attribute syn_ramstyle : string;

attribute syn_ramstyle of data_array_1 : signal is "block_ram";--"no_rw_check";

 

При этом Synplify Pro 8.4 в отчете выдает следующее сообщение:

Could not implement Block RAM. Is the read address registered using the same clock as the RAM?

 

Код примерно следующий:

 

entity name is

clock : in std_logic;

din : in signed( 15 downto 0 );

write : in std_logic;

dout : out signed( 15 downto 0 );

...

end name;

 

architecture name_body of name is

 

subtype data_type is signed( 15 downto 0 );

type data_array_type is array( 0 to 7 ) of data_type;

signal data_array_1 : data_array_type := ( others => to_signed( 0, data_type'length ) );

signal data_array_2 : data_array_type := ...;

attribute syn_ramstyle : string;

attribute syn_ramstyle of data_array_1 : signal is "block_ram";--"no_rw_check";

attribute syn_ramstyle of data_array_2 : signal is "block_ram";--"no_rw_check";

 

signal rd1_addr, wr1_addr : unsigned( 2 downto 0 ) := to_unsigned( 0, 4 );

signal rd2_addr, wr2_addr : unsigned( 2 downto 0 ) := to_unsigned( 0, 4 );

signal A, C : data_type := to_signed( 0, data_type'length );

 

body

 

A <= data_array_1( to_integer( rd1_addr ) );

C <= data_array_2( to_integer( rd2_addr ) );

 

process( reset, clock )

begin

if reset = '1' then

A <= to_signed( 0, data_type'length );

C <= to_signed( 0, data_type'length );

rd1_addr <= ...;

wr1_addr <= ...;

rd2_addr <= ...;

wr2_addr <= ...;

...

elsif rising_edge( clock ) then

dout <= A * C;

if write = '1' then

data_array_1( to_integer( wr1_addr ) ) <= din;

end if;

rd1_addr <= rd1_addr + 1;

wr1_addr <= wr1_addr + 1;

rd2_addr <= rd2_addr + 1;

end if;

end process;

 

end name_body;

 

Как нужно описывать RAM в виде массива, чтобы Synplify сделал из него BlockRAM?

 

Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на Synplify, там все достаточно подробно расписано :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проще использовать готовые RAM блоки, рекомендованые под архитектуру спартана. И они сразу будут размещаться в BlockRAM.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

откуда у блочной памяти асинхронные сбросы ?

читаем lib.pdf от хилых про BRAM изучаем

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на Synplify, там все достаточно подробно расписано :)

Да в том то и дело, что не поленился... Может я конечно чего-то недопонимаю...

Пример из файла reference.pdf, стр. 10-84 (документация Synplify):

"Two-write Port RAM Example"

 

WRITE_RAM : process (clk)

begin

if rising_edge(clk) then

if (wren_a = '1') then

mem(to_integer(unsigned(addr_a))) <= data_a;

end if;

if (wren_b='1') then

mem(to_integer(unsigned(addr_b))) <= data_b;

end if;

addr_a_reg <= addr_a;

addr_b_reg <= addr_b;

end if;

end process WRITE_RAM;

q_a <= mem(to_integer(unsigned(addr_a_reg)));

q_b <= mem(to_integer(unsigned(addr_b_reg)));

 

Как видно, чтение ассинхронное.

 

Чтение внутрь процесса вносил (под клок), результат тот же...

 

Что же касается сброса, то он относится не к памяти, а к всему вычислительному блоку (надо же мне както инициализировать сигналы).

 

Готовые RAM блоки, рекомендованые под архитектуру спартана использовать можно, но их тяжеловато подстраивать под конкретный размер массива данных. Я пытался сделать компонент в общем виде под задаваемую разрядность и объем данных.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

какая разница ? вы позволили синтезатору доопределить поведение памяти при сигналах сброса, т.к. память описана в таком процессе. Вот он и доопределил.

Опишите память в отдельных процессах. и будет вам благо. Ест-но латентность памяти на доступ нужно учесть ручками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, что дело еще в:

rd1_addr <= rd1_addr + 1;
wr1_addr <= wr1_addr + 1;
rd2_addr <= rd2_addr + 1;

 

 

Добавьте дополнительные регистры в код :rd1_addr_br,wr1_addr_br,rd2_addr_br и делайте примерно так:

...
--synthesis translate_off
rd1_addr <= ...;
wr1_addr <= ...;
rd2_addr <= ...;
wr2_addr <= ...;
--synthesis translate_on
...
data_array_1( to_integer( wr1_addr_br ) ) <= din;
...
wr1_addr_br<=wr1_addr+1;
wr1_addr<=wr1_addr+1;
...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на Synplify, там все достаточно подробно расписано :)

Да в том то и дело, что не поленился... Может я конечно чего-то недопонимаю...

Пример из файла reference.pdf, стр. 10-84 (документация Synplify):

"Two-write Port RAM Example"

 

WRITE_RAM : process (clk)

begin

if rising_edge(clk) then

if (wren_a = '1') then

mem(to_integer(unsigned(addr_a))) <= data_a;

end if;

if (wren_b='1') then

mem(to_integer(unsigned(addr_b))) <= data_b;

end if;

addr_a_reg <= addr_a;

addr_b_reg <= addr_b;

end if;

end process WRITE_RAM;

q_a <= mem(to_integer(unsigned(addr_a_reg)));

q_b <= mem(to_integer(unsigned(addr_b_reg)));

 

Как видно, чтение ассинхронное.

 

Чтение внутрь процесса вносил (под клок), результат тот же...

 

Обратите внимание, что адрес чтения защелкивается. Посмотрите в документе Synplicity FPGA Synthesis раздел Design Optimization -> Inferring RAMs.

 

Что же касается сброса, то он относится не к памяти, а к всему вычислительному блоку (надо же мне както инициализировать сигналы).

 

Разнесите по разным процессам память и остальную логику.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Извините, что врываюсь...

 

Почему-то никто ни слова не произнес про COREGEN. Это ж самый верный способ получить требуемую память. Прекрасно конфигурируется и заведомо работает. А в Симплифае вставляется как блэк-бокс. Правда, непереносимо. Так и BRAM сама по себе непереносима.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему-то никто ни слова не произнес про COREGEN.

Потому что не удобно.Сегодня я хочу память в 2К слов.Завтра дадут ценное указание и память станет 4К слов.А послезавтра разрядность увеличить придётся.

По мне править код намного проще и удобней, чем занового генерить ядра.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной),

на базе которых можно сделать универсальные параметризиремые (через generic)

бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих

и позволял строить память почти любой конфигурации!).

Для спартанов - тоже не должно быть проблем.

И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво

интерпретируется разными синтезаторами в разных условиях и для

разных (даже слегка разных!) чипов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной),

на базе которых можно сделать универсальные параметризиремые (через generic)

бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих

и позволял строить память почти любой конфигурации!).

Для спартанов - тоже не должно быть проблем.

И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво

интерпретируется разными синтезаторами в разных условиях и для

разных (даже слегка разных!) чипов.

 

Фактически, вы руками доделали некоторую часть работы. Которую запросто мог за вас сделать Кореген. Более того, вам пришлось разбираться с тонкостями использования тех примитивов - причем обременительными тонкостями, типа зануления старших адресов если используется не вся память и построение дешифраторов, если требуется бОльшая. И зачем?! Когда есть кореген, одним движением пальца делающий все это.

 

Насчет переносимости, разных синтезаторов и проч. Сдается мне, что проблему сильно преувеличивают.

 

Не знаю, кто как, но я только один раз кардинально менял окружение. С Леонардо Спектрум для Atmel FPSLIC прыгнул на Spartan2 и XST (ISE). Разумеется, блоки памяти потребовали кардинальной переделки. Которая заключалась всего лишь в генерации оных в Корегене.

Затем перешел на Спартан 3, так ничего и не поменялось. Сгенерировал то же самое в Корегене.

 

А теперь пожалуйста ответьте, как часто вам, уважаемые коллеги, пришлось переходить (в ходе разработки ОДНОГО изделия) на кардинально другие FPGA и кардинально другие синтезаторы?

 

Ото ж... А на рихтовку своих исходников с целью сделать их универсальными вы потратите очень много времени с непредсказуемым результатом. (речь идет об аппаратно-специфических вещах, память, DDR регистры и проч.).

 

Моя идеология проста: делаем на plain VHDL все, что можно. По возможности без атрибутов и прочих бубенцов. Все специфическое включаем в блэк-боксы, их генерируем в целевой среде. Констрейны и прочие весьма зависимые прибамбасы (распиновка, типы выводов и тд) делаем исключительно в целевой среде. И не паримся. При переходе на что-то другое у нас остается везде компилируемый чистый VHDL, блэк-боксы создаем по-новой - тут уж никуда не деться. А констрейны, пинауты и иже с ними в новой среде все равно придется вбивать по-новой. Каламбурчик.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... Фактически, вы руками доделали некоторую часть работы. Которую запросто мог за вас сделать Кореген....

 

... Более того, вам пришлось разбираться с тонкостями использования тех примитивов - причем обременительными тонкостями,....

 

.. А на рихтовку своих исходников с целью сделать их универсальными вы потратите очень много времени с непредсказуемым результатом. (речь идет об аппаратно-специфических вещах, память, DDR регистры и проч.)...

 

ОДИН раз сделал - и больше уже не пришлось делать что-то еще.. Вот уже пару лет как

пользую свою библиотеку памяти для разных проектов. Идея была

создать для зайлинкса такой же набор LPM памяти какая есть у

альтеры. У меня они даже совместимы по entity и generic, так-что можно

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

вашим corgen в такой ситуации.

Coregen (для памяти) - в отстое уже давно. Он явно неудобен, о чем тут

уже говорилось, не стоит об этом спорить.

А с plane (behaviorial) HDL - все равно будут проблемы, и в конце

концов проковыряешся больше, что собственно и доказывают посты

в этой ветке.

 

Нету там никаких особых тонкостей. Только заглянуть пару раз в мануалы,

что никогда не помешает.

 

А времени потратил до смешного немного. Даже удивительно, отчего это

зайлинкс сам не сделал эту работу, например как альтера.

 

Но опять же - на вкус и цвет...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

МОЕ ИМХО на весь этот счет, у памяти 2 конфигурации, 1 чистый бехавор для симуляции и первоначальной сборки (1 раз потратил день на изучение как правильно нужно писать память, после этого ни разу не было проблем при синтезе, для симуляции попробуйте на вставленых БРАМАХ при объеме памяти кил в 100-200 симуляться и натравите профайлер).

2 конфигурация это уже конфигурация сборки, с реальными вставленными брамами, к которым к тому же можно и RLOC/LOC пристегнуть.

Выбор конфигурации в ВХДЛ 1 строка. в том же топ файле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня Spartan2 а не 3, но думаю это непринципиально.

Мне нужно написать двухпортовую RAM с разными клоками на концах

с одной стороны только запись с we а с другой только чтение.

на сайте Xilinx есть примеры описания

НО мне нужна память с разной разрядностью шин на разных портах, там такого нет.

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

Вероятно кто-то уже возился с этим.

Пишу на VHDL, но Verilog тоже прочитаю.

Изменено пользователем qwqw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...