Версия для печати темы
Форум разработчиков электроники ELECTRONIX.ru _ scmRTOS _ Порт Cortex-R4
Автор: Legath Jan 19 2017, 15:22
Всем доброго дня.
Пытаюсь сделать порт для 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 , память по этому адресу просмотреть нельзя.
Прошу сильно не пинать. Процессор для меня новый.
Автор: Сергей Борщ Jan 20 2017, 06:18
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, 08:49
Цитата(Сергей Борщ @ 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 отдельно идет
Автор: Сергей Борщ Jan 20 2017, 09:21
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, 11:30
Цитата(Сергей Борщ @ 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 я видел подобное)
Ссылаюсь на http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/ch02s06s01.html
тестовый код 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);
}
}
}
Автор: Сергей Борщ Jan 20 2017, 11:45
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 Jan 20 2017, 16:55
Добавил в линковку
Код
/* 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 указывает. Видимо я еще что то не учел.
Автор: Сергей Борщ Jan 20 2017, 18:24
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 указывает. Видимо я еще что то не учел.
Так и есть. Чудес ведь не бывает
Автор: AHTOXA Jan 20 2017, 18:56
Цитата(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.
Автор: Сергей Борщ Jan 20 2017, 20:42
да, точно. У меня-то они объявлены как
CODE
extern void(* const __ctors_start__[])();
extern void(* const __ctors_end__[])();
странно, что компилятор не выругался на несоответсвие типов.
Автор: Legath Jan 20 2017, 20:55
Цитата(Сергей Борщ @ Jan 20 2017, 21:24)
for(;;) в main() не нужен - OS::run() - это путь в один конец, возврата из нее нет.
Это понятно. Я б не стал пытаться делать порт без базовых знаний
Цитата(Сергей Борщ @ 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 я убрал и память одним куском оставил
Автор: Сергей Борщ Jan 20 2017, 21:37
QUOTE (Legath @ Jan 20 2017, 22:55)
-O0 , gcc 5.4.1 оставляет если верить дизассемблеру
Ой. Это как раз и есть "без всякой оптимизации. Зачем? Впрочем, это ваше дело.
QUOTE (Legath @ Jan 20 2017, 22:55)
Действительно не ругается. Странно что ругается на редекларацию регионов памяти.
Выложите весь проект в архиве, попробуем разобраться вместе.
Автор: Legath Jan 20 2017, 21:44
Файлы ccs7 архивировал. код инициализации я вставлял в source/sys_startup.c
Вообще хочется самому разобраться, чтоб понимать до конца как все работает. Поэтому прямо мне решение не сообщайте
Автор: dxp Jan 22 2017, 08:08
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.
Вообще, стартап к кортексов http://electronix.ru/redirect.php?https://github.com/emb-lib/arm-none-eabi-startup/blob/master/startup.c.
Автор: Legath Jan 22 2017, 22:29
Цитата(dxp @ Jan 22 2017, 11:08)
В gcc'шной библиотеке есть специальная функция для прогона ctor loop: ___libc_init_array.
Вообще, стартап к кортексов http://electronix.ru/redirect.php?https://github.com/emb-lib/arm-none-eabi-startup/blob/master/startup.c.
Да там это все safety проверки. На данном этапе проекта если их все закомментировать ничего не изменится. Попробую ___libc_init_array ибо ни один из бряков в конструкторах не сработал снова.
Автор: dxp Jan 23 2017, 05:20
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 Jan 23 2017, 06:15
Цитата(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 Mar 16 2017, 17:17
Все оказалось намного проще. порт arm7 полность подходит для cortex-r4 , за исключение плавучки, но это решается дефайнами.
Работает. Но есть одна неприятность, работает только первый процесс , при попытке передачи управления процессу 2 возникает ошибка как в самом начале, sp для второго процесса указывает далеко.
сейчас занимаюсь с этим.
Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)