Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autorzy: dr Ian Logan i dr Frank O'Hara |
©2024 mgr Jerzy Wałaszek |
(Indeks 3C - zobacz na CALCULATE)
Ten podprogram tworzy 'ostatnią wartość' na szczycie stosu kalkulatora będącą wynikiem zamiany liczby podanej w postaci xEm, gdzie m jest liczbą całkowitą dodatnią lub ujemną. Wejście do podprogramu wykonywane jest z wartością x na szczycie stosu kalkulatora, a m w rejestrze A.
Wykorzystywana metoda polega na znalezieniu bezwzględnej wartości m, powiedzmy p, i na pomnożeniu lub podzieleniu x przez 10p zgodnie ze znakiem m.
Aby to osiągnąć, p jest przesuwane w prawo aż do osiągnięcia zera, a x jest mnożone lub dzielone przez 10(2^n) przy każdym ustawionym na 1 bicie bn w p. Ponieważ p nigdy nie jest większe od 39, bity 6 i 7 w p zwykle nie będą ustawione.
2D4F E-TO-FP RLCA Zbadaj znak m przez wprowadzenie bitu 7 RRCA z A do znacznika przeniesienia bez zmiany A. JR NC,2D55,E-SAVE Skocz, jeśli m jest dodatnie. CPL Zmień znak m w A bez INC A niszczenia znacznika przeniesienia. 2D55 E-SAVE PUSH AF Zapamiętaj na krótko m przechowywane w A. LD HL,+5C92 To jest MEMBOT: znacznik znaku jest teraz CALL 350B,FP-0/1 umieszczany w pierwszym bajcie mem-0, tj. 0 dla '+' i 1 dla '-'. RST 0028,FP-CALC Stos zawiera x. DEFB +A4,stk-ten x,10 DEFB +38,end-calc x,10 POP AF Odtwórz m w A. 2D60 E-LOOP SRL A W pętli wysuwaj kolejny bit m, zmieniając odpowiednio znaczniki przeniesienia i zera; JR NC,2D71,E-TST-END skocz przy wyzerowanym przeniesieniu. PUSH AF Zapamiętaj resztę m oraz znaczniki. RST 0028,FP-CALC Stos zawiera x' oraz 10^(2^n), gdzie x' jest pośrednim etapem mnożenia x przez 10^m, a n=0,1,2,3,4 lub 5. DEFB +C1,st-mem-1 (10^(2^n) jest umieszczane w mem-1). DEFB +E0,get-mem-0 x', 10^(2^n), (1/0) DEFB +00,jump-true x', 10^(2^n) DEFB +04,to E-DIVSN x', 10^(2^n) DEFB +04,multiply x'*10^(2^n)= x" DEFB +33,jump x" DEFB +02,to E-FETCH x" 2D6D E-DIVSN DEFB +05,division x/10^(2^n)=x" (x" to N'*10^(2^n) lub x'/10^(2^n), zgodnie z tym czy m to '+' lub '-'). 2D6E E-FETCH DEFB +E1,get-mem-1 x", 10^(2^n) DEFB +38,end-calc x", 10^(2^n) POP AF Odtwórz pozostałość m w A oraz znaczniki. 2D71 E-TST-END JR Z,2D7B,E-END Skocz, jeśli m zostało zredukowane do zera. PUSH AF Zachowaj pozostałość m w A. RST 0028,FP-CALC x", 10^(2^n) DEFB +31,duplicate x", 10^(2^n), 10^(2^n) DEFB +04,multiply x", 10^(2^(n+1)) DEFB +38,end-calc x", 10^(2^(n+1)) POP AF Odtwórz pozostałość m w A. JR 2D60,E-LOOP Skocz wstecz dla wszystkich bitów z m. 2D7B E-END RST 0028,FP-CALC Użyj kalkulatora, aby wykasować osiągniętą na końcu DEFB +02,delete potęgę 10, pozostawiając na stosie DEFB +28,end-calc 'ostatnią wartość' równą x*10^m. RET |
Ten podprogram umieszcza w DE małą liczbę całkowitą n (-65535<=n<=65535) z adresu podanego w HL: tj. n jest zwykle pierwszą (lub drugą) liczbą na szczycie stosu kalkulatora; lecz HL może również adresować (przez wymianę z DE) liczbę usuniętą ze stosu. Podprogram sam z siebie nie usuwa liczby ze stosu ani z pamięci; zwraca HL wskazujące na czwarty bajt liczby w jej pierwotnym miejscu.
2D7F INT-FETCH INC HL Wskaż bajt znakowy liczby. LD C,(HL) Skopiuj bajt znakowy do C. |
Poniższy fragment powoduje uzupełnienie do dwóch liczby, jeśli jest ujemna (C ma wartość FF), lecz pozostawia ją bez zmiany, jeśli jest dodatnia (C równe 00).
INC HL Wskaż młodszy bajt. LD A,(HL) Pobierz go do A. XOR C Jeśli ujemny, dokonaj uzupełnienia do dwóch. SUB C To dodaje 1 przy liczbach ujemnych; ustawia znacznik przeniesienia, chyba że bajt miał wartość 0. LD E,A Młodszy bajt teraz do E. INC HL Wskaż starszy bajt. LD A,(HL) Pobierz go do A. ADC A,C Dokończ uzupełnienia do dwóch w przypadku liczby ujemnej; zauważ, że przeniesienie jest zawsze pozostawiane wyzerowane. LD D,A Teraz starszy bajt do D. RET Skończone. |
Ten podprogram zapisuje małą liczbę całkowitą n (-65535<=n<=65535) pod adresem wskazywanym przez HL i w czterech następnych komórkach: tj. n zamienia pierwszą (lub drugą) liczbę na szczycie stosu kalkulatora. Powrót następuje z HL wskazującym pierwszy bajt n na stosie.
2D8C P-INT-STO LD C,+00 Wejście w tym miejscu zapisze liczbę dodatnią. 2D8E INT-STORE PUSH HL Wskaźnik pierwszej komórki zostaje zapamiętany. LD (HL),+00 Pierwszy baj jest ustawiany na zero. INC HL Wskazujemy drugą komórkę. LD (HL),C Wprowadzamy drugi bajt. |
Teraz zostaje użyty ten sam sposób, co w 'INT-FETCH', aby dopełnić do 2 liczby ujemne. Jest to potrzebne np. przed lub po mnożeniu małych liczb całkowitych. Jednakże dodawanie wykonywane jest bez żadnych dopełnień do 2 ani przed, ani po.
INC HL Wskaż trzecią komórkę. LD A,E Pobierz mniej znaczący bajt. XOR C Jeśli liczba jest ujemna, SUB C dokonaj uzupełnienia do 2. LD (HL),A Zapisz ten bajt. INC HL Wskaż czwartą komórkę. LD A,D Pobierz bardziej znaczący bajt. ADC A,C Wykonaj uzupełnienie do 2 XOR C dla liczby ujemnej. LD (HL),A Zapisz ten bajt. INC HL Wskaż piątą komórkę. LD (HL),+00 Piaty bajt jest ustawiany na zero. POP HL Wróć z HL wskazującym na RET pierwszy bajt n na stosie. |
Ten podprogram wywoływany jest z czterech różnych miejsc dla różnych celów, aby skompresować zmiennoprzecinkową 'ostatnią wartość' do pary rejestrów BC. Jeśli wynik jest zbyt duży, tj. większy od 65535, to podprogram wraca z ustawionym znacznikiem przeniesienia. Jeśli 'ostatnia wartość' jest ujemna, to będzie wyzerowany znacznik zera. Młodszy bajt jest również umieszczany w rejestrze A.
2DA2 FP-TO-BC RST 0028,FP-CALC Użyj kalkulatora, aby ustawić HL DEFB +38,end-calc na STKEND-5 LD A,(HL) Pobierz bajt wykładnika AND A 'ostatniej wartości'; skocze, jeśli jest JR Z,2DAD,FP-DELETE równy zero, co oznacza 'małą liczbę całkowitą'. RST 0028,FP-CALC Teraz użyj kalkulatora, aby zaokrąglić DEFB +A2,stk-half 'ostatnią wartość' do najbliższej liczby DEFB +0F,addition całkowitej, co również zmieni ją na DEFB +27,int postać 'małej liczby całkowitej' na stosie kalkulatora, DEFB +38,end-calc jeśli jest to możliwe, tj. jeśli -65535.5 <= x <65535.5 2DAD FP-DELETE RST 0028,FP-CALC Użyj kalkulatora, aby usunąć DEFB +92,delete tę liczbę całkowitą ze stosu; DE wciąż wskazuje ją DEFB +38,end-calc w pamięci (pod adresem STKEND). PUSH HL Zapamiętaj oba wskaźniki stosu. PUSH DE EX DE,HL HL teraz wskazuje liczbę. LD B,(HL) Skopiuj pierwszy bajt do B. CALL 2D7F,INT-FETCH Skopiuj bajty 2, 3 i 4 do C, E i D. XOR A Wyczyść rejestr A. SUB B To ustawia znacznik przeniesienia, o ile b nie jest równe zero. BIT 7,C To ustawia znacznik zera, jeśli liczba jest dodatnia (NZ oznacza liczbę ujemną). LD B,D Skopiuj starszy bajt do B. LD C,E A młodszy bajt do C. LD A,E Również skopiuj go do A. POP DE Odtwórz wskaźniki stosu. POP HL RET Skończone. |
Ten podprogram jest wywoływany przez 'PRINT-FP' do wyliczania przybliżonej liczby cyfr przed kropką dziesiętną w x, czyli w liczbie mającej zostać wydrukowaną, lub, jeśli nie ma cyfr przed kropką dziesiętną, do wyliczania przybliżonej liczby zer wiodących po kropce dziesiętnej. Wejście następuje z rejestrem A zawierającym e, właściwy wykładnik liczby x, lub e'-2 i zostaje wyliczone z=log przy podstawie z (2^A). Podprogram następnie ustawia wymaganą zawartość A równą ABS INT (z + 0.5), do czego wykorzystuje FP-TO-A.
2DC1 LOG (2^A) LD D,A Liczba całkowita w A jest umieszczana na stosie RLA albo jako 00 00 A 00 00 (dla dodatniego A), SBC A,A albo jako 00 FF A FF 00 (dla ujemnego A). LD E,A Te bajty są najpierw umieszczane LD C,A w A, E, D, C, B, a następnie wywołane zostaje XOR A STK-STORE w celu umieszczenia liczby LD B,A na stosie kalkulatora. CALL 2AB6,STK-STORE RST 0028,FP-CALC Używany jest kalkulator DEFB +34,stk-data Teraz na stos idzie log10 2. DEFB +EF,exponent +7F Teraz stos stos zawiera A, log10 2. DEFB +1A,+20,+9A,+85 DEFB +04,multiply A*log10 2, tj. log10(2A) DEFB +27,int INT log10(2A) DEFB +38,end-calc |
Podprogram przechodzi do FP-TO-A w celu dokończenia wyliczeń.
Ten krótki, lecz istotny podprogram jest wywoływany co najmniej 8 razy dla różnych celów. Wykorzystuje przedostatni podprogram FP-TO-BC do pobrania 'ostatniej wartości' do rejestru A, gdy jest to możliwe. Dlatego sprawdza on, czy wartość bezwzględna z liczby zaokrągla się do wartości większej od 255, a jeśli tak, to wraca z ustawionym znacznikiem przeniesienia. W przeciwnym razie wraca z wartością bezwzględną liczby zaokrągloną do najbliższej liczby całkowitej w rejestrze A oraz z ustawionym znacznikiem zera przy liczbie dodatniej lub z wyzerowanym przy liczbie ujemnej.
2DD5 FP-TO-A CALL 2DA2,FP-TO-BC Skompresuj 'ostatnią wartość' do BC. RET C Wróć, jeśli już jest poza zakresem. PUSH AF Zapamiętaj wynik oraz znaczniki. DEC B Znów będzie poza zakresem, jeśli rejestr B INC B nie zawiera wartości zero. JR Z,2DE1,FP-A-END Skocz, jeśli w zakresie. POP AF Pobierz wynik oraz znaczniki. SCF Sygnalizuj przekroczenie zakresu. RET Skończone z porażką. 2DE1 FP-A-END POP AF Pobierz wynik i znaczniki. RET Skończone z sukcesem. |
Ten podprogram wywoływany jest przez procedurę rozkazu PRINT i przez STR$ pod adresem 3630, która zamienia na łańcuch tekstowy liczbę tak, jak zostałaby wydrukowana. Podprogram drukuje x jako 'ostatnia wartość' na stosie kalkulatora. Format wydruku nigdy nie zajmuje więcej niż 14 znaków.
8 najbardziej znaczących cyfr wartości x, poprawnie zaokrąglonej, jest przechowywane w prowizorycznym buforze wydruku w mem-3 i mem-4. Osobno są obsługiwane małe liczby, mniejsze od 1, oraz liczby duże, większe od 227. Te pierwsze są wymnażane przez 10n, gdzie n jest przybliżoną liczbą zer wiodących po przecinku dziesiętnym, natomiast te drugie dzieli się przez 10n-7, gdzie n jest przybliżoną liczbą cyfr przed przecinkiem dziesiętnym. Sprowadza to wszystkie te liczby do zakresu średniego, a ilość cyfr potrzebnych przed przecinkiem jest tworzona w drugim bajcie mem-5. Na koniec wykonywane jest drukowanie przy użyciu formatu zmiennoprzecinkowego, gdy przed przecinkiem znajduje sie ponad 8 cyfr lub, dla małych liczb, po przecinku występuje więcej niż 4 zera wiodące.
Poniższy program pokazuje zakres formatów wydruku:
10 FOR a=-11 TO 12: PRINT SGN a*9↑a,: NEXT
a
i. Najpierw zostaje wzięty pod uwagę znak liczby x:
Jeśli x jest ujemne, to podprogram skacze do
PF-NEGATIVE, za x bierze ABS x i drukuje znak minus.
Jeśli x jest zerem, to x zostaje usunięte ze stosu
kalkulatora, drukowane jest '0' i wykonany zostaje powrót z podprogramu.
Jeśli x jest dodatnie, to podprogram po prostu wykonuje
się dalej.
2DE3 PRINT-FP RST 0028,FP-CALC Użyj kalkulatora
DEFB +31,duplicate x,x
DEFB +36,less-0 x, (1/0) logiczna wartość x.
DEFB +00,jump-true x
DEFB +0B,to PF-NEGTVE x
DEFB +31,duplicate x,x
DEFB +37,greater-0 x, (1/0) logiczna wartość X.
DEFB +00,jump-true x
DEFB +0D,to PF-POSTVE x od tego miejsca x'=ABS x.
DEFB +02,delete -
DEFB +38,end-calc -
LD A,+30 Wprowadź kod znaku '0'.
RST 0010,PRINT-A-1 Wypisz '0'.
RET Skończone, ponieważ ostatnia wartość była zerem.
2DF2 PF-NEGTVE DEFB +2A,abs x' x'=ABS x.
DEFB +38,end-calc x'
LD A,+2D Wprowadź kod znaku '-'.
RST 0010,PRINT-A-1 Wypisz '-'.
RST 0028,FP-CALC Użyj ponownie kalkulatora.
2DF8 PF-POSTVE DEFB +A0,stk-zero 15 bajtów mem-3, mem-4
DEFB +C3,st-mem-3 i mem-5 zostaje wyzerowanych i
DEFB +C4,st-mem-4 przeznaczonych na bufor wydruku
DEFB +C5,st-mem-5 oraz dwa liczniki.
DEFB +02,delete Stos jest czyszczony z wyjątkiem x'.
DEFB +38,end-calc x'
EXX H'L', używane do przechowywania offsetów kalkulatora
PUSH HL (np. dla 'STR$') jest zapamiętywane na stosie maszynowym
EXX |
ii. Tutaj jest początek pętli, która zajmuje się dużymi liczbami. Jednakże każda liczba x zostaje najpierw podzielona na jej część całkowitą i oraz ułamkową f. Jeśli i jest małą liczbą całkowitą, tj. jeśli -65535 <= i <= 65535, to zostaje zapamiętane w D'E' do umieszczenia w buforze drukowania.
2E01 PF-LOOP RST 0028,FP-CALC Użyj ponownie kalkulatora. DEFB +31,duplicate x', x' DEFB +27,int x', INT (x')=i DEFB +C2,st-mem-2 (i jest umieszczane w mem-2). DEFB +03,subtract x'-i=f DEFB +E2,get-mem-2 f,i DEFB +01,exchange i,f DEFB +C2,st-mem-2 (f jest umieszczane w mem-2). DEFB +03,delete i DEFB +38,end-calc i LD A,(HL) Czy i jest małą liczbą całkowitą (pierwszy bajt zero) AND A tj. czy ABS i <= 65535? JR NZ,2E56,PF-LARGE Skocz, jeśli nie CALL 2D7F,INT-FETCH i jest kopiowane do DE (i, podobnie jak x', >=0). LD B,+10 Rejestr B jest ustawiany na zliczanie 16 bitów. LD A,D D jest kopiowany do A w celu testowania: AND A Czy równy zero? JR NZ,2E1E,PF-SAVE Skocz, jeśli nie. OR E Teraz testuj E. JR Z,2E24,PF-SMALL Skocz, jeśli DE równe zero x jest czystym ułamkiem. LD D,E Przenieś E do D i ustaw B na 8 bitów: LD B,+08 D było zerem, a E nie. 2E1E PF-SAVE PUSH DE Przenieś DE do D'E' poprzez stos maszynowy EXX w celu przeniesienia do bufora wydruku POP DE pod adresem PF-BITS. EXX JR 2E78,PF-BITS Skocz naprzód. |
iii. Czyste ułamki są mnożone przez 10n, gdzie n jest przybliżoną liczbą zer znaczących po przecinku; a -n jest dodawane do drugiego bajtu mem-5, który przechowuje liczbę cyfr potrzebnych przed przecinkiem; liczba ujemna oznacza tutaj zera wiodące po przecinku.
2E24 PF-SMALL RST 0028,FP-CALC i (i=zero tutaj),
DEFB +E2,get-mem-2 i,f
DEFB +38,end-calc i,f |
Zwróć uwagę, że stos teraz nie jest w równowadze. Potrzebny jest
dodatkowy bajt 'DEFB +02, delete' pod adresem 2E25, bezpośrednio za RST
0028. Teraz wyrażenie typu
LD A,(HL) Bajt wykładnika e części ułamkowej f jest pobierany do A. SUB +7E A staje się równe e - 126, tj. e'+2, gdzie e' jest rzeczywistym wykładnikiem f. CALL 2DC1,LOG (2^A) Obliczane jest wyrażenie A = ABS INT(LOG (2^A)) (LOG jest logarytmem dziesiętnym); LD D,A tj. powiedzmy, że A=n: n jest kopiowane z A do D. LD A,(mem-5-2nd) Bieżący rachunek jest pobierany SUB D z drugiego bajtu zmiennej mem-5, LD (mem-5-2nd),A a n jest od niego odejmowane. LD A,D n jest kopiowane z D do A. CALL 2D4F,E-TO-FP Utworzone zostaje y=f*10^n i umieszczone na stosie. RST 0028,FP-CALC i, y DEFB +31,duplicate i, y, y DEFB +27,int i, y, (INT (y) = i2) DEFB +C1,st-mem-1 (i2 jest kopiowane do mem-1). DEFB +03,subtract i, y - i2 DEFB +E1,get-mem-1 i, y - i2, i2 DEFB +38,end-calc i, f2, i2 (f2 = y - i2) CALL 2DD5,FP-TO-A i2 jest przenoszone ze stosu do A. PUSH HL Wskaźnik do f2 jest zapamiętywany. LD (mem-3-1st),A i2 zostaje umieszczone w pierwszym bajcie mem-3: cyfra do wydruku. DEC A i2 nie będzie drukowane, RLA jeśli ma wartość zero; A jest tak przetwarzane, że zero da zero, SBC A,A lecz niezerowa cyfra da 1. INC A LD HL,+5CAB Zero lub jeden jest wstawiane do LD (HL),A pierwszego bajtu mem-5 (liczba INC HL cyfr do wydrukowania) i dodawane ADD A,(HL) do drugiego bajtu mem-5 LD (HL),A (liczba cyfr przed przecinkiem). POP HL Wskaźnik f2 jest odtwarzany. JP 2ECF,PF-FRACTN Skocz, aby zapisać f2 w buforze (HL teraz wskazuje na f2, DE na i2). |
iv. Liczby większe od 227 są podobnie mnożone przez 2-n+7, co zmniejsza liczbę cyfr przed przecinkiem do 8, po czym następuje ponowne wejście do pętli pod adresem PF-LOOP.
2E56 PF-LARGE SUB +80 e - 80 szesnastkowo = e', rzeczywisty wykładnik i. CP +1C Czy e' jest mniejsze od 28 dziesiętnie? JR C,2E6F,PF-MEDIUM Skocz, jeśli tak. CALL 2DC1,LOG (2^A) n jest tworzone w A. SUB +07 I pomniejszane do n - 7. LD B,A Następnie kopiowane do B. LD HL,+5CAC n - 7 zostaje dodane do drugiego ADD A,(HL) bajtu mem-5, liczba cyfr potrzebnych przed przecinkiem w x. LD (HL),A LD A,B Następnie i jest mnożone przez 10-n+7 NEG To sprowadzi je w średni zakres przy wydruku. CALL 2D4F,E-TO-FP JR 2E01,PF-LOOP Z powrotem na początek pętli, aby zająć się liczbą w średnim zakresie. |
v. Część całkowita z x jest teraz umieszczana w buforze wydruku w mem-3 i mem-4.
2E6F PF-MEDIUM EX DE,HL DE teraz wskazuje na i, HL na f. CALL 2FBA,FETCH-TWO Mantysa i jest teraz w D', E', D, E. EXX Przejdź do rejestrów zapasowych. SET 7,D Prawdziwy bit liczbowy do D'. LD A,L Bajt wykładnika e do A. EXX Powrót do głównych rejestrów. SUB +80 Prawdziwy wykładnik e'=e - 80 szesnastkowo do A. LD B,A To daje pożądaną liczbę bitów do zliczania. |
Zwróć uwagę, że w przypadku, gdy i jest małą liczbą całkowitą (mniejszą od 65536) następuje ponowne wejście w tym miejscu.
2E7B PF-BITS SLA E Mantysa i jest teraz obracana RL D w lewo i w ten sposób wszystkie bity i zostają EXX wsunięte do mem-4 a każdy RL E bajt z mem-4 jest poprawiany dziesiętnie przy każdym przesunięciu. RL D Wszystkie cztery bajty i. EXX Powrót do głównych rejestrów. LD HL,+5CAA Adres piątego bajtu mem-4 LD C,+05 do HL; liczba 5 bajtów do C. 2E8A PF-BYTES LD A,(HL) Pobierz bajt z mem-4. ADC A,A Przesuń go w lewo, wprowadzając nowy bit. DAA Popraw dziesiętnie ten bajt. LD (HL),A I wstaw go z powrotem do mem-4. DEC HL Wskaż następny bajt w mem-4. DEC C Zmniejsz o jeden liczbę bajtów. JR NZ,2E8A,PF-BYTES Skocz dla każdego bajtu z mem-4. DJNZ 2E7B,PF-BITS Skocz dla każdego bitu z INT (x). |
Poprawka dziesiętna każdego bajtu z mem-4 dała dwie cyfry dziesiętne na bajt, czyli co najwyżej 9 cyfr. Teraz cyfry te zostaną przepakowane, po jednej na bajt w mem-3 i mem-4, przy wykorzystaniu instrukcji RLD.
XOR A A jest czyszczone w celu otrzymywania cyfr.
LD HL,+5CA6 Adres źródłowy: pierwszy bajt z mem-4.
LD DE,+5CA1 Przeznaczenie: pierwszy bajt z mem-3.
LD B,+09 Jest co najwyżej 9 cyfr.
RLD Lewe 4 bity zostają pominięte.
LD C,+FF FF w C będzie sygnalizować zero wiodące, 00 zero niewiodące.
2EA1 PF-DIGITS RLD Lewe 4 bity z (HL) do A, prawe 4 bity z (HL) w lewo.
JR NZ,2EA9,PF-INSERT Skocz, jeśli cyfra w A nie jest zerem.
DEC C Test na zero wiodące:
INC C
JR NZ,2EB3,PF-TEST-2 Skocz, jeśli to było zero wiodące.
2EA9 PF-INSERT LD (DE),A Teraz wprowadź cyfrę.
INC DE Wskaż następną pozycję docelową.
INC (mem-5-1st) Jedna więcej cyfra do druku.
INC (mem-5-2nd) Jedna więcej cyfra przed przecinkiem dziesiętnym.
LD C,+00 Zmień znacznik z zera wiodącego na inne zero.
2EB3 PF-TEST-2 BIT 0,B Wskaźnik źródłowy musi być zwiększany
JR Z,2EB8,PF,ALL-9 co drugi obieg pętli, gdy B jest nieparzyste.
INC HL
2EB8 PF-ALL-9 DJNZ 2EA1,PF-DIGITS Skocz wstecz dla wszystkich 9 cyfr.
LD A,(mem-5-1st) Pobierz licznik: czy było już 9 cyfr
SUB +09 z pominięciem zer wiodących?
JR C,2ECB,PF-MORE Jeśli nie, skocz w celu pobrania więcej cyfr.
DEC (mem-5-1st) Przygotuj się na zaokrąglenie: zmniejsz liczbę do 8.
LD A,+04 Porównaj dziewiątą cyfrę, bajt 4 z mem-4
CP (mem-4-4th) z liczbą 4, aby ustawić przeniesienie do zaokrąglenia.
JR 2F0C,PF-ROUND Skocz naprzód, aby zaokrąglić.
2ECB PF-MORE RST 0028,FP-CALC Użyj ponownie kalkulatora.
DEFB +02,delete - (i zostaje teraz usunięte).
DEFB +E2,get-mem-2 f
DEFB +38,end-calc f |
vi. Teraz w buforze będzie umieszczana część ułamkowa z x.
2ECF PF-FRACTN EX DE,HL DE teraz wskazuje na f. CALL 2FBA,FETCH-TWO Mantysa z f znajduje się w D',E',D,E. EXX Dostań się do zapasowych rejestrów. LD A,+80 Wykładnik z f jest zmniejszany do SUB L zera przez przesunięcie bitów w f LD L,+00 o e miejsc w prawo, gdzie rejestr L' zawierał e. SET 7,D W bicie 7 rejestru D' ustawiamy prawdziwy bit liczbowy. EXX Odtwórz główne rejestry. CALL 2FDD,SHIFT-FP Teraz wykonaj przesunięcie. 2EDF PF-FRN-LP LP A,(mem-5-1st) Pobierz licznik cyfr. CP +08 Czy jest już 8 cyfr? JR C,2EEC,PR-FR-DGT Jeśli nie, kocz naprzód. EXX Jeśli jest 8 cyfr, to po prostu użyj f do zaokrąglenia RL D i w górę, obracając D' w lewo, aby ustawić przeniesienie. EXX Odtwórz główne rejestry JR 2F0C,PF-ROUND i skocz naprzód, aby zaokrąglić.. 2EEC PF-FR-DGT LD BC,+0200 Początkowe zero do C, liczba 2 do B. 2EEF PF-FR-EXX LD A,E D'E'DE jest mnożone przez 10 w dwóch krokach, CALL 2F8B,CA=10*A+C najpierw DE, następnie D'E', każdy bajt po bajcie LD E,A w dwóch krokach, a część całkowita LD A,D wyniku zostaje otrzymana w rejestrze C CALL 2F8B,CA=10*A+C do przeniesienia do buforu LD D,A wydruku. PUSH BC Licznik i wynik zamieniają się pomiędzy EXX parami rejestrów BC i B'C'. POP BC DJNZ 2EEF,PF-FR-EXX Wróć na początek pętli po przetworzeniu rejestrów zastępczych. LD HL,+5CA1 Początek - pierwszy bajt z mem-3. LD A,C Wynik do A w celu umieszczenia w pamięci. LD C,(mem-5-1st) Licznik dotychczasowych cyfr w liczbie do C. ADD HL,BC Adresuj pierwszy pusty bajt. LD (HL),A Umieść w pamięci następną cyfrę. INC (mem-5-1st) Zwiększ liczbę cyfr. JR 2EDF,PF-FRN-LP Skocz na początek pętli, aż będzie 8 cyfr. |
vii. Cyfry umieszczone w buforze wydruku są zaokrąglane do 8 cyfr do wydruku.
2F0C PF-ROUND PUSH AF Zapamiętaj znacznik przeniesienia do zaokrąglenia. LD HL,+5CA1 Adres bazowy liczby: mem-3, bajt 1. LD C,(mem-5-1st) Przesunięcie (liczba cyfr w liczbie) LD B,+00 do BC. ADD HL,BC Adres ostatniego bajtu liczby. LD B,C Skopiuj C do B jako licznik. POP AF Odtwórz znacznik przeniesienia. 2F18 PF-RND-LP DEC HL To jest ostatni bajt liczby. LD A,(HL) Pobierz go do A. ADC A,+00 Dodaj przeniesienie, czyli zaokrąglij w górę. LD (HL),A Zapamiętaj zaokrąglony bajt w buforze. AND A Jeśli bajt ma wartość 0 lub 10, B zostanie zmniejszone, JR Z,2F25,PF-R-BACK a ostatnie zero (lub 10) nie będzie CP +0A wliczane do wydruku. CCF Zresetuj przeniesienie dla ważnej cyfry. JR NC,2F2D,PF-COUNT Skocz, jeśli przeniesienie jest zresetowane. 2F25 PF-R-BACK DJNZ 2F18,PF-RND-LP Skocz wstecz dla dalszych zaokrągleń lub kolejnych zer końcowych. LD (HL),+01 Na lewo jest nadmiar; INC B potrzebna jest tutaj dodatkowa jedynka. INC (mem-5-2nd) Jest to również dodatkowa cyfra przed przecinkiem. 2F2D PF-COUNT LD (mem-5-1st),B B teraz ustawia liczbę cyfr do wydruku (końcowe zera nie będą drukowane). RST 0028,FP-CALC f ma zostać usunięte. DEFB +02,delete - DEFB +38,end-calc - EXX Przesunięcie kalkulatora trafia ze stosu POP HL do pary rejestrów H'L'. EXX |
viii. Teraz liczba może zostać wydrukowana. Najpierw w rejestrze C zostanie ustawiona liczba cyfr do wydruku, bez wliczania końcowych zer, natomiast B będzie przechowywać liczbę cyfr wymaganych przed kropką dziesiętną.
LD BC,(mem-5-1st) Zostają ustawione liczniki. LD HL,+5CA1 Początek cyfr. LD A,B Jeśli jest wymagane więcej niż 9 lub mniej niż minus 4 cyfry CP +09 przed kropką dziesiętną, to będzie potrzebny JR C,2F46,PF-NOT-E format zmiennoprzecinkowy. CP +FC Mniej niż -4 znaczy, że za kropką dziesiętną potrzeba więcej JR C,2F6C,PF-E-FRMT niż 4 zera wiodące. 2F46 PF-NOT-E AND A Czy przed kropką dziesiętną brak cyfr? Jeśli tak, CALL Z,15EF,OUT-CODE wydrukuj początkowe zero. |
Kolejny punkt wejścia jest również wykorzystywany do drukowania cyfr potrzebnych na wydruku formatu zmiennoprzecinkowego.
2F4A PF-E-SBRN XOR A Rozpocznij przez wyzerowanie rejestru A.
SUB B Odejmij B: minus będzie oznaczał, że przed kropką dziesiętną
JR M,2F52,PF-OUT-LP są cyfry; skocz naprzód, aby je wydrukować.
LD B,A A jest teraz potrzebne jako licznik.
JR 2F5E,PF-DC-OUT Skocz naprzód, aby wydrukować część dziesiętną.
2F52 PF-OUT-LP LD A,C Skopiuj liczbę cyfr do wydrukowania
AND A do rejestru A. Jeśli A jest równe 0, wciąż są
JR Z,2F59,PF-OUT-DT końcowe zera do wydrukowania (B jest różne od 0), więc skocz.
LD A,(HL) Pobierz cyfrę z bufora wydruku.
INC HL Wskaż na następną cyfrę.
DEC C Zmniejsz licznik o 1.
2F59 PF-OUT-DT CALL 15EF,OUT-CODE Drukuj odpowiednią cyfrę.
DJNZ 2F52,PF-OUT-LP Wróć aż B osiągnie zero.
2F5E PF-DC-OUT LD A,C Teraz nadszedł czas wydrukowania kropki dziesiętnej,
AND A o ile C nie jest równe zero; w tym przypadku
RET Z wróć - praca skończona.
INC B Dodaj 1 do B - dołącz kropkę dziesiętną.
LD A,+2E Umieść kod '.' w rejestrze A.
2F64 PF-DEC-0S RST 0010,PRINT-A-1 Drukuj znak '.'.
LD A,+30 Wprowadź kod znaku '0'.
DJNZ 2F64,PF-DEC-0S Skocz na początek pętli, aby wydrukować wszystkie potrzebne zera.
LD B,C Ustaw licznik dla wszystkich pozostałych cyfr.
JR 2F52,PF-OUT-LP Skocz wstecz, aby je wydrukować.
2F6C PF-E-FRMT LD D,B Liczba cyfr jest kopiowana do D.
DEC D Zostaje ona zmniejszona, aby otrzymać wykładnik.
LD B,+01 W formacie zmiennoprzecinkowym jedna cyfra jest potrzebna przed kropką.
CALL 2F4A,PF-E-SBRN Teraz zostaje wydrukowana cała część liczby przed 'E'.
LD A,+45 Wprowadź kod znaku 'E'.
RST 0010,PRINT-A-1 Drukuj 'E'.
LD C,D Wykładnik do C dla druku.
LD A,C Dodaj do A w celach testowych.
AND A Sprawdzany jest jego znak.
JP P,2F83,PF-E-POS Skocz, jeśli wykładnik jest dodatni.
NEG Inaczej zaneguj go w A.
LD C,A A następnie skopiuj z powrotem do C dla wydruku.
LD A,+2D Wprowadź kod znaku '-'.
JR 2F85,PF-E-SIGN Skocz, aby wydrukować znak.
2F83 PF-E-POS LD A,+2B Wprowadź kod znaku '+'.
2F85 PF-E-SIGN RST 0010,PRINT-A-1 Teraz drukuj znak: '+' lub '-'.
LD B,+00 BC przechowuje wykładnik do wydruku.
JP 1A1B,OUT-NUM Skocz wstecz, aby go wydrukować i zakończyć procedurę. |
Ten podprogram jest wywoływany przez procedurę PRINT-FP, aby wymnożyć każdy bajt D'E'DE przez 10 i zwrócić część całkowitą wyniku w rejestrze C. Na wejściu rejestr A zawiera bajt do pomnożenia przez 10, a rejestr C zawiera przeniesienie z poprzedniego bajtu. Na wyjściu rejestr A zawiera wynikowy bajt, a rejestr C przeniesienie do następnego bajtu.
2F8B CA=10*A+C PUSH DE Zapamiętaj parę rejestrów DE.
LD L,A Skopiuj mnożną z A
LD H,+00 do HL.
LD E,L Również skopiuj ją do DE.
LD D,H
ADD HL,HL Podwój HL.
ADD HL,HL Podwój jeszcze raz.
ADD HL,DE Dodaj DE, aby otrzymać HL=5*A.
ADD HL,HL Podwój jeszcze raz: teraz HL=10*A.
LD E,C Skopiuj C do DE (D jest równe) do dodawania.
ADD HL,DE Teraz HL=10*A+C.
LD C,H H jest kopiowane do C.
LD A,L L jest kopiowane do A, co kończy zadanie.
POP DE Para rejestrów DE zostaje odtworzona ze stosu.
RET Skończone. |
Ten podprogram jest pierwszym z czterech, które są używane przez główne procedury arytmetyczne – ODEJMOWANIE, DODAWANIE, MNOŻENIE i DZIELENIE.
Ten konkretny podprogram przygotowuje liczbę zmiennoprzecinkową dodawania, głównie przez zastąpienie bitu znaku prawdziwym bitem 1 liczby oraz negacją liczby (za pomocą uzupełnienia do dwóch), jeśli jest ujemna. Wykładnik jest zwracany w rejestrze A, a pierwszy bajt zostaje ustawiony szesnastkowo na 00 dla liczby dodatniej lub FF dla ujemnej.
2F9B PREP-ADD LD A,(HL) Przenieś wykładnik do A. LD (HL),+00 Załóż, że liczba jest dodatnia. AND A Jeśli liczba jest zerem, to RET Z przygotowanie jest już zakończone. INC HL Teraz wskaż na bajt znaku. BIT 7,(HL) Ustaw znacznik zera dla liczby dodatniej. SET 7,(HL) Odtwórz prawdziwy bit liczby. DEC HL Wskaż ponownie na pierwszy bajt. RET Z Liczby dodatnie zostały przygotowane, lecz ujemne wymagają uzupełnienia do dwóch. PUSH BC Zachowaj wcześniejszy wykładnik. LD BC,+0005 Należy zająć się 5 bajtami. ADD HL,BC Wskaż na adres o 1 większy od ostatniego bajtu. LD B,C Przenieś 5 do B. LD C,A Zachowaj wykładnik w C. SCF Ustaw znacznik przeniesienia dla negacji. 2FAF NEG-BYTE DEC HL Wskazuj kolejno każdy bajt. LD A,(HL) Pobieraj każdy bajt. CPL Dokonaj uzupełnienia do dwóch. ADC A,+00 Dodaj przeniesienie do negacji. LD (HL),A Wstaw bajt do liczby. DJNZ 2FAF,NEG-BYTE Powtarzaj w pętli 5 razy. LD A,C Odtwórz wykładnik w A. POP BC Odtwórz poprzedni wykładnik. RET Skończone. |
Ten podprogram jest wywoływany przez DODAWANIE, MNOŻENIE i DZIELENIE do pobrania dwóch liczb ze stosu kalkulatora i wstawienia ich do rejestrów, łącznie z rejestrami zapasowymi.
Na wejściu do podprogramu para rejestrów HL wskazuje na pierwszy bajt pierwszej liczby, a para rejestrów DE wskazuje na pierwszy bajt drugiej liczby.
Gdy podprogram jest wywoływany przez MNOŻENIE lub DZIELENIE, znak wyniku jest zachowywany w drugim bajcie pierwszej liczby.
2FBA FETCH-TWO PUSH HL HL zostaje zachowane. PUSH AF AF zostaje zachowane. |
Nazwijmy pięć bajtów pierwszej liczby jako – M1, M2, M3, M4 i M5, a drugiej liczby jako – N1, N2, N3, N4 i N5.
LD C,(HL) M1 do C. INC HL Następny. LD B,(HL) M2 do B. LD (HL),A Skopiuj znak wyniku do (HL). INC HL Następny. LD A,C M1 do A. LD C,(HL) M3 do C. PUSH BC Zapamiętaj M2 i M3 na stosie maszynowym. INC HL Następny. LD C,(HL) M4 do C. INC HL Następny. LD B,(HL) M5 do B. EX DE,HL HL teraz wskazuje na N1. LD D,A M1 do D. LD E,(HL) N1 do E. PUSH DE Zapamiętaj M1 i N1 na stosie maszynowym. INC HL Następny. LD D,(HL) N2 do D. INC HL Następny. LD E,(HL) N3 do E. PUSH DE Zapamiętaj N2 i N3 na stosie maszynowym. EXX Przejdź do rejestrów zapasowych. POP DE N2 do D' i N3 do E'. POP HL M1 do H' i N1 do L'. POP BC M2 do B' i M3 to C'. EXX Wróć do oryginalnego zestawu rejestrów. INC HL Następny. LD D,(HL) N4 do D. INC HL Następny. LD E,(HL) N5 do E. POP AF Odtwórz AF. POP HL Odtwórz HL. RET Skończone. |
Podsumowanie:
M1 – M5 są w H', B', C', C, B.
N1 – N5 są w: L', D', E', D, E.
HL wskazuje na pierwszy bajt pierwszej liczby.
Ten podprogram przesuwa liczbę zmiennoprzecinkową do 32 miejsc w prawo, aby ją właściwie wypozycjonować dla dodawania. Liczba z mniejszym wykładnikiem została umieszczona na pozycji składnika sumy przed wywołaniem tego podprogramu. Każdy nadmiar na prawo w znaczniku przeniesienia jest dodawany z powrotem do liczby. Jeśli różnica wykładników jest większa od 32 lub przeniesienie wróci z powrotem na początek liczby, to jest ona ustawiana na zero, aby dodawanie nie zmieniło drugiej liczby.
2FDD SHIFT-FP AND A Jeśli różnica wykładników wynosi zero,
RET Z to podprogram wraca natychmiast.
CP +21 Jeśli różnica jest większa od szesnastkowo 20,
JR NC,2FF9,ADDEND-0 to skocz naprzód.
PUSH BC Chwilowo zachowaj BC.
LD B,A Przenieś różnicę wykładników do B, aby zliczać przesunięcia w prawo.
2FE5 ONE-SHIFT EXX Przesunięcie arytmetyczne w prawo rejestru L',
SRA L z zachowaniem bitów znaku.
RR D Obróć z przeniesieniem D', E',
RR E D i E.
EXX W ten sposób przesuwając pełne pięć
RR D bajtów liczby w prawo tyle razy
RR E ile wynosi zawartość rejestru B.
DJNZ 2FE5,ONE-SHIFT Wracaj w pętli, aż B osiągnie zero.
POP BC Odtwórz oryginalne BC.
RET NC Skończone, jeśli nie ma przeniesienia do odzysku.
CALL 3004,ADD-BACK Odzyskaj przeniesienie.
RET NZ Wróć o ile przeniesienie nie powróciło (wtedy nie ma nic do dodania).
2FF9 ADDEND-0 EXX Przejdź do L', D' & E'.
XOR A Wyzeruj rejestr A.
2FFB ZEROS-4/5 LD L,+00 Ustaw składnik sumy na zero w D',E',
LD D,A D i E, razem z jego bajtem znacznikowym
LD E,L (znacznikiem znaku) L', który miał wartość szesnastkową 00
EXX przy liczbie dodatniej i FF przy ujemnej.
LD DE,+0000 ZEROS-4/5 tworzy tylko 4 bajty zerowe, gdy zostanie wywołane z 3160.
RET Skończone. |
Ta procedura dodaje z powrotem do liczby przeniesienie, które pojawiło się na prawo. W przypadku krańcowym przeniesienie przesunie sie na lewo liczby.
Gdy procedura jest wywoływana podczas dodawania, pojawienie się takiego przeniesienia oznacza, że mantysa 0,5 została przesunięta o pełne 32 miejsca w prawo, a składnik sumy zostanie teraz ustawiony na zero; gdy wywołanie następuje z MNOŻENIA, to oznacza to, że wykładnik musi zostać zwiększony, a to może prowadzić do nadmiaru.
3004 ADD-BACK INC E Dodaj przeniesienie do bajtu najbardziej na prawo. RET NZ Wróć, jeśli na lewo nie ma nadmiaru. INC D Kontynuuj z następnym bajtem. RET NZ Wróć, jeśli nie ma nadmiaru na lewo. EXX Dostań się do następnego bajtu. INC E Zwiększ go również. JR NZ,300D,ALL-ADDED Skocz przy braku nadmiaru. INC D Zwiększ ostatni bajt. 300D ALL-ADDED EXX Odtwórz główne rejestry. RET Skończone. |
(Indeks 03 - zobacz na CALCULATE pod 'substract')
Procedura po prostu zmienia znak odjemnika i kontynuuje w ADDITION.
Zwróć uwagę, że HL wskazuje odjemną a DE wskazuje odjemnik. (Zobacz na opis ADDITION.)
300F SUBTRACT EX DE,HL Zamień miejscami wskaźniki. CALL 346E,NEGATE Zmień znak odjemnika. EX DE,HL Zamień z powrotem wskaźniki i przejdź do ADDITION. |
(Indeks 0F - zobacz na CALCULATE pod 'addition')
Jest to pierwsza z trzech głównych procedur arytmetycznych. Procedura ta przeprowadza operację dodawania zmiennoprzecinkowego dwóch liczb, każdej z 4-ro bajtową mantysą i 1-no bajtowym wykładnikiem. W tych trzech procedurach dwie liczby znajdujące się na szczycie stosu kalkulatora są dodawane/mnożone/dzielone, a wynik tych operacji trafia z powrotem na stos kalkulatora jako 'ostatnia wartość'.
HL wskazuje na drugą liczbę na szczycie, czynnik/mnożna/dzielna. DE wskazuje na liczbę na szczycie stosu kalkulatora, czynnik/mnożnik/dzielnik. Po operacji HL wskazuje na wynikową 'ostatnią wartość', której adres można również traktować jako STKEND - 5.
Lecz procedura dodawania najpierw sprawdza, czy te dwie liczby do dodania są 'małymi liczbami całkowitymi'. Jeśli są, dodaje je po prostu w HL i BC i umieszcza wynik bezpośrednio na stosie. Nie jest potrzebne uzupełnianie do podstawy 2 ani przed, ani po dodawaniu, ponieważ takie liczby są przechowywane na stosie już w postaci uzupełnieniowej, gotowe do dodawania.
3014 ADDITION LD A,(DE) Sprawdź, czy pierwsze bajty OR (HL) obu liczb są zerami. JR NZ,303E,FULL-ADDN Jeśli nie, skocz do pełnego dodawania. PUSH DE Zachowaj wskaźnik drugiej liczby. INC HL Wskaż drugi bajt pierwszej liczby PUSH HL i zachowaj również i ten wskaźnik. INC HL Wskaż na mniej znaczący bajt. LD E,(HL) Pobierz go do E. INC HL Wskaż na bardziej znaczący bajt. LD D,(HL) Pobierz go do D. INC HL Przejdź do drugiego bajtu INC HL drugiej liczby. INC HL LD A,(HL) Pobierz go do A (to jest bajt znakowy). INC HL Wskaż mniej znaczący bajt. LD C,(HL) Pobierz go do C. INC HL Wskaż bardziej znaczący bajt. LD B,(HL) Pobierz go do B. POP HL Pobierz wskaźnik bajtu znakowego pierwszej liczby. EX DE,HL Wstaw go do DE, a liczbę do HL. ADD HL,BC Wykonaj dodawanie: wynik w HL. EX DE,HL Wynik do DE, bajt znakowy do HL. ADC A,(HL) Dodaj bajty znakowe, a przeniesienie do A; RRCA to wykryje każdy nadmiar. ADC A,+00 Wartość różna od zera w A teraz wskazuje nadmiar. JR NZ,303C,ADDN-OFLW Skocz, aby zresetować wskaźniki i wykonać pełne dodawanie. SBC A,A Określ poprawny bajt znakowy dla wyniku. 3032 LD (HL),A Umieść go na stosie. INC HL Wskaż następną komórkę. LD (HL),E Umieść w niej młodszy bajt wyniku. INC HL Wskaż następną komórkę. LD (HL),D Umieść tam starszy bajt wyniku. DEC HL Przesuń wskaźnik wstecz na pierwszy bajt wyniku. DEC HL DEC HL POP DE Odtwórz STKEND w DE. RET Skończone. |
Zwróć uwagę, że liczba dziesiętna -65536 może powstać tutaj w postaci 00 FF 00 00 00 jako wynik dodawania dwóch mniejszych liczb ujemnych, np. -65000 i -536. Zostanie ona po prostu wpisana na stos w tej postaci. To jest błąd. System komputera Spectrum nie potrafi sobie poradzić z tą liczbą. Większość funkcji traktuje ją jako zero, a jest drukowana jako -1E-38, co powstaje po potraktowaniu jej jako 'minus zero' w nieprawidłowym formacie.
Jednym z możliwych lekarstw byłby test na tą liczbę w okolicach bajtu 3032, i jeśli byłaby obecna, należałoby ustawić drugi bajt na szesnastkowe 80, a pierwszy bajt na szesnastkowe 91, tworząc w ten sposób pełną postać zmiennoprzecinkową tej liczby, tj. 91 80 00 00 00, która nie sprawiałaby żadnych dalszych kłopotów. Zobacz również na uwagi w procedurze 'truncate' poniżej, przed bajtem 3225 oraz w Dodatku.
303C ADDN-OFLW DEC HL Odtwórz wskaźnik do pierwszej liczby. POP DE Odtwórz wskaźnik do drugiej liczby. 303E FULL-ADDN CALL 3293,RE-ST-TWO Umieść z powrotem obie liczby w pełnej postaci zmiennoprzecinkowej. |
Pełna procedura dodawania najpierw wywołuje PREP-ADD dla każdej z liczb, następnie pobiera dwie liczby ze stosu kalkulatora i umieszcza tę z mniejszym wykładnikiem na pozycji liczby dodawanej. Następnie wywołuje SHIFT-FP w celu przesunięcia tej liczby do 32 pozycji dziesiętnych w prawo, aby wyrównać ją dla dodawania. Rzeczywiste dodawanie wykonywane jest na kilku bajtach, robi się pojedyncze przesunięcie dla przeniesienia (nadmiar w lewo), jeśli jest to konieczne, a wynik otrzymywany jest jako uzupełnienie do dwóch, jeśli jest ujemny. Wszelkie przepełnienia arytmetyczne są zgłaszane; jeśli natomiast nie wystąpią, to procedura skacze do TEST-NORM w celu znormalizowania wyniku i zwraca go na stos z właściwym bitem znaku wstawionym do drugiego bajtu.
EXX Wymień rejestry. PUSH HL Zachowaj adres następnego literału. EXX Wymień rejestry. PUSH DE Zachowaj wskaźnik składnika. PUSH HL Zachowaj adres dodajnej. CALL 2F9B,PREP-ADD Przygotuj dodajną. LD B,A Zapamiętaj jej wykładnik w B. EX DE,HL Wymień wskaźniki. CALL 2F9B,PREP-ADD Przygotuj składnik. LD C,A Zapamiętaj jego wykładnik w C. CP B Jeśli pierwszy wykładnik jest mniejszy, JR NC,3055,SHIFT-LEN utrzymaj pierwszą liczbę na LD A,B pozycji składnika; inaczej LD B,C wymień wykładniki oraz EX DE,HL ponownie wykładniki. 3055 SHIFT-LEN PUSH AF Zachowaj większy wykładnik w A. SUB B Różnica pomiędzy wykładnikami jest liczbą przesuwów w prawo. CALL 2FBA,FETCH-TWO Pobierz te dwie liczby ze stosu. CALL 2FDD,SHIFT-FP Przesuń składnik w prawo. POP AF Odtwórz większy wykładnik. POP HL HL ma wskazywać wynik. LD (HL),A Zapisz wykładnik wyniku. PUSH HL Ponownie zachowaj wskaźnik. LD L,B M4 do H a M5 do L, LD H,C (zobacz na FETCH-TWO). ADD HL,DE Dodaj dwa prawe bajty. EXX N2 do H' a N3 do L', EX DE,HL (zobacz na FETCH-TWO). ADC HL,BC Dodaj lewe bajty z przeniesieniem. EX DE,HL Wynik z powrotem do D'E'. LD A,H Dodaj H', L' i przeniesienie; ADC A,L wynikowy mechanizm zapewni, że będzie LD L,A wykonane pojedyncze przesunięcie w prawo, RRA jeśli suma dwóch dodatnich liczb XOR L przepełniła się na lewo, albo suma EXX 2 ujemnych liczb nie przepełniła się na lewo. EX DE,HL Wynik jest teraz w DED'E'. POP HL Pobierz wskaźnik wykładnika. RRA Test na przesunięcie (H', L' miały wartość 00 JR NC,307C,TEST-NEG przy liczbach dodatnich i FF przy ujemnych). LD A,+01 A zlicza pojedynczy przesuw w prawo. CALL 2FDD,SHIFT-FP Przesuw zostaje wykonany. INC (HL) Dodaj 1 do wykładnika; to JR Z,309F,ADD-REP-6 może prowadzić do nadmiaru arytmetycznego. 307C TEST-NEG EXX Sprawdź, czy wynik jest ujemny: pobierz LD A,L bit znaku z L' do A (to teraz poprawnie AND +80 oznacza znak wyniku). EXX INC HL Umieść go na pozycji drugiego bajtu LD (HL),A wyniku na stosie kalkulatora. DEC HL JR Z,30A5,GO-NC-MLT Jeśli ma wartość zero, to nie wykonuj uzupełnienia do dwóch wyniku. LD A,E Pobierz pierwszy bajt. NEG Zaneguj go. CCF Zaneguj przeniesienie dla dalszej negacji, LD E,A i zapisz bajt. LD A,D Pobierz następny bajt. CPL Dokonaj na nim uzupełnienia do jeden. ADC A,+00 Dodaj przeniesienie dla negacji. LD D,A Zapisz ten bajt. EXX Kontynuuj w celu pobrania następnego bajtu LD A,E do rejestru A. CPL Uzupełnij go do jeden. ADC A,+00 Dodaj przeniesienia dla negacji. LD E,A Zapisz bajt. LD A,D Pobierz następny bajt. CPL Uzupełnij go do jeden. ADC A,+00 Dodaj przeniesienie dla negacji. JR NC,30A3,END-COMPL Jeśli nie ma przeniesienia, to koniec. RRA Inaczej wstaw .5 do mantysy EXX i dodaj 1 do wykładnika; będzie to potrzebne, INC (HL) gdy dwie ujemne liczby sumują się do dokładnej potęgi 2; może to prowadzić do nadmiaru arytmetycznego. 309F ADD-REP-6 JP Z,31AD,REPORT-6 Zgłoś błąd, jeśli konieczne. EXX 30A3 END-COMPL LD D,A Zapisz ostatni bajt. EXX 30A5 GO-NC-MLT XOR A Wyczyść znacznik przeniesienia. JP 3155,TEST-NORM Wyjdź poprzez TEST-NORM. |
Ta procedura jest wywoływana przez 'GET-HL*DE' i 'MNOŻENIE' w celu wykonania mnożenia 16-bitowego.
Przepełnienie ponad 16 bitów jest obsługiwane przy powrocie z procedury.
30A9 HL=HL*DE PUSH BC BC jest zachowywane. LD B,+10 Ma to być mnożenie 16-bitowe. LD A,H A zawiera starszy bajt. LD C,L C zawiera młodszy bajt. LD HL,+0000 Ustaw wynik na zero. 30B1 HL-LOOP ADD HL,HL Podwój wynik. JR C,30BE,HL-END Skocz przy nadmiarze. RL C Obróć bit 7 rejestru C do przeniesienia. RLA Obróć bit przeniesienia do bitu 0, a bit 7 do znacznika przeniesienia. JR NC,30BC,HL-AGAIN Skocz, jeśli znacznik przeniesienia jest zresetowany. ADD HL,DE Inaczej dodaj raz DE. JR C,30BE,HL-END Skocz przy nadmiarze. 30BC HL-AGAIN DJNZ 30B1,HL-LOOP Wykonaj 16 obiegów tej pętli. 30BE HL-END POP BC Odtwórz BC. RET Skończone. |
Ta procedura przygotowuje liczbę zmiennoprzecinkową do mnożenia lub dzielenia, wracając z ustawionym znacznikiem przeniesienia, jeśli liczba ma wartość zero. Do rejestru A jest pobierany znak liczby, a bit znaku w liczbie zostaje zastąpiony prawdziwym bitem jej wartości, tzn. 1.
30C0 PREP-M/D CALL 34E9,TEST-ZERO Jeśli liczba ma wartość 0, RET C wróć z ustawionym znacznikiem przeniesienia. INC HL Wskaż na bajt znakowy. XOR (HL) Pobierz znak wyniku do A; również zresetuj przeniesienie. SET 7,(HL) Ustaw prawdziwy bit liczbowy. DEC HL Wskaż ponownie wykładnik. RET Wróż z wyzerowanym znacznikiem przeniesienia. |
(Indeks 04 - zobacz na CALCULATE pod 'multiply')
Procedura najpierw sprawdza, czy dwie liczby do pomnożenia są 'małymi liczbami całkowitymi'. Jeśli tak, to używa INT-FETCH do pobrania ich ze stosu, HL=HL*DE do pomnożenia ich i INT-STORE do zwrócenia wyniku na stos. Każdy nadmiar tego 'krótkiego mnożenia (tj. jeśli wynik sam nie jest 'małą liczbą całkowitą') powoduje skok do mnożenia w pełnej pięciobajtowej postaci zmiennoprzecinkowej (zobacz poniżej).
30CA multiply LD A,(DE) Sprawdź, czy pierwsze bajty OR (HL) obu liczb są zerami. JR NZ,30F0,MULT-LONG Jeśli nie, skocz do 'długiego' mnożenia. PUSH DE Zapamiętaj wskaźniki: do drugiej liczby. PUSH HL Oraz do pierwszej. PUSH DE I jeszcze raz do drugiej. CALL 2D7F,INT-FETCH Pobierz znad do C, liczbę do DE. EX DE,HL Liczba teraz do HL. EX (SP),HL Liczba na stos, drugi wskaźnik do HL. LD B,C Zapamiętaj pierwszy znak w B. CALL 2D7F,INT-FETCH Pobierz drugi znak do C, liczbę do DE. LD A,B Utwórz znak wyniku w A: te same znaki XOR C dają plus (00), różne dają minus (FF). LD C,A Umieść znak wyniku w C. POP HL Odtwórz pierwszą liczbę w HL. CALL 30A9,HL=HL*DE Wykonaj właściwe mnożenie. EX DE,HL Zapisz wynik do DE. POP HL Odtwórz wskaźnik do pierwszej liczby. JR C,30EF,MULT-OFLW Przy nadmiarze skocz do 'pełnego' mnożenia. 30E5 LD A,D Te 5 bajtów daje pewność, że OR E 00 FF 00 00 00 zostanie zastąpione JR NZ,30EA,MULT-RSLT zerem; co nie powinno być potrzebne, gdyby ta LD C,A liczba została wyłączona z systemu (zobacz na 303B). 30EA MULT-RSLT CALL 2D8E,INT-STORE Teraz zapisz wynik na stos. POP DE Odtwórz STKEND w DE. RET Skończone. 30EF MULT-OFLW POP DE Odtwórz wskaźnik do drugiej liczby. 30F0 MULT-LONG CALL 3293,RE-ST-TWO Ponownie umieść na stosie obie liczby w pełnej pięciobajtowej postaci zmiennoprzecinkowej. |
Procedura pełnego mnożenia przygotowuje pierwszą liczbę przez wywołanie PREP-M/D, powrót następuje przy zerze; inaczej zostaje przygotowana druga liczba przez ponowne wywołanie PREP-M/D, a jesli wynikiem jest zero, to procedura przechodzi so ustawienia wyniku zero. Następnie pobiera te dwie liczby ze stosu kalkulatora i mnoży ich mantysy w normalny sposób, przesuwając w koło bity pierwszej liczby (traktowanej jako mnożnik) i dodając drugą liczbę (traktowaną jako mnożną) do wyniku, jeśli bit mnożnika jest ustawiony na 1. Następnie wykładniki zostają dodane do siebie i jest wykonywany test na nadmiar lub niedomiar (co da wynik zero). Na koniec wynik podlega normalizacji i wraca na stos kalkulatora z odpowiednim bitem znaku ustawionym w drugim bajcie.
XOR A A jest zerowane, aby bit znaku pierwszej liczby tu trafił. CALL 30C0,PREP-M/D Przygotuj pierwszą liczbę i wróć przy zerze. RET C (Wynik już jest zerem.) EXX Wymień rejestry. PUSH HL Zapamiętaj adres następnego literału. EXX Wymień rejestry. PUSH DE Zapamiętaj wskaźnik mnożnej. EX DE,HL Wymień wskaźniki ze sobą. CALL 30C0,PREP-M/D Przygotuj drugą liczbę. EX DE,HL Ponownie wymień wskaźniki. JR C,315D,ZERO-RSLT Skocz naprzód, jeśli druga liczba jest zerem. PUSH HL Zapamiętaj wskaźnik wyniku. CALL 2FBA,FETCH-TWO Pobierz te dwie liczby ze stosu. LD A,B M5 do A (zobacz na FETCH-TWO). AND A Przygotuj się do odejmowania. SBC HL,HL Zeruj HL w celu inicjalizacji wyniku. EXX Wymień rejestry. PUSH HL Zapamiętaj M1 i N1 (zobacz na FETCH-TWO). SBC HL,HL Również inicjalizuj H'L' na wynik. EXX Wymień rejestry. LD B,+21 B zliczy 33 przesunięcia. JR 3125,STRT-MLT Skocz naprzód do pętli. |
Teraz wejdź do pętli mnożnika.
3114 MLT-LOOP JR NC,311B,NO-ADD Skocz naprzód do NO-ADD, jeśli brak przeniesienia, tj. bit mnożnika miał stan zero. ADD HL,DE Inaczej dodaj mnożną w EXX D'E'DE (zobacz na FETCH-TWO) do ADC HL,DE wyniku tworzonego EXX w H'L'HL. 311B NO-ADD EXX Czy mnożna była dodana lub nie, RR H przesuń wynik w prawo RR L w H'L'HL, tj. przesunięcie jest wykonywane EXX przez obrót każdego bajtu z przeniesieniem, RR H aby każdy bit trafiający do przeniesienia został RR L umieszczony w następnym bajcie, a przesuwanie jest kontynuowane w B'C'CA. 3125 STRT-MLT EXX Przesuń w prawo mnożnik RR B w B'C'CA (zobacz na FETCH-TWO). RR C Ostatni bit wpadający do przeniesienia EXX wyzwoli kolejne dodanie RR C mnożnej do wyniku. RRA DJNZ 3114,MLT-LOOP Wykonaj 33 obiegi pętli dla wszystkich bitów. EX DE,HL Przenieś wynik z: EXX EX DE,HL H'L'HL do D'E'DE. EXX |
Teraz dodaj do siebie wykładniki.
POP BC Odtwórz wykładniki - M1 i N1. POP HL Odtwórz wskaźnik do bajtu wykładnika. LD A,B Sumę tych dwóch wykładników umieść ADD A,C w rejestrze A i popraw przeniesienie. JR NZ,313B,MAKE-EXPT Jeśli suma wynosi zero, to wyczyść przeniesienie; AND A inaczej pozostaw je bez zmian. 313B MAKE-EXPT DEC A Przygotuj się do zwiększenia CCF wykładnika o 80 szesnastkowo. |
Pozostała część procedury jest wspólna dla mnożenia i dzielenia.
313D DIVN-EXPT RLA Te kilka bajtów bardzo sprytnie tworzą CCF poprawny bajt wykładnika. RRA Obrócenie w lewo, a następnie w prawo daje bajt wykładnika (rzeczywisty wykładnik plus 80 szesnastkowo) w A. JP P,3146,OFLW1-CLR Jeśli znacznik znaku jest wyzerowany, to nie jest potrzebny raport o przepełnieniu arytmetycznym. JR NC,31AD,REPORT-6 Jeśli nie ma przeniesienia, zgłoś raport o przepełnieniu. AND A Teraz wyczyść przeniesienie. 3146 OFLW1-CLR INC A Bajt wykładnika jest już kompletny; JR NZ,3151,OFLW2-CLR jeśli jednak A wynosi zero, to potrzebny jest JR C,3151,OFLW2-CLR jeszcze jeden test na przepełnienie. EXX Jeśli nie ma przeniesienia i wynik BIT 7,D jest już w postaci znormalizowanej EXX (bit 7 D' ustawiony), to należy zgłosić raport JR NZ,31AD,REPORT-6 o przepełnieniu; lecz jeśli bit 7 rejestru D' jest wyzerowany, to wynik leży w zakresie. 3151 OFLW2-CLR LD (HL),A Na koniec zapisz bajt wykładnika. EXX Prześlij piaty bajt wyniku do A LD A,B na potrzeby normalizacji, EXX tj. nadmiar z L do B'. |
Pozostała część procedury zajmuje się normalizacją i jest wspólna dla wszystkich procedur arytmetycznych.
3155 TEST-NORM JR NC,316C,NORMALISE Bez przeniesienia normalizuj teraz. LD A,(HL) Inaczej zajmij się niedopełnieniem AND A (wynik zero) lub prawie niedopełnieniem 3159 NEAR-ZERO LD A,+80 (wynik 2**-128): JR Z,315E,SKIP-ZERO zwróć wykładnik do A, sprawdź, czy A 315D ZERO-RSLT XOR A zawiera zero (przypadek 2**-128), a jeśli tak, 315E SKIP-ZERO EXX utwórz 2**-128 przy normalnej liczbie AND D lub zero w przypadku przeciwnym. CALL 2FFB,ZEROS-4/5 Wykładnik musi zostać ustawiony RLCA na zero (przy zerze) lub 1 (przy 2**-128). LD (HL),A Odtwórz bajt wykładnika. JR C,3195,OFLOW-CLR Skocz w przypadku 2**-128. INC HL Inaczej umieść zero w drugim LD (HL),A bajcie wyniku na stosie kalkulatora. DEC HL JR 3195,OFLOW-CLR Skocz naprzód, aby przekazać ten wynik. |
Właściwa operacja normalizacji.
316C NORMALISE LD B,+20 Znormalizuj wynik przez co najwyżej 32
316E SHIFT-ONE EXX przesunięcia w lewo
BIT 7,D D'E'DE (z dołączonym A) aż
EXX bit 7 rejestru D' zostanie ustawiony. A zawiera zero
JR NZ,3186,NORML-NOW po dodawaniu, zatem nie następuje utrata lub
RLCA zwiększenie precyzji; A zawiera piąty
RL E bajt z B' po mnożeniu lub dzieleniu;
RL D lecz ponieważ tylko około
EXX 32 bity mogą być poprawne, precyzja
RL E nie jest tracona. Zauważ, że A jest
RL D obracany wokoło poprzez znacznik przeniesienia...
EXX co w końcu daje proces przypadkowy.
DEC (HL) Wykładnik jest zwiększany przy każdym przesunięciu.
JR Z,3159,NEAR-ZERO Jeśli wykładnik się wyzeruje, to liczby z okolic
2**-129 są zaokrąglane w górę do 2**-128.
DJNZ 316E,SHIFT-ONE Powtarzaj w pętli do 32 razy.
JR 315D,ZERO-RSLT Jeśli bit 7 nigdy nie osiąga stanu 1,
to cały wynik będzie ustawiony na zero. |
Zakończ normalizację uwzględniając 'przeniesienie'.
3186 NORML-NOW RLA Po normalizacji dodaj z powrotem
JR NC,3195,OFLW-CLR każde końcowe przeniesienie, które trafiło do A.
CALL 3004,ADD-BACK Skocz naprzód, jeśli przeniesienie nie
JR NZ,3195,OFLW-CLR propaguje się bezpośrednio wstecz.
EXX Jeśli miałoby się propagować bezpośrednio wstecz,
LD D,+80 to ustaw mantysę na 0.5
EXX i zwiększ wykładnik o 1.
INC (HL) To działanie może prowadzić do
JR Z,31AD,REPORT-6 nadmiaru arytmetycznego (końcowy przypadek). |
Końcowa część procedury powoduje umieszczenie wyniku w bajtach zarezerwowanych dla niego na stosie kalkulatora oraz zresetowanie wskaźników.
3195 OFLOW-CLR PUSH HL Zachowaj wskaźnik wyniku. INC HL Wskaż bajt znakowy w wyniku. EXX Wynik jest przenoszony z jego bieżących PUSH DE rejestrów D'E'DE do EXX BCDE; a następnie do ACDE. POP BC LD A,B Bit znakowy jest przenoszony z jego tymczasowego RLA miejsca na właściwą pozycję bitu 7 mantysy. RL (HL) RRA LD (HL),A Pierwszy bajt jest umieszczany w pamięci. INC HL Następny. LD (HL),C Drugi bajt jest umieszczany w pamięci. INC HL Następny. LD (HL),D Trzeci bajt jest umieszczany w pamięci. INC HL Następny. LD (HL),E Czwarty bajt jest umieszczany w pamięci. POP HL Odtwórz wskaźnik do wyniku. POP DE Odtwórz wskaźnik do drugiej liczby. EXX Wymień wskaźniki. POP HL Odtwórz adres następnego literału. EXX Wymień wskaźniki. RET Skończone. |
Raport 6 - Nadmiar arytmetyczny
31AD REPORT-6 RST 0008,ERROR-1 Wywołaj procedurę obsługi błędów. DEFB +05 |
(Indeks 05 - zobacz na CALCULATE pod 'division')
Ta procedura najpierw przygotowuje dzielnik przez wywołanie PREP-M/D, zgłaszając przepełnienie arytmetyczne, jeśli ma wartość zero, następnie przygotowuje dzielną przez ponowne wywołanie PREP-M/D, wracając, jeśli jest równa zero. Następnie pobiera dwie liczby ze stosu kalkulatora i dzieli ich mantysy metodą zwykłego dzielenia i próbnego odejmowania dzielnika od dzielnej z odtwarzaniem, jeśli wystąpi przeniesienie, inaczej dodając 1 do ilorazu. Maksymalna precyzja jest uzyskiwana przy dzieleniu 4-bajtowym, a po odjęciu wykładników procedura kończy działanie przez przejście do dalszej części procedury MNOŻENIA.
31AF division CALL 3293,RE-ST-TWO Użyj pełnych form zmiennoprzecinkowych. EX DE,HL Wymień wskaźniki. XOR A A jest zerowany, aby znak pierwszej liczby trafił do A. CALL 30C0,PREP-M/D Przygotuj dzielnik i zgłoś błąd JR C,31AD,REPORT-6 przepełnienia arytmetycznego, jeśli jest równy zero.. EX DE,HL Wymień wskaźniki. CALL 30C0,PREP-M/D Przygotuj dzielną i powróć, RET C jeśli jest równa zero (wtedy wynikiem też jest zero). EXX Wymień wskaźniki. PUSH HL Zapamiętaj adres następnego literału. EXX Wymień rejestry. PUSH DE Zapamiętaj wskaźnik dzielnika. PUSH HL Zapamiętaj wskaźnik dzielnej. CALL 2FBA,FETCH-TWO Pobierz te dwie liczby ze stosu. EXX Wymień rejestry. PUSH HL Zapamiętaj M1 i N1 na stosie maszynowym. LD H,B Kopiuj te cztery bajty dzielnej LD L,C z rejestrów B'C'CB EXX (tj. M2, M3, M4 i M5; zobacz na FETCH-TWO) LD H,C do rejestrów H'L'HL. LD L,B XOR A Wyzeruj A i znacznik przeniesienia. LD B,+DF B będzie zliczać do przodu od -33 do -1 w kodzie U2, szesnastkowo DF do FF, wykonując obieg przy minusie i jeszcze raz przy zerze dla dodatkowej precyzji. JR 31E2,DIV-START Skocz naprzód do pętli dzielenia dla pierwszego próbnego odejmowania. |
Teraz wejdź do pętli dzielenia.
31D2 DIV-LOOP RLA Przesuń wynik w lewo do B'C'CA, RL C przesuwając bity już tam obecne EXX i dodając 1 z przeniesienia, gdy jest RL C ustawione i obracając każdy bajt RL B przez przeniesienie, aby uzyskać EXX przesunięcie 32 bitowe. 31DB DIV-34TH ADD HL,HL To co zostanie z dzielnej przesuń EXX w lewo w H'L'HL przed następnym ADC HL,HL próbnym odejmowaniem; Jeśli bit wpadnie EXX do przeniesienia, wymuś brak odtworzenia i bit dla ilorazu, odzyskując JR C,31F2,SUBN-ONLY bit i pozwalając na pełny, 32-bitowy dzielnik. 31E2 DIV-START SBC HL,DE Próbny dzielnik do odejmowania w D'E'DE EXX od reszty dzielnej w H'L'HL; SBC HL,DE nie ma wstępnego przeniesienia EXX (zobacz na poprzedni krok). JR NC,31F9,NO-RSTORE Skocz naprzód, jeśli nie ma przeniesienia. ADD HL,DE Inaczej odtwórz, tj. dodaj z powrotem EXX dzielnik. Następnie wyczyść przeniesienie, ADC HL,DE aby nie było bitu dla ilorazu EXX (dzielnik 'nie przeszedł'). AND A JR 31FA,COUNT-ONE Skocz naprzód do licznika. 31F2 SUBN-ONLY AND A Po prosu odejmij bez odtwarzania SBC HL,DE i idź do ustawienia znacznika przeniesienia, EXX ponieważ utracony bit dzielnej ma SBC HL,DE zostać odtworzony i użyty w ilorazie. EXX 31F9 NO-RSTORE SCF Jedynka dla ilorazu w B'C'CA. 31FA COUNT-ONE INC B Zwiększ licznik pętli o jeden. JP M,31D2,DIV-LOOP 32 obiegi pętli dla wszystkich bitów. PUSH AF Zapamiętaj każdy 33 bit dla dodatkowej precyzji (obecne przeniesienie). JR Z,31E2,DIV-START Jeszcze jedno próbne odejmowanie dla 34 bitu; powyższy rozkaz PUSH AF zapamiętuje również ten bit. |
Uwaga: ten skok wykonywany jest w złe miejsce. Żaden 34 bit nie zostanie osiągnięty bez wcześniejszego przesunięcia bitów dzielnej. Stąd ważne wyniki, jak 1/10 i 1/1000, nie są zaokrąglane tak dobrze, jak powinny być. Zaokrąglenie nigdy nie występuje, jeśli zależy od 34 bitu. Skok powinien być do 31DB DIV-34TH: tj. do bajt o adresie 3200 w ROM powinien mieć wartość DA szesnastkowo (128 dziesiętnie) zamiast E1 szesnastkowo (225 dziesiętnie).
LD E,A Teraz przenieś cztery bajty, które LD D,C tworzą mantysę wyniku z B'C'CA do D'E'DE. EXX LD E,C LD D,B POP AF Następnie wstaw bity 34 i 33 RR B do B', aby zostały wybrane przy normalizacji. POP AF RR B EXX POP BC Odtwórz bajty wykładników, M1 i N1. POP HL Odtwórz wskaźnik do wyniku. LD A,B Oblicz w A różnicę wykładników SUB C i ustaw przeniesienie w razie potrzeby. JP 313D,DIVN-EXPT Wyjdź poprzez DIVN-EXPT. |
(Indeks 3A - zobacz na CALCULATE pod 'truncate')
Ta procedura dokonuje zaokrąglenia wartości 'ostatniej wartości' na stosie kalkulatora, powiedzmy l(x), do liczby całkowitej w kierunku zera. W ten sposób 2,4 staje się 2, a -2,4 -2. Procedura kończy natychmiast, jeśli argument ma postać 'krótkiej liczby całkowitej'. Zwraca zero, jeśli bajt wykładnika jest mniejszy od 81 szesnastkowo (ABS x daje zero). Liczba na stosie nie jest również zmieniana, jeśli jej bajt wykładnika jest większy lub równy A0 szesnastkowo (liczba nie posiada znaczącej części ułamkowej). W przeciwnym razie właściwa ilość bajtów liczby jest ustawiana na zero i, jeśli jest to konieczne, bity w jednym z bajtów są zerowane za pomocą maski.
3214 truncate LD A,(HL) Pobierz bajt wykładnika liczby X do A. AND A Jeśli A wynosi zero, wróć, ponieważ RET Z liczba jest małą liczbą całkowitą. CP +81 Porównaj wykładnik z 81 szesnastkowo. JR NC,3221,T-GR-ZERO Skocz, jeśli jest większy od 80 szesnastkowo. LD (HL),+00 Inaczej ustaw wykładnik na zero; LD A,+20 Do A wprowadź 32 dziesiętnie, 20 szesnastkowo JR 3272,NIL-BYTES i skocz do NIL-BYTES, aby wyzerować wszystkie bity x. 3221 T-GR-ZERO CP +91 Porównaj wykładnik z 91 szesnastkowo, 145 dziesiętnie. 3223 JR NZ,323F,T-SMALL Skocz, jeśli nie jest równy 91 szesnastkowo. |
Kolejne 26 bajtów wydają się być zaprojektowane do sprawdzania, czy x w rzeczywistości jest równe -65536 dziesiętnie, tj. 91 80 00 00 00, a jeśli jest, do ustawienia go na 00 FF 00 00 00. To błąd. Jak już stwierdzono przy bajcie 303B powyżej, system Spectrum nie potrafi poradzić sobie z tą liczbą. Wynikiem tutaj będzie zwrócenie INT(-65536) jako wartości -1. Szkoda, ponieważ liczba byłaby zupełnie poprawna, gdyby zostawiono ją w spokoju. Lekarstwem byłoby po prostu pominąć te 28 bajtów od adresu 3223 do 323E włącznie (niektóre emulatory ZX Spectrum pozwalają na użycie poprawionej wersji ROM, jednakże wtedy spada kompatybilność z rzeczywistym komputerem).
3225 INC HL HL zostaje ustawione na czwarty bajt x, INC HL gdzie kończy się 17 bitowa część INC HL całkowita x po pierwszym bajcie. LD A,+80 Pierwszy bajt jest otrzymywany w A, AND (HL) używając 80 szesnastkowo jako maski. DEC HL Ten bit oraz poprzednie 8 bitów OR (HL) są testowane na zero. DEC HL HL jest ustawiane na drugi bajt liczby x. JR NZ,3233,T-FIRST Jeśli już różne od zera, test może się zakończyć. LD A,+80 Inaczej test na -65536 jest teraz kończony: XOR (HL) 91 80 00 00 00 pozostawi ustawiony znacznik zera. 3233 T-FIRST DEC HL HL jest ustawiane na pierwszy bajt x. JR NZ,326C,T-EXPNENT Jeśli znacznik zera wyzerowany, zostaje wykonany skok. LD (HL),A Pierwszy bajt jest zerowany. INC HL HL wskazuje drugi bajt. LD (HL),+FF Drugi bajt jest ustawiany na FF. DEC HL HL ponownie wskazuje pierwszy bajt. LD A,+18 Końcowe 24 bity są zerowane. JR 3272,NIL-BYTES Skok do NIL-BYTES kończy ustawianie liczby 00 FF 00 00 00. |
Jeśli bajt wykładnika liczby x zawiera się pomiędzy 81 a 90 szesnastkowo (129 a 144 dziesiętnie) włącznie, to I(x) jest 'małą liczbą całkowitą', i zostanie skompresowane do jednego lub do dwóch bajtów. Lecz najpierw wykonywany jest test, czy x nie jest jednak duże.
323F T-SMALL JR NC,326D,X-LARGE Skocz z bajtem wykładnika 92 lub więcej (lepiej byłoby skoczyć również z 91). PUSH DE Zapamiętaj STKEND z DE. CPL Zakres 129 <= A <= 144 staje się 126 >= A >= 111. ADD A,+91 Zakres teraz wynosi 15 dziesiętnie >= A >= 0. INC HL Ustaw HL na drugi bajt. LD D,(HL) Drugi bajt do D. INC HL Ustaw HL na trzeci bajt. LD E,(HL) Trzeci bajt do E. DEC HL Ponownie ustaw HL na pierwszy bajt. DEC HL LD C,+00 Załóż liczbę dodatnią. BIT 7,D Teraz test na ujemną (ustawiony bit 7). JR Z,3252,T-NUMERIC Skocz, jeśli jest jednak dodatnia. DEC C Zmień znak. 3252 T-NUMERIC SET 7,D Wstaw prawdziwy bit numeryczny, 1, do D. LD B,+08 Teraz sprawdź, czy A >= 8 (tylko jeden bajt) SUB B lub potrzebne dwa bajty. ADD A,B Pozostaw A niezmienione. JR C,325E,T-TEST Skocz, jeśli potrzebne są dwa bajty. LD E,D Umieść ten jeden bajt w E. LD D,+00 I ustaw D na zero. SUB B Teraz 1 <= A <= 7, aby zliczyć potrzebne przesuwy. 325E T-TEST JR Z,3267,T-STORE Skocz, jeśli nie są potrzebne przesuwy. LD B,A B będzie zliczać przesuwy. 3261 T-SHIFT SRL D Przesuń D i E w prawo B razy, RR E aby utworzyć poprawną liczbę. DJNZ 3261,T-SHIFT Powtarzaj w pętli aż B się wyzeruje. 3267 T-STORE CALL 2D8E,INT-STORE Umieść wynik na stosie. POP DE Odtwórz STKEND w DE. RET Skończone. |
Pozostały do obsłużenia duże wartości x.
326C T-EXPNENT LD A,(HL) Pobierz bajt wykładnika liczby x do A. 326D X-LARGE SUB +A0 Odejmij od niego 160 dziesiętnie, A0 szesnastkowo. RET P Wróć przy wartości dodatniej - x nie posiada znaczącej części ułamkowej. (Gdyby rzeczywisty wykładnik sprowadzić do zera, to 'dwójkowy przecinek' wypadłby poza końcem czwartego bajtu mantysy). NEG Inaczej zaneguj resztę; daje to liczbę bitów, które muszą zostać wyzerowane (czyli liczbę bitów po 'przecinku dwójkowym'). |
Teraz bity mantysy mogą zostać wyzerowane.
3272 NIL-BYTES PUSH DE Zapamiętaj bieżącą wartość DE (STKEND).
EX DE,HL Ustaw HL na adres za piątym bajtem.
DEC HL HL teraz wskazuje na piaty bajt liczby x.
LD B,A Pobierz do B liczbę bitów do wyzerowania
SRL B i podziel ją przez 8, aby otrzymać liczbę
SRL B pełnych bajtów.
SRL B
JR Z,3283,BITS-ZERO Skocz naprzód, jeśli wynikiem jest zero.
327E BYTE-ZERO LD (HL),+00 Inaczej ustaw te bajty na zero;
DEC HL B je zlicza.
DJNZ 327E,BYTE-ZERO
3283 BITS-ZERO AND +07 Pobierz A (mod 8); jest to liczba bitów
wciąż do ustawienia na zero.
JR Z,3290,IX-END Skocz na koniec, jeśli nie ma nic więcej do zrobienia.
LD B,A B będzie teraz zliczać te bity.
LD A,+FF Przygotuj maskę.
328A LESS-MASK SLA A Przy każdym obiegu do maski jest wstawiane zero
DJNZ 328A,LESS-MASK od strony prawej, co tworzy maskę o właściwej długości.
AND (HL) Niechciane bity są zerowane po wykonaniu na nich
LD (HL),A operacji z maską.
3290 IX-END EX DE,HL Przywróć wskaźnik w HL.
POP DE Przywróć STKEND w DE.
RET Skończone. |
Ta procedura jest wykonywana do ponownego wstawienia na stos dwóch 'małych liczb całkowitych' w pełnej, pięciobajtowej postaci zmiennoprzecinkowej przy operacjach dodawania, mnożenia i dzielenia. Wykonuje to przez dwukrotne wywołanie kolejnej procedury.
3293 RE-ST-TWO CALL 3296,RESTK-SUB Wywołaj procedurę, a następnie przejdź do niej jako drugie wywołanie. 3296 RESTK-SUB EX DE,HL Wymień wskaźniki przy każdym wywołaniu. |
(Indeks 3D - zobacz na CALCULATE pod 're-stack')
Ta procedura jest wywoływana, aby ponownie umieścić na stosie jedną liczbę (która może być 'małą liczbą całkowitą') w pełnej, pięciobajtowej postaci zmiennoprzecinkowej. Jest używana przy pojedynczej liczbie przez ARCTAN i również przez EXP, LN oraz 'get-argt'.
3297 RE-STACK LD A,(HL) Jeśli pierwszy bajt nie jest zerem, powróć AND A ponieważ liczba nie może być 'małą liczbą całkowitą'. RET NZ PUSH DE Zachowaj 'drugi' wskaźnik z DE. CALL 2D7F,INT-FETCH Pobierz znak do C, a liczbę do DE. XOR A Wyzeruj rejestr A. INC HL Wskaż piątą pozycję. LD (HL),A Ustaw piaty bajt na zero. DEC HL Wskaż czwartą pozycję. LD (HL),A Ustaw czwarty bajt na zero: bajty 2 i 3 będą przechowywały mantysę. LD B,+91 Ustaw B na 145 dziesiętnie dla wykładnika, tj. do 16 bitów w liczbie całkowitej. LD A,D Sprawdź, czy D jest zerem, co da co najwyżej AND A 8 potrzebnych bitów. JR NZ,32B1,RS-NRMLSE Skocz, jeśli potrzeba więcej niż 8 bitów. OR E Teraz sprawdź również E. LD B,D Zachowaj zero w B (da zerowy wykładnik, jeśli E jest również równe zero). JR Z,32BD,RS-STORE Skocz, jeśli E jest faktycznie zerem. LD D,E Przenieś E do D (D było zerem, a E nie). LD E,B Teraz ustaw E na zero. LD B,+89 Ustaw B na 137 dziesiętnie dla wykładnika - teraz jest nie więcej niż 8 bitów. 32B1 RS-NRMLSE EX DE,HL Wskaźnik do DE, liczba do HL. 32B2 RSTK-LOOP DEC B Zmniejszaj wykładnik przy każdym przesunięciu. ADD HL,HL Przesuń liczbę o jedną pozycję w lewo. JR NC,32B2,RSTK-LOOP Aż zostanie ustawiony znacznik przeniesienia. RRC C Teraz przenieś do znacznika przeniesienia bit znaku. RR H Wstaw go na miejsce po przesunięciu liczby RR L o jedną pozycję w prawo. EX DE,HL Wskaźnik bajtu 4 z powrotem do HL. 32BD RS-STORE DEC HL Wskaż trzeci bajt. LD (HL),E Zapisz trzeci bajt. DEC HL Wskaż drugi bajt. LD (HL),D Zapisz drugi bajt. DEC HL Wskaż pierwszy bajt. LD (HL),B Zapisz bajt wykładnika. POP DE Odtwórz 'drugi' wskaźnik w DE. RET Skończone |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.