Извлечение битов из регистра, начиная с самого старшего или старшего бита - PullRequest
3 голосов
/ 02 апреля 2019

РЕДАКТИРОВАТЬ:

Я не ожидал, что этот вопрос набирает обороты так быстро.Исходя из ответов, которые я уже получил, кажется, я, возможно, пропустил важную часть информации.Шаблон не является фиксированным количеством битов .Некоторые буквы могут иметь больше или меньше битов.Т.е. B имеет 5 битов, но C может использовать до 6 битов, но ни один не использует больше байта.Я включил в свой вопрос пример битовой комбинации «А», в которой для каждой строки используется 7 бит.Также см. Правку внизу вопроса.

Я новичок в сборке.У меня есть битовый шаблон, который соответствует текстовому представлению письма.Каждый 1 представляет $ (или любой символ), и каждый 0 представляет пробел.Т.е.:

    $$$$            11110
    $   $           10001
    $   $           10001
    $$$$            11110
    $   $           10001
    $   $           10001
    $$$$            11110

   $            0001000  
  $ $           0010100
 $$$$$          0111110  
$     $         1000001

Я написал программу на языке ассемблера, которая читает каждый шаблон и печатает правильный символ в зависимости от того, читает он 1 или 0. Чтобы определить, является ли он 1 или 0,I И регистр с 1 и затем вправо сдвигает биты количество раз, равное количеству битов в каждой строке, а затем сравнивает результат:

Обратите внимание, что биты для каждой строки хранятся в нижней частиотдельное 2-байтовое слово, которое я загружаю в 8-битный регистр.

patternb:   dw 011110b,010001b,010001b,011110b,010001b,010001b,011110b

rowloop:
    mov bl,[patternb+si]    ;iterate through each element in binary array

    patternloop:    
        mov bh,bl   ;move bit pattern into register so that we can change it
        and bh,1    ;AND register to find set bits and store back in register
        shr bl,1    ;SHIFT original bit pettern right
        cmp bh,1    ;check if bit is set or not (1=set, else 0)
        je writesym ;if set, write symbol
        jne writeblank  ;if not set, write space

Проблема в том, как работает AND.Очевидно, что он начинается с наименее значимого бита и печатается, когда биты сдвинуты вправо, но это вызывает проблему, заключающуюся в том, что буква печатается в «обратном» порядке.Т.е.:

 ####
#   #
#   #
 ####
#   #
#   #
 ####

Я попробовал несколько манипуляций, но ни одна из них не работает.Я также попытался сместить и повернуть битовый шаблон, чтобы он соответствовал правильной печати, но это не сработает для каждой строки, поскольку не нужно манипулировать каждой строкой таким образом.(Например, строка 2 будет печататься правильно, без необходимости сначала манипулировать).У меня есть один и тот же метод битового шаблона для каждой буквы из AE.

В идеале я бы хотел, чтобы он как-то начинал сравнивать с наиболее значимым битом, который затем должен был бы печататься в правильном порядке ,но я не уверен, что делать с битами для достижения этой цели.

РЕДАКТИРОВАТЬ: После ответа Питера Дунихо, я хотел бы опубликовать некоторые вещи, которые я пробовал: Я пытался ИИспользуя шаблон с 10000b, затем вернем результат, чтобы получить ответ 00001b, а затем сдвинем биты влево.Затем сравните результат, чтобы увидеть, какой символ должен быть напечатан.Это тоже не работает, но поскольку битовый шаблон не всегда фиксирован, это не будет решением в любом случае.

    mov bh,bl   ;move bit pattern into register so that we can change it
    and bh,10000b ;AND register to find set bits and store back in register
    rol bh,1    ;rol result to obtain 00001b
    shl bl,1    ;SHIFT original bit pettern right
    cmp bh,1    ;check if bit is set or not (1=set, else 0)
    je writesym ;if set, write symbol
    jne writeblank  ;if not set, write space

Самое близкое, что я сейчас сделал для решения этой проблемы (с некоторой помощьюИсходя из ответа Питера Дунихо в качестве руководства), мой массив битов должен храниться как полная 8-битная форма (т.е. 011110000b и т. д. вместо 011110b, в противном случае ассемблер хранит его как 00011101 неявно, как упомянуто в ответе Мартина Розенау, который мы надеваемне нужно) И это с полным 10000000b (так как мы используем не более 8 бит, и это позволяет нам проверять MSB) вместо 1 (000000001b), как я пытался сделать раньше, а затем с помощьюROL и сравните подход выше (или просто сравните его с 10000000b).Цикл выполняется в общей сложности 7 раз (из-за того, что каждая буква имеет 7 строчных / битовых шаблонов, за исключением A, в котором есть 4, поэтому A не печатается правильно, но эту проблему я могу решить самостоятельно с некоторыми условиями. Программа работает и печатаетправильно сейчас. Вот код, который я использовал:

        mov bh,bl   ;move bit pattern into register so that we can change it
        and bh,10000000b   ;AND register to find set bits and store back in register
        rol bh,1    ;shift MSB to LSB to compare (or could just compare with 10000000b instead)
        shl bl,1    ;SHIFT original bit pettern left
        cmp bh,1    ;check if bit is set or not (or use cmp bh,10000000b and omit rol above)
        je writesym ;if set, write symbol
        jne writeblank  ;if not set, write space

Я пометил решение Питера как ответ, так как именно он указал мне правильное направление, чтобы решить эту проблему. Но, как он упомянулЕсть множество способов решить эту проблему (как указано в различных опубликованных решениях), но мне просто оказалось, что его проще всего реализовать для собственного кода, к чему он стремился.

Ответ Мартина Розенау был также проницательным, особенно в отношении оптимизаций. Я постараюсь реализовать их, когда у меня будет больше времени, а затем обновлю решение выше.

Ответы [ 3 ]

3 голосов
/ 02 апреля 2019

Проблема в том, как работает AND.

Ваша первая проблема - способ правильного сдвига. Сдвиг вправо удалит самый правый «пиксель» вашего «изображения» и переместит пиксель влево от этого пикселя в крайнее правое положение (так, чтобы пиксель был следующим пикселем, который будет напечатан):

"$$$ $ $ " ->
" $$$ $ $" ->
"  $$$ $ " ->
"   $$$ $" ->
...

Если вы хотите напечатать пиксели слева направо, вам нужно будет выполнить сдвиг влево , а не сдвиг вправо.

(Обратите внимание, что сдвиг влево можно сделать с помощью shl bl,1 или add bl,bl.)

Поскольку ваше «изображение» имеет ширину всего 5 «пикселей», а байт имеет 8 битов, вам придется решить, добавлять ли неиспользуемые биты слева или справа от изображения.

например:.

"$$$ $" = 11101000 or 00011101 ?

Допустим, вы решили добавить пиксели с левой стороны (00011101 - что ассемблер будет делать неявно, если указать число как 011101b).

Затем вам нужно будет выполнить операцию AND со значением, бит которого представляет самый левый установленный пиксель:

Old:              New:

and bh,1          and bh, 010000b
shr bl,1          shl bl, 1

Кстати: для вашей программы возможны две оптимизации:

1) Используйте тот факт, что крайний левый бит не потерян:

patternloop:    
    shl bl,1
    test bl,0100000b
    je writesym

Эта оптимизация использует тот факт, что в байте есть 3 свободных бита, поэтому левый бит байта не "теряется" при левом сдвиге:

"0 0 0<1>1 1 0 1"
  -> Left shift ->
"0 0<1>1 1 0 1 0"

"< >" = Bit you are interested in

Инструкция test bl,xxx влияет на флаг ZF (который влияет на инструкцию je) так же, как комбинация двух инструкций and bl,xxx, за которыми следует cmp bl,0, но не изменяет bl зарегистрируйтесь!

2) Используйте тот факт, что сдвиг вправо сдвигает бит до CF:

patternloop:    
    shl bl,1
    jc writesym

Эта оптимизация предполагает, что «$$$ $» хранится как 11101000, а не как 00011101. Она использует тот факт, что shl будет копировать крайний левый (старший) бит в флаг CF перед выполнением сдвига (при условии сдвиг на 1 бит):

BL="<1>1 1 0 1 0 0 0", CF=?
   -> Left shift (using SHL or ADD) ->
BL="1 1 0 1 0 0 0 0", CF=<1>

Инструкция jc выполнит переход, если установлен флаг CF.

3 голосов
/ 02 апреля 2019

В идеале я бы хотел, чтобы он как-то начинал сравнивать с самого старшего бита, который затем должен печатать его в правильном порядке

Кажется, хорошая идея для меня. Вы пробовали что-нибудь в этом направлении? Если да, что конкретно вы пробовали? Какие конкретные трудности у вас были?

Тем временем & hellip;

Что определяет количество битовых позиций для проверки (т. Е. Количество циклов)? Это исправлено? Если так, то почему бы не просто AND с битом в верхнем конце вместо нижнего (например, 10000b, он же 16) и сдвигом влево вместо правого?

* 1013 Е.Г. *

mov bh,bl     ;move bit pattern into register so that we can change it
and bh,10000b ;AND register to find set bits and store back in register
shl bl,1      ;SHIFT original bit pattern left
cmp bh,10000b ;check if bit is set or not (1=set, else 0)
je writesym   ;if set, write symbol
jne writeblank  ;if not set, write space

Если вы не знаете количество циклов до времени выполнения, вы можете просто сдвигать для каждой итерации:

mov bh,bl     ;move bit pattern into register so that we can change it
shr bh,cl     ;the assumption being that cl has the width of your bit pattern
dec cl        ;next bit
and bh,1      ;AND register to find set bits and store back in register
cmp bh,1      ;check if bit is set or not (1=set, else 0)
je writesym   ;if set, write symbol
jne writeblank  ;if not set, write space

Если вы уже используете CX для своего цикла, очевидно, что вышеперечисленное необходимо немного изменить. Но, надеюсь, вы получите основную идею.

Разновидностью вышеупомянутого будет, например, сохранить битовую комбинацию AND в другом регистре (например, al), сохранив 1 и сместив влево соответствующий счетчик (например, shl al,cl), а затем используя al в качестве операнда вместо 10000b, как в первом пример выше.

Это далеко не ваши единственные варианты. Вам нужно будет значительно сузить ограничения вашего вопроса, чтобы получить более конкретный ответ. Но если предположить, что это упражнение по изучению ASM, это прекрасная возможность для вас прочитать и узнать больше об операциях битовой манипуляции, доступных вам. :)

0 голосов
/ 02 апреля 2019

Вы можете использовать код операции ROL, который поворачивает биты в сторону MSB на единицу, и MSB поворачивается в положение LSB, например:

11110000 -> ROL 1 -> 11100001

Так что вы можете сделать что-то вроде:

ROL1 -> проверить LSB -> ROL1 -> проверить LSB -> ....

В вашем случае bl является 8-битнымregitser, зациклите ROL, протестируйте 8 раз, чтобы нарисовать ascii art

...