Перейти к содержанию
    

AT32F437: эффективность работы команд под WS0

32 минуты назад, Arlleex сказал:

Т.е. процессор то честный, а вот особенности коммутации шин и подключенная к этим шинам память имеет свои отпечатки. Другого объяснения пока не вижу.

Вы как свои тесты выполняете? Ставите бряки в начале и в конце блока кода? Или говорите выполнить до...?

Я вот заметил разницу. Берём код почти как в тесте #2:

               LDR      R7, =0E0001004h
               LDR      R0, =10001A7Ch
               ADDS     R2, R0, #4
               ADDS     R4, R0, #8
               NOP
               NOP
               NOP
               LDR      R6, [R7, #0]
start:         NOP
               NOP
               #if      1
               LDR      R1, [R0]
               ADDS     R1, R1, #0
               STR      R1, [R0]
               LDR      R3, [R2]
               ADDS     R3, R3, #0
               STR      R3, [R2]
               LDR      R5, [R4]
               ADDS     R5, R5, #0
               STR      R5, [R4]
               #endif
stop:          NOP
               NOP
               LDR      R1, [R7, #0]
               SUBS     R1, R1, R6
               NOP
               NOP
               NOP

Выполняю его сейчас на STM32F429 от метки старт (начальное значение PC) до метки stop с помощью команды отладчика "run to cursor". Получаю время выполнения = 14 тактов (меньше на такт, чем у вас, хотя МК вроде сейчас аналогичный). Адрес я перенёс в CCM потому что у меня код сам находится в обычной ОЗУ (0x20000000) и соответственно - обращение за данными к этой же ОЗУ значительно снижает скорость выполнения. Но не суть важно. А важно другое: меняю условия теста - опять ставлю PC в ту же самую начальную точку (start), но в неё же ставлю бряк (который будет пройден сразу же, так как выполнение начнётся с него) и.... получаю время выполнения == 18 тактов! Т.е. - добавились лишние 4 такта на прохождение бряка. Может вы тоже стартуете тест с бряка, потому и получаете больше?

То же самое значение я получаю и по счётчику DWT считанному самой программой:

Прогон выполнения при аргументе if == 0: 5 тактов

Прогон выполнения при аргументе if == 1: 19 тактов

Т.е. - тестовый блок выполняется за те же 19-5=14 тактов.

 

PS: И всё равно - на 2 такта медленнее чем на XMC4700. Видимо всё-таки как-то сказывается его 256-битная шина выборки инструкций из памяти. Хоть сейчас код и выполняется из ОЗУ.  :wink:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Код теста у меня во Flash

; Reset handler
DWT_CYCCNT  EQU 0xE0001004
DWT_CONTROL EQU 0xE0001000
SCB_DEMCR   EQU 0xE000EDFC

Reset_Handler   PROC
                  EXPORT Reset_Handler
                  
                  IMPORT hwIsTargetSuit
                  IMPORT hwInitOnSysRst
                  IMPORT __main
                  
                  ; включение DWT/CYCCNT
                  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 r6, =DWT_CYCCNT
                  mov r7, #0x0
              
                  ldr r0, =0x20000000
                  ldr r2, =0x20000004
                  ldr r4, =0x20000008
          
                  b loop
        
                  LTORG

loop
                  str r7, [r6]             ; <- это тут я зануляю CYCCNT
          
                  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
          
                  ldr r8, [r6]             ; <- это тут я считываю CYCCNT
                  
                  b loop                   ; <- а вот здесь у меня точка останова (бряк)
                ENDP

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавил блок теста с примерно таким же кодом, но на 32-битных инструкциях:

               LDR      R7, =0E0001004h
               LDR      R0, =10001A7Ch
               ADDS     R2, R0, #4
               ADDS     R4, R0, #8
               NOP
               NOP
               NOP
               LDR      R6, [R7, #0]
start:         NOP
               NOP
               #if      1
               LDR      R1, [R0]      ;14 тактов
               ADDS     R1, R1, #0
               STR      R1, [R0]
               LDR      R3, [R2]
               ADDS     R3, R3, #0
               STR      R3, [R2]
               LDR      R5, [R4]
               ADDS     R5, R5, #0
               STR      R5, [R4]
               #elif    0
               LDR      R8, [R0]      ;17 тактов
               ADDS     R8, R8, #0
               STR      R8, [R0]
               LDR      R9, [R2]
               ADDS     R9, R9, #0
               STR      R9, [R2]
               LDR      R10, [R4]
               ADDS     R10, R10, #0
               STR      R10, [R4]
               #endif
stop:          NOP
               NOP
               LDR      R1, [R7, #0]
               SUBS     R1, R1, R6
               NOP
               NOP
               NOP

Получил увеличение времени для него на 3 такта.

Завтра, на работе, проверю сколько это выполняется на XMC4700.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Заметил вот что. 3 такта на LDR затрачиваются только в том случае, когда перед этой LDR стояла запись STR.

Если между STR и последующим LDR поставить любую команду, то LDR начнет выполняться 2 такта.

Это значит, что буфер записи очищается не сразу после завершения команды STR, а в момент выполнения следующей команды (т.е. тоже некий конвейер). И если следующая команда оказалась LDR, она должна будет дождаться реальной записи в память (очистки write buffer) в соответствии с описанием ARM.

Вот было бы интересно посмотреть, что получится у XMC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

Заметил вот что. 3 такта на LDR затрачиваются только в том случае, когда перед этой LDR стояла запись STR.

...

Вот было бы интересно посмотреть, что получится у XMC.

Я же писал выше: 12 тактов. Значит там нет такого ограничения.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 часов назад, jcxz сказал:

Я же писал выше: 12 тактов. Значит там нет такого ограничения.

Тогда все равно есть некое непонимание, откуда получается 12 тактов. С учетом фраз из TRM на Cortex-M4 (п. Load/store timings):

Цитата
  • STR Rx,[Ry,#imm] is always one cycle. This is because the address generation is performed in the initial cycle, and the data store is performed at the same time as the next instruction is executing. If the store is to the store buffer, and the store buffer is full or not enabled, the next instruction is delayed until the store can complete. If the store is not to the store buffer, for example to the Code segment, and that transaction stalls, the impact on timing is only felt if another load or store operation is executed before completion.
  • ...
  • Other instructions cannot be pipelined after STR with register offset. STR can only be pipelined when it follows an LDR, but nothing can be pipelined after the store. Even a stalled STR normally only takes two cycles, because of the store buffer.


В первом пункте нам четко дают понять, что приведенная форма STR занимает 1 такт, однако (внимание) этот 1 такт идет на вычисление адреса, а реальное сохранение будет в следующем такте (т.е. когда наступит выполнение следующей инструкции). Если нарисовать на бумажке множество следующих друг за другом STR, то будет видно, что "визуально" каждая из них действительно будет занимать один такт. А вот инструкция, следующая за самой последней STR в этом списке, вполне может определять, будет ли она задержана до реальной записи в память STR или нет. Второй пункт как-то расплывчато пишет об "Other instructions", не давая понимания, это для вообще любых инструкций, или только для инструкций обращения к памяти (LDR в частности). Не обратил внимание, что во втором пункте речь об STR с регистровым смещением. Мои опыты с отключением Write Buffer показывают, что если после STR идет любая инструкция, кроме загрузки из памяти, ее выполнение не будет задержано на 1 такт. А вот если после STR стоит LDR, то выполнение LDR затянется на 1 такт. Именно поэтому я видел у себя такую растактовку

STR ... ; 1 такт (фаза адреса)
LDR ... ; 3 такта (1 - очистка Write Buffer, 2 - стандартный CPI LDR)
LDR ... ; 1 такт
...

Забавно, в общем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Arlleex сказал:

Тогда все равно есть некое непонимание, откуда получается 12 тактов.

А что Вас смущает? Вроде там всё правильно. Меня вот больше смущает почему у STM32F4 лишние такты получаются? Но скорее всего - из-за того, что операции чтения (LDR) у неё не смотрят на целевой адрес содержимого WB.

2 часа назад, Arlleex сказал:

во втором пункте речь об STR с регистровым смещением.

Вот именно. Не наш случай.  :wink:

2 часа назад, Arlleex сказал:

Мои опыты с отключением Write Buffer показывают, что если после STR идет любая инструкция, кроме загрузки из памяти, ее выполнение не будет задержано на 1 такт. А вот если после STR стоит LDR, то выполнение LDR затянется на 1 такт. Именно поэтому я видел у себя такую растактовку

Подозреваю, что XMC может сравнивать целевой адрес содержимого WB и адрес слова, читаемого командой LDR. Чтобы (при необходимости) подменять чтение из реальной ОЗУ, чтением из WB. Поэтому ему и не нужна задержка на flush WB перед LDR. А в STM32F4 этого не реализовали, и потому ему нужен лишний такт на flush of WB. Почему не реализовали - вопрос. Ведь по цене (количеству вентилей в кремнии) это должно быть не дорого, а выигрыш в скорости - существенный. Потому как операции: "читаем/обрабатываем/сохраняем/читаем следующее значение" - должны быть довольно частыми в ARM-архитектуре.

Но это как версия.

2 часа назад, Arlleex сказал:

STR ... ; 1 такт (фаза адреса)
LDR ... ; 3 такта (1 - очистка Write Buffer, 2 - стандартный CPI LDR)
LDR ... ; 1 такт
...

Забавно, в общем.

Вот этой "1 - очистка WB" видимо в XMC и нету.  :unknw:  имхо

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 15.08.2023 в 18:39, Arlleex сказал:

Только за счет большей частоты. И только. У Cortex-M7 - многостадийный декодер с несколькими исполнительными конвейерами, что дает ему возможности внеочередного исполнения потока команд. Это может быть весьма эффективно, особенно, если компилятор прошаренный и умеет нормально тасовать команды.

Как это задействовать (внеочередное исполнение)? Есть ли какой пример на ассемблере?
Я не спорю, что M7 эффективнее. Я просто сравнил конечный результат, используя прагматичный расчет. Мне важно, что сможет процессор успеть сделать за цикл вычислений, и сколько будет стоить спецификация PCB.

Изменено пользователем dmitrykhom

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не сильно вдавался в подробности реализации out-of-order в M7; думаю, оно по-умолчанию включено и вообще его "выключить" нельзя.

Оно будет полезно тогда, когда несколько исполнительных блоков не испытывают зависимости по данным относительно друг друга.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 8/20/2023 at 2:06 AM, dmitrykhom said:

 

 

Здравствуйте.
Подскажите, плз, а какому STM наиболее точно соответствует AT32F437?
Я пытаюсь сконфигурировать периферию AT при помощи кубика STM (STM32F745) но там не хватает интерфейсов I2S и ещё отличия по мелочи...
А есть что полностью соответствует?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 21.10.2023 в 20:47, Alexey_N сказал:

Здравствуйте.
Подскажите, плз, а какому STM наиболее точно соответствует AT32F437?
Я пытаюсь сконфигурировать периферию AT при помощи кубика STM (STM32F745) но там не хватает интерфейсов I2S и ещё отличия по мелочи...
А есть что полностью соответствует?

Здравствуйте. Ничего полностью не соответствует. Нужно везде работать напильником

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...