Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Порт Cortex-R4
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
Legath
Всем доброго дня.
Пытаюсь сделать порт для Cortex R4F (чип RM46L852). Компилятор gcc 5.4.1.

Использую схему с программным прерыванием. Но возникает проблема в реализации функции os_start
По примеру порта ARM7
сделал ассемблерный файл со следующий содержимым (подсматривал в других ОСРВ)

Код
        .set SYS_MODE,    0x1f
        .set SVC_MODE,    0x13
        .set IRQ_MODE,    0x12
        .set STUB,    0x00


        .global context_restore

context_restore:     // os_start() passes New_SP in R0
    CPS        #SYS_MODE
    LDR        R1, [R0]
    LDR        SP, [R1]



    /* Restore the floating point context, if any. */
    POPNE     {R0}
    VPOPNE    {D0-D15}
    VMSRNE  FPSCR, R0


    /* Restore all system mode registers other than the SP (which is already
    being used). */
    POP        {R0-R12, R14}

    /* Return to the task code, loading CPSR on the way. */
    RFEIA    sp!


в отладчике штатно дохожу до строки
Код
LDR        R1, [R0]

и при ее выполнении процессор улетает в dabort handler. Это означает что инструкция обратилась к данным с которыми проблема.
Подскажите пожалуйста в какую сторону начать поиски. у меня подозрение что я что то неверно делаю с заготовкой стека.


Код
void TBaseProcess::init_stack_frame( stack_item_t * Stack
                                   , void (*exec)()
                                #if scmRTOS_DEBUG_ENABLE == 1
                                   , stack_item_t * StackBegin
                                #endif
                                   )
{
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) 0x1f;;

        if((uintptr_t)exec & (0x01UL))  {
               *Stack = *Stack | 0x20;
           }
        Stack--;
        *Stack = reinterpret_cast<stack_item_t>(exec);;
        Stack--;
        *Stack = ( stack_item_t ) 0;    /* R14 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R12 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R11 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R10 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R9 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R8 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R7 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R6 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R5 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R4 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R3 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R2 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R1 */
        Stack--;
        *Stack = ( stack_item_t ) 0; /* R0 */
        Stack--;
        *Stack = ( uint32_t ) 0;
        Stack--;
        *Stack = ( stack_item_t ) 0;

}


Это точно не MPU, я его отключал.


ADD:

в этот момент в R0 содержится значение 0xea006068 , память по этому адресу просмотреть нельзя.

Прошу сильно не пинать. Процессор для меня новый.
Сергей Борщ
QUOTE (Legath @ Jan 19 2017, 17:22) *
Пытаюсь сделать порт для Cortex R4F (чип RM46L852). Компилятор gcc 5.4.1.
Там есть общий порт для Mx (x=0, 3, 4) под gcc, его нельзя доработать? И добавить ваш процессор в него... Или они настолько радикально разные? Я просто с Rx не сталкивался никогда.

CODE
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) NULL;
        Stack--;
        *Stack = ( stack_item_t ) 0x1f;;

        if((uintptr_t)exec & (0x01UL))  {
               *Stack = *Stack | 0x20;
           }
        Stack--;
        *Stack = reinterpret_cast<stack_item_t>(exec);;
А можно ссылку на доку, в которой описан порядок сохранения регистров на стек у R4F? Понятно PSR, адрес возврата, а что это за три нуля над ними? Комментариев в этих строках явно не хватает.
QUOTE (Legath @ Jan 19 2017, 17:22) *
в этот момент в R0 содержится значение 0xea006068 , память по этому адресу просмотреть нельзя.
Надо искать, откуда это значение туда попадает. Там должен быть указатель на стековый кадр самого приоритетного процесса.
Legath
Цитата(Сергей Борщ @ Jan 20 2017, 09:18) *
Там есть общий порт для Mx (x=0, 3, 4) под gcc, его нельзя доработать? И добавить ваш процессор в него... Или они настолько радикально разные? Я просто с Rx не сталкивался никогда.


cortex r ближе к arm7 чем к cortex-m. у R нет global interrupt controller, и ассемблер отличается.
Цитата(Сергей Борщ @ Jan 20 2017, 09:18) *
Надо искать, откуда это значение туда попадает. Там должен быть указатель на стековый кадр самого приоритетного процесса.


я это понимаю и, по идее, Kernel.ProcessTable должна в кострукторе заполняться.

меня еще скрипт линковки смущает
Код
  VECTORS(rx)     : ORIGIN = 0x00000000, LENGTH = 0x00000020
  FLASH  (rx)     : ORIGIN = 0x00000020, LENGTH = 0x0013FFE0
  CPU_STACK (rw)  : ORIGIN = 0x08000000, LENGTH = 0x00001500 /* Stack is configured in sys_core.asm */
  RAM (xrw)       : ORIGIN = 0x08001500, LENGTH = 0x0002EB00
  MEMORY_B1 (rx)  : ORIGIN = 0x60000000, LENGTH = 0K

CPU_STACK отдельно идет
Сергей Борщ
QUOTE (Legath @ Jan 20 2017, 10:49) *
cortex r ближе к arm7 чем к cortex-m. у R нет global interrupt controller, и ассемблер отличается.
Понятно. Тогда да, отдельный порт.

QUOTE (Legath @ Jan 20 2017, 10:49) *
я это понимаю и, по идее, Kernel.ProcessTable должна в кострукторе заполняться.
А конструкторы глобальных объектов вообще вызываются? У множества распроняемого в интернете и в "библиотеках" начального кода запуск конструкторов просто не реализован.

QUOTE (Legath @ Jan 20 2017, 10:49) *
меня еще скрипт линковки смущает
Смущает, что стек в отдельной области (region)? А что говорит описание про эту область? Это случайно не аналог Core-coupled memory в M4? тогда размещать в ней стек было бы логично. А в нашем случае логично будет разместить в ней объекты самых высокоприоритетных процессов (сколько влезет), их стеки окажутся в этой же области. Надо завести секцию в этой области и дальше в исходнике помещать в нее объекты:
CODE
__attribute__((section(".ccm_mem")))
proc1_type Proc1("Highest priority proc");
Но это уже косметика, для начала надо запустить все остальное.

Перечитал еще раз. Кажется понял - область одна, но в скрипте автор зачем-то окусил от нее кусок для стека. Ему виднее, зачем он так сделал. Ваш процессор переключает аппаратно стек при входе в прерывания?
Legath
Цитата(Сергей Борщ @ Jan 20 2017, 12:21) *
Кажется понял - область одна, но в скрипте автор зачем-то окусил от нее кусок для стека. Ему виднее, зачем он так сделал.


Это дефолтный скрипт из HalCoGen (аналог CubeMX для процессоров TI). Я просто не нашел другого способа получить инициализацию. Но теперь более менее понятно что можно вернуть область RAM в единую.
Порт Free RTOS от TI еще больше ее дробит. Там ядро (шедулер? ) лежит в своем сегменте

Код
KRAM (xrw)      : ORIGIN = 0x08000800, LENGTH = 0x00000800


Цитата(Сергей Борщ @ Jan 20 2017, 12:21) *
А конструкторы глобальных объектов вообще вызываются? У множества распроняемого в интернете и в "библиотеках" начального кода запуск конструкторов просто не реализован.


Подозреваю что не вызываются. S/W BP ниразу не сработал внутри TKernel::register_process.


Цитата(Сергей Борщ @ Jan 20 2017, 12:21) *
Ваш процессор переключает аппаратно стек при входе в прерывания?


Чтобы ответить на этот вопрос мне не хватает знаний на данный момент . В документации я нашел

Software normally uses register R13 as a Stack Pointer (SP). The SRS and RFE instructions use Register R13


И для каждого из режимов процессора R13 имеет свой суффикс(в вашем порте arm7 я видел подобное)

Ссылаюсь на документацию от ARM


тестовый код main.cpp
Код
#include "sys_common.h"
#include "gio.h"

#include <scmRTOS.h>


typedef OS::process<OS::pr0, 300> TProc0;
typedef OS::process<OS::pr1, 300> TProc1;

TProc0 Proc0;
TProc1 Proc1;

int main(void)
{
    OS::run();
    while(1){

    }
    return 0;
}


namespace OS
{
    template <>
    OS_PROCESS void TProc0::exec()
    {
        for(;;)
        {   for (int i=0;i<10;i++)
            {

            }
            sleep(10);
        }
    }

    template <>
    OS_PROCESS void TProc1::exec()
    {
        for(;;)
        {
            for (int i=0;i<10;i++)
            {

            }
            sleep(10);

        }
    }
}


Сергей Борщ
QUOTE (Legath @ Jan 20 2017, 13:30) *
Подозреваю что не вызываются. S/W BP ниразу не сработал внутри TKernel::register_process.
Тогда в коде инициализации после обнуления .bss и копирования .data надо надо добавить что-нибудь вроде
CODE
    /* Call constructors */
    void(* const *ctor)();
    for( ctor = __ctors_start; ctor < __ctors_end; )
        (*ctor++)();
Или гляньте у Антона в примерах к кортексам - там у него более современно, с использованием init_array сделано.
QUOTE (Legath @ Jan 20 2017, 13:30) *
И для каждого из режимов процессора R13 имеет свой суффикс
А, ну значит для прерываний отдельный стек. Я использовал под него тот же стек, который работет до запуска ОС.
Legath
Добавил в линковку
Код
  /* The program code and other data goes into RAM */
  .text :
  {

        __ctors_start = .;
        KEEP(SORT(*)(.init_array))  /* eabi uses .init_array for static constructor lists */
        __ctors_end = .;

        __dtors_start = .;
        __dtors_end = .;

    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH



и перед вызовом main в аналоге reset handler
Код
        extern uint32 __ctors_start, __ctors_end;
    void(* const *ctor)();
    for( ctor = __ctors_start; ctor < __ctors_end; )
            (*ctor++)();


Все равно очень далеко указывает R0 указывает. Видимо я еще что то не учел.
Сергей Борщ
QUOTE (Legath @ Jan 20 2017, 13:30) *
тестовый код main.cpp
for(;;) в main() не нужен - OS::run() - это путь в один конец, возврата из нее нет. for (int i=0;i<10;i++) в процессах тоже лишнее - любой вменяемый компилятор этот цикл выкинет при самой минимальной оптимизации.
QUOTE (Legath @ Jan 20 2017, 18:55) *
Все равно очень далеко указывает R0 указывает. Видимо я еще что то не учел.

Так и есть. Чудес ведь не бывает wink.gif

AHTOXA
Цитата(Legath @ Jan 20 2017, 21:55) *
и перед вызовом main в аналоге reset handler
Код
        extern uint32 __ctors_start, __ctors_end;
    void(* const *ctor)();
    for( ctor = __ctors_start; ctor < __ctors_end; )
            (*ctor++)();

По-моему, здесь надо писать &__ctors_start и &__ctors_end.
Сергей Борщ
да, точно. У меня-то они объявлены как
CODE
extern void(* const __ctors_start__[])();
extern void(* const __ctors_end__[])();
странно, что компилятор не выругался на несоответсвие типов.
Legath
Цитата(Сергей Борщ @ Jan 20 2017, 21:24) *
for(;;) в main() не нужен - OS::run() - это путь в один конец, возврата из нее нет.


Это понятно. Я б не стал пытаться делать порт без базовых знаний bb-offtopic.gif
Цитата(Сергей Борщ @ Jan 20 2017, 21:24) *
for (int i=0;i<10;i++) в процессах тоже лишнее - любой вменяемый компилятор этот цикл выкинет при самой минимальной оптимизации.


-O0 , gcc 5.4.1 оставляет если верить дизассемблеру

Цитата(Сергей Борщ @ Jan 20 2017, 23:42) *
да, точно. У меня-то они объявлены как
Код
extern void(* const __ctors_start__[])();
extern void(* const __ctors_end__[])();
странно, что компилятор не выругался на несоответсвие типов.


Действительно не ругается. Странно что ругается на редекларацию регионов памяти.
Код
/Users/legath/Downloads/gcc-arm-none-eabi-5_4-2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld:/Users/legath/rm46_temp/source/sys_link.ld:19: warning: redeclaration of memory region `VECTORS'
/Users/legath/Downloads/gcc-arm-none-eabi-5_4-2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld:/Users/legath/rm46_temp/source/sys_link.ld:20: warning: redeclaration of memory region `FLASH'
/Users/legath/Downloads/gcc-arm-none-eabi-5_4-2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld:/Users/legath/rm46_temp/source/sys_link.ld:22: warning: redeclaration of memory region `RAM'
/Users/legath/Downloads/gcc-arm-none-eabi-5_4-2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld:/Users/legath/rm46_temp/source/sys_link.ld:23: warning: redeclaration of memory region `MEMORY_B1'


CPU_STACK я убрал и память одним куском оставил
Сергей Борщ
QUOTE (Legath @ Jan 20 2017, 22:55) *
-O0 , gcc 5.4.1 оставляет если верить дизассемблеру
Ой. Это как раз и есть "без всякой оптимизации. Зачем? Впрочем, это ваше дело.
QUOTE (Legath @ Jan 20 2017, 22:55) *
Действительно не ругается. Странно что ругается на редекларацию регионов памяти.
Выложите весь проект в архиве, попробуем разобраться вместе.
Legath
Файлы ccs7 архивировал. код инициализации я вставлял в source/sys_startup.c
Вообще хочется самому разобраться, чтоб понимать до конца как все работает. Поэтому прямо мне решение не сообщайте
dxp
QUOTE (Legath @ Jan 20 2017, 23:55) *
и перед вызовом main в аналоге reset handler
CODE
        extern uint32 __ctors_start, __ctors_end;
    void(* const *ctor)();
    for( ctor = __ctors_start; ctor < __ctors_end; )
            (*ctor++)();


Все равно очень далеко указывает R0 указывает. Видимо я еще что то не учел.

В gcc'шной библиотеке есть специальная функция для прогона ctor loop: ___libc_init_array.

Вообще, стартап к кортексов может быть очень простым.
Legath
Цитата(dxp @ Jan 22 2017, 11:08) *
В gcc'шной библиотеке есть специальная функция для прогона ctor loop: ___libc_init_array.

Вообще, стартап к кортексов может быть очень простым.


Да там это все safety проверки. На данном этапе проекта если их все закомментировать ничего не изменится. Попробую ___libc_init_array ибо ни один из бряков в конструкторах не сработал снова.
dxp
QUOTE (Legath @ Jan 23 2017, 05:29) *
Да там это все safety проверки.


Не помню там таких проверок. Код функции:
CODE

/*
* Copyright © 2004 CodeSourcery, LLC
*
* Permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies.
*
* This file is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* Handle ELF .{pre_init,init,fini}_array sections. */
#include <sys/types.h>

#ifdef HAVE_INITFINI_ARRAY

/* These magic symbols are provided by the linker. */
extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));

extern void _init (void);

/* Iterate over all the init routines. */
void
__libc_init_array (void)
{
size_t count;
size_t i;

count = __preinit_array_end - __preinit_array_start;
for (i = 0; i < count; i++)
__preinit_array_start[i] ();

_init ();

count = __init_array_end - __init_array_start;
for (i = 0; i < count; i++)
__init_array_start[i] ();
}
#endif


QUOTE (Legath @ Jan 23 2017, 05:29) *
На данном этапе проекта если их все закомментировать ничего не изменится. Попробую ___libc_init_array ибо ни один из бряков в конструкторах не сработал снова.

А если отладчиком это место по шагам пройти и посмотреть, вызываются ли конструкторы? И если нет, то почему. Если в линкерном скрипте символы (секций) указаны правильно, то не работать, вроде, нечему.
AHTOXA
Цитата(Legath @ Jan 23 2017, 03:29) *
Да там это все safety проверки. На данном этапе проекта если их все закомментировать ничего не изменится. Попробую ___libc_init_array ибо ни один из бряков в конструкторах не сработал снова.

По-моему, у вас снова неправильно.
Было
Код
        extern uint32 __ctors_start, __ctors_end;

, потом вы исправили на
Код
    extern void(* const __ctors_start)();
    extern void(* const __ctors_end)();

От этого ничего не поменялось.
Либо берите адрес, как я советовал, либо объявите их как массивы, как это сделано у Сергея.
Legath
Все оказалось намного проще. порт arm7 полность подходит для cortex-r4 , за исключение плавучки, но это решается дефайнами.
Работает. Но есть одна неприятность, работает только первый процесс , при попытке передачи управления процессу 2 возникает ошибка как в самом начале, sp для второго процесса указывает далеко.
сейчас занимаюсь с этим.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.