В приложении реального времени¹ на ARM Cortex M3 (аналогичном STM32F101) мне нужно опрашивать бит регистра внутренней периферии, пока он не станет равным нулю, как можно теснее всего oop. Я использую битовую полосу для доступа к соответствующему биту. (Работающий) код C:
while (*(volatile uint32_t*)kMyBit != 0);
Этот код копируется в исполняемую на кристалле оперативную память. После некоторой ручной оптимизации2 опрос l oop сводится к следующему, что я рассчитал от 3 до 6 циклов:
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 D1FC BNE 0x00600200
Как можно уменьшить неопределенность опроса? 5-тактный l oop будет соответствовать моей цели: сэмплировать этот бит как можно ближе к 15,5 циклам после того, как он достигнет нуля.
My spe c требует надежного обнаружения низкого импульса, по крайней мере, 6,5 тактовых циклов процессора ; надежно классифицировать его как короткий, если он длится менее 12,5 циклов; и надежно классифицировать его так долго, если он длится более 18,5 циклов. Импульсы не имеют определенной фазовой зависимости с тактовой частотой процессора, что является моей единственной точной временной привязкой. Для этого требуется максимум 5-часовой опрос l oop. На самом деле я эмулирую код, который работал на 8-битном процессоре, которому уже несколько десятилетий, который мог опрашивать с 5-тактовым циклом, и то, что он сделал, превратилось в spe c.
Я пытался чтобы компенсировать выравнивание кода, вставив NOP перед l oop, во многих вариантах, которые я пробовал, но никогда не наблюдал изменений.
Я пытался инвертировать CMP и LDR, но все равно получаю 6 циклов:
0x00600200 681A LDR r2,[r3,#0x00]
; we loop here
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FC BNE 0x00600202
Это 8 циклов
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 681A LDR r2,[r3,#0x00]
0x00600204 2A00 CMP r2,#0x00
0x00600206 D1FB BNE 0x00600200
Но это 9 циклов:
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FB BNE 0x00600200
¹ Измерение, сколько времени бит низок в контексте, где прерывание не происходит.
² Первоначально сгенерированный компилятором код использовал r12 в качестве регистра назначения, и это добавило 4 байта кода к l oop, стоимостью 1 цикл.
³ Указанные числа получены с предположительно точным циклом эмулятора STIce в реальном времени и его триггера эмулятора с функцией чтения по адресу регистра. Ранее я пробовал счетчик «States» с точкой останова в l oop, но результат зависит от местоположения точки останова. Одноступенчатый еще хуже: он всегда дает 4 цикла для LDR, когда, по крайней мере, иногда до 3.