2016-11-30 11 views
2

Используя Arduino, я должен написать функцию в сборке Atmel AVR для моего класса компьютерных наук, которая вычисляет 8-битное среднее из двух 8-битных значений в сборке. Мне также не разрешено использовать какие-либо инструкции по ветвлению (но пропуски прекрасны).Как вычислить 8-битное среднее из двух 8-битных значений в сборке?

Это то, что я до сих пор:

.global average 
average: 
    add r24, r22 
    asr r24 
    ret 

Для части моей программы, где я должен вычислить среднее значение 69 и 60, она возвращает -64 вместо 64. Кто-нибудь знает, как я будет ли эта функция работать? Любая помощь приветствуется.

+3

Уловка для усреднения, избегая целых переполнений/обертывания: http://stackoverflow.com/a/3816471/224132. Который я нашел менее чем за минуту, ища «целое среднее без переполнения», так как я знал, что это был трюк, но не мог его запомнить. Вероятно, это работает для подписного дополнения 2, а также без знака, но я не проверял. Положите 'signed' в условия поиска google, если хотите. –

+0

Обратите внимание, что ответ, который я связывал, работает только для неподписанных, если вы знаете, в каком порядке они находятся. Самый высокий голос не нужен, но требует гораздо больше операций, чем ADD и ROR. В любом случае, это просто показывает, что при поиске целых трюков не ограничивайте себя AVR asm. Вы найдете много вещей в C, которые вы можете реализовать в AVR самостоятельно или даже подать в компилятор и посмотреть, как он это делает. например некоторые из них полезны: https://graphics.stanford.edu/~seander/bithacks.html –

ответ

10

Трюк состоит в том, чтобы добавить, а затем rotate-with-carry, чтобы разделить 9-битный результат на 2 и оставить 8-битный результат в регистре.

Два ответа на вопрос, который я связал в комментариях, используют это: first, second.

AVR реализация именно:

add r24, r25  ; 9-bit result in C and r24 
    ror r24   ; rotate-through-carry, like x86's RCR instruction 

Это работает знаком или без знака интерпретации битов, так как все, что мы делаем, отбрасывая младший бит из 9-битного полного результата добавления , Нет выбора арифметики и выбора логического сдвига, и нет обмана.

Также обратите внимание, что деление смещает раунды в направлении -infinity (не усекается к нулю, как оператор с целым делением C). Таким образом, (1 + -2) >> 1 - -1.


Это достаточно мало, что вы должны поместить его в макрос, а не в функцию. Это, вероятно, занимает не менее двух инструкций на большинстве сайтов вызовов, поэтому вложение этого размера сохраняет размер кода, даже если вы могли бы использовать 1-слово RCALL instruction вместо 2-словального CALL.

+0

интересно. Поэтому в x86 мы можем использовать 'RCL' для достижения того же. К сожалению, компиляторы не распознают эту оптимизацию. –

+0

@ LưuVĩnhPhúc: Да, я не знаю, как выразить это в C иначе, чем при использовании более строкового беззнакового типа, а затем используя '>>'. Вероятно, никакой компилятор не будет оптимизировать это для RCL для типов, которые шире регистра. –

+0

Даже RCL на 1 больше, чем 1 мкп на Intel (3 на Skylake), поэтому для более узких аргументов ADD + SHR в 64-битном или 32-битном регистре дешевле на процессорах Intel. Если только один из входов требует дополнительной инструкции для нулевого расширения, MOVZX (или MOV)/ADD/SHR должен нормально бить ADD + RCL. Тем более, что MOV с нулевым расширением позволяет делать это без разрушения. –