Как разделить 16-битное число на 2 в 6502 asm?

Я хочу разделить 16-битное число на два. Мое решение проблемы было следующим

    lda $17 ;set high byte
    ldx $32    ;set low byte

divide:
    PHA         ;push A to stack        
    TXA         ;X > A  
    LSR         ;divide low byte by 2   
    TAX         ;A > X

    PLA         ;pull A from stack  
    LSR         ;divide high byte by 2
    BCC +       ;C=0, skip

    PHA         ;while C=1
    TXA         ;add $80 to the lsb
    ADC #$80
    TAX
    PLA 
+   
    +printDecimal $0400+120

Вся хитрость PHA/PLA связана с тем, что мой макрос printDecimal считывает MSB из A и LSB из X.

Когда я искал альтернативы в Интернете, я нашел альтернативу 4 инструкциям для моей скромной процедуры деления. Но я не понял.

div2:
    LDA counter_hi       ;Load the MSB
    ASL                  ;Copy the sign bit into C
    ROR counter_hi       ;And back into the MSB
    ROR counter_lo       ;Rotate the LSB as normal

    LDA counter_hi
    LDX counter_lo      
    +printDecimal $0400+40    

Как это работает?


person wizofwor    schedule 09.12.2014    source источник


Ответы (5)


Деление на 2 (беззнакового числа) равносильно сдвигу всех битов на одну позицию вправо. Например, число 100 представлено в двоичном виде:

01100100

Перемещение всех позиций на одну вправо дает

00110010

что является двоичным представлением 50.

Команда ROR перемещает все позиции вправо. Новый MSB байта будет равен старому значению флага переноса, а новое значение флага переноса будет равно старому LSB байта.

Если 16-битное число беззнаковое, достаточно сдвинуть старший и младший байты числа вправо:

LSR counter_hi
ROR counter_lo

LSR и ROR оба сдвигают свои аргументы вправо, но LSR делает старший бит counter_hi равным 0 и сдвигает младший бит counter_hi во флаг переноса, в то время как ROR делает старший бит counter_lo равным (старому) младшему биту counter_hi.

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

person Hoopje    schedule 09.12.2014
comment
Этот. Умножение и деление на (кратные) два — это не что иное, как битовые сдвиги влево или вправо. «LSR hi-byte, ROR lo-byte» позволит достичь вашей цели 16-битного деления без кучи кода цикла, перестановки регистров и т. д. - person Eight-Bit Guru; 09.12.2014

Это работает, как говорится в комментариях в коде ;) В 6502, к сожалению, нет арифметического сдвига вправо, который оставил бы знаковый бит нетронутым. Значит надо подражать. Для этого сначала из старшего слова извлекается знаковый бит. Обратите внимание, что это делается с помощью аккумулятора, поэтому исходное значение не изменяется. ROR используется в старшем слове, которое вращает 9-битное значение, полученное в результате расширения операнда с помощью флага переноса. Таким образом, бит знака, который в настоящее время находится в CF, будет заменен на MSB, остальные биты будут сдвинуты вправо, а LSB окажется в CF. Это выполнило знаковое деление. Второй ROR в младшем слове просто переносит младший бит из старшего слова в старший бит младшего слова и сдвигает остальные биты вправо.

person Jester    schedule 09.12.2014

(Очевидно, вы знаете, что сдвиг вправо на N бит делится на 2 ^ N, и аналогично сдвиг влево умножается на 2)

Из этой ссылки:

ASL помещает старший значащий бит (MSB) старшего байта counter_hi в регистр переноса (чтобы знак запоминался при сдвиге — деление на положительное целое число (2) не изменит исходный знак нашего 16-битного числа) .

ROR counter_hi сдвигает counter_hi на 1 бит вправо. Важно:

Перенос сдвигается в бит 7, а исходный бит 0 сдвигается в перенос.

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

ROR counter_lo затем делает то же самое для младшего байта. Младший бит counter_hi теперь смещается в старший бит counter_lo.

person StuartLC    schedule 09.12.2014

Если я правильно помню, ROR и ROL сдвигают биты в указанном направлении, а младший бит (для ROR) и старший бит (для ROL) перемещаются во флаг переноса.

Я уже лет 25 как не смотрел ни на один 6502, правда поэтому мне не очень всё понятно, но я сразу так и подумал, что это будет сделано.

Редактировать: Кроме того, в ROR и ROL существующее состояние флага переноса передается в младший/самый значащий бит аккумулятора.

person Mick Waites    schedule 09.12.2014

Не помните все режимы адресации инструкций, но, возможно, это нормально:

LSR
PHA
TXA
ROR
TAX
PLA
person i486    schedule 09.12.2014