SergNK 0 February 7, 2017 Posted February 7, 2017 · Report post Спасибо за доверие! Первый вариант. Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 February 7, 2017 Posted February 7, 2017 · Report post Спасибо за доверие! Первый вариант. Написал в личку. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 19, 2020 Posted March 19, 2020 · Report post Добрый день! простите за поднятие старющей темы, но ответа не нашёл. Да и с 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. Спасибо) Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 March 19, 2020 Posted March 19, 2020 · Report post Насколько я помню, универсального порта для IAR нет. Последние коммиты в порт Cortex-M3 под IAR датированы летом 2012 года. Так что, если есть желание и силы, то предложение актуально :-) Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 19, 2020 Posted March 19, 2020 · Report post 1 hour ago, AHTOXA said: Так что, если есть желание и силы, то предложение актуально :-) Отлично! Возможно, приму участие. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 19, 2020 Posted March 19, 2020 · Report post Узкое место с этой функцией 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. Следовательно, указатель стека первого процесса оказывается совершенно левым((( Когда оптимизация влкючена, вызова функции записи в регистр просто не проиходит, она инлайнится. Вот скрин дизассемблера с оптимизацией А вот без оптимизации Я не особо знаком с синтаксисом инлайн-ассемблера iar, но, полагаю, тут проблема написания кода. Буду думать, как решить красиво. Мне не очень нравится что без оптимизации код ломается(((( Сорри, за качество скринов, пишу не с рабочей машины( Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 March 19, 2020 Posted March 19, 2020 · Report post Да, косяк. 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-порте. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 20, 2020 Posted March 20, 2020 · Report post Странноватый этот 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 функция не обязана сохранять этот регистр. И успешно его портит))) Уф. Либо работает только с оптимизацией, либо только без неё((( Что-то я пока запутался. Подумать надо. Пока видится вариант только переписать os_start всю на инлайн-ассемблере, либо в отдельном модуле. Но, главное, указать компилятору какие регистры использовать и сохранять в стеке в лоб. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 20, 2020 Posted March 20, 2020 · Report post Ой, вы же первый вариант ещё предложили. Как-то я его сразу не испробовал) Чуть позже проверю! Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 March 20, 2020 Posted March 20, 2020 · Report post А, теперь вспоминаю. Я ведь не зря использовал R4, а не переменную в ассемблере. Именно потому, что вызываемая функция инициализации таймера имеет право портить R0-R3. Надо такие вещи записывать в комментариях. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 20, 2020 Posted March 20, 2020 · Report post 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. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 March 20, 2020 Posted March 20, 2020 · Report post Ну и ладненько. Надо и в порте gcc тоже на всякий случай R4 внести в список clobbers. 54 минуты назад, haker_fox сказал: Кстати, а ваш компилятор позволяет команды компилировать для Cortex-M0 без префикса S? Например, В inline-ассемблерных вставках, судя по всему, разрешает. В ассемблерных файлах - нет. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 20, 2020 Posted March 20, 2020 · Report post 56 minutes ago, AHTOXA said: В inline-ассемблерных вставках, судя по всему, разрешает. В ассемблерных файлах - нет. Ясно) Но, если быть откровенным, что-то мне инлайн-ассемблер всё равно не нравится) Субъективно, естественно. Модули на ассемблере вроде как-то серьезно выглядят. 57 minutes ago, AHTOXA said: Ну и ладненько. Надо и в порте gcc тоже на всякий случай R4 внести в список clobbers. Рад, что смог поспособствовать поиску бага. Сейчас текущий вариант оськи попробую на реальном проекте, котоырй по-маленьку растёт. Потом, можно будет думать о заливке в репозитаорий. Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 51 March 20, 2020 Posted March 20, 2020 · Report post Уважаемый @AHTOXA, правильно ли я понимаю, что могу свою ветку fb-feature-iar-mx-port загрузить в репозитарий? Я сейчас только Cortex-M0 протестировал, и то на простой задаче. Возможно скоро смогу проверить на Cortex-M4F. Старался максимально придерживаться документа. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 March 20, 2020 Posted March 20, 2020 · Report post Надеюсь, вы свою ветку ответвили от ветки develop? (Хотя в плане именно порта IAR ветки develop и master не отличаются, так что это не очень важно). Насколько я понимаю, загрузить напрямую не получится - нужно быть членом организации scmrtos Можете прислать pull request, мы его рассмотрим, и, если всё будет нормально, примем. Или напишите @dxp в личку, как вы называетесь на гитхабе, и он вас добавит в организацию. Тогда будете вести ветку прямо в репозитории. Quote Share this post Link to post Share on other sites More sharing options...