Использую аппаратный регистр CYCCNT для подсчета реального количества тактов, затрачиваемых на исполнение кода.
Предварительно процессор настраивается на 180МГц, количество тактов процессора, затрачиваемое на чтение 128 бит из Flash - 6 циклов (5WS).
Код теста:
Код
AREA MY_PROGRAM, CODE, READONLY
ENTRY
MyProg PROC
EXPORT Main
DWT_CYCCNT EQU 0xE0001004
DWT_CONTROL EQU 0xE0001000
SCB_DEMCR EQU 0xE000EDFC
Main
ldr r0, =SCB_DEMCR
mov r1, #0x01000000
str r1, [r0]
ldr r0, =DWT_CONTROL
ldr r1, [r0]
mov r2, #0x1
orr r1, r2
str r1, [r0]
ldr r0, =DWT_CYCCNT
mov r1, #0x0
b loop
LTORG
loop
str.w r1, [r0]
mul.w r3, r4, r5
; ...
; ТЫСЯЧА ТАКИХ ИНСТРУКЦИЙ
; ...
mul.w r3, r4, r5
ldr.w r2, [r0]
b.w loop
ENDP
END
ENTRY
MyProg PROC
EXPORT Main
DWT_CYCCNT EQU 0xE0001004
DWT_CONTROL EQU 0xE0001000
SCB_DEMCR EQU 0xE000EDFC
Main
ldr r0, =SCB_DEMCR
mov r1, #0x01000000
str r1, [r0]
ldr r0, =DWT_CONTROL
ldr r1, [r0]
mov r2, #0x1
orr r1, r2
str r1, [r0]
ldr r0, =DWT_CYCCNT
mov r1, #0x0
b loop
LTORG
loop
str.w r1, [r0]
mul.w r3, r4, r5
; ...
; ТЫСЯЧА ТАКИХ ИНСТРУКЦИЙ
; ...
mul.w r3, r4, r5
ldr.w r2, [r0]
b.w loop
ENDP
END
Инструкции как раз подобраны наихудшие: 1 такт исполнение, 32-разрядные из набора Thumb-2.
1. Отключаю кэш инструкций и данных, отключаю prefetch-buffer выборки.
2. Запускаю код на исполнение под отладчиком без точек останова.
3. Пока код выполняется, ставлю точку останова на строку
Код
b.w loop
и смотрю содержимое регистра R2 (считанное значение в 180МГц тактах): 0x8CB = 2251.
4. Время математики: 1000 однотактных 32-разрядных команд, 1000/4=250 циклов обращения к Flash-памяти по 128 бит. С учетом того, что WS=5, 5*250=1250 тактов накладных расходов на ожидание доступа к данным. Прибавляем такты выполнения команд: 1250 + 1000 = 2250. Что на 1 такт меньше считанного показания с системного регистра. Двигаемся дальше.
5. Включаем prefetch-buffer выборки и повторяем шаги 2-3. Содержимое CYCCNT = 1501.
6. Выключаем prefetch-buffer, включаем кэш. Содержимое CYCCNT = 2250. По-моему логично, поскольку в кэше хранятся адреса команд начала последних использованных подпрограмм и веток кода, а не сам код (в документации вроде про это написано).
7. Включаем prefetch-buffer и кэш. Содержимое CYCCNT = 1501.
Как видно, при включенном буфере предвыборки будет потеря производительности, однако если в коде будут использованы не только 32-разрядные инструкции Thumb-2, а 16-разрядные, скорее всего количество тактов совпадет с количеством инструкций между метками замера. Замерил - CYCCNT = 1001.
Отключаю prefetch - CYCCNT = 1251. Интересно, почему сейчас 1251, ведь 8 однотактных инструкций перекрывают 5WS при доступе к Flash... Это пока под вопросом, я разберусь.
Собственно говоря, этих сведений мне достаточно, чтобы полагать, что большого толку от широкой шины на Tiva-C не будет. Она сделана точно для таких же целей, для каких и ART-ускоритель в STM32 - обеспечить нулевое состояние задержки при выполнении смешанного (32-разрядного и 16-разрядного) кодов Thumb и Thumb-2.
Если сравнивать производительность выполнения 32-битного кода Thumb-2 STM32, работающего на частоте, допустим, 150МГц, над производительностью Tiva-C, работающего на 120МГц при выполнении того же 32-битного кода, то плюс широкой шине - бесспорно предвыборка 8 команд лучше чем предвыборка 4. Однако на реальной практике код представляет из себя смесь 16- и 32-разрядных инструкций, поэтому подобный метод расчета производительности не годится, нужны данные CoreMark или Dhrystone.