Программирование Xilinx Контроллер SDRAM на FPGA Mon, December 09 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Контроллер SDRAM на FPGA Печать
Добавил(а) microsin   

Несмотря на то, что современные FPGA содержат внутренние блоки памяти (BRAM), количество этой доступной памяти всегда на порядки меньше, чем может быть с выделенными внешними микросхемами. Так что не сюрприз, что многие разработчики FPGA подключают некоторые типы памяти к своим проектам. В частности, микросхемы SDRAM очень популярны, так как они достаточно быстрые, имеют большую емкость и недорогие. К сожалению, управлять динамической памятью не так же просто, как статической, так что для этого часто используется контроллер SDRAM.

Для нашего контроллера мы будем подключать возможно самую простую их доступных SDRAM: Micron MT48LC1M16A1 16Mb SDRAM. Нашей тестовой системой будет Xylo-E, Xylo-EM и Xylo-LM (Xilinx или Altera FPGA с памятью от 16Mb до 256Mb SDRAM).

Обсуждение поделено на 3 части (это перевод статьи [1]). В первой будет введение про память, используемую с FPGA. Затем мы покажем, как сделать контроллер 16Mb SDRAM. И в конце будет показана продвинутая память DDR SDRAM.

[От статики к динамике]

Представим себе, что нужно подключить 16Mb память к FPGA.

16Mb означает, что в памяти хранится 16 миллионов бит (или, если быть точным, 16777216 бит). Очень редко биты адресуются индивидуально, обычно они обрабатываются порциями по 8 или 16 (мы называем эти порции словами). Так что если наша память 16Mb организована как 1M слов по 16 бит, то понадобится 20-разрядная шина адреса и 16-разрядная шина данных, плюс сигналы разрешения записи (write enable, WE) и разрешения чтения (read enable, RE).

fpga4fun SDRAM01

Реальные микросхемы памяти также имели бы сигнал выборки CS (chip select), и если память синхронная, еще и тактовый сигнал (на картинке для ясности эти сигналы опущены).

Стоит сделать оговорку, что если память находится внутри FPGA (так называемая блочная память BRAM), то она конечно совсем другая - нет BRAM такого размера. Просто предположим, что такая память 16Mb BRAM существует.

fpga4fun SDRAM02

Как Вы можете видеть, это все еще один блок памяти, но здесь 2 адресные шины, это так называемая двухпортовая память (dual port memory BRAM), которая присутствует на современных кристаллах FPGA. Такая память позволяет двум агентам получить доступ к массиву памяти одновременно. Обычно один агент записывает в память, в то время как другой агент читает. Таким образом, у памяти есть независимые шины адреса и данных для каждого агента. Рисунок выше показывает, что шины первого (записывающего) агента находятся сверху, и шины второго (читающего) снизу. Более продвинутые BRAM позволяют каждому агенту и читать и записывать, но чаще всего используется архитектура, показанная выше. Также BRAM обычно используются синхронно, так что каждый агент предоставляет сигнал тактов (не показан на рисунке).

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

Динамическая память. Перейдем к SDRAM, которая является динамической памятью (dynamic, отсюда появилась "D" в аббревиатуре SDRAM). И в динамической памяти мы больше не увидим линейную организацию слов, вместо этого память организована как матрица слов со строками и столбцами (row, column).

fpga4fun SDRAM03

Рисунок выше показывает 12 бит на строку и 8 бит на столбец, и всего получается 20 бит адреса.

Здесь есть одно усложнение: чтобы повысить быстродействие, каждая память делится на одинаковые по размеру куски, которые называются "банками". Это потому что операции с динамической памятью медленные, и делением памяти на банки позволяет работать с одним из банком, ожидая готовности к работе другого банка.

Если в нашей памяти 16Mb SDRAM есть 2 банка, то в каждом будет 8Mb.

fpga4fun SDRAM04

Когда осуществляется доступ к SDRAM, FPGA выбирает банк (bank, 1 бит), строку (row, теперь это только 11 бит) и столбец (column 8 бит), всего получается 20 бит. Но этот процесс занимает 2 шага: сначала row+bank, затем column:

• FPGA выбирает банк, и активирует одну из его строк. Затем FPGA ждет несколько тактов (для того, чтобы строка стала готова к работе).
• Теперь строка активна, и FPGA может осуществить доступ (на чтение и/или запись) к любым нужным данным, просто предоставив адрес столбца.
• Как только FPGA завершила работу со строкой, она должна закрыть её перед открытием новой.

Для лучшей производительности пользователь (т. е. FPGA) хотел бы избежать слишком частого открытия и закрытия строк, вместо этого максимально часто, насколько это возможно, работая со строками, и чередовать операции в разных банках, чтобы не терять такты на ожидание. Большинство микросхем SDRAM в действительности имеют 4 или 8 банков, и каждый банк не зависим друг от друга, так что может иметь свою собственную активную строку.

Выводы SDRAM. Если мы посмотрим на выводы реальной микросхемы SDRAM, то увидим кое-что новое.

fpga4fun SDRAM05

Обновление данных. SDRAM является динамической памятью: её содержимое нуждается в периодическом обновлении, потому что значение каждого бита памяти (0 или 1) содержится в маленьком конденсаторе, у которого заряд со временем снижается из-за токов утечек. Однако скорость разряда конденсатора достаточно низкая, чтобы допускать периодические операции чтения и записи обратно (так называемая операция обновления, refresh). Когда эти операции обновления делаются через определенные периоды времени, производитель гарантирует, что данные не будут потеряны.

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

• FPGA использует команду "auto-refresh": обновление осуществляется периодической отправкой в SDRAM этой команды.
• FPGA достаточно часто осуществляет доступ к каждой строке: открытие строки приводит в действие специальную схему усилителей (sense amplifiers) в SDRAM, чтобы получить копию всех зарядов конденсаторов строки. Тогда когда строка закрывается, значения, прочитанные ранее, копируются обратно в конденсаторы, обновляя данные во время этого процесса.

Почему нужен контроллер памяти? Микросхемы динамической памяти более сложные для доступа, чем статические. У нас есть строки, столбцы, банки, и циклы обновления, и обо всем этом нужно заботиться. Но SDRAM востребованы благодаря их достаточно высокой скорости и низкой стоимости в пересчете на бит.

Таким образом, нам нужен способ доступа к SDRAM, достаточно простой, как доступ к статической памяти. Это именно та причина, по которой делают контроллеры памяти. Они функционируют как слой трансляции: с одной стороны они предоставляют простой для пользователя интерфейс к памяти, и с другой стороны делают всю грязную работу по управлению сигналами микросхемы SDRAM, в том числе функции обновления.

[Простой контроллер SDRAM]

У нашего контроллера SDRAM будут следующие свойства:

• Простой в использовании: SDRAM будет выглядеть как статическая память (или все равно максимально близко к этому, насколько возможно).
• Быстрый: SDRAM используется в пакетном режиме (burst mode), если Вы предоставите следующие друг за другом адреса.
• Простой: без планировщика, в любой момент времени активен только один банк.
• Мощный: SDRAM появляется как простая двухпортовая память (т. е. с одним агентом записи и одним агентом чтения).

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

Сигналы контроллера. Вот упрощенный вид на наш контроллер SDRAM.

fpga4fun SDRAM06

Первые 3 сигнала слева используются для агента записи (запрос записи "write request", за которым идет адрес записи "write address" и записываемые данные "write data"). Ниже идут 3 сигнала для агента чтения. Справа сигналы, которыми контролер управляет SDRAM. Для рассмотрения в перспективе ниже показана типовая система FPGA с использованием нашего контроллера SDRAM.

fpga4fun SDRAM06b

Контроллер представляет SDRAM для использования как двухпортовую память. Но SDRAM в реальности память однопортовая, поэтому нашему контроллеру нужен какой-то трюк для обработки двух запросов. Если 2 запроса поступили одновременно, то либо один из агентов приостанавливается, или их запросы записываются и выполняются позже. Наш контроллер выбирает первую стратегию. Для этого добавлены сигналы предоставления доступа "grant": агент может выставить запрос в любое время, но контроллер решает, предоставлять доступ или нет. Если запрос запрещен, нужно его удерживать, и доступ будет предоставлен по возможности.

fpga4fun SDRAM07

Еще одна сложность с SDRAM происходит от факта, что данные, возвращаемые в ответ на запрос чтения, поступают с задержкой (это называется CAS latency в даташитах на SDRAM). Контроллер также может добавлять несколько тактов задержки. Так что даже когда контроллер может предоставить разрешение на запрос чтения, соответствующие данные становятся доступными только через фиксированное количество тактов. Для удобства добавлен сигнал достоверности данных "data valid", который выставляется тогда, когда данные действительно доступны.

fpga4fun SDRAM08

Машина состояний. Сердцем нашего контроллера SDRAM является машина состояний. Контроллер ждет запроса (чтения read или записи write), открывает соответствующий банк/строку (bank/row), выдает команды чтения ли записи (столько, сколько активный агент запрашивает в активной строке), и в конце закрывает строку.

fpga4fun SDRAM09

По этой схеме в любой момент времени активен только один банк. Продвинутые контроллеры SDRAM позволяли бы одновременную активность нескольким банкам, но здесь мы решили упростить задачу.

Закрытие и открытие строки занимает некоторое время. Например, даташит на SDRAM дает следующие значения:

tRCD = 20ns (от состояния активности до чтения/записи)
tRP = 21ns (от состояния precharge до активности)

Таким образом, если мы будем работать с SDRAM на частоте 100 МГц, то период тактов окажется 10ns, и нужно добавить несколько пустых тактов (так называемых NOP) в машину состояний. Также нужны циклы восстановления, если агент чтения не гарантирует регулярного открытия каждой строки.

Машина состояний становится немного сложнее.

fpga4fun SDRAM10

И наконец, может понадобиться подстроить количество тактов NOP. Например, на частоте 100MHz с временем tRP = 21ns, возможно будет достаточным применить 2 такта NOP после precharge (дает нам 30ns перед следующей активацией).

Инициализация. У SDRAM есть некоторые программируемые настройки (наподобие CAS latency), для этого есть регистр MODE, который нужно инициализировать при включении питания. Для этой цели существует команда LOAD MODE. В контроллер должна быть добавлена инициализация SDRAM, или отдельный шаг перед тем, как контроллер запустится.

Код контроллера показан ниже. Чтобы получить самые лучшие интервалы времени IO, все сигналы управления SDRAM сделаны без какой-либо комбинаторной логики вне FPGA.

always @(posedge clk)  // машина состояний
case(state)
   2'h0: begin
      // Это запрос чтения или записи?
      if(RdReq | WrReq) begin
         SDRAM_CMD <= SDRAM_CMD_ACTIVE;   // если так, то открытие
         SDRAM_BA <= Addr[19];            // этого банка
         SDRAM_A <= Addr[18:8];           // этой строки
         SDRAM_DQM <= 2'b11;
         state <= 2'h1;
      end
      else
      begin
         SDRAM_CMD <= SDRAM_CMD_NOP;      // иначе продолжится состояние ожидания
         SDRAM_BA <= 0;
         SDRAM_A <= 0;
         SDRAM_DQM <= 2'b11;
         state <= 2'h0;
      end
   end
   2'h1: begin
      SDRAM_CMD <= ReadSelected ? SDRAM_CMD_READ : SDRAM_CMD_WRITE;
      SDRAM_BA <= AddrR[19];
      SDRAM_A[9:0] <= {2'b00, AddrR[7:0]};   // столбец
      SDRAM_A[10] <= 1'b0;                   // без auto-precharge
      SDRAM_DQM <= 2'b00;
      state <= (ReadSelected ? RdReq : WrReq) & SameRowAndBank ? 2'h1 : 2'h2;
   end
   2'h2: begin
      // закрыть строку, когда завершилась работа с ней:
      SDRAM_CMD <= SDRAM_CMD_PRECHARGE;
      SDRAM_BA <= 0;
      // precharge всех банков:
      SDRAM_A <= 11'b100_0000_0000;
      SDRAM_DQM <= 2'b11;
      state <= 2'h0;
   end
endcase

Полный демонстрационный код можно скачать по ссылке []. Он функционален, но поскольку он обучающий, то максимально упрощен, и из него удалены не обязательные функции. См. комментарии в коде, описывающие ограничения и требования.

Пример использования. SDRAM часто используется в видеоадаптерах, где память нужна для сохранения графики. Это работает примерно так: процессор компьютера посылает данные графики в видеокарту. Видеокарта использует SDRAM для сохранения данные, и контроллер в карте периодически читает память, чтобы послать данные на дисплей. Поскольку чтение периодическое, в течение этого процесса данные, находящиеся в SDRAM, обновляются автоматически (специальный refresh не требуется).

Подобная базовая система была создана на плате Xylo-EM как часть проверки правильности работы контроллера. Тот факт, что контроллер SDRAM сделан двухпортовым, значительно упростил дизайн (PC/FX2 это агент записи, а видеоконтроллер это агент чтения).

fpga4fun SDRAM11

[SDRAM DDR - борьба за скорость]

Когда производители памяти пытались найти способы повысить скорость SDRAM, была представлена память DDR SDRAM. DDR означает "double data rate", т. е. двойная скорость доступа.

Ячейки DDR SDRAM подобны обычной (single data rate) SDRAM (все еще есть банки и строки, которые нужно открывать). Ускорение происходит с повышением частоты тактов, удлинением периодов пакета, и доступ к двум битам за 1 такт (отсюда и пошло имя DDR). Это потребовало очень жесткой организации интервалов времени на сигналах данных, чтобы обеспечить надежное перемещение данных.

[Ссылки]

1. FPGA SDRAM controller site:fpga4fun.com.

 
Top of Page