Programowanie: Mnożenie 16-bitowe z wynikiem 32-bitowym
From Atariki
Wersja z dnia 08:46, 21 gru 2005 KMK (Dyskusja | wkład) (→65C816) ← Previous diff |
Aktualna wersja KMK (Dyskusja | wkład) (ulepszenia i poprawki) |
||
Linia 1: | Linia 1: | ||
- | Procedura mnoży dwie 16-bitowe liczby bez znaku umieszczone w rejestrach FR0 ($D4) i FR1 ($E0). 32-bitowy wynik umieszczany jest w FR0. Jeśli po zakończeniu procedury znacznik C jest ustawiony, oznacza to, że nastąpiło przepełnienie i wynik nie jest prawidłowy. | + | Procedura mnoży dwie 16-bitowe liczby bez znaku umieszczone w rejestrach FR0 ($D4) i FR1 ($E0). 32-bitowy wynik umieszczany jest w FR0. |
== 6502 == | == 6502 == | ||
Linia 7: | Linia 7: | ||
?frf = fr1+2 | ?frf = fr1+2 | ||
- | clc | ||
lda fr0 ;gdy mnoznik albo mnozna jest zerem | lda fr0 ;gdy mnoznik albo mnozna jest zerem | ||
ora fr0+1 ;to zerem jest rowniez wynik. | ora fr0+1 ;to zerem jest rowniez wynik. | ||
Linia 16: | Linia 15: | ||
beq ?clr | beq ?clr | ||
- | ldx #$01 ;kopiujemy mnozna do rejestru pomocniczego | + | lda fr0 ;kopiujemy mnozna do rejestru pomocniczego |
- | ?cp lda fr0,x | + | sta ?frf |
- | sta ?frf,x | + | lda fr0+1 |
- | dex | + | sta ?frf+1 |
- | bpl ?cp | + | |
jsr ?clr ;zerujemy bajty wyniku | jsr ?clr ;zerujemy bajty wyniku | ||
Linia 36: | Linia 34: | ||
adc ?frf+1 | adc ?frf+1 | ||
sta fr0+3 | sta fr0+3 | ||
- | bcs ?exit | ||
- | ?noad lsr fr0+3 | + | ?noad ror fr0+3 |
ror fr0+2 | ror fr0+2 | ||
ror fr0+1 | ror fr0+1 | ||
Linia 44: | Linia 41: | ||
dex | dex | ||
bne ?mul | bne ?mul | ||
- | clc | ||
?exit rts | ?exit rts | ||
Linia 75: | Linia 71: | ||
sta ?frf | sta ?frf | ||
- | jsr ?clr ;zerujemy bajty wyniku | + | stz fr0 ;zerujemy bajty wyniku |
+ | lda #$0000 | ||
ldx #16 | ldx #16 | ||
Linia 82: | Linia 79: | ||
clc | clc | ||
- | lda fr0+2 | ||
adc ?frf | adc ?frf | ||
- | sta fr0+2 | ||
- | bcs ?exit | ||
- | ?noad lsr fr0+2 | + | ?noad ror |
ror fr0 | ror fr0 | ||
dex | dex | ||
bne ?mul | bne ?mul | ||
- | clc | + | sta fr0+2 |
+ | |||
?exit rts | ?exit rts | ||
Linia 98: | Linia 93: | ||
stz fr0+2 | stz fr0+2 | ||
rts | rts | ||
+ | .ab | ||
+ | .ib | ||
</pre> | </pre> | ||
- | Główna pętla zajmuje od 432 do 656 cykli maszynowych. | + | Główna pętla zajmuje od 384 do 464 cykli maszynowych. |
Elegancka procedura biblioteczna powinna jeszcze przechowywać na stosie i przed powrotem do miejsca wywołania przywracać rozmiar rejestrów. W powyższym przykładzie pominięto to, żeby nie zaciemniać zagadnienia. | Elegancka procedura biblioteczna powinna jeszcze przechowywać na stosie i przed powrotem do miejsca wywołania przywracać rozmiar rejestrów. W powyższym przykładzie pominięto to, żeby nie zaciemniać zagadnienia. |
Aktualna wersja
Procedura mnoży dwie 16-bitowe liczby bez znaku umieszczone w rejestrach FR0 ($D4) i FR1 ($E0). 32-bitowy wynik umieszczany jest w FR0.
6502
int16mul ?frf = fr1+2 lda fr0 ;gdy mnoznik albo mnozna jest zerem ora fr0+1 ;to zerem jest rowniez wynik. beq ?clr lda fr1 ora fr1+1 beq ?clr lda fr0 ;kopiujemy mnozna do rejestru pomocniczego sta ?frf lda fr0+1 sta ?frf+1 jsr ?clr ;zerujemy bajty wyniku ldx #16 ?mul lsr fr1+1 ;glowna petla ror fr1 bcc ?noad clc lda fr0+2 adc ?frf sta fr0+2 lda fr0+3 adc ?frf+1 sta fr0+3 ?noad ror fr0+3 ror fr0+2 ror fr0+1 ror fr0 dex bne ?mul ?exit rts ?clr ldx #$03 lda #$00 ?cl sta fr0,x dex bpl ?cl rts
Główna pętla zajmuje - w zależności od wartości mnożnika - od 612 do 944 cykli maszynowych.
65C816
int16mul ?frf = fr1+2 .aw .ib rep #$21 ;CPU musi byc w trybie natywnym sep #$10 lda fr0 ;gdy mnoznik albo mnozna jest zerem and fr1 ;to zerem jest rowniez wynik beq ?clr lda fr0 ;kopiujemy mnozna do rejestru pomocniczego sta ?frf stz fr0 ;zerujemy bajty wyniku lda #$0000 ldx #16 ?mul lsr fr1 ;glowna petla bcc ?noad clc adc ?frf ?noad ror ror fr0 dex bne ?mul sta fr0+2 ?exit rts ?clr stz fr0 stz fr0+2 rts .ab .ib
Główna pętla zajmuje od 384 do 464 cykli maszynowych.
Elegancka procedura biblioteczna powinna jeszcze przechowywać na stosie i przed powrotem do miejsca wywołania przywracać rozmiar rejestrów. W powyższym przykładzie pominięto to, żeby nie zaciemniać zagadnienia.
Uwagi
Procedura nie jest "optymalna", w szczególności można łatwo uniknąć kopiowania mnożnej do rejestru pomocniczego. Chodziło jednak o to, żeby procedura działała zgodnie z konwencją, jaką stosuje umieszczony w pamięci ROM komputera pakiet procedur zmiennoprzecinkowych - dla czterech działań arytmetycznych składniki są zawsze w FR0 i FR1, a wynik umieszczany jest w FR0. Przyjęcie takiej konwencji jest wygodne, gdy mamy w programie wykonać bardziej złożone obliczenie, zwłaszcza dłuższą serię mnożeń i dzieleń - wtedy wynik jednej procedury przechodzi w naturalny sposób jako składnik dalszych obliczeń do procedury następnej.