Напишите программу на языке ассемблера ARM для выполнения умножения чисел с плавающей запятой

#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. * псевдо-инструкция