Arlleex 131 2 июня, 2021 Опубликовано 2 июня, 2021 · Жалоба Приветствую! Собственно, вот что. Имеем Keil uVision 5 с ARM Compiler 6.14, ядро Cortex-M0 в облике STM32F072. Допустим, есть некая функция void func(void) { SetMSP(...); SetPSP(...); SelPSP(); ... // <- хочу, чтобы пролог был тут while(1) { u32 i = get(); if(i) proc(i); } } Хочу, чтобы пролог оказался (либо дублировался) в месте, который указан комментарием. Возможно ли это? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 2 июня, 2021 Опубликовано 2 июня, 2021 · Жалоба А зачем там пролог? __attribute__((naked)) скорее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 2 июня, 2021 Опубликовано 2 июня, 2021 · Жалоба Он сохраняет LR, один из регистров (не помню какой, на работе смотрел) общего назначения, ну и резервирует немного стека для переменной i. Смысл в том, что приведенный псевдокод - это кусочек из моей самописной кооперативной миниОС. Эта функция в полном виде выглядит так void eds_RunTskManager(void) { __attribute__((aligned(8))) static u32 stk[EDS_MNGSTK_SIZE]; EDS.tskpsp[EDS_TSKID_EDS] = (u32)&stk[EDS_MNGSTK_SIZE]; EntrCritSect(); extern const u32 AppSPAftRst; SetMSP(AppSPAftRst); SetPSP(EDS.tskpsp[EDS_TSKID_EDS]); SelPSP(); ExitCritSect(); for(u32 i = 0; i < EDS_USRTSK_QNT; ++i) eds_SwitchTsk(i + 1); SetFreqSysTmr(EDS_SYSTMR_FREQ); RstSysTmr(); RunSysTmr(); while(1) { static void (*hnd[])(void) = { 0 }; u32 evt = GetEvt(); if(evt > 0) { if(evt <= EDS_USRTSK_QNT) eds_SwitchTsk(evt); else hnd[evt - EDS_USRTSK_QNT - 1](); } #ifdef EDS_IDLEHOOK_USE else eds_IdleHook(); #endif } } При сбросе МК в MSP записывается адрес основного стека (его я использую для стека прерываний), и равен он AppSPAftRst. В main() у меня происходит инициализация массива верхушек стеков задач EDS.tskpsp[], а также вызов eds_RunTskManager(). Эта функция - по факту, тоже некий процесс с бесконечным циклом опроса очереди событий (менеджер событий). В ее начале я заношу в EDS.tskpsp[0] адрес верхушки стека для данного процесса. Когда ни одной пользовательской задачи не выполняется, процессор крутится именно в этом цикле. Так вот, там же в начале функции я "сбрасываю" MSP на его значение при сбросе AppSPAftRst, так как чего память попусту тратить, все равно она теперь только для стека прерываний будет использоваться; затем переключаюсь на PSP, предварительно инициализировав его верхушкой стека процесса "менеджера". Только вот теперь грабли: при входе в функцию пролог резервирует LR + Rn, а также память под i в for() и evt в MSP, не подозревая, что мы его скорректировали и вовсе перешли на активный PSP. Отсюда и неприятности: строка evt = GetEvt() располагает содержимое evt по адресу SP + 4, а там как бы область памяти "над" стеком данной задачи. Трет переменную левую, короче. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба 7 hours ago, Arlleex said: Хочу, чтобы пролог оказался (либо дублировался) в месте, который указан комментарием. Возможно ли это? Добрый день! Снова у вас весьма занятные эксперименты)))) По-моему, такие вещи следует писать на ассемблере. Слишком нестандартного вы хотите от компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба 3 часа назад, haker_fox сказал: Добрый день! Давненько Вас не видел 3 часа назад, haker_fox сказал: По-моему, такие вещи следует писать на ассемблере. Слишком нестандартного вы хотите от компилятора. Порой возникает ощущение, что что-то делаю не так и есть некий "народный", "правильный" рецепт... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба 6 minutes ago, Arlleex said: Давненько Вас не видел Да, решил взять себе передышку) Слишком под конец прошлый год задолбал)) 7 minutes ago, Arlleex said: Порой возникает ощущение, что что-то делаю не так и есть некий "народный", "правильный" рецепт... Гм... ну тогда ждём советов ещё более компетентных коллег. Мне тоже интересно, чем всё закончится) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба Короче сделал вот так // main.cpp int main(void) { InitDevDrv(); ActAftSysRst(); RunUsrApp(); eds_RunTskMng(); } // eds.hpp // EDS_TSKID_EDS равен 0 typedef struct sEDS { u32 cid, tskpsp[EDS_MAXTSK_QNT]; volatile u32 tmr, tsktmr[EDS_USRTSK_QNT]; sEDS(u32 sp) {tskpsp[EDS_TSKID_EDS] = sp;} }sEDS; // eds.cpp __attribute__((aligned(8))) static u32 MngStk[EDS_MNGSTK_SIZE]; sEDS EDS((u32)&MngStk[EDS_MNGSTK_SIZE]); __attribute__((used)) static void MngTsk(void) { for(u32 i = 0; i < EDS_USRTSK_QNT; ++i) eds_SwitchTsk(i + 1); SetFreqSysTmr(EDS_SYSTMR_FREQ); RstSysTmr(); RunSysTmr(); while(1) { static void (*hnd[])(void) = { 0 }; u32 evt = GetEvt(); if(evt > 0) { if(evt <= EDS_USRTSK_QNT) eds_SwitchTsk(evt); else hnd[evt - EDS_USRTSK_QNT - 1](); } #ifdef EDS_IDLEHOOK_USE else eds_IdleHook(); #endif } } __attribute__((naked)) void eds_RunTskMng(void) { EntrCritSect(); __asm("ldr r0, =__MSPStart"); // MSP устанавливаем __asm("ldr r1, [r0]"); // в значение __asm("msr msp, r1"); // при сбросе __asm("ldr r0, =EDS"); // PSP устанавливаем __asm("ldr r1, [r0, #4]"); // в значение, которое __asm("msr psp, r1"); // легло в EDS.tskpsp[0] __asm("movs r0, #2"); // переводим __asm("msr control, r0"); // активный SP на PSP __asm("isb"); ExitCritSect(); __asm("ldr r0, =%P0" :: "i"(MngTsk)); __asm("bx r0"); } Вроде в отладчике все хорошо, но буду еще проверять. В железке даже моргает лампочкой... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба 1 час назад, Arlleex сказал: Короче сделал вот так Я бы идущие подряд ассемблерные вставки объединил в одну. Это не даст компилятору вставить между ними какие-то свои команды. И выбор конкретных регистров тоже отдал бы компилятору или хотя бы сообщал ему, что соответствующий регистр портится в этой вставке. Примерно так (это код для ARM7TDMI, чисто для иллюстрации): #if scmRTOS_CONTEXT_SWITCH_SCHEME == 0 extern "C" INLINE void os_context_switcher(stack_item_t** Curr_SP, stack_item_t* Next_SP) { asm volatile( // - store - "STMFD SP!, {R0-R12,LR} \r\n" // store R0_R12, LR to reserve space in context "MRS r2, CPSR \r\n" // move CPSR of process to register "STMFD SP!, {r2,LR} \r\n" // store CPSR, LR on top of context and adjust SP "ADR LR, 1f \r\n" // load context switcher exit address, // to branch to if context stored in OS_ContextSwitcher "STR LR, [SP, #4*15] \r\n" // store return address in reserved space (instead of first saved LR) "STR SP, [%0] \r\n" // - restore - "LDMFD %1!, {r2, LR} \r\n" // restoring LR_user, saved CPSR_user "ADD SP, %1, #4*14 \r\n" // set process SP "MSR CPSR_c, %2 \r\n" // switch to IRQ mode to get access to SPSR_irq "MSR SPSR_cxsf, r2 \r\n" // store process CPSR to SPSR_irq to restore at return from irq "LDMFD %1, {R0-R12,PC}^ \r\n" // restoring remaining context, CPSR and reti "1:" : :"r"(Curr_SP), "r"(Next_SP), "n"(NIRQ | MODE_IRQ) :"r2" ); } #endif или вот для AVR, тут вместо номеров параметров используются вменяемые имена: asm volatile ( /* OCR1A = pTmp->OCR; PORTB = pTmp->Port[bpm_driver::PORT_B]; PORTC = pTmp->Port[bpm_driver::PORT_C]; */ "LD %[tmp], %a[ptr]+ \n\t" "STS %B[OCR], %[tmp] \n\t" "LD %[tmp], %a[ptr]+ \n\t" "STS %A[OCR], %[tmp] \n\t" "LD %[tmp], %a[ptr]+ \n\t" "OUT %[port_b], %[tmp] \n\t" "LD %[tmp], %a[ptr]+ \n\t" "OUT %[port_c], %[tmp] \n\t" : [ptr]"+e"(pTmp), [tmp]"=r"(Tmp) : [OCR] "M" (_SFR_MEM_ADDR(OCR1A)) , [port_b] "I" (_SFR_IO_ADDR(PORTB)) , [port_c] "I" (_SFR_IO_ADDR(PORTC)) : ); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба Сергей, за примеры благодарю. Как более менее вменяемо начну понимать сей чудный синтаксис, возможно, пересмотрю топик Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 9 hours ago, Arlleex said: Как более менее вменяемо начну понимать сей чудный синтаксис Это инлайн ассемблер. В принципе, выглядит сначал довольно заморочисто. Но я, помню, разобрался за день неспешно. Правда, сейчас уже немного помню. Ведь пишешь на нём не каждый день) Почитайте доку, разберите примерчики) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться