Vadim_nsk 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно. При объявлении массива указываю атрибут: 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? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
oval 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба При описании памяти как массива производится чтение и запись по разным адресам, при этом чтение производится ассинхронно, а запись синхронно. При объявлении массива указываю атрибут: 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, там все достаточно подробно расписано :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
avesat 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Проще использовать готовые RAM блоки, рекомендованые под архитектуру спартана. И они сразу будут размещаться в BlockRAM. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба откуда у блочной памяти асинхронные сбросы ? читаем lib.pdf от хилых про BRAM изучаем Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vadim_nsk 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на 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 блоки, рекомендованые под архитектуру спартана использовать можно, но их тяжеловато подстраивать под конкретный размер массива данных. Я пытался сделать компонент в общем виде под задаваемую разрядность и объем данных. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба какая разница ? вы позволили синтезатору доопределить поведение памяти при сигналах сброса, т.к. память описана в таком процессе. Вот он и доопределил. Опишите память в отдельных процессах. и будет вам благо. Ест-но латентность памяти на доступ нужно учесть ручками. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vetal 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Возможно, что дело еще в: 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; ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
oval 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Канал чтения должен быть также синхронным. Не поленитесь, посмотрите в документацию на 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. Что же касается сброса, то он относится не к памяти, а к всему вычислительному блоку (надо же мне както инициализировать сигналы). Разнесите по разным процессам память и остальную логику. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gorby 6 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Извините, что врываюсь... Почему-то никто ни слова не произнес про COREGEN. Это ж самый верный способ получить требуемую память. Прекрасно конфигурируется и заведомо работает. А в Симплифае вставляется как блэк-бокс. Правда, непереносимо. Так и BRAM сама по себе непереносима. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MadMakc 0 28 июня, 2006 Опубликовано 28 июня, 2006 · Жалоба Почему-то никто ни слова не произнес про COREGEN. Потому что не удобно.Сегодня я хочу память в 2К слов.Завтра дадут ценное указание и память станет 4К слов.А послезавтра разрядность увеличить придётся. По мне править код намного проще и удобней, чем занового генерить ядра. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maior 0 29 июня, 2006 Опубликовано 29 июня, 2006 · Жалоба Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной), на базе которых можно сделать универсальные параметризиремые (через generic) бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих и позволял строить память почти любой конфигурации!). Для спартанов - тоже не должно быть проблем. И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво интерпретируется разными синтезаторами в разных условиях и для разных (даже слегка разных!) чипов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gorby 6 30 июня, 2006 Опубликовано 30 июня, 2006 · Жалоба Hо ведь есть еще стандартные примитивы памяти (блочной и распределенной), на базе которых можно сделать универсальные параметризиремые (через generic) бибиотечные элементы. Я так и делал для виртексов 2 и 4 (один элемент годился для обоих и позволял строить память почти любой конфигурации!). Для спартанов - тоже не должно быть проблем. И не заморачивался ни с coregen, ни с behaviorial, которое по-разному и неустойчиво интерпретируется разными синтезаторами в разных условиях и для разных (даже слегка разных!) чипов. Фактически, вы руками доделали некоторую часть работы. Которую запросто мог за вас сделать Кореген. Более того, вам пришлось разбираться с тонкостями использования тех примитивов - причем обременительными тонкостями, типа зануления старших адресов если используется не вся память и построение дешифраторов, если требуется бОльшая. И зачем?! Когда есть кореген, одним движением пальца делающий все это. Насчет переносимости, разных синтезаторов и проч. Сдается мне, что проблему сильно преувеличивают. Не знаю, кто как, но я только один раз кардинально менял окружение. С Леонардо Спектрум для Atmel FPSLIC прыгнул на Spartan2 и XST (ISE). Разумеется, блоки памяти потребовали кардинальной переделки. Которая заключалась всего лишь в генерации оных в Корегене. Затем перешел на Спартан 3, так ничего и не поменялось. Сгенерировал то же самое в Корегене. А теперь пожалуйста ответьте, как часто вам, уважаемые коллеги, пришлось переходить (в ходе разработки ОДНОГО изделия) на кардинально другие FPGA и кардинально другие синтезаторы? Ото ж... А на рихтовку своих исходников с целью сделать их универсальными вы потратите очень много времени с непредсказуемым результатом. (речь идет об аппаратно-специфических вещах, память, DDR регистры и проч.). Моя идеология проста: делаем на plain VHDL все, что можно. По возможности без атрибутов и прочих бубенцов. Все специфическое включаем в блэк-боксы, их генерируем в целевой среде. Констрейны и прочие весьма зависимые прибамбасы (распиновка, типы выводов и тд) делаем исключительно в целевой среде. И не паримся. При переходе на что-то другое у нас остается везде компилируемый чистый VHDL, блэк-боксы создаем по-новой - тут уж никуда не деться. А констрейны, пинауты и иже с ними в новой среде все равно придется вбивать по-новой. Каламбурчик. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maior 0 30 июня, 2006 Опубликовано 30 июня, 2006 · Жалоба ... Фактически, вы руками доделали некоторую часть работы. Которую запросто мог за вас сделать Кореген.... ... Более того, вам пришлось разбираться с тонкостями использования тех примитивов - причем обременительными тонкостями,.... .. А на рихтовку своих исходников с целью сделать их универсальными вы потратите очень много времени с непредсказуемым результатом. (речь идет об аппаратно-специфических вещах, память, DDR регистры и проч.)... ОДИН раз сделал - и больше уже не пришлось делать что-то еще.. Вот уже пару лет как пользую свою библиотеку памяти для разных проектов. Идея была создать для зайлинкса такой же набор LPM памяти какая есть у альтеры. У меня они даже совместимы по entity и generic, так-что можно прыгать с зайлинкса на альтеру без труда. Посмотрел бы я на вас с вашим corgen в такой ситуации. Coregen (для памяти) - в отстое уже давно. Он явно неудобен, о чем тут уже говорилось, не стоит об этом спорить. А с plane (behaviorial) HDL - все равно будут проблемы, и в конце концов проковыряешся больше, что собственно и доказывают посты в этой ветке. Нету там никаких особых тонкостей. Только заглянуть пару раз в мануалы, что никогда не помешает. А времени потратил до смешного немного. Даже удивительно, отчего это зайлинкс сам не сделал эту работу, например как альтера. Но опять же - на вкус и цвет... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 1 июля, 2006 Опубликовано 1 июля, 2006 · Жалоба МОЕ ИМХО на весь этот счет, у памяти 2 конфигурации, 1 чистый бехавор для симуляции и первоначальной сборки (1 раз потратил день на изучение как правильно нужно писать память, после этого ни разу не было проблем при синтезе, для симуляции попробуйте на вставленых БРАМАХ при объеме памяти кил в 100-200 симуляться и натравите профайлер). 2 конфигурация это уже конфигурация сборки, с реальными вставленными брамами, к которым к тому же можно и RLOC/LOC пристегнуть. Выбор конфигурации в ВХДЛ 1 строка. в том же топ файле. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
serg_Fry 0 23 августа, 2006 Опубликовано 23 августа, 2006 (изменено) · Жалоба У меня Spartan2 а не 3, но думаю это непринципиально. Мне нужно написать двухпортовую RAM с разными клоками на концах с одной стороны только запись с we а с другой только чтение. на сайте Xilinx есть примеры описания НО мне нужна память с разной разрядностью шин на разных портах, там такого нет. Есть вариант использовать готовую память типа RAMB4_Sm_Sn или, как говорилось выше, использовать COREGEN, но хочется иметь возможность изменять под себя (выбирать фронты и пр.) ну и по-возможности не использовать черных ящиков. Очевидно, что написать самому возможно, но пока не получается. Вероятно кто-то уже возился с этим. Пишу на VHDL, но Verilog тоже прочитаю. Изменено 23 августа, 2006 пользователем qwqw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться