Поговорим о растактовке исполнения команд в вычислительном ядре STM8

Занялся я тут экспериментами в области выяснения времени выполнения команд ядром STM8. Мой мозг уже на грани взрыва! Что-то проясняется, что-то становится только непонятнее.

Задача у нас пока что простая до безобразия: в цикле передёргивать ножку со светодиодом.
loop:
 bcpl PC_ODR,#7
 jpf loop

Выполняется за 3 такта. Если допустить, что BCPL выполняется за 1 такт, а JPF — за 2, то всё логично. Подтверждается следующим кодом:
loop:
 nop
 bcpl PC_ODR,#7
 jpf loop

Выполняется за 4 такта. А вот дальше начинаются не совсем логичные вещи.
Попробуем передёргивать ножку в каждой итерации цикла вручную, как мы это делали на AVR командами SBI и CBI:
loop:
 bset PC_ODR,#7
 bres PC_ODR,#7
 jpf loop

По идее, должно выполняться за 1+1+2=4 такта. Однако эксперимент на «живом» контроллере показал, что итерация цикла исполняется за 5 тактов! Допустим, что одна из команд: BRES или BSET — исполняется не 1 такт, а целых два. Попробуем вычислить какая из них:
Вариант 1:
loop:
 bset PC_ODR,#7
 bset PC_ODR,#7
 bres PC_ODR,#7
 jpf loop

Вариант 2:
loop:
 bset PC_ODR,#7
 bres PC_ODR,#7
 bres PC_ODR,#7
 jpf loop

Предположение было в том, что один из вариантов будет исполняться 6 тактов, а другой — 7. А вот фиг там! Оба варианта исполняются в течение 7 тактов!
Пробуем разбавить NOP-ами:
loop:
	bset PC_ODR,#7
	nop
	bset PC_ODR,#7
	nop
	bres PC_ODR,#7
	jpf loop

Результат — 8 тактов.
loop:
	bset PC_ODR,#7
	nop
	bres PC_ODR,#7
	nop
	bres PC_ODR,#7
	jpf loop

Тоже 8 тактов.

Такое впечатление, что один раз команда исполняется 2 такта, а остальные разы — по 1… Пробуем извращаться далее, пользуясь вместо BRES или BSET командой BCPL. Или даже вместо обеих сразу:
loop:
	bset PC_ODR,#7
	bcpl PC_ODR,#7
	jpf loop

Исполняется 5 тактов.
loop:
	bcpl PC_ODR,#7
	bres PC_ODR,#7
	jpf loop

Исполняется тоже 5 тактов.
loop:
	bcpl PC_ODR,#7
	bcpl PC_ODR,#7
	jpf loop

Исполняется, вы не поверите, тоже 5 тактов! Я вам более того скажу!
loop:
	bcpl PC_ODR,#7
	nop
	jpf loop

Исполняется 5 тактов, а если поменять BCPL и NOP местами (как в начале статьи), то исполяться будет 4 такта!

За сим позвольте на сегодня откланяться, завтра вечером обязательно продолжим наши эксперименты!

UPD 13.07 22:24: Кстати говоря, в режиме «свободного полёта» и в режиме отладки по SWIM скорость выполнения программы абсолютно одинаковая даже при наличии брейкпоинтов и режиме «Run to cursor». Кто-то где-то здесь спрашивал, не могу найти кто и где.
  • +7
  • 13 июля 2011, 22:19
  • Deer

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

RSS свернуть / развернуть
Не могу точно утверждать, но припоминаю, мало того что команда выполняется за 1 такт, но и из-за вида адресации, тоже команда может выполняться дольше, но могу жёстко ошибаться)
0
  • avatar
  • pkm
  • 13 июля 2011, 22:35
Ну… я пробовал и label.b, .w, .l
И JRA, и JP вместо JPF. На растактовку не влияло!
0
надо смотреть как конвеер работает в вашем мк, у вас какой stm8?
0
  • avatar
  • pkm
  • 13 июля 2011, 23:06
STM8L152C6T6
0
Я конечно могу ошибаться, но у стм кажется есть «частота перефирии». В больших процах это выглядит так: ядро, при обращении к переферии (порту ввода-вывода) ожидает исполнения им операции, т.е. попросту тормозится. таким образом если на 3гиговом проце выполнить команду OUT то «частота процессора падает до 133МГц шины». Эфект как бы очень хорошо известный (оттого и появилась память ввода-вывода).
0
Хм, наскока я знаю, в STM8 переходы жрут больше чем в AVR, т.к. конвеер длиннее…
0
Проверено лично: те же 2 такта! В этом уверен на все 100%!
0
А если цикл развернуть в линейный код, чтоб исключить влияние перезагрузки конвеера после перехода?
Типа такого:
bset PC_ODR,#7
bres PC_ODR,#7
bset PC_ODR,#7
bres PC_ODR,#7
...
bset PC_ODR,#7
bres PC_ODR,#7
0
Делал. В статью не включил, но при 20-кратном повторении пар BSET-BRES получал выборку каждые 2 такта ЦПУ
0
Я то же с этого начинал :)
Из-за наличия конвейера тяжело отследить количество тактов. Команды сброса и установки битов требуют два такта, однако второй цикл может уходить уже на обработку следующей команды, поэтому команда установки или сброса бита может выполняться как за один так и за два такта. Почитайте вот этот документ
ziblog.ru/wp-content/plugins/download-monitor/download.php?id=34
в нём графически представлена работа конвейера (стр 15). И ещё много чего полезного.
0
  • avatar
  • ZiB
  • 14 июля 2011, 05:39
косяк, не та ссылка
ziblog.ru/wp-content/plugins/download-monitor/download.php?id=48
0
дело в шине. для неё команды bres, bset, bcpl и подобные инициируют две передачи: от порта и к порту. А на выполнение кода в ядре это не влияет.
0
может дело в выравнивании кода
код загружается по 4 байта (32бита)

и лишние такты это дозагрузка кода следующей команды

последний пример очень хорошо вписывается в это
когда поставили команду nop перед bcpl
получили выравнивание.

сможете проверить?
0
Что именно хотим проверить-то? А то я как-то недопонял… Сегодня оказалось не до экспериментов с процессорами, но в ближайшее время вернёмся!
0
ребят, кажись, уже в комментариях всё сказано…
конвейер и «отвязанная» от ядра периферия…
сам в своё время очень сильно голову ломал, когда переходил с интелловских с51 и сименсовских с166 на мипс32…
кроме того, смотрите на flush, stall и так далее
следующий шаг в вывихе мозга процы с ОоО, слава Б-гу, на текущий момент самое слабое — это некоторые реализации ARM v7A
0
что такое ОоО?
0
Видимо, Out of Order Execution. Если какая-то команда (скажем, выборка из ОЗУ, не попавшая в кэш — на х86 это сотни тактов) застряла в конвеере, то не зависящие от нее последующие команды будут выполнены раньше, чем пройдет эта команда. Позволяет снизить простои конвеера не меняя в корне принципы работы с памятью (как это сделано, например, в PS3, где ядра работают с небольшой выделенной ОЗУ, работающей на частоте ядра, а необходимые данные из общей ОЗУ грузят относительно большими кусками через DMA). Но предсказать, сколько код будет выполняться на подобных процах (и особенно — на x86 со всеми его фичами) — довольно сложно (к тому же, это может зависеть от погоды на марсе).
0
Не, ну понятное дело, что конвейер. Но т.к. первый цикл весь целиком, включая переход на начало, выполняется за 3 такта, команда явно как-то «продавливается» через несколько (а именно две, или как минимум одну) ступень этого конвейера. Вот с этого места мозг конкретно взрывается!..
0
Я тут понял, что с арифметикой немного ошибся… :(
Стыдно, стыдно…

А так как мой осциллограф вернулся из ремонта, скоро будет статья с преинтересными рисунками, касаемая растактовок!..
0
  • avatar
  • Deer
  • 22 ноября 2011, 20:58
Пардон, погорячился… Только в одном месте стыдно, про 3 такта где.
К выходным, если дела мирские меня не одолеют, будет новая пища для размышлений… :)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.