adnega 11 12 августа, 2023 Опубликовано 12 августа, 2023 · Жалоба В 12.08.2023 в 23:55, jcxz сказал: Вот именно: 4 + 4 = 8 Первый класс школы, если что LDRD - это загрузка двух 32-битных слов (данные занимают 2 * 4 байта = 8 байт). Плюс сама команда 4 байта. 8 + 4 = 12 байт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 12 августа, 2023 Опубликовано 12 августа, 2023 · Жалоба 29 минут назад, adnega сказал: LDRD - это загрузка двух 32-битных слов (данные занимают 2 * 4 байта = 8 байт). Плюс сама команда 4 байта. 8 + 4 = 12 байт. Изначально я вам советовал применить команду: 14 часов назад, jcxz сказал: Не хватает варианта с заменой этого на одну LDRD R5, R6, =0x40020418 Но такая команда не скомпилится. Я ошибся. Беру свои слова обратно. PS: 8 байт должны занять: LDR R5, =0x40020418 LDR R6, =0x40020418 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 13 августа, 2023 Опубликовано 13 августа, 2023 · Жалоба В 13.08.2023 в 01:01, jcxz сказал: Но такая команда не скомпилится. "=imm32" я понимаю как "[PC, label]". Команда "LDRD R5, R6, [PC, label]" компилируется, и листинг я приводил (данные лежат по метке "cc"): 80052bc: e9df 5604 ldrd r5, r6, [pc, #16] ; 80052d0 <cc> .. 080052d0 <cc>: 80052d0: 40020418 .word 0x40020418 80052d4: 40020418 .word 0x40020418 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 13 августа, 2023 Опубликовано 13 августа, 2023 · Жалоба В 13.08.2023 в 01:01, jcxz сказал: PS: 8 байт должны занять: LDR R5, =0x40020418 LDR R6, =0x40020418 Ммм.. ; 20.4ns = 6t ; LDR R5, =0x40020418 800530a: 4d04 ldr r5, [pc, #16] ; (800531c <cc+0x3c>) ; LDR R6, =0x40020418 800530c: 4e03 ldr r6, [pc, #12] ; (800531c <cc+0x3c>) 800531c: 40020418 .word 0x40020418 Да 8 байт. Но какой толк от второй команды, когда есть MOV ? Пока делаю вывод, что у МК с WS0 для кода самая быстрая загрузка imm32 будет с использованием MOV/MOVT, но более расточительна по памяти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 13 августа, 2023 Опубликовано 13 августа, 2023 · Жалоба 4 часа назад, adnega сказал: Ммм.. ; 20.4ns = 6t ; LDR R5, =0x40020418 800530a: 4d04 ldr r5, [pc, #16] ; (800531c <cc+0x3c>) ; LDR R6, =0x40020418 800530c: 4e03 ldr r6, [pc, #12] ; (800531c <cc+0x3c>) 800531c: 40020418 .word 0x40020418 Да 8 байт. Но какой толк от второй команды, когда есть MOV ? В данном случае - никакой. Это ведь был тест для сравнения разных вариантов загрузки. 4 часа назад, adnega сказал: Пока делаю вывод, что у МК с WS0 для кода самая быстрая загрузка imm32 будет с использованием MOV/MOVT, но более расточительна по памяти. Не факт. Если имеется последовательность: LDR R0, [PC, #imm] ;загрузка const из адреса PC+imm LDR R1, [R2] И последовательность, грузящая ту же константу, но с помощью с MOV/MOVT: MOV R0, #0x0418 MOVT R0, #0x4002 LDR R1, [R2] То первый вариант может на CM4+ выполниться за 3 или за 4 такта; а 2-й вариант = всегда 4 такта. За счёт декодирования адреса второй LDR во время выполнения первой LDR (согласно тому документу, что я приводил выше). Хотя не уверен, в данном случае сработает конвееризация. Надо проверять. Ну и размер у 1-го варианта меньше, а значит косвенно это тоже может увеличивать скорость. 4 часа назад, adnega сказал: "=imm32" я понимаю как "[PC, label]". Команда "LDRD R5, R6, [PC, label]" компилируется Я писал не про LDRD R5, R6, [PC, label], а про LDRD R5, R6, =imm32. По крайней мере на IAR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vov4ick 39 13 августа, 2023 Опубликовано 13 августа, 2023 · Жалоба У LDR(D) по описанию ARM последний операнд строго адрес в памяти. Транслятор IAR видимо не требует обязательного ввода квадратных скобок для адресов, типа режим MASM на х86. Хотя мне по душе режим TASM IDEAL, где за такое бьют по рукам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dmitrykhom 0 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба Нашел ошибку у себя: задал частоту процессора вдвое меньше (144 против 288). Но результаты исследования были очень полезны! Я поигрался с памятью, с оптимизацией и вот что получилось. Попробовал поиграться с взятием из памяти - получилось улучшить. Пример (R0 = 0x20001A7C, R2 = 0x20001A80, R4 = 0x20001A84): LDR R1, [R0] ADD R1, #0 STR R1, [R0] LDR R3, [R2] ADD R3, #0 STR R3, [R2] LDR R5, [R4] ADD R5, #0 STR R5, [R4] выполняется 49 нс (14 тактов), а последовательность LDR R1, [R0] LDR R3, [R2] LDR R5, [R4] ADD R1, #0 STR R1, [R0] ADD R3, #0 STR R3, [R2] ADD R5, #0 STR R5, [R4] выполняется 42 нс (12 тактов). (Да, я мерил своим любимым GPIO, но все сходится). В принципе, разница невелика, но есть. Да, AT действительно работает быстрее STM. Поэтому, если речь идет об оптимизации, то лучше, если будет длительная вычислительная цепочка. Т.е. взял значения - и долго-долго обрабатываешь, потом кладешь. Но, если говорить о целочисленных вычислениях, то взять значения особо-то и некуда - регистров всего 12. Иное дело обстоит с регистрами FPU - их 32. Но AT работает быстрее! Так, я запустил весь алгоритм (без оптимизации!), и получилось, что эффективность возросла где-то на 30-40 % (собственно, пропорционально тактовой частоте - 288/216 МГц). Выводы. 1. AT на Cortex-M4 работает быстрее во всех отношениях, чем STM на Cortex-M7. 2. Оптимизация при целочисленных вычислениях не имеет смысла - мало регистров, да и процесс, как правило, один. 3. Оптимизация при "плавучных" вычислениях даст превосходный результат, т.к. есть 32 FPU регистра. 4. Если программа, требующая быстрой работы (0WS), до 512 кБ, то не надо кэшировать ее, создавать системы управления памятью - она сама грузится в SRAM и работает быстро. 5. Цена где-то в 2-3 раза ниже у китайца. Резюме: выбираю китайца AT32F437, всё закладываю под него. Но делаю так, чтобы можно было запаять STM32F745. Всем спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 3 часа назад, dmitrykhom сказал: ADD R1, #0 Если бы вместо этого, написали бы: ADDS R1, #0, то было бы ещё лучше. 3 часа назад, dmitrykhom сказал: 1. AT на Cortex-M4 работает быстрее во всех отношениях, чем STM на Cortex-M7. При одной и той же частоте CPU? 3 часа назад, dmitrykhom сказал: 2. Оптимизация при целочисленных вычислениях не имеет смысла Не согласен. Не всё решается количеством регистров. 3 часа назад, dmitrykhom сказал: 3. Оптимизация при "плавучных" вычислениях даст превосходный результат, т.к. есть 32 FPU регистра. Опять не факт. Команды FPU как правило - длиннее, и кроме того - часто их требуется больше, чем при аналогичных целочисленных вычислениях (условные вевтвления, преобразования к/от целочисленным значениям и т.п.). Так что очень часто - как раз наоборот. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 3 часа назад, dmitrykhom сказал: Но результаты исследования были очень полезны! Я поигрался с памятью, с оптимизацией и вот что получилось. Весьма странные результаты у Вас получились... Я сейчас проверил на STM32F4, код LDR R1, [R0] ; +2 LDR R3, [R2] ; +1 LDR R5, [R4] ; +1 ADD R1, #0 ; +1 STR R1, [R0] ; +2 ADD R3, #0 ; +1 STR R3, [R2] ; +2 ADD R5, #0 ; +1 STR R5, [R4] ; +2 выполняется 13 тактов (смотрю CYCCNT). И это законно, ибо соответствует документации на Cortex-M4 (рядом подписал CPI). Код LDR R1, [R0] ; +2 ADD R1, #0 ; +1 STR R1, [R0] ; +2 LDR R3, [R2] ; +2 ADD R3, #0 ; +1 STR R3, [R2] ; +2 LDR R5, [R4] ; +2 ADD R5, #0 ; +1 STR R5, [R4] ; +2 выполняется 15 тактов, и это тоже законно, ибо соответствует растактовке (опять же, рядом подписал такты выполнения). Я не понимаю, что Вы там измеряете, получая меньшее кол-во тактов. Очень вряд ли китайцы допилили Cortex-M4, сократив циклы. Причем, я могу таких блоков инструкций наплодить весьма много, и результат будет пропорционален. А попробуйте и Вы - тоже будет кратно 14 тактам? Раз в 10 блок инструкций увеличьте. Цитата 1. AT на Cortex-M4 работает быстрее во всех отношениях, чем STM на Cortex-M7. Только за счет большей частоты. И только. У Cortex-M7 - многостадийный декодер с несколькими исполнительными конвейерами, что дает ему возможности внеочередного исполнения потока команд. Это может быть весьма эффективно, особенно, если компилятор прошаренный и умеет нормально тасовать команды. Цитата 2. Оптимизация при целочисленных вычислениях не имеет смысла - мало регистров, да и процесс, как правило, один. 3. Оптимизация при "плавучных" вычислениях даст превосходный результат, т.к. есть 32 FPU регистра. Вот здесь вообще не понял, ибо плавучка - та еще гадость, и лично я к ней привожу какие-то финальные результаты вычислений (для сопряжения с внешним миром), а так все считаю в фиксированной точке. FPU регистры удобны только их наличием для разовой загрузки из памяти и обратно. Цитата 5. Цена где-то в 2-3 раза ниже у китайца. Ну это да. Хотя бывает, что можно урвать STM32 (если были заложены изначально в проект) по весьма неплохой цене. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 26 минут назад, Arlleex сказал: Весьма странные результаты у Вас получились... У Вас - тоже 26 минут назад, Arlleex сказал: Я сейчас проверил на STM32F4, код LDR R1, [R0] ; +2 LDR R3, [R2] ; +1 LDR R5, [R4] ; +1 ADD R1, #0 ; +1 STR R1, [R0] ; +2 ADD R3, #0 ; +1 STR R3, [R2] ; +2 ADD R5, #0 ; +1 STR R5, [R4] ; +2 выполняется 13 тактов (смотрю CYCCNT). И это законно Это странно. Так как при наличии write buffer, операции STR должны бы занимать по такту. У вашего МК нет WB? Померил сейчас этот код на XMC4700 = 11 тактов. Т.е. - на 1 такт больше, чем должно быть (видимо влияние предвыборки или ещё чего). 26 минут назад, Arlleex сказал: Код LDR R1, [R0] ; +2 ADD R1, #0 ; +1 STR R1, [R0] ; +2 LDR R3, [R2] ; +2 ADD R3, #0 ; +1 STR R3, [R2] ; +2 LDR R5, [R4] ; +2 ADD R5, #0 ; +1 STR R5, [R4] ; +2 выполняется 15 тактов, и это тоже законно, ибо соответствует растактовке (опять же, рядом подписал такты выполнения). На XMC4700 = 12 тактов. Что тоже законно, так как работает WB. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба Да, каюсь. Ошибся в измерении. У меня тоже сейчас 11 тактов получилось. Причем действительно 11 тактов, даже если наплодить этих блоков друг за другом и посмотреть, насколько изменяется CYCCNT. Ровно 11 тактов. Видимо последний STR выполняется 2 такта, ибо добавление ADD R5, #0 в конце блока тоже дает 11 тактов. А вот второй пример дает ровно 15 тактов. Добавление одного и того же куска кода прибавляет ровно по 15 тактов. При этом включенный/отключенный prefetch buffer вообще не влияет на такты. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 1 час назад, Arlleex сказал: А вот второй пример дает ровно 15 тактов. Йес! Значит XMC оказался круче! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 2 минуты назад, jcxz сказал: Йес! Значит XMC оказался круче! Самое забавное, что я стал гуглить, не один ли я счастливый обладатель такой особенности - и нет, не один)) Оказывается, при чтении из обычной области ОЗУ, одиночный LDR в любом месте кода занимает 3 такта. Если за LDR есть еще LDR - они конвейеризуются до 1 такта. Т.е. портянка типа LDR LDR LDR будет выполнена за 5 тактов Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 3 минуты назад, Arlleex сказал: Оказывается, при чтении из обычной области ОЗУ, одиночный LDR в любом месте кода занимает 3 такта. Разве? Вы же сами приводили растактовки для варианта 2, где написали "2 такта". Да и мои эксперименты на XMC4700 это подтверждают. Если бы отдельная LDR во втором тесте выполнялась за 3 такта, то одна из последующих за ней ADD или STR должны были выполниться за 0 тактов. Во-вторых - открываем тот документ, ссыль на который я приводил выше и читаем на стр.2: Цитата CORTEX-M4 INSTRUCTION TIMING — LDR R0,[R1,R5]; LDR R1,[R2]; LDR R2,[R3,#4] - normally 4 cycles total. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 15 августа, 2023 Опубликовано 15 августа, 2023 · Жалоба 7 минут назад, jcxz сказал: Во-вторых - открываем тот документ, ссыль на который я приводил выше и читаем на стр.2: Дак это для теоретически голого процессора в TRM на Cortex-M4 указаны такты. А в реальном МК надо еще учитывать, что между памятью и процессором есть матрица шин, к которой еще и отладчик подключен и ему тоже надо уступать пользование System Bus (просто мне так проще было на коленке собрать "смотрелку" тактов). Я интереса ради пробую LDR грузить из CCM-памяти (она висит на D-bus процессора, в обход матрицы шин) - LDR - 2 такта. А из SRAM-регионов - 3 такта на первый LDR. Т.е. процессор то честный, а вот особенности коммутации шин и подключенная к этим шинам память имеет свои отпечатки. Другого объяснения пока не вижу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться