Содержание

Запускаем отладку многопроцессорной системы

В данной статье мы рассмотрим как настроить среду CM-LYNX, чтобы выполнить отладку сразу нескольких процессоров 1967ВНxx. Связь отладчика с процессором осуществляется посредством JTAG интерфейса, поэтому чтобы в режиме отладки иметь доступ сразу к нескольким процессорам, необходимо объединить процессоры в JTAG цепочку. В нашем проекте мы будем использовать отладочный комплект для процессора цифровой обработки сигналов 1967ВН028, на отладочной плате которого уже реализовано соединение двух процессоров 1967ВН028 в JTAG цепочку.

Особенности JTAG цепочки на отладочной плате для 1967ВН028

Подключение процессоров 1967ВН028 к отладчику по интерфейсу JTAG может быть настроено с помощью перемычек XP3-XP5. В зависимости от установленного положения на XP3-XP5 могут быть использованы следующие режимы:

Режим подключения отладчика к процессорамПоложение XP3Положение XP4Положение XP5
Подключён только процессор D5 1-2не установлена1-2
Подключён только процессор D6 2-3не установлена2-3
Подключены оба процессора: JTAG цепочка D6-D5 2-3установлена1-2

Рисунок, наглядно демонстрирующий различные режимы подключения отладчика к процессорам.

Для использования многопроцессорной отладки нам необходимо объединить процессоры в JTAG цепочку, поэтому устанавливаем перемычки на XP3-XP5 для режима с подключением двух процессоров.

Настройка проекта

В качестве тестового примера для отладки мы будем использовать проект Hello World, описанный в статье Создаем проект в среде CM-LYNX. По статье выполняем все пункты по созданию проекта до настроек режима Debug, т.е. указываем новый workspace, создаём в нём проект для 1967ВН028 и добавляем файл main.c с кодом мигания светодиодами. Далее настройка режима Debug будет несколько отличаться от стандартной.

Текущая реализация отладки предусматривает запуск многопроцессорного режима с таким же интерфейсом, как и для однопроцессорного. Однако, т.к. процессоров мы используем сразу несколько, то стандартный файл конфигурации компоновщика (LDF файл) нам не подойдёт, и его необходимо изменить. Чтобы среда понимала наличие нескольких процессоров, в LDF файл, по умолчанию это Name_project.ldf, с помощью оператора PROCESSOR необходимо добавить описание второго процессора, а по сути, скопировать описание имеющегося процессора, но изменив название с P0 на P1.

Чтобы не загромождать LDF файл описаниями процессоров, причём в нашем случае это будет одно и тоже описание, вынесем описание в отдельный файл.

Алгоритм изменения LDF файла будет следующим:

1. Создаём файл с произвольным расширением, например, «two_proc.sec», для этого кликаем правой кнопкой мыши по названию проекта и в выпадающем меню выбираем New→File. В открывшемся окне вводим название файла и расширение.

2. Из стандартного LDF (Name_project.ldf) перемещаем блок SECTIONS из описания PROCESSOR P0 в созданный файл «two_proc.sec».

Ниже приведён листинг фрагмента, который мы перемещаем:

SECTIONS
    {
        program
        {
            FILL(0xb3c00000) // Fill any gaps with NOPs.
            INPUT_SECTION_ALIGN(4)
            INPUT_SECTIONS( StartUp.doj(.program) )
            INPUT_SECTIONS( $OBJECTS(.program*) )

            // The next line adds 10 nops after the last piece of code in the 
            // code section. This is required on TS201 to prevent uninitialised 
            // memory getting into the pipeline.
             . = . + 10;

        } >M0Code

        cdata
        {
            INPUT_SECTIONS( $OBJECTS(.cdata*) )
            INPUT_SECTIONS( $OBJECTS(.strings*) )

            ldf_ctor_start = .;
            INPUT_SECTIONS( $OBJECTS(.ctor0) )
            INPUT_SECTIONS( $OBJECTS(.ctor1) )
            INPUT_SECTIONS( $OBJECTS(.ctor2) )
            INPUT_SECTIONS( $OBJECTS(.ctor3) )
            INPUT_SECTIONS( $OBJECTS(.ctor4) )
            INPUT_SECTIONS( $OBJECTS(.ctor5) )
            ldf_ctor_end = .;

        } >M0Code

        bss ZERO_INIT
        {
            bss_start = .;
            INPUT_SECTIONS( $OBJECTS(.bss*) )
            bss_end = .;
        } >M2DataA

        data
        {
            INPUT_SECTIONS( $OBJECTS(.data*) )
        } >M4DataA

        // Allocate stacks for the application. Note that stacks
        // grow downward, and must be quad-word aligned. This means
        // that the location just after the highest word of the stack
        // is quad-word aligned (evenly divisible by 4). There are two
        // labels for each stack: "*_base" is the location just ABOVE
        // the top of the stack, and "*_limit" is the lowest word that
        // is part of the stack. Each stack occupies all of its own
        // memory block.

        jstackseg
        {
            ldf_jstack_limit = .;
            ldf_jstack_base = . + MEMORY_SIZEOF(M6Stack);
        } >M6Stack

        kstackseg
        {
            ldf_kstack_limit = .;
            ldf_kstack_base = . + MEMORY_SIZEOF(M8Stack);
        } >M8Stack

        // The default heap occupies its own memory block
        defheapseg
        {
            _ldf_defheap_base = .;
            _ldf_defheap_size = MEMORY_SIZEOF(M10Heap);
        } >M10Heap
    }

3. Теперь в стандартном LDF файле вместо описания каждого процессора просто подключим созданный ранее файл: #include «two_proc.sec». Листинг получившегося LDF файла представлен ниже:

#if defined(__1967VN028R2__)
	#define INT_MEM_BANK_SIZE  0x20000  // Internal memory blocks are 0x20000 (128k)
#elif defined(__1967VN044__)
	#define INT_MEM_BANK_SIZE  0x10000  // Internal memory blocks are 0x10000 (64k)
#else
	#define INT_MEM_BANK_SIZE  0x10000  // Internal memory blocks are 0x10000 (64k)
#endif

ARCHITECTURE(ADSP-TS201)

$OBJECTS =  $COMMAND_LINE_OBJECTS;

MEMORY
{
    M0Code      { TYPE(RAM) START(0x00000000) END(0x00000000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }
    M2DataA     { TYPE(RAM) START(0x00040000) END(0x00040000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }
    M4DataA     { TYPE(RAM) START(0x00080000) END(0x00080000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }
    M6Stack     { TYPE(RAM) START(0x000C0000) END(0x000C0000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }
    M8Stack     { TYPE(RAM) START(0x00100000) END(0x00100000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }
    M10Heap     { TYPE(RAM) START(0x00140000) END(0x00140000 + (INT_MEM_BANK_SIZE - 1)) WIDTH(32) }

    MS0         { TYPE(RAM) START(0x30000000) END(0x37FFFFFF) WIDTH(32) }
    MS1         { TYPE(RAM) START(0x38000000) END(0x3FFFFFFF) WIDTH(32) }
    MSSD0       { TYPE(RAM) START(0x40000000) END(0x43FFFFFF) WIDTH(32) }
    MSSD1       { TYPE(RAM) START(0x50000000) END(0x53FFFFFF) WIDTH(32) }
    MSSD2       { TYPE(RAM) START(0x60000000) END(0x63FFFFFF) WIDTH(32) }
    MSSD3       { TYPE(RAM) START(0x70000000) END(0x73FFFFFF) WIDTH(32) }

// Memory blocks need to be less than 2 Gig.
    HOST        { TYPE(RAM) START(0x80000000) END(0x8FFFFFFF) WIDTH(32) }
    HOST1       { TYPE(RAM) START(0x90000000) END(0xAFFFFFFF) WIDTH(32) }
    HOST2       { TYPE(RAM) START(0xB0000000) END(0xCFFFFFFF) WIDTH(32) }
    HOST3       { TYPE(RAM) START(0xD0000000) END(0xEFFFFFFF) WIDTH(32) }
    HOST4       { TYPE(RAM) START(0xF0000000) END(0xFFFFFFFF) WIDTH(32) }
}

PROCESSOR P0
{
    OUTPUT( p0_$COMMAND_LINE_OUTPUT_FILE )
    #include "two_proc.sec"
}

PROCESSOR P1
{
    OUTPUT( p1_$COMMAND_LINE_OUTPUT_FILE )
    #include "two_proc.sec" 
}

Обратите внимание на строки:

OUTPUT( p0_$COMMAND_LINE_OUTPUT_FILE )
...
OUTPUT( p1_$COMMAND_LINE_OUTPUT_FILE )

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

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

console.jpg

Теперь создаём отладочную конфигурацию. Для этого нажимаем на стрелку у значка жука и переходим в Debug configurations.

Так как у нас выбран тулчейн LLVM, то в открывшемся окне слева выбираем тип Milandr Application (LLVM) и выбираем иконку "New". Для тулчейн Milandr необходимо выбрать Milandr Application, дальнейший процесс создания отладочной конфигурации будет таким же, как и для LLVM.

Создастся конфигурация {Name_project} Debug. Теперь во вкладке main, в поле C/C++ Application необходимо указать путь к файлу с расширением .dxe. Файла dxe у нас два, но выбрать нужно обязательно первый полученный файл (по первому оператору PROCESSOR). Сделать это можно, кликнув на кнопку «Search Project…» и выбрав в открывшемся окне файл с процессором 0.

Теперь нажимаем на кнопку «Debug», после чего среда автоматически загрузит во все процессоры копию программы в соответствии с отладочной информацией о многопроцессорной конфигурации, хранящейся в "dxe"-файле, и запустится режим отладки.

Режим Debug

Теперь после запуска режима Debug в отладочной сессии будет отображаться два потока, по одному потоку на каждый процессор.

Выбрав соответствующий поток, можно по отдельности запускать выполнение программы на разных процессорах. Чтобы запустить выполнение программы одновременно на двух процессорах, воспользуемся функцией «Multicore Commands Mode».

Когда данная функция активирована, отладочные команды (Resume, Suspend, Terminate, Step Into, Step Over, Step Return) выполняются одновременно для всех активных процессоров.

plata.jpg


Старая версия статьи для CM-LYNX 1.05.04 доступна здесь: Тестирование совместной работы двух процессоров 1967ВН028.