Представим себе, что мы увидели какой-то интересный FPGA проект и захотели запустить его на своей плате, но, проблема - плата у нас другая и микросхема FPGA у нас другая. Как перенести тот проект на нашу плату? Возможен ли такой перенос/портирование и трудно ли его выполнить?
В общем случае портирование FPGA проектов - это не очень простая задача. Зависит от многих факторов. Иногда это возможно, иногда нет. Самое главное: ресурсы платы (установленные компоненты, разъемы, интерфейсы) и ресурсы FPGA чипа (количество доступных логических элементов, объем встроенной памяти, PLL, умножители). К примеру, если исходный проект использует SDR память платы, а на нашей плате этой памяти нет или меньше, чем нужно, то что тут можно сделать? В таком случае полный перенос проекта не возможен. Или, к примеру, для проекта требуется минимум 12 тысяч логических элементов FPGA, а на нашей плате их всего 10, тоже не очень хорошо. В общем, по ресурсам имеющейся платы и FPGA нужно смотреть можно ли реализовать в ней проект или нет. Если же платы хотя бы примерно похожи и емкости чипа хватает, то можно пробовать делать перенос проекта.
У нас на сайте уже накопилось довольно много разных проектов для разных плат серии Марсоход. В этой статье я хочу рассказать, как производить портирование проекта с платы Марсоход2 c FPGA Cyclone III на плату Марсоход2bis, Cyclone IV. Я буду портировать проект "Простой текстовый терминал".
В этом проекте реализован текстовый видеоадаптер 56 строк по 180 символов, формируется видеосигнал 1440x900, 60Гц и картинка отображается на VGA дисплее. Плата принимает символы из последовательного порта и печатает их в экран. При этом, если приходит символ 0x0D, это "Enter"/"перевод каретки", то производится скроллирование экрана. Кроме того, терминал понимает символ табуляции 0x09.
Марсоход2 и Марсоход2bis визуально почти ничем не отличаются, но и на самом деле они производятся на одной и той же печатной плате. Главное отличие этих плат обусловлено установленными чипами.
Плата Марсоход2, FPGA Cyclone III, чип EP3C10E144C8, 10 тысяч логических элементов, 414Кбит встроенной памяти, 2 PLL, 23 (18x18) или 46 (9x9) встроенных умножителей.
Плата Марсоход2bis, FPGA Cyclone IV E, чип EP4CE6E22C8, 6 тысяч логических элементов, 270Кбит встроенной памяти, 2 PLL, 15 (18x18) или 30 (9x9) умножителей.
Плата Марсоход2bis немного дешевле, она в базовой комплектации имеет менее емкий чип. К тому же у Cyclone IV меньше I/O выводов, из-за этого на этой плате три светодиода и одна кнопка, у платы Марсоход2 есть 4 светодиода и две кнопки. Но зато Cyclone IV поддерживается современным программным обеспечением Intel Quartus Prime Lite 18.1 Edition, а для Cyclone III последняя версия квартуса - это Quartus II v13.1.
Посмотрим, смогу ли я перенести проект "Простой текстовый терминал" на плату Марсоход2bis?
Скачаю проект с нашего сайта из раздела згрузки и распакую его:
Начнем с того, что проект сделан в среде Quartus II v13. Этот проект даже нельзя открыть в современной среде Intel Quaruts Prime, так как Cyclone III этой средой не поддерживается. Что делать?
Сейчас вручную создадим новую ревизию этого проекта. Для этого скопируем существующий файл cyclone.qsf (Quartus Settings File) в новый файл m2bis_6K_LE.qsf. Это будут настройки новой ревизии. Ревизиии - это отдельные конфигурации проекта, которые позволяют запускать его на разных платах и чипах.
В новом файле настроек m2bis_6K_LE.qsf меняем строки
set_global_assignment -name FAMILY "Cyclone III"
set_global_assignment -name DEVICE EP3C10E144C8
на
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22C8
Таким образом, я указываю, что настройки делаются для конкретной микросхемы EP4CE6E22C8 из серии Cyclone IV E.
Дальше из этого файла удаляем все существующие строки начинающиеся с set_location_assignment. Это назначения конкретного сигнала модуля верхнего уровня из проекта конкретному выводу микросхемы. Вместо старых назначений нужно вставить новые назначения, конкретно для платы Марсоход2bis:
set_location_assignment PIN_24 -to FTDI_BD0
set_location_assignment PIN_28 -to FTDI_BD1
set_location_assignment PIN_11 -to FTDI_BD2
set_location_assignment PIN_10 -to FTDI_BD3
set_location_assignment PIN_25 -to CLK100MHZ
set_location_assignment PIN_23 -to KEY0
set_location_assignment PIN_30 -to SDRAM_DQ[15]
set_location_assignment PIN_31 -to SDRAM_DQ[14]
set_location_assignment PIN_32 -to SDRAM_DQ[13]
set_location_assignment PIN_33 -to SDRAM_DQ[12]
set_location_assignment PIN_34 -to SDRAM_DQ[11]
set_location_assignment PIN_38 -to SDRAM_DQ[10]
set_location_assignment PIN_39 -to SDRAM_DQ[9]
set_location_assignment PIN_42 -to SDRAM_DQ[8]
set_location_assignment PIN_71 -to SDRAM_DQ[7]
set_location_assignment PIN_72 -to SDRAM_DQ[6]
set_location_assignment PIN_73 -to SDRAM_DQ[5]
set_location_assignment PIN_74 -to SDRAM_DQ[4]
set_location_assignment PIN_75 -to SDRAM_DQ[3]
set_location_assignment PIN_76 -to SDRAM_DQ[2]
set_location_assignment PIN_77 -to SDRAM_DQ[1]
set_location_assignment PIN_80 -to SDRAM_DQ[0]
set_location_assignment PIN_60 -to SDRAM_A[0]
set_location_assignment PIN_64 -to SDRAM_A[1]
set_location_assignment PIN_65 -to SDRAM_A[2]
set_location_assignment PIN_66 -to SDRAM_A[3]
set_location_assignment PIN_46 -to SDRAM_A[4]
set_location_assignment PIN_49 -to SDRAM_A[5]
set_location_assignment PIN_50 -to SDRAM_A[6]
set_location_assignment PIN_51 -to SDRAM_A[7]
set_location_assignment PIN_52 -to SDRAM_A[8]
set_location_assignment PIN_53 -to SDRAM_A[9]
set_location_assignment PIN_59 -to SDRAM_A[10]
set_location_assignment PIN_54 -to SDRAM_A[11]
set_location_assignment PIN_70 -to SDRAM_LDQM
set_location_assignment PIN_43 -to SDRAM_UDQM
set_location_assignment PIN_55 -to SDRAM_BA0
set_location_assignment PIN_58 -to SDRAM_BA1
set_location_assignment PIN_67 -to SDRAM_RAS
set_location_assignment PIN_68 -to SDRAM_CAS
set_location_assignment PIN_69 -to SDRAM_WE
set_location_assignment PIN_44 -to SDRAM_CLK
set_location_assignment PIN_83 -to LED[2]
set_location_assignment PIN_84 -to LED[1]
set_location_assignment PIN_85 -to LED[0]
set_location_assignment PIN_144 -to VGA_RED[4]
set_location_assignment PIN_1 -to VGA_RED[3]
set_location_assignment PIN_2 -to VGA_RED[2]
set_location_assignment PIN_3 -to VGA_RED[1]
set_location_assignment PIN_7 -to VGA_RED[0]
set_location_assignment PIN_136 -to VGA_GREEN[5]
set_location_assignment PIN_137 -to VGA_GREEN[4]
set_location_assignment PIN_138 -to VGA_GREEN[3]
set_location_assignment PIN_141 -to VGA_GREEN[2]
set_location_assignment PIN_142 -to VGA_GREEN[1]
set_location_assignment PIN_143 -to VGA_GREEN[0]
set_location_assignment PIN_128 -to VGA_BLUE[4]
set_location_assignment PIN_129 -to VGA_BLUE[3]
set_location_assignment PIN_132 -to VGA_BLUE[2]
set_location_assignment PIN_133 -to VGA_BLUE[1]
set_location_assignment PIN_135 -to VGA_BLUE[0]
set_location_assignment PIN_127 -to VGA_HSYNC
set_location_assignment PIN_126 -to VGA_VSYNC
set_location_assignment PIN_100 -to ADC_D[0]
set_location_assignment PIN_99 -to ADC_D[1]
set_location_assignment PIN_98 -to ADC_D[2]
set_location_assignment PIN_91 -to ADC_D[3]
set_location_assignment PIN_90 -to ADC_D[4]
set_location_assignment PIN_89 -to ADC_D[5]
set_location_assignment PIN_88 -to ADC_D[6]
set_location_assignment PIN_87 -to ADC_D[7]
set_location_assignment PIN_86 -to ADC_CLK
set_location_assignment PIN_101 -to IO[0]
set_location_assignment PIN_103 -to IO[1]
set_location_assignment PIN_104 -to IO[2]
set_location_assignment PIN_105 -to IO[3]
set_location_assignment PIN_106 -to IO[4]
set_location_assignment PIN_110 -to IO[5]
set_location_assignment PIN_111 -to IO[6]
set_location_assignment PIN_112 -to IO[7]
set_location_assignment PIN_113 -to IO[8]
set_location_assignment PIN_114 -to IO[9]
set_location_assignment PIN_115 -to IO[10]
set_location_assignment PIN_119 -to IO[11]
set_location_assignment PIN_120 -to IO[12]
set_location_assignment PIN_121 -to IO[13]
set_location_assignment PIN_124 -to IO[14]
set_location_assignment PIN_125 -to IO[15]
set_location_assignment PIN_12 -to DCLK
set_location_assignment PIN_13 -to DATA0
set_location_assignment PIN_8 -to NCSO
set_location_assignment PIN_6 -to ASDO
В нашем случае, возможно, этого можно было и не делать, так как чипы на обеих платах очень похожы, хоть и разных серий. Да и печатная плата одна и та же. Однако, я рассказываю про общий случай переноса проектов. В общем случае менять назначения выводов в соответствии со схемой платы обязательно! Да даже и при переходе от платы Марсоход2 к плате Марсоход2bis есть отличия в назначениях выводов. Ведь у платы Марсоход2bis нет сигнала KEY1 и LED[3], в qsf файле для cyclone3 платы Марсоход2 есть еще две строки:
set_location_assignment PIN_22 -to KEY1
set_location_assignment PIN_79 -to LED[3]
Самое главное, нужно проследить, чтобы каждый входной или выходной сигнал проекта имел назначение на конкретный вывод микросхемы FPGA. Иначе Fitter имееет право самопроизвольно назначать сигнал первому попавшемуся свободному выводу микросхемы.
Обращаю внимание, что желательно, чтобы в файле настроек проекта, *.qsf, имена сигналов совпадали по регистру с именами в проекте. То есть если в проекте сигнал назван большими буквами, то рекомендую и в настройках проекта делать назначения по имени сигнала с большими буквами.
Итак, назначения сделаны.
Далее добавляем ревизию в проект, в файл cyclone3.qpf (Quartus Project File) добавляю строку с "m2bis_6K_LE" перед существующей строкой "cyclone3"
# Revisions
PROJECT_REVISION = "m2bis_6K_LE"
PROJECT_REVISION = "cyclone3"
Теперь проект можно открыть в среде Intel Quartus Prime.
Вы можете попробовать откомпилировать, но сразу скажу, что будут ошибки. Портирование еще не завершено.
Как я уже писал, есть отличия по ресурсам платы, нет одного светодиода и нет одной кнопочки. Значит их нужно удалить из проекта, ведь они здесь не несут какой-то значимой роли:
Вторая проблема серьезней. Не хватает встроенной памяти для видеоадаптера..
Первое, что можно сделать - это отключить использующийя в проекте модуль SignalTap, он сам по себе занимает какую-то часть внутренней памяти. Этого мало.
Можно попробовать сократить объем памяти приемного фифо. Я пробовал, но все равно не достаточно
Если внимательно прочитать статью об этом проекте "Простой текстовый терминал", то там написано, что он написан очень просто, без мысли об экономии внутренней памяти. Все дело в компоненте txtd - текстовый дисплей, он содержит память на 8196 символов и аттрибутов символов. Этот модуль был готов и переделывать его тогда не хотелось. Но хотелось реализовать функцию скроллирования текста. А чтобы сделать scroll нужно скопировать нижнюю часть экрана на одну строку вверх и очистить самую нижнюю строку. Тогда родилась "блестящая идея" поместить в проект вторую копию экрана из которой можно было читать и писать в память модуля txtd во время скроллирования. Получается, что проект имеет двойной перерасход по внутренней памяти. Логично было бы переделать эту часть проекта, но что проще, полный редизайн или "слегка поправить"? Я выбираю второй путь. Посмотрев по исходникам проекта я вижу, что для аттрибутов экрана именно в этом проекте используется всего 2 цвета: черный, где нет символов и бело-синий для символов. Цвет символа можно кодировать всего одним битом. Сейчас же для кодировки аттрибутов используется 8 бит. Значит я нашел место, где можно по-быстрому сделать оптимизацию!
Пишу на Verilog HDL вот такой модуль конвертации аттрибутов:
module conv(
input wire [15:0] a16,
input wire [8:0] b9,
output wire [8:0] a9,
output wire [15:0] b16
);
assign a9 = { |a16[15:8], a16[7:0]};
wire [7:0]char_color;
assign char_color = b9[8] ? 8'h1F : 8'h00;
assign b16 = { char_color, b9[7:0]};
endmodule
Этот модуль конвертирует 16-ти битную шину { аттрибут, символ } в 9-ти битную, где цвет теперь задается только одним битом. Ну и наоборот, девять бит шины преобразуется в шестнадцать. Делаю из этого модуля графический компонент через меню File => Create / Update => Create Symbol Files for Current File, чтобы можно было вставить в схему, так чтобы соседние компоненты продолжали думать, что символы шестнадцатибитные, что все еще 8 бит на аттрибут/цвет символа:
Этот конвертор нужно вставить в проект в два места: в топ модуль и в модуль Verilog txtd:
..............
wire [8:0]wrdata9;
wire [8:0]rddata9;
conv conv2(
.a16( wrdata ),
.a9( wrdata9 ),
.b9( rddata9 ),
.b16( scr_data)
);
screen2 my_screen2 (
.data( wrdata9 ),
.rdaddress( scr_addr ),
.rdclock( pixel_clock ),
.wraddress( wradr ),
.wrclock( pixel_clock ),
.wren( wren ),
.q( rddata9 )
);
.........
Ну и, конечно, в визарде компонента screen2 (Dual-port ram) меняю разрядность памяти с 16-ти бит до 9-ти:
Теперь кажется все.
Хотелось бы еще обратить внимание на два момента.
1. Нужно зайти в меню Assignments => Device => в диалоговом окне кнопка Device and Pin Options.. => далее смотреть Unused Pins. Я рекомендую ставить неиспользуемые пины проекта в As input tri-stated.
Если про создании нового проекта или при переносе проекта с одной платы на другую мы забудем назначить какой-то вывод, то ничего страшного не произойдет, так как неиспользуемые выводы микросхемы ПЛИС будут включены в режим ввода с высоким входным сопротивлением. Если же в этой опции будет стоять к примеру As output driving ground, то можно получить неприятности: какая-то внешняя микросхема платы будет подавать нам полезный сигнал, а мы со стороны ПЛИС его коротим на землю. Не хорошо будет.
2. Есть еще момент связанный с назначением пинов. В этом же диалоговом окне Device and Pin Options есть пункт Dual Purpose Pins. Может оказаться так, что делаем назначение сигнала на конкретный пин согласно схемы платы, а компилятор и Fitter ругаются, говорят, что этот сигнал сюда нельзя назначить, так как там уже есть другой сигнал. Эту проблему можно попробовать решить здесь:
Действительно некоторые выводы в FPGA могут играть двойную роль и эта вторая функция может быть отключена или включена. В микросхемах Cyclone III и Cyclone IV есть такие пины - это сигналы для подключения внешней загрузочной флеш памяти: DCLK, Data, nCEO, nCSO и другие.
В данном случае, при переносе проекта мне не нужны Dual-Purpose Pins и неиспользуемые пины уже стоят в As input tri-state. Но будьте внимательны при переносе других проектов. В этох местах может быть установлено не то, что нужно.
Компилирую и запускаю проект в моей плате:
Все работает! На видео показано, как загружается проект в ПЛИС платы с подключенным VGA монитором, затем запускается программа TeraTerm, с ее помощью на терминал через последовательный порт посылается текстовый файл. Потом запускается программа Putty, она позволяет печатать текст на терминале.
Перенос проекта на другой чип состоялся успешно, но кое-где пришлось шаманить - немножно менять проект для уменьшения требований по необходимой встроенной памяти. И, кстати, теперь проект можно компилировать и в 13м квартусе для прежней микросхемы Cyclone III, так как ревизию для этого чипа я оставил без изменений.
PS: раньше мы делали архивы проектов, которые можно было бы скачать в разделе загрузки на нашем сайте. Теперь же в основном, мы публикуем проекты на github. Теперь смотрите этот проект вот здесь: https://github.com/marsohod4you/fpga_simple_tty
Подробнее...