реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Block RAM на VHDL в Spartan3, Could not implement Block RAM. Is the read address registered using th
Vadim_nsk
сообщение Jun 28 2006, 09:38
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 7-09-05
Из: г. Новосибирск
Пользователь №: 8 335



При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно.
При объявлении массива указываю атрибут:
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?
Go to the top of the page
 
+Quote Post
oval
сообщение Jun 28 2006, 09:43
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 265
Регистрация: 15-03-05
Из: Москва
Пользователь №: 3 367



Цитата(Vadim_nsk @ Jun 28 2006, 13:38) *
При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно.
При объявлении массива указываю атрибут:
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, там все достаточно подробно расписано smile.gif
Go to the top of the page
 
+Quote Post
avesat
сообщение Jun 28 2006, 10:03
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 14-08-05
Из: Украина
Пользователь №: 7 621



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


--------------------
"Мы будем играть, пока не треснут наши гитары, и все те, кто любит рок - я отдаю вам честь!" AC/DC
Go to the top of the page
 
+Quote Post
des00
сообщение Jun 28 2006, 10:44
Сообщение #4


Вечный ламер
******

Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453



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


--------------------
Go to the top of the page
 
+Quote Post
Vadim_nsk
сообщение Jun 28 2006, 11:47
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 7-09-05
Из: г. Новосибирск
Пользователь №: 8 335



Цитата(oval @ Jun 28 2006, 16:43) *
Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на Synplify, там все достаточно подробно расписано smile.gif

Да в том то и дело, что не поленился... Может я конечно чего-то недопонимаю...
Пример из файла 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 блоки, рекомендованые под архитектуру спартана использовать можно, но их тяжеловато подстраивать под конкретный размер массива данных. Я пытался сделать компонент в общем виде под задаваемую разрядность и объем данных.
Go to the top of the page
 
+Quote Post
des00
сообщение Jun 28 2006, 12:07
Сообщение #6


Вечный ламер
******

Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453



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


--------------------
Go to the top of the page
 
+Quote Post
vetal
сообщение Jun 28 2006, 12:09
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 2 095
Регистрация: 27-08-04
Из: Россия, СПб
Пользователь №: 553



Возможно, что дело еще в:
Код
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;
...
Go to the top of the page
 
+Quote Post
oval
сообщение Jun 28 2006, 12:16
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 265
Регистрация: 15-03-05
Из: Москва
Пользователь №: 3 367



Цитата(Vadim_nsk @ Jun 28 2006, 15:47) *
Цитата(oval @ Jun 28 2006, 16:43) *
Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на Synplify, там все достаточно подробно расписано smile.gif

Да в том то и дело, что не поленился... Может я конечно чего-то недопонимаю...
Пример из файла 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.

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


Разнесите по разным процессам память и остальную логику.
Go to the top of the page
 
+Quote Post
Gorby
сообщение Jun 28 2006, 12:16
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 449
Регистрация: 28-10-04
Из: Украина
Пользователь №: 1 002



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

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


--------------------
Умею молчать на 37 языках...
Go to the top of the page
 
+Quote Post
Mad Makc
сообщение Jun 28 2006, 13:11
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 244
Регистрация: 2-10-04
Из: Мухосранска
Пользователь №: 763



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

Потому что не удобно.Сегодня я хочу память в 2К слов.Завтра дадут ценное указание и память станет 4К слов.А послезавтра разрядность увеличить придётся.
По мне править код намного проще и удобней, чем занового генерить ядра.
Go to the top of the page
 
+Quote Post
Wild
сообщение Jun 29 2006, 11:54
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 216
Регистрация: 26-05-06
Из: Коломна
Пользователь №: 17 479



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

Сообщение отредактировал Wild - Jun 29 2006, 11:55
Go to the top of the page
 
+Quote Post
maior
сообщение Jun 29 2006, 14:26
Сообщение #12


Частый гость
**

Группа: Свой
Сообщений: 177
Регистрация: 21-10-04
Пользователь №: 948



Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной),
на базе которых можно сделать универсальные параметризиремые (через generic)
бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих
и позволял строить память почти любой конфигурации!).
Для спартанов - тоже не должно быть проблем.
И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво
интерпретируется разными синтезаторами в разных условиях и для
разных (даже слегка разных!) чипов.
Go to the top of the page
 
+Quote Post
Gorby
сообщение Jun 30 2006, 09:32
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 449
Регистрация: 28-10-04
Из: Украина
Пользователь №: 1 002



Цитата(maior @ Jun 29 2006, 18:26) *
Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной),
на базе которых можно сделать универсальные параметризиремые (через generic)
бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих
и позволял строить память почти любой конфигурации!).
Для спартанов - тоже не должно быть проблем.
И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво
интерпретируется разными синтезаторами в разных условиях и для
разных (даже слегка разных!) чипов.


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

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

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

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

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

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


--------------------
Умею молчать на 37 языках...
Go to the top of the page
 
+Quote Post
maior
сообщение Jun 30 2006, 12:58
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 177
Регистрация: 21-10-04
Пользователь №: 948



Цитата(Gorby @ Jun 30 2006, 13:32) *
... Фактически, вы руками доделали некоторую часть работы. Которую запросто мог за вас сделать Кореген....

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

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


ОДИН раз сделал - и больше уже не пришлось делать что-то еще.. Вот уже пару лет как
пользую свою библиотеку памяти для разных проектов. Идея была
создать для зайлинкса такой же набор LPM памяти какая есть у
альтеры. У меня они даже совместимы по entity и generic, так-что можно
прыгать с зайлинкса на альтеру без труда. Посмотрел бы я на вас с
вашим corgen в такой ситуации.
Coregen (для памяти) - в отстое уже давно. Он явно неудобен, о чем тут
уже говорилось, не стоит об этом спорить.
А с plane (behaviorial) HDL - все равно будут проблемы, и в конце
концов проковыряешся больше, что собственно и доказывают посты
в этой ветке.

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

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

Но опять же - на вкус и цвет...
Go to the top of the page
 
+Quote Post
des00
сообщение Jul 1 2006, 06:42
Сообщение #15


Вечный ламер
******

Группа: Модераторы
Сообщений: 7 248
Регистрация: 18-03-05
Из: Томск
Пользователь №: 3 453



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


--------------------
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 13th July 2025 - 08:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.01477 секунд с 7
ELECTRONIX ©2004-2016