Jump to content

    

запрягаем хлопцы кони...

Програма без ОС, в основной программе тоже кое-где есть float, хотя и довольно редко.

Нужно ли предпринимать какие-то шаги, для сохранения контекста FPU в прерываниях, или Keil с этим самостоятельно разберется и можно не переживать?

Если без ОС, то должно нормально работать - для совместного использования FPU в обработчиках прерываний особых телодвижений от компилятора вроде не требуется.

 

Share this post


Link to post
Share on other sites
А тут - при переключении контекста задачи RTOS старшие регистры s16-s31 нужно сохранить ручками в любом случае, даже если задача последний раз пользовалась FPU полчаса назад и может больше и не собирается дальше пользоваться.

Я ещё глубоко не вникал, но во-первых, не в любом случае, а только если задача использовала FPU, а во-вторых наверное можно CONTROL.FPCA сбросить вручную, если уж известно, что не собирается дальше пользоваться:)

То, что ручками - это может быть и достоинством, ибо добавляет гибкости.

ИМХО, на сегодняшний день такое решение для смены контекста FPU немного диковато, и не видится способа как эту "Lazy stacking feature" красиво встроить в переключатель контекста в RTOS.

Можно глянуть во FreeRtos. Хотя там ничего особенного нет, всё тривиально. Но по крайней мере, процессы, не использующие FPU, не сохраняют плавучий контекст.

ЗЫ. Вот соберусь наконец портировать scmRTOS под M4F - тогда возможно смогу рассказать что-то более конкретное.

Share this post


Link to post
Share on other sites
а во-вторых наверное можно CONTROL.FPCA сбросить вручную, если уж известно, что не собирается дальше пользоваться:)

Общесистемному переключателю контекста намерения задачи известны быть не могут. Это только сама задача знает, и нормальных средств запустить переключатель по требованию (как в x86 по исключению использования FPU с неактуальным контекстом) нету. Приходится гонять регистры s0-s31 всегда, при каждом переключении контекста.

 

Можно глянуть во FreeRtos.

Глянул, все печально, как я и предполагал. Если процесс использовал FPU то при вытеснении s16-s31 сохраняются "ручками", вызывая неявное "ленивое" сохранение s0-s15. Если новый процесс использует FPU - то ему вгружают явно s16-s31 и неявно s0-s15 при выходе из исключения PendSV. Работать-то будет, но некрасиво и затратно.

Share this post


Link to post
Share on other sites
Общесистемному переключателю контекста намерения задачи известны быть не могут. Это только сама задача знает

Ну да, я об этом и говорю. Пусть задача сбрасывает CONTROL.FPCA, если надобность в FPU отпала.

и нормальных средств запустить переключатель по требованию (как в x86 по исключению использования FPU с неактуальным контекстом) нету.

Я всё равно не понял, как работает описанный вами механизм. Вот скажем, задачи 1 и 10 используют FPU, а задачи 2-9 - нет. После переключения с 1й на вторую задачу плавучий контекст не сохраняется, так? Потом при переключении со 2й на 3-ю, 3-4...4-9 - тоже не сохраняется. А при переключении с 9й на десятую надо сохранить. Как переключатель узнает, куда надо сохранять этот контекст?

 

Share this post


Link to post
Share on other sites
Пусть задача сбрасывает CONTROL.FPCA, если надобность в FPU отпала

Ну да, бит можно сбросить, вариант.

Я всё равно не понял, как работает описанный вами механизм. Вот скажем, задачи 1 и 10 используют FPU, а задачи 2-9 - нет. После переключения с 1й на вторую задачу плавучий контекст не сохраняется, так? Потом при переключении со 2й на 3-ю, 3-4...4-9 - тоже не сохраняется. А при переключении с 9й на десятую надо сохранить. Как переключатель узнает, куда надо сохранять этот контекст?

Заводится одна общесистемная переменная типа ptcb_fpu_context, которая указывает на TCB задачи, конекст FPU которой в данный момент загружен в физические регистры FPU. Когда эта задача вытесняется, то сохраняются только РОНы, и FPU запрещается, например битами в CPACR. Для новой вбрасываемой задачи загружаются только ее РОНы, FPU не трогается. Если новая задача не трогает FPU и потом возвращается к старой задаче - отлично, надо только разрешить снова FPU, а содержимое его регистров там и осталось нужное. А если эта новая задача (или еще более новая N-ая, которая ее вытеснит) начнет использовать FPU, то возникнет исключение UsageFault, обработчик посмотрит что ptask_fpu_context не соответствует tcb_current_task, сохранит регистры FPU согласно ptask_fpu_context, загрузит новый контекст из tcb_current_task, назначит новое значение ptask_fpu_context (задача-владелец FPU ведь поменялась), разрешит FPU в CPACR и продолжит исполнение с корректным контекстом FPU. Таким образом, фактически FPU-контекст переключается только при его совместном одновременном использовании несколькими задачами, и только тогда когда это реально нужно, а не тупо при каждом переключении задачи. Такой механизм реализован в x86 и в PowerPC, например. А для Cortex-M4F нужно вот CPACR руками рулить.

 

Share this post


Link to post
Share on other sites
..

Теперь всё ясно, спасибо.

Мне кажется, что этот механизм может получиться достаточно тяжеловесным. Не уверен, что дополнительные исключения + всякие проверки не будут дольше, чем простое безусловное сохранение регистров у процессов, использующих FPU. Да, возможно потребуется более внимательное планирование процессов, чтобы FPU не использовался в процессах, которым это без надобности.

Хм, аж прямо руки зачесались попробовать и сравнить эти варианты:)

Share this post


Link to post
Share on other sites
Теперь всё ясно, спасибо.

Мне кажется, что этот механизм может получиться достаточно тяжеловесным. Не уверен, что дополнительные исключения + всякие проверки не будут дольше, чем простое безусловное сохранение регистров у процессов, использующих FPU. Да, возможно потребуется более внимательное планирование процессов, чтобы FPU не использовался в процессах, которым это без надобности.

Хм, аж прямо руки зачесались попробовать и сравнить эти варианты:)

мдя.. тема интересная поднялась.

будет время переделаю переключатель контекстов и TCB FreeRTOS, в проект добавлю обработчик UsageFault по FPU, все под дефайнами влючит новый механизм или оставить прежний - это совсем просто , выложу - тогда вместе проверим как быстрее на круг из смеси задач разносортных, если Вы ранье меня это не сделаете :)

.. как говорят игроки в ala Diablo - еще одна возможность повысить скилл мага... :) а мож у фпу есть какаюнибудь скрытая секретная шинка по которой сохраняется .... не нупые же в ARM инженеры сидят, экономить тут не начем было...

Share this post


Link to post
Share on other sites
а мож у фпу есть какаюнибудь скрытая секретная шинка по которой сохраняется ...

Маловероятно - FPU в ядре сидит, а внешние шины ядра документированы. Даже если оно теоретически ходит одновременно по S-bus и D-bus или даже "секретной шине", то это лишено смысла - замыкается-то оно все равно на один и тот же блок RAM (в котором стек сидит), будет арбитраж, выиграша никакого.

 

не нупые же в ARM инженеры сидят, экономить тут не начем было..

Ну как бы не тупые, для однопоточного приложения и совместного использования FPU в обработчиках прерываний вроде бы неплохо оно все заточено. И совместимость с кодом для М3 отличная, наверное это за главный критерий приняли. Но вот с вытесняющей RTOS не все так гладко, что и удивляет - использование RTOS для чипов подобного класса на сегодня мейнстрим, имхо.

Share this post


Link to post
Share on other sites

Уважаемые VslavX, klen и другие, кто в теме. Проясните мне пожалуйста такой вопрос. В текущей теме использую плавучку. Очень много. У меня FreeRTOS. Она контекст задачи сохраняет с учётом плавучки или нет? В прерываниях я плавучку не использую.

Заранее благодарю за ответ.

Share this post


Link to post
Share on other sites
Уважаемые VslavX, klen и другие, кто в теме. Проясните мне пожалуйста такой вопрос. В текущей теме использую плавучку. Очень много. У меня FreeRTOS. Она контекст задачи сохраняет с учётом плавучки или нет? В прерываниях я плавучку не использую.

Заранее благодарю за ответ.

 

да, свитчер контекста провепяет использовала задача фпу или нет - от этого и пляшет

... рас уж пошла такая пьянка то давайте смотрет в пациента:

 

void xPortPendSVHandler( void )

{

/* This is a naked function. */

 

__asm volatile

(

" mrs r0, psp \n"

" \n"

" ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */

" ldr r2, [r3] \n"

" \n"

" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, push high vfp registers. */

" it eq \n"

" vstmdbeq r0!, {s16-s31} \n"

" \n"

" stmdb r0!, {r4-r11, r14} \n" /* Save the core registers. */

" \n"

" str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */

" \n"

" stmdb sp!, {r3, r14} \n"

" mov r0, %0 \n"

" msr basepri, r0 \n"

" bl vTaskSwitchContext \n"

" mov r0, #0 \n"

" msr basepri, r0 \n"

" ldmia sp!, {r3, r14} \n"

" \n"

" ldr r1, [r3] \n" /* The first item in pxCurrentTCB is the task top of stack. */

" ldr r0, [r1] \n"

" \n"

" ldmia r0!, {r4-r11, r14} \n" /* Pop the core registers. */

" \n"

" tst r14, #0x10 \n" /* Is the task using the FPU context? If so, pop the high vfp registers too. */

" it eq \n"

" vldmiaeq r0!, {s16-s31} \n"

" \n"

" msr psp, r0 \n"

" bx r14 \n"

" \n"

" .align 2 \n"

"pxCurrentTCBConst: .word pxCurrentTCB \n"

::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)

);

}

Share this post


Link to post
Share on other sites

отпортировал библиотеку GSL для юзания на FPU

в раздел открытого софта запостил тему http://electronix.ru/forum/index.php?showtopic=108275

былобы неплохо если комунибудь пригодилось и заодно потестилось.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this