2014-12-09 18 views
5

Voglio dividere un numero di 16 bit per due. La mia soluzione al problema è stata, come di seguitoCome dividere il numero di 16 bit per 2 in 6502 asm?

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 

Tutto PHA/PLA inganno è perché il mio printDecimal macro legge MSB da A e LSB da X.

Quando controllo alternative in linea, ho trovato 4 istruzioni alternativa a mio modesto routine di divisione. Ma non ho capito.

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  

Come funziona?

risposta

8

La divisione per 2 (di un numero senza segno) equivale a spostare tutti i bit di una posizione a destra. Ad esempio, il numero 100 è rappresentato in binario da:

01100100 

Moving tutte le posizioni delle rese giuste

00110010 

che è la rappresentazione binaria di 50.

Il comando sposta ROR tutte le posizioni a destra. Il nuovo MSB del byte sarà uguale al vecchio valore del flag carry, mentre il nuovo valore del flag carry sarà uguale al vecchio LSB del byte.

Se il numero a 16 bit è firmato, è sufficiente spostare l'alto e il basso byte del numero a destra:

LSR counter_hi 
ROR counter_lo 

LSR e ROR entrambi spostare loro tesi a destra, ma LSR rende l'MSB di counter_hi 0 e sposta l'LSB di counter_hi nel flag di carry, mentre ROR rende il MSB di counter_lo uguale al (vecchio) LSB di counter_hi.

Se il numero è firmato, è necessario memorizzare il bit di segno e assicurarsi che il bit di segno del nuovo numero sia lo stesso. Questo è ciò che fanno i primi due comandi del codice che hai citato. Si noti che questo funziona perché il numero è memorizzato in two's complement.

+5

LSR = CLC + ROR – i486

+0

questo. Moltiplicazioni e divisioni per (multipli di) due non sono altro che bitshift a sinistra oa destra. 'LSR hi-byte, ROR lo-byte' raggiungerà il tuo obiettivo di divisione a 16 bit senza risme di codice di loop, swap di registro, ecc. –

+0

@ i486. Grazie I486. Ho modificato la risposta. – Hoopje

2

Se ricordo correttamente, ROR e ROL spostano i bit nella direzione indicata e il bit meno significativo (per ROR) e più significativo (per ROL) vengono spostati nel contrassegno di trasporto.

Sono passati circa 25 anni da quando ho guardato qualsiasi 6502, anche se quindi non è tutto molto chiaro per me, ma è immediatamente come pensavo che sarebbe stato fatto.

Modifica: Inoltre, in ROR e ROL, lo stato esistente del flag di trasporto viene trasferito nel bit meno significativo/significativo dell'accumulatore.

4

Funziona come dicono i commenti nel codice;) Nel 6502 non c'è purtroppo uno spostamento aritmetico a destra, che lascerebbe il segno un po 'intatto. Quindi deve essere emulato. Per questo, prima il bit del segno viene estratto dalla parola alta. Si noti che questo viene fatto usando l'accumulatore, quindi il valore originale non viene modificato. Il ROR viene utilizzato sulla parola alta, che ruota il valore a 9 bit ottenuto dall'estensione dell'operando con il flag di trasporto. Come tale, il bit di segno che è attualmente in CF verrà ruotato nel MSB, il resto dei bit sarà spostato a destra e l'LSB finirà nel CF. Questo ha compiuto una divisione firmata. Il secondo ROR nella parola bassa trasferisce semplicemente l'LSB dalla parola alta nel MSB della parola bassa e sposta il resto dei bit a destra.

2

(Ovviamente si sa spostando destra di n bit divide per 2^N, e allo stesso modo ha lasciato moltiplica spostamento da 2)

Da this reference:

mette il bit più significativo (MSB) del hi byte counter_hi nel registro di trasporto (in modo che il segno venga ricordato quando si sposta - Divisione per un numero intero positivo (2) non cambierà il segno originale del nostro numero a 16 bit).

ROR counter_hi sposta lo counter_hi di 1 bit a destra. Importante:

Il Carry viene spostato nel bit 7 e il bit originale 0 viene spostato nel Carry.

che serve a due scopi - mantenendo il segno originale, e anche trasferirà l'LSB di counter_hi per la seconda ROR

ROR counter_lo fa poi la stessa cosa per il byte basso. La LSB del counter_hi è ora spostato nella MSB di counter_lo

2

Non ricordo tutte le modalità di indirizzamento di istruzioni, ma forse questo è OK:

LSR 
PHA 
TXA 
ROR 
TAX 
PLA