#assembly #arm
#сборка #arm
Вопрос:
Мне необходимо написать программу на языке ассемблера ARM, которая принимает целое число в качестве входных данных и возвращает целочисленное значение этого целого числа, умноженное на 6,985. Например, если в качестве входных данных введено 36, то результатом будет 251.
Я могу использовать только встроенную функцию add (которая добавляет два целых числа), mul (которая умножает два целых числа), divide (которая делит два целых числа), getnum (который получает целое число в качестве входных данных от пользователя) и printnum (который выводит выходные данные на экран). Мой подход заключается в том, чтобы сначала умножить на 6985, а затем разделить на 1000.
Вот мой код для функции mul:
bl getnum
mul r0, r0, #6985
bl printnum
Вот мой код для функции деления:
bl getnum
mov r1, #1000
bl divide
mov r4, r0
mov r5, r1
bl printnum
mov r0, r5
bl printnum
Мой вопрос в том, как я могу объединить два метода, чтобы он выполнял умножение и деление одновременно? Я все еще новичок в этом языке, поэтому я не знаю, как избавиться от getnum в функции divide и объединить ее с функцией mul .
Комментарии:
1. Какой набор команд ARM и семейство процессоров вы используете; ARMv7 для Cortex-M4 и т. Д.? Как правило, не существует единой инструкции, которая выполняет умножение и деление одновременно, а некоторые процессоры ARM не имеют инструкции деления.
2. Если у вас нет очень точных требований к точности, вы можете выполнить *57221, а затем разделить значение на 8192 = *6.9849853515625 .. дело в том, что 8192 равно 2 ^ 13, поэтому деление выполняется простым сдвигом влево на 13 бит. (чтобы получить лучшую точность, просто продолжайте умножать исходное значение 6.985 на 2, пока вы не будете достаточно довольны десятичными дробями, чтобы усечь их, и подсчитайте, сколько раз вы его умножили). В противном случае ваш подход верен, не уверен, что вы спрашиваете, просто используйте результат
mul
для части деления. (и если вы используете степени 2, попробуйте, какое максимальное число можно умножить до его переполнения)3. Деление на степени двойки — это, конечно, сдвиг вправо, сдвиг влево умножается на степени 2.
4. @Ped7g Вообще говоря, div / mul по степеням двух (2) сдвигов работает, просто не во всех случаях. См. publications.ai.mit.edu/ai-publications/pdf/AIM-378.pdf
5. @InfinitelyManic да, но это не проблема в этом особом случае (целое число со знаком * 57221 / 8192 .. для ввода -1 будет выведено правильное -6). При работе с десятичными числами всегда важна точность (если вы не обрабатываете их цифрой за цифрой), поэтому вы также должны быть осторожны при использовании *6985 / 1000, поскольку у него есть свой собственный набор проблем (переполнение и / 1000 усечение).).
Ответ №1:
Чтобы получить полную картину, вам нужно опубликовать весь код, включая фактические определения getnum
, divide
, и printnum
.
Давайте предположим:
getnum
получает целое число откуда-то (консоль?) и сохраняет его вr0
divide
функция, на которую ссылается ваш код, делитr0
наr1
и сохраняет результат в тех же регистрах (не уверен, чтоr1
это такое, возможно, напоминание о делении).printnum
просто выводит значениеr0
.
Если мое предположение верно, просто объедините свой код вместе:
bl getnum
mul r0, r0, #6985
mov r1, #1000
bl divide
bl printnum
Бонус
AFAIK, вы не можете использовать один и тот же регистр для mul
команды. Не уверен, применимо ли это ко всем ARM или нет.
Комментарии:
1. Cainkovs — да, mul r0, r0 … работает на Cortex-A9, A53 и M-4. Однако сначала множитель (#6985) должен быть помещен в другой регистр; например, Cortex-A9 movw r9, #6985, Cortex-M4 ldr r9, = #6985 *, Cortex-A53 mov x9, 6985. * псевдо-инструкция