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

Как правильно создать 2-х портовую память в виде набора регистров?

Здравствуйте!

Потребовалось сделать небольшую 32 х 8 бит ( 32 байта ) 2-х портовую память, причём возможна ситуация, когда запись и чтение по ячейкам по одному и тому же адресу будет происходить одновременно.

По шаблону в Квартусе создал создал True Dual Port RAM with dual clocks, т.к запись и чтение будут из разных клоковых доменов.

 

// Quartus II Verilog Template
     // True Dual Port RAM with dual clocks
     
     module true_dual_port_ram_dual_clock
     #(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=5)
     (
         input [(DATA_WIDTH-1):0] data_a, data_b,
         input [(ADDR_WIDTH-1):0] addr_a, addr_b,
         input we_a, we_b, clk_a, clk_b,
         output reg [(DATA_WIDTH-1):0] q_a, q_b
     );
     
         // Declare the RAM variable
         reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
     
         always @ (posedge clk_a)
         begin
             // Port A 
             if (we_a) 
             begin
                 ram[addr_a] <= data_a;
                 q_a <= data_a;
             end
             else 
             begin
                 q_a <= ram[addr_a];
             end 
         end
     
         always @ (posedge clk_b)
         begin
             // Port B 
             if (we_b) 
             begin
                 ram[addr_b] <= data_b;
                 q_b <= data_b;
             end
             else 
             begin
                 q_b <= ram[addr_b];
             end 
         end
     
     endmodule

 

Правильно ли я понимаю, что чтобы такая память правильно работала ( когда запись и чтение по ячейкам по одному и тому же адресу будет происходить одновременно ) надо, чтобы она была организована не как память, а как набор регистров?

 

Если верно, что чтобы задать в Квартусе надо в *.qsf файл добавить строчку

set_global_assignment -name AUTO_RAM_RECOGNITION OFF -entity true_dual_port_ram_dual_clock ,

где true_dual_port_ram_dual_cloc - это название entity этой самой памяти?

Если это тоже верно, то данный порядок действий вызывает странные ошибки:

 

Error (10028): Can't resolve multiple constant drivers for net "ram[31][7]" at TrueDualPortDualClockRAM.v(30)
Error (10029): Constant driver at TrueDualPortDualClockRAM.v(16)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][6]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][5]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][4]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][3]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][2]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][1]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[31][0]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][7]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][6]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][5]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][4]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][3]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][2]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][1]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[30][0]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[29][7]" at TrueDualPortDualClockRAM.v(30)
Error (10028): Can't resolve multiple constant drivers for net "ram[29][6]" at TrueDualPortDualClockRAM.v(30)
Error (12152): Can't elaborate user hierarchy "true_dual_port_ram_dual_clock:inst"
Error: Result: ERROR: Error(s) found while running an executable. See report file(s) for error message(s). Message log indicates which executable was run last.

Error: Failed to discover source files from compiler. Check Analysis & Elaboration report.

 

Или всё-таки нельзя такую память задать в виде регистров?

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


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

Или всё-таки нельзя такую память задать в виде регистров?
На сколько я понимаю, нет.

Полноценную 2-х портовую память на регистрах организовать нельзя, ибо могут быть случаи когда запись происходит в одну и туже ячейку с разных клоков, но с небольшим смещением по времени. Это нужны какие-то спец. триггеры с двумя тактовыми входами. А память хардовая, т.е. имеющаяся на кристалле как самостоятельный ресурс, как раз обладает такими возможностями.

В Вашем случае, наверно, имеет смысл воспользоваться мегавизардом Квартуса.

 

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


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

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

При это не будет разницы в функционировании схемы. Для вас, как разработчик, на стадии функционального описания не имеет значения будет эта память блоком памяти или набором регистров.

 

Может я не прав, надеюсь кто-нибудь поправит.

 

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

Так вот. В верилоге не допускается присвоение значений к одному и тому же регистру в разных блоках always в рамках одного модуля, т.к. это вызывает разночтения. Может с массивами не совсем так (хотя масив это набор регистров), я не уверен.

Вобщем если как-то на это явно не указывать, просто описание не пройдет синтезтор, как мне кажется.

 

 

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

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


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

Здравствуйте!

Потребовалось сделать небольшую 32 х 8 бит ( 32 байта ) 2-х портовую память, причём возможна ситуация, когда запись и чтение по ячейкам по одному и тому же адресу будет происходить одновременно.

По шаблону в Квартусе создал создал True Dual Port RAM with dual clocks, т.к запись и чтение будут из разных клоковых доменов.

 

 

Или всё-таки нельзя такую память задать в виде регистров?

На самом деле все немного не так.

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

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

Так что рекомендую начать с условия задачи.

А все остальное могу рассказать по скайпу...

 

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


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

Я действовал согласно вот этому хелпу от Альтеры :

http://quartushelp.altera.com/13.1/master...._dual_clock.htm

В нём в последнем абзаце сказано, что можно принудительно заставить Квартус сделать память в виде регистров:

If you are concerned about a potential mismatch, you can prevent Analysis & Synthesis from converting the registers into an altsyncram megafunction by turning off the Auto RAM Replacement logic option for the entity or instance that contains the dual-clock RAM.

Я так и сделал ( set_global_assignment -name AUTO_RAM_RECOGNITION OFF -entity true_dual_port_ram_dual_clock ), но это вызывает ошибки...

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


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

С такой памятью, которая приведена по ссылке скорее всего все это и заработает. Она однопортовая, тут все просто.

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


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

Я так и сделал ( set_global_assignment -name AUTO_RAM_RECOGNITION OFF -entity true_dual_port_ram_dual_clock ), но это вызывает ошибки...

 

Что и закономерно, так как в регистры, которые есть в альтере, физически нельзя писать по разным клокам (читайте документацию, какие регистры там в LAB-ах есть, и какие у них входы. Если бы Вы глянули в документацию, то этот вопрос бы тут не задали. То есть, ответ на изначальный вопрос - никак). А в блоки памяти - можно. Так что, используйте блок памяти для этой цели.

 

Память, кстати, внутри состоит из защелок, а не из регистров, поэтому, сделав к массиву защелок формирователь импульсов записи из двух доменов и соотв. мультиплексор данных, можно сделать память и на ячейках (но на логике, а не на регистрах). Но описывать констрейны на все это и строить нужную структуру - потратите огромную кучу времени. Так что, применяйте блочную.

 

UPD: можно сделать так и с регистрами тоже, с формирователем импульса записи. Но, в общем, кол-во геморроя по описанию такой конструкции, чтобы она как надо разводилась, не меньше.

 

UPD2:

Конструкция устроена примерно так - во входной регистр данных записывается данное по фронту клока. Во входной регистр адреса - адрес. Дальше строится дешифратор этого, записанного в регистр, адреса, и по спаду клока формируется импульс записи, свой в каждую ячейку. Соотв. и реальная запись в ячейку произойдет по спаду. Результирующий импульс записи формируется как лог. или обоих импульсов из обоих доменов - итого, имеем столько клоков, сколько однобитных ячеек памяти. Данные должны подаваться через мультиплексор, который управляется от того, от чего происходит управление импульсами записи - то есть, чтобы данное на входах в ячейки соответствовало тому, от какого клок-домена идет ближайший активный фронт импульса записи (вот тут будет самое сложное).

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


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

Хорошо, всё понятно, всех благодарю за разъяснения.

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

 

Тогда взял память из Мегавизарда ( RAM: 2-PORT ) , задал всё как мне надо, установил, что при одновременном обращении по одинаковому адресу чтобы считывалось старое значение ( Old Data ).

post-5832-1412088173_thumb.png

Сделал тест по записи и чтению пока с одного только порта.

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

post-5832-1412088167_thumb.png

В случае с памятью из шаблона ( True Dual Port RAM with dual clocks ) такого эффекта не было.

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

 

Вопрос.

Если применять память RAM: 2-PORT , то есть ли какой-нибудь приём/ухищрение, чтобы правильное значение читать всё-таки из той же ячейки, куда была сделана запись, а не со сдвигом на единицу?

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


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

Если применять память RAM: 2-PORT , то есть ли какой-нибудь приём/ухищрение, чтобы правильное значение читать всё-таки из той же ячейки, куда была сделана запись, а не со сдвигом на единицу?

сдается мне что выводы у вас не верные. вейвформы выложите

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


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

сдается мне что выводы у вас не верные. вейвформы выложите

Не понял Вас, что значит выводы неверные?

Вейформы не применяю.

В случае с памятью из шаблона ( True Dual Port RAM with dual clocks ) такого эффекта ( необходимость сдвигаться на одну ячейку ) не было.

Если для RAM: 2-PORT в Визарде задать, что при одновременном обращении по одинаковому адресу чтобы считывалось новое значение ( New Data ), то сдвигаться придётся уже на 2 ячейки.

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


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

Не понял Вас, что значит выводы неверные?

Вейформы не применяю.

В случае с памятью из шаблона ( True Dual Port RAM with dual clocks ) такого эффекта ( необходимость сдвигаться на одну ячейку ) не было.

Если в Визарде задать, что при одновременном обращении по одинаковому адресу чтобы считывалось новое значение ( New Data ), то сдвигаться придётся уже на 2 ячейки.

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

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


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

Если для RAM: 2-PORT в Визарде задать, что при одновременном обращении по одинаковому адресу чтобы считывалось новое значение ( New Data ), то сдвигаться придётся уже на 2 ячейки.

 

Это Вы видимо с конвейеризацией запутались, на каком такте происходит реальная запись, и на сколько задерживается чтение из-за входных и выходных регистров. Например, задав адрес, на выходе соответствующее ему данное может появиться на следующем такте, а может через такт, а может даже через два, в зависимости от кол-ва регистров на входе и на выходе.

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


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

Это Вы видимо с конвейеризацией запутались, на каком такте происходит реальная запись, и на сколько задерживается чтение из-за входных и выходных регистров. Например, задав адрес, на выходе соответствующее ему данное может появиться на следующем такте, а может через такт, а может даже через два, в зависимости от кол-ва регистров на входе и на выходе.

Я не запутался, я задаю минимальные требования из того, что требует от меня Визард при определении параметров RAM: 2-PORT ( меньше, чем Old Data не поставишь, а другую конвееризацию я не задаю ) и получаю такой вот эффект сдвига, который мне не нравится и которого не было в случае с памятью из шаблона ( True Dual Port RAM with dual clocks ), но которую нельзя применять , т.к возможен конфликт при записи и чтении по одному и тому же адресу из разных портов.

А для RAM: 2-PORT такого конфликта не будет, но есть сдвиг.

Можно ли от него избавиться?

 

 

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

Адреса, данные, стробы для обоих случаев ( память из шаблона True Dual Port RAM with dual clocks и RAM: 2-PORT ) одинаковые, но результат разный.

Поэтому вейформы смотреть нет смысла.

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


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

А для RAM: 2-PORT такого конфликта не будет, но есть сдвиг.

Как уже выше сказали - RAM не FIFO, и ничего сдвигать сама не может никак. Так что вникайте глубже в работу этой памяти. Эти кажущиеся сдвиги только от непонимания. А в чем оно конкретно - телепатов тут нет... надо полный расклад видеть - диаграммы со всеми стробами, адресами и данными.

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


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

Недоглядел, на входе и выходе есть регистры и оба заданы были. Причём входной отключить нельзя.

А выходной сейчас отключил , сейчас перекомпиилирую и посмотрю результат.

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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