Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с двухпортовой блочной памятью xilinx
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
gotcha
Подскажите, может чего-то не учел.

Использую true dual block memory сгенеренный из сoregen Xilinx под spartan3e, клок на кристалле 50МГц.
В порт А пишется инфа внешним устройством (частота меньше 25мгц).
Из порта В чтение и запись FSMкой на частоте 50мгц.
Т.к память синхронная на порт A подан клок прямой, на блок B через инвертор.
По идее setup\hold time выдержаны, коллизий не должно быть.
SM
у true dual port памяти коллизий вообще быть не может, по определению, так как она внутри спроектирована так, чтобы обеспечивать работу на полностью асинхронных тактовых сигналах по обоим портам.

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

что касается Вашего случая, то зачем Вам true dual port? Когда у Вас одна сторона только читает, другая только пишет, и, докучи, все по одному клоку?
gotcha
Пардон, на порт B чтение и запись (отредактировал).
Используется системный клок 50МГц, на A прямой вариант, а на B через инвертор.

Судя по xapp463, на чтение тоже возможна коллизия.
Bad0512
Цитата(gotcha @ Oct 13 2014, 14:40) *
Пардон, на порт B чтение и запись (отредактировал).
Используется системный клок 50МГц, на A прямой вариант, а на B через инвертор.

Судя по xapp463, на чтение тоже возможна коллизия.

Опишите плиз что вам в итоге надо получить, а то складывается некоторое впечатление что вы изобретаете велосипед,
и, к примеру, обычная фифошка полностью удовлетворит отца русской демократии...
gotcha
Надо реализовать 8 приемопередатчиков полудуплекс на 513 байт.
Приемопередатчик может работать в режиме мастер\слейв.
В мастере постоянно чего-то шлет, иногда переключается на прослушивание.
В слейве слушает, иногда переключается на передачу.
Арм заливает\читает 513 байт, кофигурирует режимы.
FSMка плис читает\заливает 513байт, отдает\принимает в нужном формате дальше по тракту.

Передатчик и приемник у каждого своя память по 1026 байт.
Есть 2 указателя для FSM и Арма (меняются значениями 0 и 513).
Юзкейс:
Мастер
FSMка постоянно шлет из своей области 0-512, генерит прерывание арму по каждому циклу (отправка 513 байт)
Арм заливает в область 513-1025, паприм. конфигурит на прослушку на след цикл.
Указатели меняются значениями.
FSMка передает 513байт и переключается на прослушку.
Во время прослушки записывает до 513 байт, в конце цикла генерит прерывание.
В это время Aрм может что-то залить для след цикла.
Указатели меняются и т.д.

Возник еще вопрос
если укладывается в bram 18K, есть ли разница в утилизации лутов для true двухпортовой и просто двухпортовой памяти?
andrew_b
Цитата(gotcha @ Oct 13 2014, 13:14) *
если укладывается в bram 18K, есть ли разница в утилизации лутов для true двухпортовой и просто двухпортовой памяти?
Если память блочная, то лутов там нет вообще.
И зачем инвертировать клок на втором порту?
gotcha
Цитата(andrew_b @ Oct 13 2014, 13:47) *
Если память блочная, то лутов там нет вообще.

В смысле луты под погику обработки записи\чтения, разной ширины портов, разного режима (WRITE_FIRST, READ_FIRST, NO_CHANGE)
Т.е примитив еще какой-то логикой оборачивается?

Цитата(andrew_b @ Oct 13 2014, 13:47) *
И зачем инвертировать клок на втором порту?

А как удовлетворить hold\setup time? Или читать за три такта?
SM
Цитата(gotcha @ Oct 13 2014, 13:58) *
А как удовлетворить hold\setup time? Или читать за три такта?


Инверсия клока УСУГУБЛЯЕТ удовлетворение требований по setup ровно вдвое. Так что, это еще вопрос - а стоит ли усложнять себе жизнь.
gotcha
Цитата(SM @ Oct 13 2014, 14:32) *
Инверсия клока УСУГУБЛЯЕТ удовлетворение требований по setup ровно вдвое. Так что, это еще вопрос - а стоит ли усложнять себе жизнь.

...может я и не прав, поэтому и появилась эта тема.
Почему усугубляет?
Рассмотрим работу FSM по тактам (полупериод 10нс)
Передний фронт клока: выставляются адрес, управляющие сигналы (согласно ds312 минимал setup time 1.26нс).
По заднему фронту: память начинает обрабатывать сигналы (минимал hold time 0.14нс).
Данные из памяти появятся максимально через 2.82 нс, т.е. по переднему фронту можно читать.

С другой стороны, при разгоне клока, критический путь не покажет реальные проблемы?
Вы советуете читать за 3 такта? Легче читать результаты синтеза?
SM
Путь сигнала (допустим, что выход данных влияет на следующий вход данных или адреса) - Tco (clock-to-out) + Tsu = 2.82 нс + 1.26 нс = 4.08 нс. Если у Вас работа по фронту и у источника, и у приемника - то запас = 20 нс - 4.08 нс = 15.92 нс (на разводку и промежуточную логику). А если фронт-спад, то 10 нс-4.08нс = 5.92 нс. В данном конкретном случае это даже не вдвое жестче, а в 2.7 раз! Почти втрое жестче.

Про холды вообще забудьте, их PAR сам скорректирует, если путь вдруг слишком короткий и быстрый окажется.

---

Вдогонку... Работать на чтение по спаду есть смысл лишь в одном случае - если требуется эмулировать асинхронное ОЗУ, а есть только синхронное - то есть, считывать текущее записываемое данное из второго порта в том же такте, когда и происходит его же запись в первый порт. А иначе работа фронт-спад бессмысленна, и усугбляет временные соотношения, как я показал выше.
gotcha
Цитата(SM @ Oct 13 2014, 16:00) *
Путь сигнала (допустим, что выход данных влияет на следующий вход данных или адреса) - Tco (clock-to-out) + Tsu = 2.82 нс + 1.26 нс = 4.08 нс. Если у Вас работа по фронту и у источника, и у приемника - то запас = 20 нс - 4.08 нс = 15.92 нс (на разводку и промежуточную логику). А если фронт-спад, то 10 нс-4.08нс = 5.92 нс. В данном конкретном случае это даже не вдвое жестче, а в 2.7 раз! Почти втрое жестче.

Про холды вообще забудьте, их PAR сам скорректирует, если путь вдруг слишком короткий и быстрый окажется.

---

Вдогонку... Работать на чтение по спаду есть смысл лишь в одном случае - если требуется эмулировать асинхронное ОЗУ, а есть только синхронное - то есть, считывать текущее записываемое данное из второго порта в том же такте, когда и происходит его же запись в первый порт. А иначе работа фронт-спад бессмысленна, и усугбляет временные соотношения, как я показал выше.

Тогда все операции проходят в 3 такта (60нс). А если надо быстрее, разгоняем клок и получаем те же жесткие условия, что за собой может потянуть изменения FSMок (введения хэндшейка, задержек).

Если в проекте используется спад клока, хватает ли констрейнта на скважность (clock duty)?
SM
Цитата(gotcha @ Oct 14 2014, 09:45) *
Тогда все операции проходят в 3 такта (60нс).

Это с какого перепуга? Считать данное из памяти можно уже на следующем такте после записи. То есть, задержка = 1 такт. А если читать по спаду, то за счет ужесточения setup-времянок можно добиться задержки в 0 (ноль) тактов. Откуда три то?
gotcha
Цитата(SM @ Oct 14 2014, 13:47) *
Это с какого перепуга? Считать данное из памяти можно уже на следующем такте после записи. То есть, задержка = 1 такт. А если читать по спаду, то за счет ужесточения setup-времянок можно добиться задержки в 0 (ноль) тактов. Откуда три то?

Первый тик: выставляем адрес, управляющие сигналы.
Удовлетворяется setup time.
Второй тик: память обрабатывает выставленные сигналы.
Удовлетворяются: hold time, clock-to-out.
Третий тик: забираем валидные данные.
Bad0512
Цитата(SM @ Oct 14 2014, 16:47) *
Это с какого перепуга? Считать данное из памяти можно уже на следующем такте после записи. То есть, задержка = 1 такт. А если читать по спаду, то за счет ужесточения setup-времянок можно добиться задержки в 0 (ноль) тактов. Откуда три то?

Если речь идёт за блочную память,то транзитная задержка при одинаковых клоках на запись и чтение в принципе не может быть меньше 2 клоков(1 клок на запись и 1 клок на чтение).
Все игрища с rising/falling edge приведут лишь к тому, что будут считаны "старые" данные, т.е. то, что там лежало до цикла записи.

Кроме того, есть и ещё одна мелкая неприятность (речь идёт за Xilinx). Если задержка на чтение равна 1, то это означает что регистр в примитивах
блочной памяти не используется (если бы был использован задержка увеличилась бы до 2 клоков). В этом случае времянка по выходу шины данных памяти сильно ухудшается(например 0.5нС при включенном регистре и 1.5нс без него).На высоких тактовых частотах это может быть критично.
SM
Цитата(Bad0512 @ Oct 14 2014, 14:14) *
Если речь идёт за блочную память,то транзитная задержка при одинаковых клоках на запись и чтение в принципе не может быть меньше 2 клоков(1 клок на запись и 1 клок на чтение).
Все игрища с rising/falling edge приведут лишь к тому, что будут считаны "старые" данные, т.е. то, что там лежало до цикла записи.

Речь о том, что если писать по rising, а читать по falling (или наоборот) - можно получить эмуляцию асинхронной памяти, то есть, грубо говоря, защелки - считать данное, записанное в этом же цикле записи - то есть, за 1 такт. Собственно, я этим пользовался для эмуляции работы регистрового файла процессора, используя несколько блоков памяти, в которые запись делается по фронту, как положено, а чтение - по спаду (где адрес уже готов по фронту). Это как раз соответствует конвейерной задержке на 0 тактов.
На высоких частотах, естественно, это сделать невозможно. Только на половинной от максимально допустимой.
Maverick
Цитата(gotcha @ Oct 13 2014, 10:21) *
Подскажите, может чего-то не учел.

Использую true dual block memory сгенеренный из сoregen Xilinx под spartan3e, клок на кристалле 50МГц.
В порт А пишется инфа внешним устройством (частота меньше 25мгц).
Из порта В чтение и запись FSMкой на частоте 50мгц.
Т.к память синхронная на порт A подан клок прямой, на блок B через инвертор.
По идее setup\hold time выдержаны, коллизий не должно быть.

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

не большой и памяти не много понадобиться...

PS Совет не используйте инверсию частот - на данном этапе без этого можно обойтись и глюков в дальнейшем меньше будет...
gotcha
Есть ли рекомендации по синхронизации с двунаправленной шиной?
Достаточно ли сигналы cs, we, oe, addr, data положить в один триггер по системному клоку в плисе?
Bad0512
Цитата(gotcha @ Oct 20 2014, 17:20) *
Есть ли рекомендации по синхронизации с двунаправленной шиной?
Достаточно ли сигналы cs, we, oe, addr, data положить в один триггер по системному клоку в плисе?

В ПЛИС уже давно внутри не может быть двунаправленной шины. Только на входах-выходах, но это не имеет никакого отношения к блочной памяти.
gotcha
Цитата(Bad0512 @ Oct 20 2014, 14:28) *
В ПЛИС уже давно внутри не может быть двунаправленной шины. Только на входах-выходах, но это не имеет никакого отношения к блочной памяти.

В моем случае внешнее устройство (арм) общается с плис как с памятью.

SM
Цитата(gotcha @ Oct 20 2014, 14:20) *
Достаточно ли сигналы cs, we, oe, addr, data положить в один триггер по системному клоку в плисе?


Нет, недостаточно. Глючить будет, особенно если клок ПЛИС не синхронен с клоком, тактирующим интерфейс памяти у процессора.

наиболее простой вариант такой:
Надо data защелкивать сигналом WE (использованным в качестве клока), с разрешением, сделанным логикой из CS, addr. этим же клоком и разрешением "взводить" флаг наличия данных. Затем, этот флаг через два триггера перегнать в домен клока ПЛИС, и по нему уже использовать данное дальше, и асинхронно сбросить этот флаг.

Чтение, это уже посложнее. Можно реализовать по аналогии - по активному фронту OE и правильных данных на CS/ADDR взвести некий флаг, пропустить его через два триггера, и по этому синхронизированному флагу асинхронно сбросить исходный флаг, и выставить данные наружу.

Почему удобно использовать OE и WE в качестве клоков на входныхх триггерах-флагах, это потому, что времянки WE/OE относитлеьно CS/ADDR/DATA всегда документированы и легко констрейнятся, и такой расклад позволяет сократить длительность цикла записи, за счет того, что проход данных в основной домен может идти уже после окончания чикла записи на самой шине (все уже защелкнуто по WE)
gotcha
Цитата(SM @ Oct 20 2014, 14:55) *
Надо data защелкивать сигналом WE (использованным в качестве клока), с разрешением, сделанным логикой из CS, addr. этим же клоком и разрешением "взводить" флаг наличия данных. Затем, этот флаг через два триггера перегнать в домен клока ПЛИС, и по нему уже использовать данное дальше, и асинхронно сбросить этот флаг.

Если использовать WE как клок и адрес меняется синхронно с WE (судя по осциллу), можем словить не тот адрес? Надо цепляться за фронт WE при переключении в неактивное состояние.
Как "асинхронно сбросить этот флаг"? Или сформировать строб, что есть новые адрес и данные?
Maverick
Цитата(gotcha @ Oct 20 2014, 13:33) *
В моем случае внешнее устройство (арм) общается с плис как с памятью.

так сделайте автомат эмулирущий память в плис - навскидку для примера общение через контролер памяти только наоборот

посмотрите SSRAM - преимущество в синхронности

какие виды памяти поддерживает арм процессор?
может достаточно вывести выводы блочной памяти (один порт) наружу к процессору?
скорость обмена какая должна быть?

Цитата(gotcha @ Oct 21 2014, 10:18) *
Или сформировать строб, что есть новые адрес и данные?

формировать строб - есть новые данные - отдельный пин у плис и арм
SM
Цитата(gotcha @ Oct 21 2014, 11:18) *
Если использовать WE как клок и адрес меняется синхронно с WE (судя по осциллу), можем словить не тот адрес? Надо цепляться за фронт WE при переключении в неактивное состояние.


Э. Я то думал, что у Вас асинхронный интерфейс к памяти. При этом фронт ~WE (задний, нарастающий ) соответствует моменту, когда CS/ADDR/DATA гарантировано стабильны.

Цитата(gotcha @ Oct 21 2014, 11:18) *
Как "асинхронно сбросить этот флаг"?
Или сформировать строб, что есть новые адрес и данные?

Ну да, три триггера последовательно - два первых - синхронизаторы, третий - запоминает состояние выхода синхронизатора. И когда на втором единица, а на третьем еще ноль - формируется импульс асинхронного сброса триггера, работающего на клоке "WE", и этот же импульс является сигналом "защелкнутые по WE данные можно использовать в этом тактовом домене".
gotcha
Сделал так
io буфер управляется напрямую
Код
wire ArmReading = ~iCSn & ~iOEn;
assign ioData = ArmReading ? dataOut : 8'hzz;

далее сигналы cs, oe, we пропускаются через два триггера, после формируются стробы
Код
    always @(posedge iClk) begin
            {rrCSn, rCSn} <= {rCSn, iCSn};
            {rrWEn, rWEn} <= {rWEn, iWEn};
            {rrOEn, rOEn} <= {rOEn, iOEn};
        end
    
    wire wwArmWriting = ~rrCSn & ~rrWEn;
    wire wwArmReading = ~rrCSn & ~rrOEn;

    always @(posedge iClk) begin
        syncArmWr <= wwArmWriting;
        syncArmWrStr <= wwArmWriting & ~syncArmWr;
        syncArmRd <= wwArmReading;
        syncArmRdStr <= wwArmReading & ~syncArmRd;
    end

соответственно iAddr, ioData обрабатываются в fsmке по стробам, далее в 3 такта происходит работа (чтение\запись) с блочной памятью

Maverick, напрямую с блочной работало как часы, но еще нужна конфигурация через регистры. Скорость обмена около 20ms на чтение\запись 8 каналов и конфигурацию.
SM
Цитата(gotcha @ Oct 24 2014, 10:44) *
Сделал так

Если нет цели максимально поднять быстродействие по записи (конвейеризировать, чтобы работать около предела скорости асинхронной шины для Вашей тактовой), то такая схема вполне нормальная.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.