Ну, очевидно, вам нужно скопировать бит знака char
на каждый бит в верхней половине. На большинстве архитектур проще всего скопировать регистр и арифметико-правое смещение на 7. Но AVR имеет только shift-by-1 instruction, поэтому мы не можем эффективно это делать.
Другой уловкой для условного получения 0 или -1 в регистр является subtract-with-borrow регистр от себя, чтобы получить 0 - C
. например sbc r25, r25
.
Теперь нам нужен способ установить флаг Carry, если 8-разрядное число отрицательное, т. Е. Если оно> 127, когда рассматривается как целое без знака, потому что C всегда задается на основе неподписанной интерпретации вещей. AVR имеет команду сравнения-немедленного действия, CPI, но она работает только для r16-r31, а не для низких регистров. Кроме того, он устанавливает флаг C напротив того, что мы действительно хотим, поэтому нам пришлось бы использовать другую инструкцию для инвертирования результата. Так что я думаю, что мы лучше делает сравнение другой путь против значения в регистре:
; Most efficient way, I think:
sign_extend:
ldi r25, 127 ; can be hoisted out of loops, and any reg is fine.
cp r25, r24 ; C = (r24 < 0)
sbc r25, r25 ; r25 = (r24 < 0) ? -1 : 0
; result in r25:r24
Еще лучше, если вам нужно сделать, это в цикле, вы можете сохранить 127 в другом регистре.
С ИВК, вы могли бы сделать это:
; slightly worse: only works with r16-r31, and worse in loops
sign_extend:
cpi r24, 127 ; C = (r24 < 128U) = ((signed)r24 >= 0)
sbc r25, r25 ; r25 = (r24>=0) ? -1 : 0
com r25 ; ones-complement negation: 0 : -1
Или, чтобы избежать ограничений, на которых используется регистр, сделайте сравнение другой путь:
Я никогда не работал с AVR , поэтому я просто основываю это на справочном руководстве по набору инструкций, которое найдено google (и мои знания asm для других ISA, таких как x86 и ARM). Согласно этим документам, все эти инструкции являются 1 словом (2 байта) с 1 задержкой цикла. Это лучше, чем то, что делает gcc4.5:
Обычный способ найти хорошие последовательности инструкций является задать компиляторAVR gcc4.5 -O3
on godbolt делает это:
short sign_extend(signed char a) { return a; }
sign_extend:
mov r18,r24 ;; IDK why gcc uses r18 and r19.
clr r19
sbrc r18,7
com r19
mov r25,r19
ret
Так zeros R19, а затем использует SBRC для условного выполнения логического-not (COM), в зависимости от бита знака (бит 7) R18.
Я не уверен, для чего нужны дополнительные MOV. Я также не уверен, почему он инвертирует нуль, а не устанавливает все биты без зависимости от ввода. (например, ldi r19, $FF
или SBR alias for it.Если когда-либо существовал AVR вне очереди, это было бы более эффективно: P
Я не уверен, что для инструкций MOV. SBRC - разрушительный.Так AFAICT, действительное осуществление будет
sign_extend:
clr r25
sbrc r24,7
ldi r25, $FF
ret
Это еще хуже, чем CP/SBC, поскольку SBRC занимает 2 цикла, если пропуск берется.
Я предполагаю, что «ложная зависимость» SBC от старого значения R25 не является частью AVR. На процессорах x86 с невыполнением заказа только AMD распознает sbb eax, eax
как независимое от старого значения eax и зависит только от флагов. Процессоры Intel просто запускают его нормально. (Они признают инструкции, как xor eax,eax
как независимый и it's the standard zeroing-idiom for x86.)
Так что на не-процессоры AMD, если последний код, который написал EAX сделал это с грузом, который пропустил в кэше, или что-то еще с большой задержкой, sbb eax, eax
не удалось выполнить, даже если флаги были готовы (т. е. из независимой цепочки зависимостей). Но на процессорах AMD он начнет новую цепочку зависимостей для EAX.
В любом случае, я предполагаю, что AVR - это довольно простой конвейерный дизайн в заказе, поэтому старый реестр не может быть наземным миномлом производительности, если только код, который сделал (например) загрузку кэш-памяти никогда не использовал результат. (Даже внутрипорядковые конвейеры не должны ждать операций с высокой задержкой, пока что-то не использует результат.)
Какой формат для подписанных номеров учитель неявно предполагает? Два дополнения? –
@MargaretBloom: флаг знака AVR выглядит так, как будто он установлен на основе интерпретации дополнений 2-х, поэтому я думаю, что это само собой разумеется. Кроме того, [инструкция NEG] (http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_NEG.html) делает отрицание дополнений 2. –
@PeterCordes Eh, Может быть, или нет. Разумно предположить, что это дополнение к курсу, но упражнение может состоять в реализации других подписанных представлений (именно из-за отсутствия поддержки со стороны ISA). Я тоже предположил, что это дополнение. –