Обратный байт с использованием ассемблера
Я нахожусь в классе микропроцессоров, и мы используем ассемблер в Freescale CodeWarrior для программирования микроконтроллера 68HCS12. Наше назначение на этой неделе состоит в обращении байта, поэтому, если бы байт был 00000001, выходной результат был бы 10000000 или от 00101011 до 11010100. Мы должны использовать язык ассемблера, и нам сказали, что мы можем использовать повороты и сдвиги (но не ограничиваясь!) выполнить эту задачу. Я действительно в растерянности относительно того, с чего мне начать.
8 ответов
Если вы можете сэкономить дополнительный размер кода в 256 байт, таблица поиска, вероятно, является наиболее эффективным способом обращения байта в 68HCS12. Но я уверен, что это не то, чего ожидает твой инструктор.
Для "нормального" решения рассмотрим биты данных индивидуально. Вращения и сдвиги позволяют вам перемещать биты вокруг. Для первого решения выделите восемь битов (с помощью побитовых операций "и"), переместите их в их целевые позиции (сдвиги, повороты...), затем снова объедините их вместе (с помощью побитовых операций "или"). Это будет не самая эффективная или самая простая реализация, но вы должны сначала сконцентрироваться на получении правильного результата - оптимизация может подождать.
Подсказки: если вы делаете сдвиг, один бит сдвигается, и ноль (вероятно) сдвигается внутрь. Куда идет этот сдвинутый бит? Вам нужно переместить это на другой конец регистра назначения или адреса памяти.
Я уверен, что 25 лет назад я мог сделать это в машинном коде Z80 без ассемблера:)
Рассмотрим два регистра как стопки битов. Что произойдет, если вы будете переходить по одному биту от одного к другому?
Когда вы делаете правильный сдвиг, то младший бит попадает в флаг переноса.
Когда вы делаете поворот, флаг переноса используется для заполнения освобожденного бита результата (LSB для ROL, MSB для ROR).
Прежде всего, разработайте алгоритм для того, что вам нужно сделать. Выразите это в виде псевдокода, или C, или простого английского языка, или диаграмм, или того, что вам удобно. После устранения этого концептуального барьера фактическая реализация должна быть довольно простой.
Ваш ЦП, вероятно, имеет инструкции, которые позволяют вам сдвигать и / или вращать регистр, возможно, включая флаг переноса в качестве дополнительного бита. Эти инструкции будут очень полезны.
Например, если у вас есть номер байта, самый простой способ
mov al, 10101110
mov ecx, 8
мы помещаем 8 в ecx для цикла
mov ebx, 0
В bl мы получим результат, сделаем ebx, только чтобы посмотреть, что получится лучше
loop1:
sal al, 1;
Во флаге выполнения теперь у вас есть последний бит слева
rcr bl, 1;
теперь вы добавляете в бл, что у вас есть в переноске
loop loop1
и это все
Это был комментарий, но я думал, что WTH!
Для экономии места над 256-байтовой таблицей у вас может быть 16-байтовая таблица, содержащая значения для четырех битов (полубайтов) за раз. Алгоритм тогда будет
revval=(revdigit[inval&0x0f]<<4)|
revdigit[inval>>4];
Если бы я был профессором, я бы, конечно, хотел бы две части, где одна смена находится в индексации, а другая снаружи.
В следующем коде используются вращения и сдвиг. Я использую синтаксис Intel x86, см. Пояснения справа:
mov cx, 8 ; we will reverse the 8 bits contained in one byte
loop: ; while loop
ror di ; rotate `di` (containing value of the first argument of callee function) to the Right in a non-destructive manner
adc ax, ax ; shift `ax` left and add the carry, the carry is equal to 1 if one bit was rotated from 0b1 to MSB from previous operation
dec cx ; Decrement cx
jnz short loop ; Jump if cx register Not equal to Zero else end loop and return ax
Я использую инструкцию dec вместо sub, потому что она занимает только один байт, а sub - 3 байта. Вдобавок ко всему, компиляторы, кажется, всегда оптимизируют, выбирая dec вместо sub.
изменить: также обратите внимание, что rcl ax
(3 байта), а эквивалент adc ax, 0
(2 байта), за которым следует shl ax
(2 байта) менее эффективен. См. Комментарии ниже, большое спасибо Питеру Кордесу за его идеи.
Я также должен был запрограммировать этот бит в обратном порядке для университета (для 8 бит). Вот как я это сделал:
MOV AL, 10001011B ;set the value to test
MOV CL, 7
MOV DH, 1
MOV DL, 0
loop1: PUSH AX
AND AL, DH
PUSH CX
MOV CL, DL
SHR AL, CL
POP CX
MOV BH, AL
SHL BH,CL
OR CH,BH
DEC CL
INC DL
SHL DH, 1
POP AX
CMP DL, 8
JE END
JMP LOOP1
END:
Я не прокомментировал это так, вот как это работает:
DH является 1
который путешествует в байте, как в первый раз: 00000001
; второй раз 00000010
и так далее. Когда вы делаете AND
с AL вы получаете 0
или что-то вроде 100
или же 10000
Вы должны сдвинуть это вправо, чтобы получить его как 0
или же 1
, Затем поместите его в ЧД и переместите в нужное положение, которое 7
для байта 0
, 6
для байта 1
и так далее. затем OR
к нашему конечному результату и INC
а также DEC
что необходимо. Не забудьте условные прыжки и поп AX
для следующего цикла:)
Результат будет в СН.