Перейти к содержанию
    

Добрый день! простите за поднятие старющей темы, но ответа не нашёл. Да и с scmRTOS давно не работал. Но чем закончилось дело? Уважаемый @SergNK предоставил порт для IAR? Дело в том, что я его не нашёл в репозитарии. Смутило также, что, что у него используются макросы от GCC, например в обработчике PendSV 

#if defined __ARM_ARCH_6M__   // Cortex-M0(+)/Cortex-M1

При этом в документации на IAR таких макросов нет. Есть __CORE__ и сопутствующие значения, которые позволяют определить архитектуру процессора. Сейчас ваяю свой порт. Мой обработчик (не претендую на авторство!!!!!), например, выглядит так

PendSV_Handler

#if (__CORE__ == __ARM6M__)
    // Cortex-M0(+)/Cortex-M1
    CPSID   I                   // Prevent interruption during context switch
    MRS     R0, PSP             // Load process stack pointer to R0
    SUBS    R0, #32             // Adjust R0 to point to top of saved context in stack
    MOV     R1, R0              // Preserve R0 (needed for os_context_switch_hook() call)
    STMIA   R1!, {R4-R7}        // Save low portion of remaining registers (r4-7) on process stack
    MOV     R4, R8              // Move high portion of remaining registers (r8-11) to low registers
    MOV     R5, R9
    MOV     R6, R10
    MOV     R7, R11
    STMIA   R1!, {R4-R7}        // Save high portion of remaining registers (r8-11) on process stack

// At this point, entire context of process has been saved
    PUSH    {LR}                // we must save LR (exc_return value) until exception return
    LDR     R1, =os_context_switch_hook   // call os_context_switch_hook();
    BLX     R1

// R0 is new process SP;
    ADDS    R0, #16            // Adjust R0 to point to high registers (r8-11)
    LDMIA   R0!, {R4-R7}       // Restore r8-11 from new process stack
    MOV     R8, R4             // Move restored values to high registers (r8-11)
    MOV     R9, R5
    MOV     R10, R6
    MOV     R11, R7
    MSR     PSP, R0            // R0 at this point is new process SP
    SUBS    R0, #32            // Adjust R0 to point to low registers
    LDMIA   R0!, {R4-R7}       // Restore r4-7
    CPSIE   I
    POP     {PC}               // Return to saved exc_return. Exception return will restore remaining context


#elif (__CORE__ == __ARM7M__ || !defined(__ARMVFP__) )
    // M3/M4 cores without FPU
    CPSID   I                  // Prevent interruption during context switch
    MRS     R0, PSP            // PSP is process stack pointer
    STMDB   R0!, {R4-R11}      // Save remaining regs r4-11 on process stack

// At this point, entire context of process has been saved
    PUSH    {LR}               // we must save LR (exc_return value) until exception return
    LDR     R1, =os_context_switch_hook     // call os_context_switch_hook();
    BLX     R1

// R0 is new process SP;
    LDMIA   R0!, {R4-R11}      // Restore r4-11 from new process stack
    MSR     PSP, R0            // Load PSP with new process SP
    CPSIE   I
    POP     {PC}               // Return to saved exc_return. Exception return will restore remaining context


#else
    // Core with FPU (cortex-M4F)
    CPSID     I                  // Prevent interruption during context switch
    MRS       R0, PSP            // PSP is process stack pointer
    TST       LR, #0x10          // exc_return[4]=0? (it means that current process
    IT        EQ                 // has active floating point context)
    VSTMDBEQ  R0!, {S16-S31}     // if so - save it.
    STMDB     R0!, {R4-R11, LR}  // save remaining regs r4-11 and LR on process stack

// At this point, entire context of process has been saved
    LDR     R1, =os_context_switch_hook     // call os_context_switch_hook();
    BLX     R1

// R0 is new process SP;
    LDMIA     R0!, {R4-R11, LR}  // Restore r4-11 and LR from new process stack
    TST       LR, #0x10          // exc_return[4]=0? (it means that new process
    IT        EQ                 // has active floating point context)
    VLDMIAEQ  R0!, {S16-S31}     // if so - restore it.
    MSR       PSP, R0            // Load PSP with new process SP
    CPSIE     I
    BX        LR                 // Return to saved exc_return. Exception return will restore remaining context
#endif

Также пришлось поменять кучу макросов в других файлов с GCC на IAR. Простенький тестовый пример (мигание двух светодиодов на платке дискавери) работает))) Мне интересно самому повозиться с портированием, но всё же интересно и знать, есть ли официальный универсальный порт для всех кортексов под IAR.

Спасибо)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насколько я помню, универсального порта для IAR нет. Последние коммиты в порт Cortex-M3 под IAR датированы летом 2012 года.

Так что, если есть желание и силы, то предложение актуально :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, AHTOXA said:

Так что, если есть желание и силы, то предложение актуально :-)

Отлично! Возможно, приму участие.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Узкое место с этой функцией

extern "C" NORETURN void os_start(stack_item_t *sp)
{
    // Set PendSV lowest priority value
#if (defined SHP3_WORD_ACCESS)
    SHPR3 |= (0xFF << 16);
#else
    PendSvPriority = 0xFF;
#endif

#if (defined __ARMVFP__)
    FPCCR |= ASPEN | LSPEN;
#endif

    asm volatile (
#if (!defined __ARMVFP__)  // code without FPU
        "    LDR     R4, [%[stack], #(4 * 14)] \n" // Load process entry point into R4
        "    ADDS     %[stack], #(4 * 16)      \n" // emulate context restore
#else
        "    LDR     R4, [%[stack], #(4 * 15)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]             \n" // store process SP to PSP
        "    MOVS     R0, #2                   \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, R0               \n"
        "    ISB                               \n" // Insert a barrier
        "    LDR     R1, =__init_system_timer  \n" //
        "    BLX     R1                        \n" //
        "    CPSIE   I                         \n" // Enable interrupts at processor level
        "    BX      R4                        \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
    );

   while(1); // suppress compiler warning "'noreturn' func does return"
}

Я её маленько поправил для IAR. В режиме полной оптимизации всё работает, но без оптимизации валится в хардфолт. Дело в том, что параметр sp, переданный в R0, перед вызовом функции записи в регистр SHPR3, компилятор сохраняет точненько в R4, который затем "портится" командой LDR. Следовательно, указатель стека первого процесса оказывается совершенно левым((( Когда оптимизация влкючена, вызова функции записи в регистр просто не проиходит, она инлайнится.

Вот скрин дизассемблера  с оптимизацией

image.png.77d2afbcc5b9739b1b762400a28302f4.png

А вот без оптимизации

image.thumb.png.20ce1c1cdaea83ea29bd6ab141f5b996.png

Я не особо знаком с синтаксисом инлайн-ассемблера iar, но, полагаю, тут проблема написания кода. Буду думать, как решить красиво. Мне не очень нравится что без оптимизации код ломается(((( Сорри, за качество скринов, пишу не с рабочей машины(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, косяк. GCC таких трюков не делал, поэтому никто до сих пор не натыкался. Ну или по крайней мере никто не сообщал :-)

Тут два выхода. Первый, простой - указать компилятору, что ассемблерная вставка портит регистры R0, R1 и R4:

        "    BX      R4                        \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
        :                   // no input
        : "r0", "r1", "r4"  // clobbers

(На самом деле достаточно указать только R4, потому что остальные уже не важны).

И второй, посложнее, избавиться от явного использования регистра R4 во вставке, заменив всё на параметры. Типа так:

    asm volatile (
#if (defined __SOFTFP__)  // code without FPU
        "    LDR     %[tmp], [%[stack], #(4 * 14)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 16)       \n" // emulate context restore
#else
        "    LDR     %[tmp], [%[stack], #(4 * 15)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]             \n" // store process SP to PSP
        "    MOV     R0, #2                    \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, R0               \n"
        "    ISB                               \n" // Insert a barrier
        "    LDR     R1, =__init_system_timer  \n" //
        "    BLX     R1                        \n" //
        "    CPSIE   I                         \n" // Enable interrupts at processor level
        "    BX      %[tmp]                    \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
        : [tmp]"r" (0)   // dummy param
    );

Мой GCC сделал из этого код на одну инструкцию длиннее (обнулил временный регистр). Но, думаю, ради надёжности и аккуратности кода можно это потерпеть. Надо будет исправить и в gcc-порте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странноватый этот IAR))) Сделал, как вы предложили, плюс избавился от явного использования остальных регистров (но также безуспешно пробовал и первоначальный вариант с избавлением только от R4), но всё равно не работает.

    asm volatile (
#if (!defined __ARMVFP__)  // code without FPU
        "    LDR     %[tmp], [%[stack], #(4 * 14)]  \n" // Load process entry point into R4
        "    ADDS    %[stack], #(4 * 16)            \n" // emulate context restore
#else
        "    LDR     %[tmp], [%[stack], #(4 * 15)]  \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)            \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]                  \n" // store process SP to PSP
        "    MOVS    %[ctrl], #2                    \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, %[ctrl]               \n"
        "    ISB                                    \n" // Insert a barrier
        "    LDR     %[tmr], =__init_system_timer   \n" //
        "    BLX     %[tmr]                         \n" //  
        "    CPSIE   I                              \n" // Enable interrupts at processor level
        "    BX      %[tmp]                         \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
        : [tmp]"r"  (0)     // dummy value
        , [ctrl]"r" (0)     // control register value
        , [tmr]"r"  (0)     // init timer procedure address
    );

Вот, что в дизассемблере со включенной оптимизацией. Компилятор использует R1 для сохранения адреса первой задачи. По условиям AAPCS функция не обязана сохранять этот регистр. И успешно его портит)))

image.png.75137716a02170e8a21fc4204c74b7ad.png

Уф. Либо работает только с оптимизацией, либо только без неё((( Что-то я пока запутался. Подумать надо.

Пока видится вариант только переписать os_start всю на инлайн-ассемблере, либо в отдельном модуле. Но, главное, указать компилятору какие регистры использовать и сохранять в стеке в лоб.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ой, вы же первый вариант ещё предложили. Как-то я его сразу не испробовал) Чуть позже проверю!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А, теперь вспоминаю. Я ведь не зря использовал R4, а не переменную в ассемблере. Именно потому, что вызываемая функция инициализации таймера имеет право портить R0-R3.

Надо такие вещи записывать в комментариях.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, AHTOXA said:

Я ведь не зря использовал R4,

Я тоже к этому выводу в ходе экспериментов пришёл)

@AHTOXA, предложенный вами вариант №1 заработал. Я проверил только на оптимизации "Balanced" и без оптимизации. Вот полный вариант функции

extern "C" NORETURN void os_start(stack_item_t *sp)
{
    // Set PendSV lowest priority value
#if (defined SHP3_WORD_ACCESS)
    SHPR3 |= (0xFF << 16);
#else
    PendSvPriority = 0xFF;
#endif

#if (defined __ARMVFP__)
    FPCCR |= ASPEN | LSPEN;
#endif

    asm volatile (
#if (!defined __ARMVFP__)  // code without FPU
        "    LDR     R4, [%[stack], #(4 * 14)] \n" // Load process entry point into R4
        "    ADDS     %[stack], #(4 * 16)      \n" // emulate context restore
#else
        "    LDR     R4, [%[stack], #(4 * 15)] \n" // Load process entry point into R4
        "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
        "    MSR     PSP, %[stack]             \n" // store process SP to PSP
        "    MOVS     R0, #2                   \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
        "    MSR     CONTROL, R0               \n"
        "    ISB                               \n" // Insert a barrier
        "    LDR     R1, =__init_system_timer  \n" //
        "    BLX     R1                        \n" //
        "    CPSIE   I                         \n" // Enable interrupts at processor level
        "    BX      R4                        \n" // Jump to process exec() function
        : [stack]"+r" (sp)  // output
        :                   // no input
        : "r0", "r1", "r4"  // clobbers
    );

   while(1); // suppress compiler warning "'noreturn' func does return"
}

Спасибо вам! Я же думал, что проще уже вынести os_start в файл os_target_asm.S, переписав её полностью на ассемблере.

 

Кстати, а ваш компилятор позволяет команды компилировать для Cortex-M0 без префикса S? Например,

"    MOVS     R0, #2                   \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level

у меня только так. Т.е. на MOV R0, #2 ругается. По мурзилке всё правильно со стороны IAR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и ладненько. Надо и в порте gcc тоже на всякий случай R4 внести в список clobbers.

54 минуты назад, haker_fox сказал:

Кстати, а ваш компилятор позволяет команды компилировать для Cortex-M0 без префикса S? Например, 

В inline-ассемблерных вставках, судя по всему, разрешает. В ассемблерных файлах - нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

56 minutes ago, AHTOXA said:

В inline-ассемблерных вставках, судя по всему, разрешает. В ассемблерных файлах - нет.

Ясно) Но, если быть откровенным, что-то мне инлайн-ассемблер всё равно не нравится) Субъективно, естественно. Модули на ассемблере вроде как-то серьезно выглядят.

57 minutes ago, AHTOXA said:

Ну и ладненько. Надо и в порте gcc тоже на всякий случай R4 внести в список clobbers.

Рад, что смог поспособствовать поиску бага. Сейчас текущий вариант оськи попробую на реальном проекте, котоырй по-маленьку растёт. Потом, можно будет думать о заливке в репозитаорий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уважаемый @AHTOXA, правильно ли я понимаю, что могу свою ветку fb-feature-iar-mx-port загрузить в репозитарий? Я сейчас только Cortex-M0 протестировал, и то на простой задаче. Возможно скоро смогу проверить на Cortex-M4F. Старался максимально придерживаться документа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Надеюсь, вы свою ветку ответвили от ветки develop? (Хотя в плане именно порта IAR ветки develop и master не отличаются, так что это не очень важно).

Насколько я понимаю, загрузить напрямую не получится - нужно быть членом организации scmrtos :biggrin:

Можете прислать pull request, мы его рассмотрим, и, если всё будет нормально, примем.

Или напишите @dxp в личку, как вы называетесь на гитхабе, и он вас добавит в организацию. Тогда будете вести ветку прямо в репозитории.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...