MIPSfpga и внутрисхемная отладка

Поставляемые в составе пакета MIPSfpga документация, ПО и конфигурационные файлы предполагают применение Bus Bluster в качестве аппаратного отладчика. Статья содержит инструкции по использованию для этой цели практически любого USB-UART адаптера, построенного на микросхеме FTDI с поддержкой MPSSE (FT232H, FT2232H, FT4232H, FT2232D). Кратко описывается интеграция среды разработки Visual Studio Code и отладчика GNU GDB.
Все конфигурационные файлы, описываемые в статье, а также часть документации доступны на github.


Элементы системы


image


MIPSfpga — промышленное процессорное ядро MIPS microAptiv, исходные коды которого доступны под академической лицензий [L1]. MIPSfpga-plus — проект системы на кристалле, построенной на базе ядра MIPSfpga [L2]. В моем случае система развернута на плате Terasic DE10-Lite c ПЛИС Altera MAX10 на борту [L3].
В качестве адаптера (программатора, отладчика) между MIPSfpga-plus и ПК выступает плата Pinboard II [L4] с микросхемой FT2232 [D1] производства компании FTDI [L5]. Физически платы связаны между собой интерфейсами UART и JTAG [L6]. Первый используется для консольного доступа к отлаживаемой системе. Второй — является базовым интерфейсом для отладки с использованием EJTAG [D7]. Разница между JTAG и EJTAG очень хорошо показана в [L7].
Ключевой технологией, которая существенно упрощает построение программаторов и отладчиков на базе микросхем FTDI, является Multi-Protocol Synchronous Serial Engine (MPSSE) [D2, D3, D4]. Поддержка MPSSE является принципиальным моментом для описываемой в статье конфигурации. Получить схожие результаты вы сможете только на USB-адаптерах, построенных на базе следующих микросхем FTDI: FT232H, FT2232H, FT4232H, FT2232D.
На стороне ПК взаимодействие с USB-платой осуществляется: для канала UART — с использованием обычных драйверов от FTDI и любой терминальной программы, для канала MPSSE используются драйвер WinUSB (работа проводилась на Windows — системе).
Для компиляции используются Codescape GNU Tools [D9], для отладки — традиционная связка OpenOCD [L8, D8] и GNU GDB [D5]. Эти программные пакеты входят в состав Codescape MIPS SDK [L12]. Их взаимодействие между собой осуществляется по протоколу gdbserver [L9].
В качестве GUI при отладке применена Visual Studio Code (VSCode) [L10] с установленным расширением vscode-cpptools [L11]. В силу того, что это расширение ориентировано на высокоуровневую разработку (C/C++), в интерфейсе отсутствуют такие представления как просмотр инструкций ассемблера, просмотр памяти, прямой доступ к регистрам.


Кратко об MPSSE и FTDI


MPSSE — это аппаратно реализованный набор примитивных функций, которые существенно упрощают реализацию последовательных интерфейсов (SPI, I2C, JTAG). Например: отправить N бит по фронту тактового сигнала, прочитать M бит по спаду, установить вывод Х в ноль и т.д.
До 2014 года китайцы в существенных масштабах клепали контрафактные микросхемы FTDI, по этой причине USB-UART преобразователи на их основе были одними из самых распространенных на площадках типа ebay или aliexpress. А разработчики — с радостью строили на них свои решения, взять хотя бы ту же поддержку со стороны OpenOCD. Список выпускаемых FTDI микросхем USB-адаптеров приведен ниже, имеющие поддержку MPSSE — отмечены цветом.
В 2014 году компания FTDI выпускает обновленные драйвера, которые отказываются работать с контрафактными устройствами [L13, L14]. Количество предложений на эти USB-UART адаптеры с тех пор несколько сократилось, но они все равно остаются одними из самых распространенных из имеющихся на руках у разработчиков.
Еще FTDI, несмотря на прекрасные чипы, иногда ругают за качество ПО к ним. Возможно, это у меня кривые руки, но изрядно намучившись в свое время с работой с libMPSSE из под .NET, я написал свой аналог этой библиотеки на C# [L15].
Если кто-то из читателей знает адекватную альтернативу для чипов FTDI, недорогую и при этом корректно поддерживаемую OpenOCD — буду благодарен за информацию.
image


Схема USB-модуля


Ниже представлен фрагмент схемы отладочной платы Pinboard II, в вашем случае схема модуля может отличаться. Основным определяющим для нас параметром является возможность прямого доступа к портам микросхемы: для работы достаточно одного свободного MPSSE канала (для TCK, TDI, TDO, TMS) + 1 GPIO выход для сигнала сброса (SRSTn). Для второго канала микросхемы функциональность MPSSE обязательной не является, его при этом удобно использовать для UART взаимодействия с отлаживаемой системой.
Выводы микросхемы FTDI напрямую подключаются к портам ПЛИС. Строго говоря, это является нарушением [D7, D6], т.к. предполагается, что там должны быть установлены pull-up, pull-down или последовательно включенные резисторы. У меня все работает без них: внимательно проверяйте настройку портов на вход-выход, проверьте ограничение максимального тока на задействованных для EJTAG портах ПЛИС.
Напряжение на выводах адаптера установлено в 3.3V. В случае Pinboard II для выбора этого напряжения предусмотрен отдельный джампер (VCCIO_PWR_SEL). Для других плат — ориентируйтесь на их схемы и настройки ПЛИС, в отдельных случаях может потребоваться доработка адаптера (что проще) и/или схема преобразования уровней [L16] (что сложнее и может привести к помехам или снижению скорости).
image


Типовое подключение EJTAG


Типовая схема подключения по EJTAG интерфейсу получена из [D6]. Опциональные входы DINT и TRSTn в рассматриваемой конфигурации не используются. Соответствие остальных — приведено в таблице.
image
Таблица подключения USB-модуля к ПЛИС
image


Конфигурационные файлы (на github)


mipsfpga_ftdi.cfg
#
# OpenOCD config for using FT2232D that is directly connected
# to FPGA as MIPSfpga EJTAG debugger
# Any FTDI USB IC with MPSSE support (required) can be used 
# 
# 2017, Stanislav Zhelnio
# 

# ##########################################################
# interface part
# ##########################################################

# interface, transport and channel setup 
# (use zadig to install WinUSB driver instead of FTDI one)
interface ftdi
transport select jtag

ftdi_channel 0
ftdi_vid_pid 0x0403 0x6010

# ftdi MPSSE initial value and direction
# for detailed description of Magic Numbers look at 
# connection table and FTDI AppNote AN_108:
#   chapter 2.1 Data bit Definition
ftdi_layout_init 0x0018 0x081b

# special signals
# described in OpenOCD User’s Guide:
#   chapter 8.2 Interface Drivers (ftdi)
#   chapter 9 Reset Configuration
# nTRST is not used
ftdi_layout_signal nSRST -data 0x0010 -oe 0x0020
ftdi_layout_signal LED -ndata 0x0800 -oe 0x0800

# speed setup
# decrease when errors
adapter_khz 10000

# ##########################################################
# target part
# ##########################################################

# reset delays 
# described in OpenOCD User’s Guide:
#   chapter 9 Reset Configuration
adapter_nsrst_delay 100
jtag_ntrst_delay 100

# reset sygnal config
# nSRST is directly connected to MIPSfpga (~SI_ColdReset) wire
reset_config srst_only separate srst_nogate srst_push_pull 

# To check connection and scan EJTAG chain uncomment this
# and comment all that is bellow then 'shutdown' command.
# Use IDCODE value to detect connection errors:
# IDCODE that was set in RTL config should be identical
# to -expected-id result in 'shutdown' output.
# The IDCODE structure is described in EJTAG Specification:
#   chapter 6.5.1 Device Identification (ID) Register

#shutdown

# tap connector and target creation
# change -expected-id to your IDCODE value
# for other arguments see at OpenOCD User’s Guide
jtag newtap auto0 tap -expected-id  0x000f1005 -irlen 5 -ircapture 0x1 -irmask 0x1f
target create auto0.tap mips_mAptiv -endian little -chain-position auto0.tap

# tap configuration 
# change params acording to compile and memory settings
# for details see at OpenOCD User’s Guide
auto0.tap configure -work-area-phys 0xa0003ff00 -work-area-size 256 -work-area-backup 0

# EJTAG scan perion 
mips32 scan_delay 20000

# run the debugger process and wait for gdb connection
init

  • основной и единственный конфигурационный файл для OpenOCD;
  • условно может быть разделен на 2 части: одна описывает соединение программатора и целевой системы (interface part), вторая — настройки, специфические для отлаживаемого ядра (target part). Внутри каталога OpenOCD они обычно размещаются в разных папках, здесь — для упрощения объединены в один.

c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "/usr/include",
                "/usr/local/include"
            ],
            "browse": {
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        },
        {
            "name": "Linux",
            "includePath": [
                "/usr/include",
                "/usr/local/include"
            ],
            "browse": {
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        },
        {
            "name": "Win32",
            "includePath": [
                "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*"
            ],
            "browse": {
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        },
        {
            "name": "mips-mti-elf",
            "includePath": [
                "D:/Codescape/Toolchains/mips-mti-elf/2016.05-03/lib/gcc/mips-mti-elf/4.9.2/include/*"
            ],
            "browse": {
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ]
}

  • файл конфигурации расширения vscode-cpptools;
  • содержит информацию о местонахождении заголовочных файлов, необходимую для упрощения навигации по исходникам и работе функции автозавершения в окне редактора VSCode.

launch.json
{
    "version": "0.2.0",
    "configurations": [

        {
            "name": "MIPS Load",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/program.elf",
            "cwd": "${fileDirname}",
            "miDebuggerPath": "d:/CODESC~1/TOOLCH~1/mips-mti-elf/2016.05-03/bin/mips-mti-elf-gdb.exe",
            "setupCommands": [
                {"text": "file 'D:/mipsfpga-plus/programs/00_counter/program.elf'"},
                {"text": "target remote localhost:3333"},
                {"text": "set endian little"},
                {"text": "monitor reset halt"},
                {"text": "load"},
                {"text": "br main"},
                {"text": "monitor continue"}
            ],
            "customLaunchSetupCommands": [],
            "launchCompleteCommand": "None",
            "targetArchitecture": "mips"

            //Uncomment this to debug
            //,"logging": { "engineLogging": true }
            //or this for verbose debug
            //,"logging": { "engineLogging": true, "trace": true, "traceResponse": true }
        },
        {
            "name": "MIPS Attach",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/program.elf",
            "cwd": "${fileDirname}",
            "miDebuggerPath": "d:/CODESC~1/TOOLCH~1/mips-mti-elf/2015.06-05/bin/mips-mti-elf-gdb.exe",
            "setupCommands": [
                {"text": "file 'D:/mipsfpga-plus/programs/00_counter/program.elf'"},
                {"text": "target remote localhost:3333"},
                {"text": "set endian little"}
            ],
            "customLaunchSetupCommands": [],
            "launchCompleteCommand": "None",
            "targetArchitecture": "mips"

            //Uncomment this to debug
            //,"logging": { "engineLogging": true }
            //or this for verbose debug
            //,"logging": { "engineLogging": true, "trace": true, "traceResponse": true }
        }
    ]
}

  • конфигурационный файл VSCode, содержащий настройки запуска отлаживаемой программы;
  • в данном случае описывает два профиля запуска: «MIPS Load» — загрузить прошивку в память системы, после чего приступить к отладке; «MIPS Attach» — подключиться к уже прошитой системе.

Первичная настройка


  • подключить USB-модуль к ПК;
  • дождаться, пока установятся драйвера FTDI, используя программу Zadig, выполнить смену драйвера на канале с MPSSE на WinUSB;
  • скопировать конфигурационный файл mipsfpga_ftdi.cfg в каталог с OpenOCD;
  • в случае, если ваша схема подключения по каким-то причинам отличается от приведенной в таблице, необходимо пересчитать параметры инициализации OpenOCD, в частности, аргументы команд ftdi_layout_init и ftdi_layout_signal.
  • рассмотрим порядок их получения для приведенной выше таблицы подключения:
    0×0018 — установить 1 как начальное значение на портах ADBUS3 и ADBUS4 (биты 3 и 4 соответственно);
    0×081b — настроить порты ADBUS0,1,3,4, ACBUS3 на выход (биты 0–3,4, 11).


    ftdi_layout_init 0x0018 0x081b

  • для команды ftdi_layout_signal логика та же, совпадающие аргументы параметров -data и -oe (output enable) означают, что подключение производится напрямую, без какого-либо буфера. Использование -ndata — позволяет инвертировать выход.
  • соответствие выводов конкретным битам приведено в разделе 2.1 аппноты [D3].

Настройки на стороне MIPSFpga


  • при инициализации EJTAG-подключения отлаживаемое устройство передает на ПК значение регистра IDCODE, которое задается разработчиком в RTL коде. Рекомендую установить какие-либо произвольные (ненулевые) значения в этот регистр, т.к. это поможет при определении ошибок подключения: если полученный при подключении IDCODE не соответствует заданному в коде, значит где-то уже закралась ошибка.
  • формат этого регистра [D7] следующий:
    image
  • параметры EJ_ManufID и EJ_PartNumber задаются в файле mfp_system.v;
  • проверить и установить значения EJ_DINT и EJ_TRST_N. В рассматриваемой конфигурации для подключения они не используется:
    assign EJ_DINT         = 1'b0;
    assign EJ_TRST_N       = 1'b1;

Настройки компиляции


  • убедиться в том, что настройки компилятора в части использования памяти соответствуют параметрам команды configure в файле mipsfpga_ftdi.cfg;
  • добавить отладочные символы — параметры -g -gdwarf-2
  • установить уровень оптимизации -O0 или -O1. С -O2 отладка также будет работать, но исполнение кода может быть не последовательным: указатель текущей выполняемой строки кода будет «прыгать».

Тест подключения


  • открыть файл mipsfpga_ftdi.cfg и закомментировать все команды, которые идут после настройки сигнала сброса (после reset_config). Раскомментировать команду shutdown. В этой конфигурации OpenOCD будет подключаться к отлаживаемому устройству, получать IDCODE и отключаться;
  • выполнить в консоли команду openocd-0.9.2.exe -f mipsfpga_ftdi.cfg
  • результатом ее корректного выполнения является следующий вывод, где 0×000f1005 — это ранее заданный IDCODE


    Open On-Chip Debugger 0.9.1-dev-microAptiv-dirty (2015-05-08-15:32)
    Licensed under GNU GPL v2
    For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
    adapter speed: 10000 kHz
    adapter_nsrst_delay: 100
    jtag_ntrst_delay: 100
    srst_only separate srst_nogate srst_push_pull connect_deassert_srst
    shutdown command invoked
    Info : clock speed 10000 kHz
    Warn : There are no enabled taps.  AUTO PROBING MIGHT NOT WORK!!
    Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x000f1005 ..."
    Warn : AUTO auto0.tap - use "... -irlen 5"
    Warn : gdb services need one or more targets defined

  • проверить, что получено именно то значение, которое ранее было задано в RTL-коде (mfp_system.v);
  • в случае, если значения расходятся, необходимо найти и устранить ошибку подключения. Возможно, что следует снизить скорость. В моем случае, к примеру, помеху вносили щупы подключенного логического анализатора;
  • после того, как корректное значение IDCODE успешно получено, файл можно вернуть в начальное состояние.

Отладка в консольном режиме


  • запустить openocd-0.9.2.exe -f mipsfpga_ftdi.cfg. Иногда, при внезапной потере связи OpenOCD может зависнуть, поэтому я предпочитаю запускать его в отдельном окне терминала.
  • корректным является следующий вывод, после чего OpenOCD не прерывает работу и ожидает подключения от gdb:


    Open On-Chip Debugger 0.9.1-dev-microAptiv-dirty (2015-05-08-15:32)
    Licensed under GNU GPL v2
    For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
    adapter speed: 10000 kHz
    adapter_nsrst_delay: 100
    jtag_ntrst_delay: 100
    srst_only separate srst_nogate srst_push_pull connect_deassert_srst
    scan delay: 20000 nsec
    running in fast queued mode
    Info : clock speed 10000 kHz
    Info : JTAG tap: auto0.tap tap/device found: 0x000f1005 (mfg: 0x002, part: 0x00f1, ver: 0x0)

  • в отдельном окне терминала запустите gdb: mips-mti-elf-gdb -q program.elf и выполните несколько операций по отладке


    > mips-mti-elf-gdb -q program.elf
    Reading symbols from program.elf...done.

  • подключение к отлаживаемой системе


    (gdb) target remote localhost:3333
    Remote debugging using localhost:3333
    0xbfc00000 in ?? ()

  • настройка целевого порядка байтов


    (gdb) set endian little
    The target is assumed to be little endian

  • останов системы


    (gdb) monitor reset halt
    JTAG tap: auto0.tap tap/device found: 0x000f1005 (mfg: 0x002, part: 0x00f1, ver: 0x0)
    target state: reset
    entered debug state at PC 0xbfc00000, target->state: halted
    target state: halted
    target halted in MIPS32 mode due to debug-request, pc: 0xbfc00000

  • загрузка прошивки


    (gdb) load
    Loading section .text_ram, size 0x260 lma 0x80001000
    Loading section .init, size 0x24 lma 0x80001260
    Loading section .fini, size 0x1c lma 0x80001284
    Loading section .eh_frame, size 0x4 lma 0x800012a0
    Loading section .data, size 0xc lma 0x800012a4
    Loading section .ctors, size 0x8 lma 0x800012b0
    Loading section .dtors, size 0x8 lma 0x800012b8
    Loading section .jcr, size 0x4 lma 0x800012c0
    Loading section .reset, size 0x280 lma 0x9fc00000
    Start address 0xbfc00000, load size 1348
    Transfer rate: 12 KB/sec, 149 bytes/write.

  • установка точки останова на вход в функцию main


    (gdb) b main
    Breakpoint 1 at 0x800011e0: file main.c, line 14.

  • запуск кода на выполнение


    (gdb) c
    Continuing.
    entered debug state at PC 0x800011e0, target->state: halted
    [Remote target] #1 stopped.
    main () at main.c:14
    warning: Source file is more recent than executable.
    14      {

  • получение значения регистров после останова
    (gdb) i r
          zero       at       v0       v1       a0       a1       a2       a3
    R0   00000000 deadbeef 800011e0 00000010 00000000 00000002 80001000 00000000
            t0       t1       t2       t3       t4       t5       t6       t7
    R8   deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
            s0       s1       s2       s3       s4       s5       s6       s7
    R16  deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
            t8       t9       k0       k1       gp       sp       s8       ra
    R24  deadbeef deadbeef deadbeef deadbeef 800092a8 80040000 00000000 9fc00274
        status       lo       hi badvaddr    cause       pc
      00400000 00000100 00000000 c0000000 00000008 800011e0
    (gdb)

Настройка VSCode


  • скачать и установить Visual Studio Code [L17];
  • запустить, перейти в раздел расширений, установить расширение vscode-cpptools [L11];
  • открыть в VSCode каталог (т.н. workspace directory), который содержит исходные коды отлаживаемой программы;
  • в корне workspace directory создать папку .vscode, скачать и поместить в нее файлы c_cpp_properties.json и launch.json;
  • открыть эти файлы и скорректировать пути к заголовочным файлам, gdb, а также к elf файлу, который предполагается загружать на отлаживаемую систему;
  • я столкнулся с небольшим багом, из-за которого пришлось явно указывать полный путь к elf файлу.

Отладка в VSCode


  • предполагается, что компиляция уже произведена и elf файл находится там, где установлено настройками launch.json;
  • запустить openocd-0.9.2.exe -f mipsfpga_ftdi.cfg аналогично тому, как это было описано выше;
  • в интерфейсе VSCode перейти в панель «Debug», выбрать профиль отладки MIPS Load;
  • запустить отладку;
  • если все настроено верно, то окно VSCode будет выглядеть примерно также, как изображено на скриншоте ниже;
  • если что-то пошло не так, то следует раскомментировать раздел «logging» в файле launch.json и выполнить анализ ошибок в консоли отладки (открывается сочетанием клавиш (ctrl + `);

image


Благодарности


Автор выражает благодарность коллективу переводчиков учебника Дэвида Харриса и Сары Харрис «Цифровая схемотехника и архитектура компьютера», компании Imagination Technologies за академическую лицензию на современное процессорное ядро, персонально Юрию Панчулу YuriPanchul за его работу по популяризации MIPSfpga, а также DIHALT за отладочную плату, которая вот уже который год не покидает поверхность моего стола.


Ссылки


[L1] — Как начать работать с MIPSfpga;
[L2] — Проект MIPSfpga-plus на github;
[L3] — FPGA плата Terasic DE10-Lite;
[L4] — Отладочная плата Pinboard II;
[L5] — Сайт компании FTDI;
[L6] — Интерфейс JTAG? — Это очень просто!
[L7] — EJTAG: аттракцион для хакеров;
[L8] — OpenOCD: руководство пользователя (перевод);
[L9] — Wikipedia. gdbserver;
[L10] — Документация VSCode: Debugging;
[L11] — Документация VSCode: C/C++ for VS Code;
[L12] — Codescape MIPS SDK;
[L13] — FTDI наносит ответный удар;
[L14] — Воскрешаем FTDI в картинках;
[L15] — MPSSELight. Lightweight .net MPSSE library;
[L16] — Согласование логических уровней 5В и 3.3В устройств
[L17] — Visual Studio Code;


Документация


[D1] — FTDI FT2232D Datasheet;
[D2] — FTDI Application Note AN 135. FTDI MPSSE Basics;
[D3] — FTDI Application Note AN 108. Command Processor for MPSSE and MCU Host Bus Emulation Modes;
[D4] — FTDI Software Application Development. D2XX Programmer’s Guide;
[D5] — Debugging with gdb. Codescape GNU Tools 2016.05–03 for MIPS MTI Bare Meta;
[D6] — MIPS32 microAptiv UP Processor Core Family Integrator«s Guide;
[D7] — EJTAG Specification. Document Number: MD00047;
[D8] — OpenOCD User«s Guide for release 0.8.0;
[D9] — Using the GNU Compiler Collection. Codescape GNU Tools 2016.05–03 for MIPS MTI Bare Metal;
[D10] — MIPSfpga Getting Started Guide;


Изображения


[P1] Основные элементы системы;
[P2] Характеристики микросхем USB-адаптеров FTDI (источник: L5);
[P3] Фрагмент схемы отладочной платы Pinboard II (источник: L4);
[P4] Типовая схема подключения по EJTAG интерфейсу (источник: D6);
[P5] Таблица подключения USB-модуля к ПЛИС;
[P6] Регистр IDCODE (источник: D7);
[P7] Visual Studio Code в режиме отладки (скриншот).

Комментарии (0)

© Habrahabr.ru