Почему первые два аргумента выражения MUL на ARM7 не могут быть одинаковыми?
Я помогал с лабораторными занятиями по курсу на ассемблере ARM7 и сегодня столкнулся с проблемой, когда студент ввел следующее выражение:
MUL R0, R0, R1
Код не скомпилирован. Решение состоит в том, чтобы изменить выражение на:
MUL R0, R1, R0
т.е. первые два аргумента MUL не могут быть одним и тем же регистром. Я уже знал это, поскольку это является частью документации для ARM: http://infocenter.arm.com/help/topic/com.arm.doc.dui0489i/DUI0489I_arm_assembler_reference.pdf
Студент был достаточно счастлив, что их проблема была исправлена, но я довольно расстроен, что не знаю, почему ARM7 требует, чтобы аргументы передавались таким образом. Я думал, что это может иметь какое-то отношение к одному из регистров, используемых для хранения промежуточных значений во время сдвига и добавления множителя, но я даже не уверен, работает ли это как умножение на ARM (на самом деле, я довольно конечно это не так). Почему порядок аргументов так важен здесь?
2 ответа
Тот факт, что "Rn должен отличаться от Rd в архитектурах до ARMv6", говорит о том, что это ограничение конструкции того, как умножения были реализованы в исходном трехступенчатом конвейере ARM. До ARMv6 подразумеваются процессоры с ARM7 или более ранними версиями, и все они использовали простой трехступенчатый конвейер. В отличие от большинства команд для выполнения умножения команд требуется несколько циклов, и, исходя из ограничений набора команд, кажется, что ваше подозрение верно, регистр назначения Rd изменяется каждый цикл для вычисления результата.
В статье " Проверка умножения ARM6" Энтони Фокса это подтверждается, показывая на рисунке 4 (переформатированный ниже, чтобы соответствовать ограничениям разметки Stack Exchange), как Rd изменяется во время выполнения инструкций умножения ядром ARM6:
т3
- Получить инструкцию
- Увеличить счетчик программ
- Задавать
mul1
вreg[Rs]
- Задавать
borrow
ложноЗадавать
count1
в нольЗадавать
reg[Rd]
вreg[Rn]
если накапливать, иначе ноль- Задавать
mul
вmul1[1:0]
- Задавать
mul2
вmul1[31:2]
- Задавать
borrow2
вborrow
- Задавать
mshift
вMSHIFT2(borrow,mul,count1)
тн
- Задавать
alub
вreg[Rm]
сдвинут влево наmshift
- Задавать
alua
вreg[Rd]
- Задавать
mul1
вmul2[29:0]
- Задавать
borrow
вmul[1]
Задавать
count1
вmshift[4:1] + 1
Задавать
reg[Rd]
вALU6*(borrow2,mul,alua,alub)
- Задавать
mul
вmul1[1:0]
- Задавать
mul2
вmul1[31:2]
- Задавать
borrow2
вborrow
- Задавать
mshift
вMSHIFT2(borrow,mul,count1)
- Обновить
NZC
флагиCPSR
(еслиS
флаг установлен)- Если последняя итерация, то декодировать следующую инструкцию
Рис. 4: ARM6 реализация команд умножения. Каждый цикл делится на две фазы. Цикл tn повторяется до
MULX(mul2,borrow,mshift)
правда. регистрRd
не обновляется, когдаRd
равноRm
или пятнадцать
поскольку reg[Rd]
модифицируется как во время начального цикла установки t3, так и в течение повторяющихся циклов tn, результат будет мусором, если Rd == Rm
начиная с шага "Набор alua
в reg[Rm]
сдвинут влево на mshift
"ожидает прочитать исходное неизмененное значение Rm, а не текущее промежуточное значение, сохраненное в Rd.
Некоторые процессоры ARM7 имели "быстрый множитель", который обрабатывал 8 бит за цикл, а не 2 бита за цикл, как описано выше, но, похоже, он также изменяет регистр во время вычисления.
Я предполагаю, что это ошибка в ip для одного или нескольких ядер.
Это значительно проще, особенно в дни arm7, когда вам дали компоновку от arm, а не к исходному коду, чтобы компилятор работал над ошибкой ip, чем исправлял ошибку, вызывал все блоки, отбрасывал те, что в процессе., если ошибка была обнаружена после того, как поставщик вложил средства в маски или уже работает.
со временем (и другими) есть больше вещей, которые вы можете прочитать и определить, какое именно ядро у вас есть, и следовать ошибкам (хотя программное обеспечение, такое как Linux, делает ужасную работу, применяя неправильные ошибки к неправильным ядрам), чтобы знать, каких ошибок следует избегать.
Некоторое количество "непредсказуемых результатов" было на самом деле предсказуемым, только что сломанным, и могло быть использовано рукой, чтобы определить, является ли это клоном или украденным ip.