|
Порт Cortex-R4, Попытка реализации |
|
|
|
Jan 19 2017, 15:22
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Всем доброго дня. Пытаюсь сделать порт для 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 , память по этому адресу просмотреть нельзя. Прошу сильно не пинать. Процессор для меня новый.
Сообщение отредактировал Legath - Jan 19 2017, 16:32
|
|
|
|
2 страниц
1 2 >
|
|
Ответов
(1 - 14)
|
Jan 20 2017, 06:18
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
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 , память по этому адресу просмотреть нельзя. Надо искать, откуда это значение туда попадает. Там должен быть указатель на стековый кадр самого приоритетного процесса.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 08:49
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Цитата(Сергей Борщ @ 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 отдельно идет
Сообщение отредактировал Legath - Jan 20 2017, 08:54
|
|
|
|
|
Jan 20 2017, 09:21
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
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"); Но это уже косметика, для начала надо запустить все остальное. Перечитал еще раз. Кажется понял - область одна, но в скрипте автор зачем-то окусил от нее кусок для стека. Ему виднее, зачем он так сделал. Ваш процессор переключает аппаратно стек при входе в прерывания?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 11:30
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Цитата(Сергей Борщ @ 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);
} } }
Сообщение отредактировал Legath - Jan 20 2017, 11:39
|
|
|
|
|
Jan 20 2017, 11:45
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
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 имеет свой суффикс А, ну значит для прерываний отдельный стек. Я использовал под него тот же стек, который работет до запуска ОС.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 16:55
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Добавил в линковку Код /* 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 указывает. Видимо я еще что то не учел.
Сообщение отредактировал Legath - Jan 20 2017, 16:56
|
|
|
|
|
Jan 20 2017, 18:24
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
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 указывает. Видимо я еще что то не учел. Так и есть. Чудес ведь не бывает
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 18:56
|
фанат дивана
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684
|
Цитата(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
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
да, точно. У меня-то они объявлены как CODE extern void(* const __ctors_start__[])(); extern void(* const __ctors_end__[])(); странно, что компилятор не выругался на несоответсвие типов.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 20:55
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Цитата(Сергей Борщ @ 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 я убрал и память одним куском оставил
Сообщение отредактировал Legath - Jan 20 2017, 20:58
|
|
|
|
|
Jan 20 2017, 21:37
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (Legath @ Jan 20 2017, 22:55) -O0 , gcc 5.4.1 оставляет если верить дизассемблеру Ой. Это как раз и есть "без всякой оптимизации. Зачем? Впрочем, это ваше дело. QUOTE (Legath @ Jan 20 2017, 22:55) Действительно не ругается. Странно что ругается на редекларацию регионов памяти. Выложите весь проект в архиве, попробуем разобраться вместе.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 20 2017, 21:44
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Файлы ccs7 архивировал. код инициализации я вставлял в source/sys_startup.c Вообще хочется самому разобраться, чтоб понимать до конца как все работает. Поэтому прямо мне решение не сообщайте
Сообщение отредактировал Legath - Jan 20 2017, 21:49
|
|
|
|
|
Jan 22 2017, 08:08
|
Adept
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343
|
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. Вообще, стартап к кортексов может быть очень простым.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 22 2017, 22:29
|
Участник
Группа: Участник
Сообщений: 37
Регистрация: 30-12-10
Из: Рязань
Пользователь №: 61 958
|
Цитата(dxp @ Jan 22 2017, 11:08) В gcc'шной библиотеке есть специальная функция для прогона ctor loop: ___libc_init_array. Вообще, стартап к кортексов может быть очень простым. Да там это все safety проверки. На данном этапе проекта если их все закомментировать ничего не изменится. Попробую ___libc_init_array ибо ни один из бряков в конструкторах не сработал снова.
|
|
|
|
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|