STM8: Скорость выполнения кода из RAM

Я расскажу вам историю, которая началась много тактов назад, где-то в секции NearFuncCode…

0x81C0
Тактовый генератор жужжит на мегагерцовой частоте. Счетчик команд летит по коду. Конвеер работает на все 100%, проталкивая через себя команды:
Такт! Четыре байта улетают по шине в АЛУ. Такт! Команда декодируется, а в это время уже читается следующая. Третий такт! Команда выполняется, вторая декодируется, а из памяти достается третья.

Но вот попадается команда CALL. Конвеер сбрасывается, в стек заносится адрес возврата, механизм готовится к прыжку, как кот перед столом с едой. Прыжок!

0x0100
Счетчик команд получил новый адрес и выполнение кода продолжается. Секундочку. Что это?! Почему все так медленно?! Почему я не могу загрузить сразу 4 байта? Первая ступень конвеера со скрипом извлекает команду — байт за байтом. Весь механизм перекосило: части, отвечающие за декодирование и выполнение постоянно вставали из-за отсутствия данных, которые медленно ползли через восьмибитную шину. Единственной каплей меда в этой бочке дегтя было то, что команды теперь стали короткми, и если конвеер и вставал, то всего на один-два такта. А бывало и вовсе летел почти так-же свободно, как во флеш памяти. В те редкие моменты, когда попадалась кучка команд, состоящих из одного байта. Но потом он снова спотыкался о длиную команду и все начиналось сначала: получить байт — устройство декодирования встает в ожидании данных — получить следующий байт — тут уже замирает, оставшись без данных, механизм отвечающий за выполнение — прочитан последний байт — конвеер стоит — и наконец на четвертом такте команда передается на декодирование…

… Я убрал палец с кнопки сброса. За какие-то полторы сотни миллисекунд пронеслось несколько прыжков по памяти, пол-дюжины циклов-задержек, на которые косо смотрел оптимизатор. Пин A2 станцевал забавное самбо, а логический анализатор его записал.

Теперь пришло время посмотреть на результат. Вот он:

Начнем по порядку.

1) Цикл в main

GPIOA->ODR |= GPIO_Pin_2;
 for (i=0; i<1000; i++);
 GPIOA->ODR &= ~GPIO_Pin_2;

GPIOA->ODR |= GPIO_Pin_2;
    PA_ODR, #2
 for (i=0; i<1000; i++);
    CLRW      X
    LDW       i, X
    JRA       ??main_2
 for (i=0; i<1000; i++);
??main_3:
    LDW       X, i
    INCW      X
    LDW       i, X
 for (i=0; i<1000; i++);
??main_2:
    LDW       X, i
    CPW       X, #0x03E8
    JRC       ??main_3
 GPIOA->ODR &= ~GPIO_Pin_2;
    BRES      PA_ODR, #2

Выполнился за 12 мс.

2) Прыжок из main в функцию во флеш памяти. Выполнился за 5us.

3) Тот-же цикл в функции. Просто интересна ради, хотя ясно что результат будет аналогичным. Почему-то за 13мс. Что это было?

4) Выпрыгивание из функции обратно в main. 6us.

5) Прыжок в RAM — 8us

6) Цикл в оперативке — 32 (!) мс

7) Выход из оперативки в main — 6us.

Вот такие вот результаты забега с препятствиями.
  • +1
  • 05 августа 2012, 22:22
  • dcoder

Комментарии (11)

RSS свернуть / развернуть
Дык известно же уже, что код из ОЗУ выполняется медленно из-за шины. Зато в этом режиме в работе не участвует акселератор флеш-памяти и тайминги исполнения получаются четкими и предсказуемыми.
Хотя всего в 2.5 раза медленнее не соответсвует выводу предыдущего исследователя — «теперь идеально ровно, но безобразно медленно».
+1
  • avatar
  • Vga
  • 05 августа 2012, 22:51
А мне было не известно :) То есть, нет, я знал конечно что из ОЗУ выполняется медленнее. Но все-таки забыл об этом, перенеся критичный ко времени выполнения код из флеша в озу
0
we.easyelectronics.ru/Deer/pochemu-ya-ne-speshu-prodolzhat-razgovor-o-rastaktovke-vypolneniya-instrukciy-vychislitelnym-yadrom-stm8.html Вот мы тут в своё время пытались посмотреть скорость выполнения инструкций и только волосы дыбом встали от того, насколько мистически плавают тайминги!

we.easyelectronics.ru/Deer/pochemu-ya-ne-speshu-prodolzhat-razgovor-o-rastaktovke-vypolneniya-instrukciy-vychislitelnym-yadrom-stm8.html#comment41069 Но да, из RAM тоже выполняли. Вот тут видно, как время выполнения резко увеличилось, но тайминги стали строго постоянными и предсказуемыми
0
Меня не покидает ощущение дежавю. От вас то ожидал полного раскрытия проблемы, означенной в предидущих постах, не мог подумать что вы наступите на озвученные грабли.
Но форма изложения понравилась.
0
У меня просто сейчас нету желания писать что-то большое :) Я тут писал демо-прошивку для stm8l модуля к пинборде, по ходу дела выдавая заметки. А эта — следствие того, что я сейчас играюсь с бутлоадером
0
для задержек пора бы и таймеры юзать :)
0
Да там были даже не задержки — скорость выполнение функции влияла на результат. После переноса в рам пришлось корректировать, иначе не работало — так как результат получался за рамками приличного :)
А что самое забавное, потом она обратно во флеш переехала а в рам осталась только маленькая функция, которая кладет в буфер флеша последний байт (тем самым начиная запись) и ждет ее окончания
0
Тогда вопрос — зачем вам вообще рамка. запись последнего байта при выполнении из флеш точно так же стартанет запись, но заблокирует цпу до оконцания операции записи -> ждать ничего не надо, на следующую команду попадаем по окончании записи. На сколько помню ни каких багов с «блокированием цп навечно» нет.
Выполнение из рамки нужно когда в фоне требуется ещё обрабатывать какую либо задачу (как взаимодействие по уарт для приёма очередного блока данных, например, таймауты и пр.). Хотя да, является более правильным на случай последующих улучшений.
0
А почему тогда в RM0031 написано, что:
Block program operations to the main program memory have to be executed totally
from RAM.
(стр 50)
?

Или я что-то не понимаю, или это недокументированная фича :)
0
Гм… да. «Тут помню, тут не помню». PM0051 стр.17:
The block program operation has to be executed totally from RAM.
The program execution continues from RAM. If the program goes back to main program memory, it is stalled until the block program operation is complete.
и далее
Caution: During a block program or erase operation, it is recommended to avoid executing instructions performing a read access to program memory.
Получается документированная фича, которой лучше не пользоваться.
Вообщем ждете в рамке, и это правильно, однако «totally from RAM» и «только последний байт» — несколько разные вещи :)
0
Танец — «самба». Так что если станцевал, то «забавную самбу».
Есть ещё танец «румба». :-)
-1
  • avatar
  • Alfa
  • 17 августа 2012, 13:27
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.