Programowanie: Mnożenie 16-bitowe z wynikiem 32-bitowym
From Atariki
| Wersja z dnia 07:49, 21 gru 2005 KMK (Dyskusja | wkład) (fmt + procedura dla 816) ← 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 64: | Linia 60: | ||
| .aw | .aw | ||
| - | rep #$20 ;CPU musi byc w trybie natywnym | + | .ib |
| - | clc | + | rep #$21 ;CPU musi byc w trybie natywnym |
| + | sep #$10 | ||
| + | |||
| lda fr0 ;gdy mnoznik albo mnozna jest zerem | lda fr0 ;gdy mnoznik albo mnozna jest zerem | ||
| - | beq ?clr ;to zerem jest rowniez wynik. | + | and fr1 ;to zerem jest rowniez wynik |
| - | + | ||
| - | lda fr1 | + | |
| beq ?clr | beq ?clr | ||
| 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 97: | Linia 93: | ||
| stz fr0+2 | stz fr0+2 | ||
| rts | rts | ||
| + | .ab | ||
| + | .ib | ||
| </pre> | </pre> | ||
| + | |||
| + | 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 == | == Uwagi == | ||
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.
