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

Возможно ли переместить пролог функции?

Приветствую!

Собственно, вот что. Имеем 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);
  }
}


Хочу, чтобы пролог оказался (либо дублировался) в месте, который указан комментарием. Возможно ли это?

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


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

Он сохраняет 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, а там как бы область памяти "над" стеком данной задачи. Трет переменную левую, короче.

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


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

7 hours ago, Arlleex said:

Хочу, чтобы пролог оказался (либо дублировался) в месте, который указан комментарием. Возможно ли это?

Добрый день! Снова у вас весьма занятные эксперименты)))) По-моему, такие вещи следует писать на ассемблере. Слишком нестандартного вы хотите от компилятора.

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


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

3 часа назад, haker_fox сказал:

Добрый день!

Давненько Вас не видел:smile:

3 часа назад, haker_fox сказал:

По-моему, такие вещи следует писать на ассемблере. Слишком нестандартного вы хотите от компилятора.

Порой возникает ощущение, что что-то делаю не так и есть некий "народный", "правильный" рецепт...

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


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

6 minutes ago, Arlleex said:

Давненько Вас не видел:smile:

Да, решил взять себе передышку) Слишком под конец прошлый год задолбал))

7 minutes ago, Arlleex said:

Порой возникает ощущение, что что-то делаю не так и есть некий "народный", "правильный" рецепт...

Гм... ну тогда ждём советов ещё более компетентных коллег. Мне тоже интересно, чем всё закончится)

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


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

Короче сделал вот так

// 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");
}


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

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


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

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))
        :
    );

 

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


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

Сергей, за примеры благодарю. Как более менее вменяемо начну понимать сей чудный синтаксис, возможно, пересмотрю топик:smile:

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


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

9 hours ago, Arlleex said:

Как более менее вменяемо начну понимать сей чудный синтаксис

Это инлайн ассемблер. В принципе, выглядит сначал довольно заморочисто. Но я, помню, разобрался за день неспешно. Правда, сейчас уже немного помню. Ведь пишешь на нём не каждый день) Почитайте доку, разберите примерчики)

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


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

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

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

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

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

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

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

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

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

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