Отладочные средства🔗
Создание и настройка отладочной сессии Vitis🔗
Отладочная конфигурация🔗
Для осуществления процесса отладки с возможностью доступа ко внутренним ресурсам SoC необходимо создать отладочную сессию. Для этого требуется создать и настроить отладочную конфигурацию. Все действия выполняются средствами GUI Vitis.
СОВЕТ
Графическая оболочка Vitis при запуске использует системную тему оформления, и если эта тема тёмная, то отображение окон программы оказывается очень некомфортным – многие места является нечитаемыми из-за низкого контраста текста и фона. Исправить это путём настройки цветовой схемы в полной мере не удаётся, намного более простым и эффективным путём является указание темы при загрузке программы, например:
Для загрузки битстрима PL и исполняемого файла программы PS используется Tcl консоль xsct
:
ВНИМАНИЕ
Для того, чтобы консоль xsct была способна подключаться к SoC, нужно предварительно запустить hw_server
(опция -d
запускает сервер в режиме службы (daemon)):
Создание отладочной конфигурации🔗
Диалог отладочных сессий🔗
Оболочка Vitis позволяет создавать различные вариаты сессий, начиная от полноценного проекта со сборой и загрузкой исполняемого в SoC и заканчивая подключением к уже загруженной программе. Ниже показан вариант подключения к уже загруженной программе, т.к. Vitis используется только в качестве front-end отладчика, а сборка и загрузка исполняемого осуществляются другими средствами.
Первым действием является активация диалога отладочных сессий:
Далее, нужно создать отладочную конфигурацию, указав имя и тип:
После этого можно просто подключиться к SoC – будут доступны внутренности микросхемы.
Пример загрузки с помощью консоли xsct
показан ниже.
Загрузка в режиме отладки🔗
В процессе разработки значительно удобнее и быстрее запускать код путём непосредственной загрузки образов (ELF) в память SoC. Для корректной работы необходимо проимитировать процесс штатной загрузки, который состит из двух этапов:
- запуск загрузчика (это часть, которой посвящен данный раздел);
- загрузка битстрима PL (если нужно);
- запуск целевой программы.
В результате работы загрузчика и непосредственно перед запуском целевой программы SoC находится в следующем состоянии:
- низкоуровневая инициализация (SCU, MMU, кэши) выполнена;
- все четыре сегмента OCM размещены по адресу
0xfffc0000
в виде непрерывной области памяти. - таблица векторов прерываний размещена по адресу
0xfffc0000
; - таблица трансляции MMU находится по адресу
0xffffc000
; - инициализация периферийных устройств PS части SoC выполнена загрузчиком (файл
ps7_init.c
).
Всю эту работу осуществил загрузчик, и проэмулировать его работу средствами отладки весьма проблематично. С другой стороны, программировать флешь память при каждой отладочной итерации является неудачным решением: это затратно по времени, это расходует ресурс флешь памяти и, главное, теряется (или сильно затрудняется) возможность иметь доступ к отладочным средствам в виде инспекции объектов программы, установки точек останова и т.п.
Поэтому для организации отладочной сессии применяется следующий сценарий. Хост:
- производит сброс SoC;
- загружает (через JTAG) образ загрузчика (ELF);
- устанавливает точку останова на функции
load_img
; - запускает программу загрузчика;
- дожидается останова работы программы, что означает, что загрузчик остановился в точке перед непосредственно загрузкой целевой программы из флешь памяти;
- удаляет точки останова;
- загружает образ целевой программы (вместо
load_img
); - запускает работу программы.
Описанный сценарий в виде Tcl скрипта, пригодный для запуска из консоли xsct:
proc rl { } {
set timeout 10
bpadd 0xc800; # address of "_start" function
puts "-> set bp at _start"
puts [bplist]
puts "-> reset!"
rst
puts "-> wait for stop at _start"
while { $timeout } {
if { [state] == "Running" } {
after 10
incr timeout -1
if { $timeout == 0 } {
puts "no _start breakpoint, timeout expired"
break
}
} else {
break
}
}
puts "-> remove breakpoint at _start"
bpremove -all
puts "---------------------------------------"
puts "-> load bld.elf"
dow build/prj/${::bv}/ps/bld/bld.elf
puts "-> loading bld.elf done"
puts "-> verify bld.elf"
verify build/prj/${::bv}/ps/bld/bld.elf
puts "-> verification of bld.elf loading done"
puts "---------------------------------------"
puts "-> add breakpoint at 'load_img'"
bpadd load_img
bplist
puts "-> run bld.elf"
con
puts "-> wait for bld.elf complete"
while { [state] == "Running" } {
}
puts "-> remove breakpoints"
bpremove -all
puts "---------------------------------------"
puts "-> load fpga"
fpga build/prj/${::bv}/syn/${::bv}.runs/impl_1/lwircam.bit
puts "-> loading FPGA done"
puts "---------------------------------------"
puts "-> load cam.elf"
dow build/prj/${::bv}/ps/cam/cam.elf
puts "-> loading cam.elf done"
puts "---------------------------------------"
con
Таким образом, описанный алгоритм эмулирует работу связки "загрузчик-целевая программа", позволяя при этом иметь все возможности пользоваться отладочными средствами благодаря тому, что в SoC заргужен полноценный образ ELF.
В коде скрипта можно увидеть ещё одну точку останова – в самом начале на адрес 0xc800
. Это связано с особенностями запуска, когда в загрузочной флеши присутствует валидный образ загрузчика – подробнее эта ситуация описана на странице описания стартапа.