; =====================================================================
; Listing Asemblerowy Systemu Operacyjnego w pamięci ROM komputera ZX81
; =====================================================================

; ----------------------------------------
; Data ostatniej aktualizacji: 13-LIS-2011
; ----------------------------------------

; Ten plik można poddać asemblacji bezpośrednio w TASM'e, który jest darmowo dostępny w sieci Internet. Można dokonywać w nim
; zmian w celu uzyskania nowych funkcji, np. w symulatorze ZX81, lecz miejsca na takie modyfikacje jest bardzo mało. To właśnie
; brak miejsca w 8KB pamięci ROM wymusił na programistach oszczędności, które niejednokrotnie zwalniają i tak już wolnego ZX-81.

; Dokumentacja nie jest kompletna i w miarę możliwości, a przede wszystkim czasu, będzie stopniowo rozbudowywana. Zawarte tutaj
; procedury są doskonałym przykładem technik programowania mikroprocesora Z80 i mogą być bardzo cennym źródłem wiedzy o tym układzie.

; Ze swej strony zmodyfikowałem plik dostępny w wersji angielskiej w Internecie, tak aby zastąpić etykiety adresowe etykietami
; słownymi. W tym celu został napisany prosty program w C++, który przeglądnął plik źródłowy, zapamiętał wszystkie etykiety,
; a następnie odpowiednio przekonwertował go na postać HTML, dodając hiperłącza, które umożliwiają szybkie poruszanie się po
; całym listingu. Zamieniłem również odwołania adresowe do zmiennych systemowych na ich nazwy mnemotechniczne. Sądzę, iż dzięki
; tym zabiegom kod stał się bardziej czytelny. Adresy etykiet są zawsze wypisane w komentarzu bezpośrednio nad nazwą etykiety
; w kodzie szesnastkowym i dziesiętnym.

;*************************************
;** Definicje zmiennych systemowych **
;*************************************

ERR_NR     .EQU $4000             ; $4000 : 16384
FLAGS      .EQU $4001             ; $4001 : 16385
ERR_SP     .EQU $4002             ; $4002 : 16386
RAMTOP     .EQU $4004             ; $4004 : 16388
MODE       .EQU $4006             ; $4006 : 16390
PPC        .EQU $4007             ; $4007 : 16391
VERSN      .EQU $4009             ; $4009 : 16393
E_PPC      .EQU $400A             ; $400A : 16394
D_FILE     .EQU $400C             ; $400C : 16396
DF_CC      .EQU $400E             ; $400E : 16398
VARS       .EQU $4010             ; $4010 : 16400
DEST       .EQU $4012             ; $4012 : 16402
E_LINE     .EQU $4014             ; $4014 : 16404
CH_ADD     .EQU $4016             ; $4016 : 16406
X_PTR      .EQU $4018             ; $4018 : 16408
STKBOT     .EQU $401A             ; $401A : 16410
STKEND     .EQU $401C             ; $401C : 16412
BREG       .EQU $401E             ; $401E : 16414
MEM        .EQU $401F             ; $401F : 16415
UNUSED1    .EQU $4020             ; $4020 : 16416
UNUSED2    .EQU $4021             ; $4021 : 16417
DF_SZ      .EQU $4022             ; $4022 : 16418
S_TOP      .EQU $4023             ; $4023 : 16419
LAST_K     .EQU $4025             ; $4025 : 16421
DBOUNC     .EQU $4027             ; $4027 : 16423
MARGIN     .EQU $4028             ; $4028 : 16424
NXTLIN     .EQU $4029             ; $4029 : 16425
OLDPPC     .EQU $402B             ; $402B : 16427
FLAGX      .EQU $402D             ; $402D : 16429
STRLEN     .EQU $402E             ; $402E : 16430
T_ADDR     .EQU $4030             ; $4030 : 16432
SEED       .EQU $4032             ; $4032 : 16434
FRAMES     .EQU $4034             ; $4034 : 16436
COORDS     .EQU $4036             ; $4036 : 16438
PR_CC      .EQU $4038             ; $4038 : 16440
S_POSN     .EQU $4039             ; $4039 : 16441
CDFLAG     .EQU $403B             ; $403B : 16443
PRBUFF     .EQU $403C             ; $403C : 16444
MEMBOT     .EQU $405D             ; $405D : 16477

;**********************************************
;** Część 1. PROCEDURY RESTARTU ORAZ TABLICE **
;**********************************************

; --------------------------------
; PUNKT WEJŚCIA DLA STARTU SYSTEMU
; --------------------------------
; Wszystkie mikroprocesory Z80 rozpoczynają wykonywanie programu asemblerowego od adresu 0. Przy starcie systemu ustawiony jest
; Tryb Przerwań 0, komputery ZX korzystają z Trybu Przerwań 1. Przerwania są wyłączone.

; $0000 : 0
START:    OUT  ($FD),A            ; wyłącz generator przerwań niemaskowanych, jeśli ten ROM pracuje na sprzęcie ZX81.
                                  ; Jeśli sprzętem jest wcześniejszy ZX80, to operacja nie wywołuje żadnego efektu.
          LD   BC,$7FFF           ; Ustaw BC na szczyt możliwej pamięci RAM. ZX81 może wykonywać kod maszynowy tylko
                                  ; poniżej adresu $8000, ponieważ wyższe adresy są wykorzystywane do sprzętowo-programowej
                                  ; obsługi obrazu telewizyjnego. Jeśli komputer ma więcej pamięci, to można ją wykorzystywać
                                  ; do przechowywania danych - jednakże bufor wyświetlania musi być poniżej $8000.
          JP   RAM_CHECK

; -----------------------
; PUNKT WEJŚCIA DLA BŁĘDU
; -----------------------
; Punkt wejścia natychmiastowej obsługi błędu. Komputery ZX wykonują ten sam kod maszynowy zarówno w trakcie interpretacji programu
; w języku BASIC, jak i podczas sprawdzania składni. Jeśli błąd powstał w trakcie pracy programu, tworzony jest krótki komunikat.
; Jeśli błąd powstał przy wprowadzania wiersza programu w języku BASIC lub przy wprowadzaniu danych itd., to znacznik błędu wskazuje
; dokładne położenie błędu.

; $0008 : 8
ERROR_1:  LD   HL,(CH_ADD)        ; pobierz adres znaku z CH_ADD
          LD   (X_PTR),HL         ; i ustaw wskaźnik błędu X_PTR.

          JR   ERROR_2            ; przeskocz do przodu, aby kontynuować w ERROR-2.

; -------------------------------------------------
; PUNKT WEJŚCIA DLA DRUKOWANIA ZNAKU W AKUMULATORZE
; -------------------------------------------------
; Drukowany jest znak w akumulatorze przy użyciu zapasowego zestawu rejestrów, zatem nie ma potrzeby zachowywania głównych rejestrów
; mikroprocesora.

; $0010 : 16
PRINT_A:  AND  A                  ; test zera, czyli spacji

          JP   NZ,PRINT_CH        ; jeśli jest to znak różny od spacji, to drukujemy go w PRINT_CH.

          JP   PRINT_SP           ; a spację drukujemy w PRINT_SP.

         .BYTE $FF                ; nieużywane

; ----------------------------------
; PUNKT WEJŚCIA DLA POBIERANIA ZNAKU
; ----------------------------------
; Pobrany zostaje znak adresowany zmienną systemową CH_ADD i jeśli jest on różny od spacji, to zostaje zwrócony. W przeciwnym razie
; zmienna CH_ADD jest zwiększana i pobrany zostanie kolejny znak aż do natrafienia na znak różny od spacji

; $0018 : 24
GET_CHAR: LD   HL,(CH_ADD)        ; pobieramy adres znaku do pary rejestrów HL
          LD   A,(HL)             ; pobieramy do A znak o adresie z CH_ADD

; $001C : 28
TEST_SP:  AND  A                  ; sprawdzamy, czy jest spacją

          RET  NZ                 ; jeśli nie, to wracamy ze znakiem w A

          NOP                     ; inaczej przechodzimy do następnej procedury - dwie instrukcje NOP wykonane
          NOP                     ; zostają w 8 taktach

; ------------------------------------------
; PUNKT WEJŚCIA DLA POBRANIA KOLEJNEGO ZNAKU
; ------------------------------------------
; Adres znaku CH_ADD zostaje zwiększony o 1 i pobierany jest kolejny znak, który będzie zwrócony, jeśli nie jest spacją lub kursorem.
; W przeciwnym razie proces jest powtarzany.

; $0020 : 32
NEXT_CHAR: CALL CH_ADD_1          ; zwiększ CH_ADD i pobierz kolejny znak

          JR   TEST_SP            ; ponownie dokonaj testu na spację

         .BYTE $FF, $FF, $FF      ; nieużywane

; --------------------------------------------------
; PUNKT WEJŚCIA DLA KALKULATORA ZMIENNOPRZECINKOWEGO
; --------------------------------------------------
; Następuje skok do rekurencyjnej procedury kalkulatora zmiennoprzecinkowego, który jest sterowany wewnętrznym językiem podobnym do
; FORTH'a i opartym na stosie. Za wywołaniem RST 28H następuje ciąg kodów bajtowych, które są poleceniami w języku kalkulatora.
; Kalkulator jest wykorzystywany do wyliczania wartości wszystkich funkcji arytmetycznych języka ZX81 BASIC.

; W pięciu pozostałych bajtach umieszczono procedurę obsługi rozkazu kalkulatora END_CALC, który kończy wykonywanie poleceń kalkulatora.

; $0028 : 40
FP_CALC:  JP   CALCULATE          ; skocz bezpośrednio do procedury obsługi kalkulatora

; $002B : 43
END_CALC: POP  AF                 ; usuń ze stosu adres powrotu do kalkulatora
          EXX                     ; przełącz się na zapasowy zestaw rejestrów
          EX   (SP),HL            ; jako adres powrotu wykorzystaj wskaźnik programu kalkulatora w HL'. Przy zakończeniu rekurencji poprzedni
                                  ; wskaźnik jest umieszczany w HL'
          EXX                     ; przełącz na podstawowy zestaw rejestrów

          RET                     ; powróć z obliczeń w kalkulatorze do programu

; ---------------------------------
; PUNKT WEJŚCIA TWORZENIA BC SPACJI
; ---------------------------------
; Wejście to wykorzystywane jest osiem razy do tworzenia w obszarze roboczym odpowiedniej liczby spacji, których liczba przekazywana
; jest w parze rejestrów BC.

; $0030 : 48
BC_SPACES: PUSH BC                ; umieść liczbę spacji na stosie
          LD   HL,(E_LINE)        ; pobierz do HL adres obszaru wiersza edycji ze zmiennej systemowej E_LINE
          PUSH HL                 ; zachowaj ten adres na stosie

          JP   RESERVE            ; kontynuuj w procedurze RESERVE.

; --------------------------
; PUNKT WEJŚCIA DLA PRZERWAŃ
; --------------------------

; Procedura obsługi przerwania w trybie 1 zajmuje się całkowicie tworzeniem obrazu telewizyjnego. Na ZX81 przerwania maskowane są
; włączone tylko w czasie wykonywania procedury obsługującej je. Ta procedura obsługi przerwań automatycznie wyłącza przerwania
; na samym początku i ostatnie przerwanie w kolejce kończy się zanim obsługa przerwań ponownie zostanie włączona. W pamięci ROM ZX81
; nie znajdziesz instrukcji DI wyłączającej obsługę przerwań maskowanych. Przerwanie maskowane jest wyzwalane, gdy bit 6 rejestru
; odświeżania mikroprocesora Z80 zmienia się ; z jedynki na 0. Dzieje się tak dlatego, iż linia adresowa A6 jest połączona z
; wejściem INT.  W trakcie cyklu odświeżania na liniach adresowych A0-A8 umieszczana jest zawartość rejestru R. Z kolei mikroprocesor Z80
; testuje linię INT przy ostatnim cyklu wykonania instrukcji, gdy trwa jeszcze cykl odświeżania.

; Z80 zawsze będzie wykonywał instrukcję HALT (NEWLINE), gdy zdarzy się przerwanie. Instrukcja HALT w kółko wykonuje instrukcje NOP,
; lecz przy każdej z nich zawartość rejestru R jest zwiększana, podobnie jak przy każdej prostej instrukcji (młodsze 7 bitów jest
; zwiększane dwukrotnie dla instrukcji z przedrostkiem). Proces ten jest kontrolowany przez układ ULA - Sinclair Computer Logic Chip -
; wyprodukowany w firmie:
; Ferranti - ULA = Uncommitted Logic Array.

; Gdy wystąpi przerwanie w trybie 1 rejestr licznika rozkazów PC, który adresuje instrukcję za rozkazem NEWLINE/HALT w górnej połówce
; pamięci powyżej 32K, zostanie umieszczony na stosie maszynowym. Potrzebne są 193 przerwania do utworzenia końca 56-tej linii górnego
; marginesu oraz ; 192 linii środkowego obrazu TV, a chociaż każde przerwanie przerywa obsługę poprzedniego, nie wystąpi problem
; z rozrostem stosu maszynowego, ponieważ za każdym razem adresy powrotne są z niego usuwane.

; Licznik linii skanujących w rejestrze C zlicza w dół od 8 do 1 w czasie tworzenia każdego wiersza tekstu. Dla ostatniej linii
; marginesu górnego licznik w C jest ustawiany na 1.

; Czas wykonania kodu ma podstawowe znaczenie, ponieważ prawy margines, powrót strumienia elektronów oraz lewy margines zajmuje
; dokładnie 58 taktów zegara i przez tyle taktów wykonuje się ta procedura.

; $0038 : 56
INTERRUPT: DEC  C                 ; (4)     zmniejsz licznik linii skanujących w rejestrze C.

          JP   NZ,SCAN_LINE       ; (10/10) jeśli C różne od 0, skocz naprzód do SCAN_LINE

          POP  HL                 ; (10)    ustaw adres początku następnego wiersza w buforze wyświetlania 
          DEC  B                  ; (4)     zmniejsz licznik wierszy

          RET  Z                  ; (11/5)  gdy obrazek jest skończony, powróć do L028B z wyłączonymi przerwaniami.

          SET  3,C                ; (8)     załaduj licznik linii skanujących wartością 8.
                                  ; Uwaga: LD C,$8 ma 7 taktów zegara, co jest zbyt mało 
; $0041 : 65
WAIT_INT: LD   R,A                ; (9)     załaduj R początkową wartością $DD, która będzie zwiększana przy każdej instrukcji
          EI                      ; (4)     włącz obsługę przerwań. [ R ma teraz wartość $DE ].

          JP   (HL)               ; (4)     skocz do echa bufora wyświetlania w górnej połówce pamięci i wykonaj kody znaków  $00 - $3F 
                                  ;         jako instrukcje NOP. Układ wideo w ZX81 potrafi odczytać te znaki i przy pomocy rejestru I umie 
                                  ;         zamienić matryce znaków z ROM na wiersze bajtów. Na końcu każdego wiersza zostanie napotkany 
                                  ;         kod NEWLINE/HALT zanim rejestr R zliczy do $FF. Jednakże to przejście z $FF na $80 wyzwala 
                                  ;         następne przerwanie. [R ma teraz wartość $DF]
; $0045 : 69
SCAN_LINE: POP  DE                ; (10)    usuń adres za NEWLINE, ponieważ ten sam wiersz tekstu musi być "wykonany" 8 razy

          RET  Z                  ; (5)     opóźnienie - instrukcja nigdy nie powoduje powrotu, ponieważ warunek jest zawsze fałszywy

          JR   WAIT_INT           ; (12)    z powrotem do WAIT_INT

; Uwaga. W komputerze z pamięcią mniejszą niż 4K RAM bufor wyświetlania będzie zwinięty, a powyższy mechanizm obsługuje zarówno pełny
; jak i zwinięty bufor. Przy pełnym buforze 32 znaki w wierszu jest traktowane jako instrukcje NOP, a rejestr odświeżania R zwiększy
; zawartość z $E0 (pierwszy znak) do $FF (ostatni znak) i przy następnej instrukcji HALT wystąpi przerwanie (R zmieni stan na $80).
; Przy zwiniętym buforze wyświetlania wykonywanie kodów zatrzyma się na instrukcji HALT, która cyklicznie rozpocznie wykonywanie NOP.
; Rejestr R będzie zwiększany, aż do osiągnięcia $FF, a następnie $80, co wyzwoli przerwanie. Działa to bezbłędnie dla wszystkich wierszy
; ekranu, które zawierają od 0 do 32 znaków zakończonych kodem NEWLINE/HALT. Jedna linia obrazu zajmuje zawsze 128 cykli zegara.

; ------------------------------
; PROCEDURA ZWIĘKSZANIA CH_ADD
; ------------------------------
; Procedura zwiększa zmienną systemową CH_ADD i kończy działanie, jeśli pod nowym adresem (CH_ADD) nie znajduje się znak kursora.
; W przeciwnym  razie pobiera znak za kursorem. ZX81 umieszcza na pozycji kursora prawdziwy znak kursora - w przeciwieństwie do poprzedników
; i następców ZX81, gdzie stosowano jedynie wskaźnik.
; Na wyjściu mamy:
; A  - pobrany znak
; HL - adres znaku

; $0049 : 73
CH_ADD_1: LD   HL,(CH_ADD)        ; pobierz zawartość zmiennej systemowej CH_ADD

; $004C : 76
TEMP_PTR1: INC  HL                ; zaadresuj następną pozycję

; $004D : 77
TEMP_PTR2: LD   (CH_ADD),HL       ; uaktualnij zmienną systemową CH_ADD
          LD    A,(HL)            ; pobierz znak z nowej pozycji
          CP $7F                  ; sprawdź, czy jest to znak kursora

          RET   NZ                ; jeśli nie, powróć z procedury

          JR    TEMP_PTR1         ; cofnij się do TEMP_PTR1, aby pobrać następny znak

; ---------------------
; KONTYNUACJA 'ERROR_2'
; ---------------------
; Jest to kontynuacja punktu wejścia dla błędów ERROR_1. Jeśli błąd wystąpił w czasie wykonywania programu, to na stosie będzie odłożony
; adres numeru błędu, który należy  wyświetlić, chyba że błąd wystąpił w trakcie wprowadzania danych. Jeśli błąd powstał w czasie
; sprawdzania składni, to na stosie będzie adres procedury edycji, a pozycja błędu pojawi się po ponownym wydruku zawartości spodu ekranu.

; $0056 : 86
ERROR_2:  POP  HL                 ; pobierz ze stosu adres powrotu, który wskazuje na bajt z kodem błędu, umieszczony tuż za rozkazem RST 08H.
          LD   L,(HL)             ; pobierz kod błędu do L. HL nie jest już potrzebne

; $0058 : 88
ERROR_3:  LD   (IY+$00),L         ; umieść kod błędu w zmiennej systemowej ERR_NR
          LD   SP,(ERR_SP)        ; ustaw stos ze zmiennej ERR_SP

          CALL SLOW_FAST          ; wybierz tryb SLOW.

          JP   SET_MIN            ; wyjdź do adresu na stosie poprzez procedurę SET_MIN.

         .BYTE $FF                ; nieużywane

; ------------------------------------------
; PROCEDURA OBSŁUGI PRZERWAŃ NIE MASKOWANYCH
; ------------------------------------------
; Techniczna sztuczka Jima Westwooda z wykorzystaniem przerwań niemaskowanych rozwiązała problem migania obrazu nękający użytkowników
; modelu ZX80, a dla komputera ZX81 podarowała tryb SLOW z jednoczesnymi obliczeniami oraz wyświetlaniem obrazu. Zwróć uwagę, iż dla tej
; funkcji oraz współdziałania w tworzeniu obrazu zarezerwowana została para rejestrów AF'. Przy zliczaniu linii obrazu telewizyjnego NMI
; nie wykorzystuje głównych rejestrów. Obwód elektroniczny dla generatora NMI jest zawarty wewnątrz układu ULA. Zliczanie w kierunku zera
; zajmuje jej 32 takty zegarowe. 

; $0066 : 102
NMI:      EX   AF,AF'             ; (4)     przełącz się na kopię akumulatora dla procedury NMI
          INC  A                  ; (4)     zwiększ zawartość licznika linii o 1

          JP   M,NMI_RET          ; (10/10) jeśli wynik ujemny w kodzie U2, to skocz do NMI_RET, ponieważ będzie to część testu
                                  ;         sprawdzającego, czy generacja NMI pracuje lub wartość pośrednia dla licznika pustych linii,
                                  ;         zliczającego w przód na wartościach zanegowanych.
          JR   Z,NMI_CONT         ; (12)    naprzód do NMI_CONT, gdy licznik przekręcił się na 0

; Uwaga. Synchronizowanie NMI, gdy A zwiększane jest z zera na jeden zajmuje 7 taktów zegara dając w sumie 32 + 7 = 39 taktów na obieg
; procedury.

; $006D : 109
NMI_RET:  EX  AF,AF'              ; (4)  przełącz z licznika linii lub wyniku testu $80 na zwykły A

          RET                     ; (10) powróć na chwilę do aplikacji użytkownika.

; To odgałęzienie jest wykonywane, gdy narysowana została 55 (lub 31) linia marginesu.

; $006F : 111
NMI_CONT: EX   AF,AF'             ; (4)  przywróć główny akumulator.
          PUSH AF                 ; (11) zapisz główne rejestru na stosie.
          PUSH BC                 ; (11)
          PUSH DE                 ; (11)
          PUSH HL                 ; (11)

; następna procedura ustawiająca jest faktycznie potrzebna tylko po wygenerowaniu górnego zbioru pustych linii marginesu

          LD   HL,(D_FILE)        ; (16) pobierz adres startu bufora obrazu ze zmiennej D_FILE wskazujący instrukcję
                                  ;      NEWLINE/HALT umieszczoną na początku.
          SET  7,H                ;  (8) przelicz adres na echo bufora w górnej połówce pamięci ponad 32K

          HALT                    ;  (1) HALT synchronizuje z NMI. Używa się go ze specjalnym obwodem połączonym
                                  ;      z liniami HALT i WAIT mikroprocesora Z80 w celu wstrzymania na 1 takt zegara.

; ----------------------------------------------------------------------------
; Przerwanie NMI zostało wygenerowane - zaczynamy zliczanie. Strumień elektronów jest przy prawej krawędzi ekranu telewizyjnego.
; Najpierw obsługa NMI, podobna do instrukcji CALL    =  17 taktów zegara.
; Teraz czas zużyty przez NMI na ścieżkę zero-jeden   =  39 taktów.
; Powyższa instrukcja HALT                            =   1 takt.
; Dwie instrukcje poniżej                             =  19 taktów.
; Kod pod adresem 281H do instrukcji CALL włącznie    =  43 takty.
; Wywołana procedura pod adresem 2B5H                 =  24 takty.
; --------------------------------------                ---
; W sumie wszystkie instrukcje Z80                    = 143 takty.

; Tymczasem po stronie telewizora:
; Powrót poziomy strumienia elektronów                =  15 taktów.
; Lewy margines o szerokości 8 znaków                 =  32 takty
; Tworzenie 75% linii skanowania z pierwszego NEWLINE =  96 takty
; ---------------------------------------               ---
;                                                       143 takty

; Ponieważ do czasu napotkania pierwszej instrukcji JP (HL), która wykona echo bufora wyświetlania, należy dodatkowo wyświetlić 8
; pozycji znakowych lewego marginesu, to rejestr odświeżania musi zawierać $F8. Idąc zatem wstecz i uwzględniając fakt, iż każda
; instrukcja zwiększa rejestr R o 1, dochodzimy do wniosku, iż rejestr R należy załadować wartością $F5.

          OUT  ($FD),A            ; (11) zatrzymaj generator NMI.

          JP   (IX)               ; (8)  naprzód do 281H (po górnym marginesie) lub do 28FH

; **********************
; ** TABLICE KLAWISZY **
; **********************

; ------------------------------
; KODY ZNAKÓW BEZ KLAWISZA SHIFT
; ------------------------------

; $007E : 126
K_UNSHIFT:.BYTE $3F ; Z
         .BYTE $3D  ; X
         .BYTE $28  ; C
         .BYTE $3B  ; V
         .BYTE $26  ; A
         .BYTE $38  ; S
         .BYTE $29  ; D
         .BYTE $2B  ; F
         .BYTE $2C  ; G
         .BYTE $36  ; Q
         .BYTE $3C  ; W
         .BYTE $2A  ; E
         .BYTE $37  ; R
         .BYTE $39  ; T
         .BYTE $1D  ; 1
         .BYTE $1E  ; 2
         .BYTE $1F  ; 3
         .BYTE $20  ; 4
         .BYTE $21  ; 5
         .BYTE $1C  ; 0
         .BYTE $25  ; 9
         .BYTE $24  ; 8
         .BYTE $23  ; 7
         .BYTE $22  ; 6
         .BYTE $35  ; P
         .BYTE $34  ; O
         .BYTE $2E  ; I
         .BYTE $3A  ; U
         .BYTE $3E  ; Y
         .BYTE $76  ; NEWLINE
         .BYTE $31  ; L
         .BYTE $30  ; K
         .BYTE $2F  ; J
         .BYTE $2D  ; H
         .BYTE $00  ; SPACE
         .BYTE $1B  ; .
         .BYTE $32  ; M
         .BYTE $33  ; N
         .BYTE $27  ; B

; -----------------------------
; KODY ZNAKÓW Z KLAWISZEM SHIFT
; -----------------------------

; $00A5 : 165
K_SHIFT: .BYTE $0E  ; :
         .BYTE $19  ; ;
         .BYTE $0F  ; ?
         .BYTE $18  ; /
         .BYTE $E3  ; STOP
         .BYTE $E1  ; LPRINT
         .BYTE $E4  ; SLOW
         .BYTE $E5  ; FAST
         .BYTE $E2  ; LLIST
         .BYTE $C0  ; ""
         .BYTE $D9  ; OR
         .BYTE $E0  ; STEP
         .BYTE $DB  ; <=
         .BYTE $DD  ; <>
         .BYTE $75  ; EDIT
         .BYTE $DA  ; AND
         .BYTE $DE  ; THEN
         .BYTE $DF  ; TO
         .BYTE $72  ; kursor w lewo
         .BYTE $77  ; RUBOUT
         .BYTE $74  ; GRAPHICS
         .BYTE $73  ; kursor w prawo
         .BYTE $70  ; kursor w górę
         .BYTE $71  ; kursor w dół
         .BYTE $0B  ; "
         .BYTE $11  ; )
         .BYTE $10  ; (
         .BYTE $0D  ; $
         .BYTE $DC  ; >=
         .BYTE $79  ; FUNCTION
         .BYTE $14  ; =
         .BYTE $15  ; +
         .BYTE $16  ; -
         .BYTE $D8  ; **
         .BYTE $0C  ;  L 
         .BYTE $1A  ; ,
         .BYTE $12  ; >
         .BYTE $13  ; <
         .BYTE $17  ; *

; --------------------
; KODY ZNAKOWE FUNKCJI
; --------------------

; $00CC : 204
K_FUNCT: .BYTE $CD  ; LN
         .BYTE $CE  ; EXP
         .BYTE $C1  ; AT
         .BYTE $78  ; KL
         .BYTE $CA  ; ASN
         .BYTE $CB  ; ACS
         .BYTE $CC  ; ATN
         .BYTE $D1  ; SGN
         .BYTE $D2  ; ABS
         .BYTE $C7  ; SIN
         .BYTE $C8  ; COS
         .BYTE $C9  ; TAN
         .BYTE $CF  ; INT
         .BYTE $40  ; RND
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $C2  ; TAB
         .BYTE $D3  ; PEEK
         .BYTE $C4  ; CODE
         .BYTE $D6  ; CHR$
         .BYTE $D5  ; STR$
         .BYTE $78  ; KL
         .BYTE $D4  ; USR
         .BYTE $C6  ; LEN
         .BYTE $C5  ; VAL
         .BYTE $D0  ; SQR
         .BYTE $78  ; KL
         .BYTE $78  ; KL
         .BYTE $42  ; PI
         .BYTE $D7  ; NOT
         .BYTE $41  ; INKEY$

; --------------------------
; KODY ZNAKÓW 'GRAFICZNYCH'
; --------------------------

; $00F3 : 243
K_GRAPH: .BYTE $08 ; grafika
         .BYTE $0A ; grafika
         .BYTE $09 ; grafika
         .BYTE $8A ; grafika
         .BYTE $89 ; grafika
         .BYTE $81 ; grafika
         .BYTE $82 ; grafika
         .BYTE $07 ; grafika
         .BYTE $84 ; grafika
         .BYTE $06 ; grafika
         .BYTE $01 ; grafika
         .BYTE $02 ; grafika
         .BYTE $87 ; grafika
         .BYTE $04 ; grafika
         .BYTE $05 ; grafika
         .BYTE $77 ; RUBOUT
         .BYTE $78 ; KL
         .BYTE $85 ; grafika
         .BYTE $03 ; grafika
         .BYTE $83 ; grafika
         .BYTE $8B ; grafika
         .BYTE $91 ; negatyw )
         .BYTE $90 ; negatyw (
         .BYTE $8D ; negatyw $
         .BYTE $86 ; grafika
         .BYTE $78 ; KL
         .BYTE $92 ; negatyw >
         .BYTE $95 ; negatyw +
         .BYTE $96 ; negatyw -
         .BYTE $88 ; grafika

; --------------
; TABELE 'NAZW'
; --------------

; $0111 : 273
TOKENST: .BYTE $0F+$80                     ; '?'+$80
         .BYTE $0B,$0B+$80                 ; ""
         .BYTE $26,$39+$80                 ; AT
         .BYTE $39,$26,$27+$80             ; TAB
         .BYTE $0F+$80                     ; '?'+$80
         .BYTE $28,$34,$29,$2A+$80         ; CODE
         .BYTE $3B,$26,$31+$80             ; VAL
         .BYTE $31,$2A,$33+$80             ; LEN
         .BYTE $38,$2E,$33+$80             ; SIN
         .BYTE $28,$34,$38+$80             ; COS
         .BYTE $39,$26,$33+$80             ; TAN
         .BYTE $26,$38,$33+$80             ; ASN
         .BYTE $26,$28,$38+$80             ; ACS
         .BYTE $26,$39,$33+$80             ; ATN
         .BYTE $31,$33+$80                 ; LN
         .BYTE $2A,$3D,$35+$80             ; EXP
         .BYTE $2E,$33,$39+$80             ; INT
         .BYTE $38,$36,$37+$80             ; SQR
         .BYTE $38,$2C,$33+$80             ; SGN
         .BYTE $26,$27,$38+$80             ; ABS
         .BYTE $35,$2A,$2A,$30+$80         ; PEEK
         .BYTE $3A,$38,$37+$80             ; USR
         .BYTE $38,$39,$37,$0D+$80         ; STR$
         .BYTE $28,$2D,$37,$0D+$80         ; CHR$
         .BYTE $33,$34,$39+$80             ; NOT
         .BYTE $17,$17+$80                 ; **
         .BYTE $34,$37+$80                 ; OR
         .BYTE $26,$33,$29+$80             ; AND
         .BYTE $13,$14+$80                 ; <=
         .BYTE $12,$14+$80                 ; >=
         .BYTE $13,$12+$80                 ; <>
         .BYTE $39,$2D,$2A,$33+$80         ; THEN
         .BYTE $39,$34+$80                 ; TO
         .BYTE $38,$39,$2A,$35+$80         ; STEP
         .BYTE $31,$35,$37,$2E,$33,$39+$80 ; LPRINT
         .BYTE $31,$31,$2E,$38,$39+$80     ; LLIST
         .BYTE $38,$39,$34,$35+$80         ; STOP
         .BYTE $38,$31,$34,$3C+$80         ; SLOW
         .BYTE $2B,$26,$38,$39+$80         ; FAST
         .BYTE $33,$2A,$3C+$80             ; NEW
         .BYTE $38,$28,$37,$34,$31,$31+$80 ; SCROLL
         .BYTE $28,$34,$33,$39+$80         ; CONT
         .BYTE $29,$2E,$32+$80             ; DIM
         .BYTE $37,$2A,$32+$80             ; REM
         .BYTE $2B,$34,$37+$80             ; FOR
         .BYTE $2C,$34,$39,$34+$80         ; GOTO
         .BYTE $2C,$34,$38,$3A,$27+$80     ; GOSUB
         .BYTE $2E,$33,$35,$3A,$39+$80     ; INPUT
         .BYTE $31,$34,$26,$29+$80         ; LOAD
         .BYTE $31,$2E,$38,$39+$80         ; LIST
         .BYTE $31,$2A,$39+$80             ; LET
         .BYTE $35,$26,$3A,$38,$2A+$80     ; PAUSE
         .BYTE $33,$2A,$3D,$39+$80         ; NEXT
         .BYTE $35,$34,$30,$2A+$80         ; POKE
         .BYTE $35,$37,$2E,$33,$39+$80     ; PRINT
         .BYTE $35,$31,$34,$39+$80         ; PLOT
         .BYTE $37,$3A,$33+$80             ; RUN
         .BYTE $38,$26,$3B,$2A+$80         ; SAVE
         .BYTE $37,$26,$33,$29+$80         ; RAND
         .BYTE $2E,$2B+$80                 ; IF
         .BYTE $28,$31,$38+$80             ; CLS
         .BYTE $3A,$33,$35,$31,$34,$39+$80 ; UNPLOT
         .BYTE $28,$31,$2A,$26,$37+$80     ; CLEAR
         .BYTE $37,$2A,$39,$3A,$37,$33+$80 ; RETURN
         .BYTE $28,$34,$35,$3E+$80         ; COPY
         .BYTE $37,$33,$29+$80             ; RND
         .BYTE $2E,$33,$30,$2A,$3E,$0D+$80 ; INKEY$
         .BYTE $35,$2E+$80                 ; PI

; -----------------------------------------
; PROCEDURA 'UAKTUALNIANIA ODCZYTU-ZAPISU'
; -----------------------------------------
;
; HL jest zwiększane aż do momentu, gdy zrówna się z wartością przechowywaną w E_LINE

; $01FC : 508
LOAD_SAVE: INC  HL                ; zwiększ HL o 1
          EX   DE,HL              ; przenieś HL do DE, chwilowo
          LD   HL,(E_LINE)        ; pobierz adres wiersza edycyjnego do HL
          SCF                     ; ustaw znacznik przeniesienia
          SBC  HL,DE              ; porównaj HL z E_LINE, wynik w HL nas nie interesuje
          EX   DE,HL              ; przywróć HL zwiększone o 1 z DE

          RET  NC                 ; wróć, jeśli należy załadować/zapisać więcej bajtów HL < E_LINE

          POP  HL                 ; inaczej usuń ze stosu adres powrotu

; -------------------------
; PROCEDURY 'WYŚWIETLANIA'
; ------------------------
;
; Sprawdzenie, w jakim trybie pracuje aktualnie komputer: FAST czy SLOW.
; Testowany jest znacznik SLOW - bit nr 6 zmiennej systemowej CDFLAG. Procedura kończy się powrotem, jeśli program pracuje
; w trybie FAST lub gdy obraz dla trybu SLOW jest niedostępny.

; $0207 : 519
SLOW_FAST: LD  HL,CDFLAG          ; Pobierz do HL adres zmiennej CDFLAG.
          LD   A,(HL)             ; Załaduj jej zawartość do akumulatora.
          RLA                     ; przesuń bit nr 6 na pozycję nr 7.
          XOR  (HL)               ; bit 7 <- bit 6 xor bit 7
          RLA                     ; umieść bit nr 7 w znaczniku przeniesienia.

          RET  NC                 ; jeśli bity były takie same, to powróć.

; Teraz sprawdzamy, czy rzeczywiście mamy do czynienia z ZX81 lub, czy jest to ZX80 z nowym ROM'em. Standardowy ZX80 nie
; posiadał generatora NMI.

          LD   A,$7F              ; Załaduj do akumulatora %011111111
          EX   AF,AF'             ; zachowaj to w AF'
          LD   B,$11              ; licznik, po którym powinno pojawić się przerwanie NMI, jeśli mamy do czynienia z ZX81.
          OUT  ($FE),A            ; uruchom generator NMI.

; Uwaga: jeśli to jest ZX81, to procedura obsługi NMI powinna zwiększyć AF'

; $0216 : 534
LOOP_11:  DJNZ LOOP_11            ; pętla, w którą wskoczy NMI = 16*13 cykli + 8 = 216 cykli.
          OUT  ($FD),A            ; wyłącz generator NMI.
          EX   AF,AF'             ; odtwórz wartość AF'.
          RLA                     ; testuj bit 7 poprzedniego AF'

          JR   NC,NO_SLOW         ; skocz naprzód do NO_SLOW, jeśli bit 7 jest wciąż 0

; Jeśli AF' zostało zwiększone, to generator NMI działa i tryb SLOW może być ustawiony.

          SET  7,(HL)             ; oznacza tryb SLOW - liczenie i wyświetlanie.
          PUSH AF                 ; *  zapisz główne rejestry
          PUSH BC                 ; **
          PUSH DE                 ; ***
          PUSH HL                 ; ****

          JR   DISPLAY_1          ; przejdź naprzód do DISPLAY_1.

; $0226 : 550
NO_SLOW:  RES  6,(HL)             ; skasuj bit 6 zmiennej CDFLAG.

          RET

; --------------------------
; GŁÓWNA PĘTLA WYŚWIETLANIA
; --------------------------
; Ta procedura jest wykonywana jeden raz dla każdej wyświetlanej ramki. Najpierw pobierany jest i zmniejszany o 1 licznik ramek.
; Gdy licznik osiągnie zero, następuje powrót.


; $0229 : 553
DISPLAY_1: LD  HL,(FRAMES)        ; pobierz 2-bajtową zmienną systemową FRAMES.
          DEC  HL                 ; zmniejsz licznik ramek.

; $022D : 557
DISPLAY_P: LD  A,$7F              ; przygotuj maskę
          AND  H                  ; wybierz bity 6-0 z H.
          OR   L                  ; połącz je z bitami L.
          LD   A,H                ; przeładuj A wszystkimi bitami z H dla testu PAUSE. Poprzednie dwa rozkazy ustawiły znacznik Z.

; Uwaga: oba skoki muszą zająć dokładnie ten sam czas.

          JR   NZ,ANOTHER         ; (12/7) naprzód do ANOTHER, jeśli bity 14-0 są niezerowe 

          RLA                     ; (4)    testuj bit 15 zmiennej FRAMES.

          JR   OVER_NC            ; (12)   naprzód do OVER_NC z wynikiem

; $0237 : 567
ANOTHER:  LD   B,(HL)             ; (7)    Uwaga: wprowadza jedynie opóźnienie.
          SCF                     ; (4)    ustaw znacznik przeniesienia.

; Uwaga: skok do tego miejsca zajmuje albo (12)(7)(4) cykli, albo (7)(4)(12) cykli.

; $0239 : 569
OVER_NC:  LD   H,A                ; (4)    ustaw H na zero
          LD   (FRAMES),HL        ; (16)   uaktualnij zmienną systemową FRAMES 

          RET  NC                 ; (11/5) wróć, jeśli FRAMES jest używane przez PAUSE 

; $023E : 574
DISPLAY_2: CALL KEYBOARD          ; procedura KEYBOARD wstawia rząd klawisza do H i kolumnę do L. Odczyt portów również
                                  ; rozpoczyna impuls synchronizacji ramki TV.
          LD   BC,(LAST_K)        ; pobierz wartość ostatniego klawisza z LAST_K
          LD   (LAST_K),HL        ; uaktualnij LAST_K nową wartością.
          LD   A,B                ; do A wpisz poprzednią kolumnę - będzie $FF, jeśli nie naciśnięto żadnego klawisza
          ADD  A,$02              ; dodanie 2 ustawi przeniesienie, jeśli nie było klawisza.
          SBC  HL,BC              ; odejmij z przeniesieniem te dwie wartości klawiszowe.

; Jeśli w obu był ten sam klawisz, to HL otrzyma wartość 0.

          LD   A,(DBOUNC)         ; pobierz zmienną systemową DEBOUNCE
          OR   H                  ; i utwórz sumę logiczną z obu bajtami różnicy
          OR   L                  ; ustawiając znacznik zera dla nadchodzącego skoku.
          LD   E,B                ; przenieś wartość kolumny do E
          LD   B,$0B              ; a do B wstaw jedenaście
          LD   HL,CDFLAG          ; W HL ustaw adres zmiennej systemowej CDFLAG
          RES  0,(HL)             ; wyzeruj bit 0 zmiennej CDFLAG

          JR   NZ,NO_KEY          ; przeskocz naprzód, jeśli DEBOUNCE/różnicę >0 do NO-KEY

          BIT  7,(HL)             ; sprawdź bit liczenia i wyświetlania w CDFLAG
          SET  0,(HL)             ; ustaw na 1 bit 0 zmiennej CDFLAG.

          RET  Z                  ; wróć, jeśli bit 7 oznaczał tryb fast.

          DEC  B                  ; (4) zmniejsz licznik.
          NOP                     ; (4) opóźnienie - 4 cykle zegara
          SCF                     ; (4) ustaw znacznik przeniesienia

; $0264 : 612
NO_KEY:   LD   HL,DBOUNC          ; pobierz adres zmiennej DEBOUNCE
          CCF                     ; zaneguj znacznik przeniesienia
          RL   B                  ; obróć w lewo rejestr B pobierając bit przeniesienia C<-76543210<-C

; $026A : 618
LOOP_B:   DJNZ LOOP_B             ; pętla dopóki B>0 do LOOP-B
          LD   B,(HL)             ; pobierz wartość DEBOUNCE do B
          LD   A,E                ; przenieś wartość kolumny do A
          CP   $FE
          SBC  A,A
          LD   B,$1F
          OR   (HL)
          AND  B
          RRA
          LD   (HL),A             ; uaktualnij DEBOUNCE
          OUT  ($FF),A            ; zakończ impuls synchronizacji ramki TV.
          LD   HL,(D_FILE)        ; (12) ustaw w HL adres bufora wyświetlania z D_FILE
          SET  7,H                ; (8)  ustaw bit 15, aby adresować echo bufora w górnej połówce RAM.

          CALL DISPLAY_3          ; (17) procedura DISPLAY-3 wyświetla górny zbiór pustych linii

; -------------------
; PROCEDURA 'VIDEO-1'
; -------------------

; $0281 : 641
R_IX_1:   LD   A,R                ; (9)  nieszkodliwe opóźnienie lub coś bardzo sprytnego?
          LD   BC,$1901           ; (10) 25 wierszy, 1 linia skanująca w pierwszym.
          LD   A,$F5              ; (7)  Ta wartość zostanie załadowana do R i zapewni, iż cykl rozpocznie się we właściwej
                                  ;      części ekranu po pozycji znaku nr 32
          CALL DISPLAY_5          ; (17) procedura DISPLAY-5 kończy bieżącą pustą linię a następnie tworzy obraz zawartości 
                                  ;      bufora wyświetlania wykorzystując przerwania INT. Ostatnie przerwanie powraca do następnego adresu. 
; $028B : 651
L028B     DEC  HL                 ; ustaw  HL na ostatnie NEWLINE/HALT.

          CALL DISPLAY_3          ; procedura DISPLAY-3 wyświetla dolny zbiór pustych linii

; $028F : 655
R_IX_2:   JP   DISPLAY_1          ; wróć do DISPLAY-1

; --------------------------------------
; PROCEDURA 'WYŚWIETLANIA PUSTYCH LINII'
; --------------------------------------
; Ten podprogram wywoływany jest dwukrotnie (zobacz powyżej) do utworzenia najpierw pustych linii u góry obrazu telewizyjnego,
; a następnie pustych linii na spodzie obrazu. 

; $0292 : 658
DISPLAY_3: POP IX                 ; pobierz adres powrotny do rejestru IX. będzie to albo L0281, albo L028F - zobacz wyżej.

          LD   C,(IY+$28)         ; załaduj C wartością stałej systemowej MARGIN.
          BIT  7,(IY+$3B)         ; sprawdź w CDFLAG, czy działa tryb wyświetlania i liczenia.

          JR   Z,DISPLAY_4        ; w trybie FAST naprzód do DISPLAY-4

          LD   A,C                ; przenieś MARGIN do A  - 31d lub 55d.
          NEG                     ; zaneguj
          INC  A
          EX   AF,AF'             ; umieść zanegowaną liczbę pustych linii w A'

          OUT  ($FE),A            ; włącz generator NMI.

          POP  HL                 ; ****
          POP  DE                 ; ***
          POP  BC                 ; **
          POP  AF                 ; *     Odtwórz główne rejestry

          RET                     ; powróć - koniec przerwania. Powrót nastąpi do programu użytkownika - BASIC lub kod maszynowy,
                                  ; który będzie przerywany przy każdym NMI.

; ----------------------
; PROCEDURA 'TRYBU FAST'
; ----------------------

; $02A9 : 681
DISPLAY_4: LD  A,$FC              ; (7)  załaduj A z wartością opóźnienia dla R
          LD   B,$01              ; (7)  tylko jeden wiersz.

          CALL DISPLAY_5          ; (17) procedura DISPLAY-5

          DEC  HL                 ; (6)  wskaż z powrotem na HALT.
          EX   (SP),HL            ; (19) Niegroźne opóźnienie, jeśli stosowane w parze.
          EX   (SP),HL            ; (19) Niegroźne opóźnienie.

          JP   (IX)               ; (8)  do L0281 lub L028F

; ---------------------
; PROCEDURA 'DISPLAY-5'
; ---------------------
; Ta procedura jest wywoływana z trybów SLOW i FAST do utworzenia środka obrazu TV. W trybie SLOW rejestr R jest zwiększany przy
; każdej instrukcji do wartości $F7 przy zakończeniu procedury. W trybie FAST wartość końcowa będzie równa $FF, a przerwanie pojawi
; się, gdy tylko Licznik Rozkazów osiągnie instrukcję HALT. (24 cykle zegara)

; $02B5 : 693
DISPLAY_5: LD  R,A                ; (9) Załaduj R z A.     R = wolno: $F5 szybko: $FC
          LD   A,$DD              ; (7) załaduj przyszłą wartość R.   $F6      $FD
          EI                      ; (4) Włącz przerwania           $F7      $FE

          JP   (HL)               ; (4) skocz do echa obrazu.      $F8      $FF

; -------------------------------------
; PROCEDURA 'PRZESZUKIWANIA KLAWIATURY'
; -------------------------------------
; Klawiatura jest czytana w czasie okresu synchronizacji pionowej, gdy nie jest wyświetlany obraz. Odczyt portu z wyzerowanym najmłodszym
; bitem adresu, np. $FE rozpoczyna impuls synchronizacji pionowej.

; $02BB : 699
KEYBOARD: LD   HL,$FFFF           ; (16) przygotuj bufor na przyjęcie klawisza
          LD   BC,$FEFE           ; (20) ustaw BC na port $FEFE. Rejestr B ze swoim wyzerowanym jednym bitem pełni rolę licznika do 8.
          IN   A,(C)              ; (11) odczytaj port - na magistrali adresowej są umieszczane wszystkie 16 bitów.  Start impulsu VSYNC.
          OR   $01                ; (7)  ustaw prawy bit, aby ignorować klawisz SHIFT.

; $02C5 : 709
EACH_LINE: OR  $E0                ; [7] OR %11100000
          LD   D,A                ; [4] przenieś do D.
          CPL                     ; [4] zaneguj - teraz znaczą tylko bity 4-0.
          CP   $01                ; [7] ustawia przeniesienie, jeśli A zawiera zero.
          SBC  A,A                ; [4] $FF, jeśli $00, inaczej zero.
          OR   B                  ; [7] $FF lub port FE, FD, FB....
          AND  L                  ; [4] O ile nie naciśnięto kilku klawiszy, L wciąż będzie $FF. Jeśli naciśnięto więcej niż jeden klawisz,
                                  ;     to A ma teraz nieważną wartość.
          LD   L,A                ; [4] przenieś do L.

; teraz rozważ identyfikator kolumny.

          LD   A,H                ; [4] będzie równe $FF, jeśli nie było poprzednich klawiszy.
          AND  D                  ; [4] 111xxxxx
          LD   H,A                ; [4] przenieś A do H

; ponieważ tylko jeden klawisz może być naciśnięty, H będzie zawierało, jeśli ważne, jedną z wartości 11111110, 11111101, 11111011,
; 11110111, 11101111 od zewnętrznej kolumny, powiedzmy Q, do wewnętrznej kolumny, powiedzmy T.

          RLC  B                  ; [8]  obróć licznik 8 / adres portu. ustawia przeniesienie, jeśli więcej do zrobienia.
          IN   A,(C)              ; [10] odczytaj kolejną połówkę wiersza. Tym razem wszystkie pięć bitów.

          JR   C,EACH_LINE        ; [12](7) kontynuuj w pętli, aż będzie zrobione

; Za drugim razem ostatnim odczytywanym wierszem jest SHIFT,Z,X,C,V.

          RRA                     ; (4) sprawdź klawisz SHIFT - przeniesienie zostanie wyzerowane jeśli ten klawisz jest wciśnięty.
          RL   H                  ; (8) obróć w lewo H biorąc przeniesienie, co daje wartości kolumnowe -
                                  ;      $FD, $FB, $F7, $EF, $DF.
                                  ;     lub $FC, $FA, $F6, $EE, $DE z SHIFT.

; Teraz H identyfikuje kolumnę, a L identyfikuje wiersz w matrycy klawiatury.

; Teraz jest dobry moment na sprawdzenie, czy jest to komputer brytyjski lub amerykański. Wersja amerykańska posiada dodatkową diodę,
; która zeruje bit 6 odczytany z portu.

          RLA                     ; (4) skompensuj test na klawisz SHIFT.
          RLA                     ; (4) wyprowadź obrotem bit 7.
          RLA                     ; (4) testuj bit 6.

          SBC  A,A                ; (4) $FF lub $00 {USA}
          AND  $18                ; (7) $18 lub $00
          ADD  A,$1F              ; (7) $37 lub $1F

; wynikiem jest albo 31 (USA), albo 55 (WB) pustych linii ponad i poniżej obrazu TV.

          LD   (MARGIN),A         ; (13) uaktualnij zmienną systemową MARGIN

          RET                     ; (10) powróć

; ---------------------------------
; PROCEDURA 'USTAWIANIA TRYBU FAST'
; ---------------------------------

; $02E7 : 743
SET_FAST: BIT  7,(IY+$3B)         ; zmienna systemowa CDFLAG

          RET  Z

          HALT                    ; Czekaj na przerwanie
          OUT  ($FD),A
          RES  7,(IY+$3B)         ; zmienna systemowa CDFLAG

          RET

; ----------
; 'RAPORT-F'
; ----------

; $02F4 : 756
REPORT_F: RST  08H                ; ERROR-1
         .BYTE $0E                ; Raport błędu: Brak nazwy programu.

; ------------------------
; PROCEDURA 'ROZKAZU SAVE'
; ------------------------

; $02F6 : 758
SAVE:     CALL NAME

          JR   C,REPORT_F         ; jeśli pusta nazwa, wróć do REPORT-F powyżej.

          EX   DE,HL
          LD   DE,$12CB           ; pięć sekund czasu

; $02FF : 767
HEADER:   CALL BREAK_1

          JR   NC,BREAK_2         ; do BREAK-2

; $0304 : 772
DELAY_1:  DJNZ DELAY_1            ; pętla opóźniająca

          DEC  DE
          LD   A,D
          OR   E

          JR   NZ,HEADER          ; wstecz do HEADER dla opóźnienia

; $030B : 779
OUT_NAME: CALL OUT_BYTE

          BIT  7,(HL)             ; test na zanegowany bit.
          INC  HL                 ; adres następnego znaku nazwy.

          JR   Z,OUT_NAME         ; jęli brak zanegowanego bitu, wróć do OUT-NAME

; teraz zacznij zapisywać zmienne systemowe.

          LD   HL,VERSN           ; ustaw start obszaru na VERSN, zachowując przy okazji RAMTOP i inne.

; $0316 : 790
OUT_PROG: CALL OUT_BYTE

          CALL LOAD_SAVE

          JR   OUT_PROG           ; pętla do OUT-PROG

; --------------------
; PROCEDURA 'OUT-BYTE'
; --------------------
; Ta procedura zapisuje bajt danych bit po bicie na domowy magnetofon.

; $031E : 798
OUT_BYTE: LD   E,(HL)             ; pobierz bajt do zapisu.
          SCF                     ; ustaw znacznik przeniesienia - jako marker.

; $0320 : 800
EACH_BIT: RL   E                  ;  C < 76543210 < C

          RET  Z                  ; wróć, gdy przejdzie bit markera 
                              
          SBC  A,A                ; $FF jeśli bit ustawiony lub $00 bez przeniesienia
          AND  $05                ; $05                      $00
          ADD  A,$04              ; $09                      $04
          LD   C,A                ; przenieś licznik czasu do C. bit ustawiony ma dłuższy impuls niż bit wyzerowany.
; $0329 : 809
PULSES:   OUT  ($FF),A            ; impuls do magnetofonu.
          LD   B,$23              ; ustaw stałą czasową

; $032D : 813
DELAY_2:  DJNZ DELAY_2            ; samozapętlenie do DELAY-2

          CALL BREAK_1            ; procedura BREAK-1 testuje klawisz BREAK.

; $0332 : 818
BREAK_2:  JR   NC,REPORT_D        ; jeśli przerwa, to naprzód do REPORT-D

          LD   B,$1E              ; ustaw wartość opóźnienia.

; $0336 : 822
DELAY_3:  DJNZ DELAY_3            ; samozapętlenie do DELAY-3

          DEC  C                  ; zmniejsz licznik

          JR   NZ,PULSES          ; wróć w pętli do PULSES

; $033B : 827
DELAY_4:  AND  A                  ; wyzeruj przeniesienie dla następnego testu bitu.
          DJNZ DELAY_4            ; samozapętlenie do DELAY-4 (B jest zero - 256)

          JR   EACH_BIT           ; wróć w pętli do EACH-BIT

; ------------------------
; PROCEDURA 'ROZKAZU LOAD'
; ------------------------

; $0340 : 832
LOAD:     CALL NAME

; DE wskazuje początek nazwy w RAM.

          RL   D                  ; pobierz przeniesienie 
          RRC  D                  ; teraz przeniesienie w bicie 7.

; $0347 : 839
NEXT_PROG: CALL IN_BYTE

          JR   NEXT_PROG          ; pętla do NEXT-PROG

; -------------------
; PROCEDURA 'IN-BYTE'
; -------------------

; $034C : 844
IN_BYTE:  LD   C,$01              ; przygotuj licznik do ośmiu 00000001.

; $034E : 846
NEXT_BIT: LD   B,$00              ; ustaw licznik na 256

; $0350 : 848
BREAK_3:  LD   A,$7F              ; odczytaj wiersz klawiatury 
          IN   A,($FE)            ; z klawiszem SPACE.

          OUT  ($FF),A            ; wyślij sygnał na ekran.

          RRA                     ; sprawdź naciśnięcie SPACE.

          JR   NC,BREAK_4         ; jeśli tak, skocz naprzód do BREAK-4

          RLA                     ; odwróć powyższy obrót bitów
          RLA                     ; sprawdź bit taśmy.

          JR   C,GET_BIT          ; jeśli ustawiony, idź naprzód do GET-BIT

          DJNZ BREAK_3            ; wróć w pętli do BREAK-3

          POP  AF                 ; usuń adres powrotu.
          CP   D

; $0361 : 865
RESTART:  JP   NC,INITIAL         ; jeśli D jest zero, skocz naprzód do INITIAL, aby zresetować system jeśli sygnał z taśmy
                                  ; przekroczył dozwolony czas, np. przy zatrzymaniu magnetofonu. Nie wystarczy zwykły raport błędów,
                                  ; ponieważ część zmiennych systemowych została nadpisana.

          LD   H,D                ; w przeciwnym razie przenieś start nazwy
          LD   L,E                ; do rejestru HL

; $0366 : 870
IN_NAME:  CALL IN_BYTE            ; procedura IN-BYTE jest pewnego rodzaju rekursją dla części nazwy. Odebrany bajt jest w C.

          BIT  7,D                ; czy nazwa jest pustym łańcuchem?
          LD   A,C                ; przenieś bit do A.

          JR   NZ,MATCHING        ; przy pustym łańcuchu naprzód do MATCHING

          CP   (HL)               ; inaczej porównaj z łańcuchem w pamięci.

          JR   NZ,NEXT_PROG       ; wróć przy niezgodności do NEXT-PROG (na pozór koniec procedury, lecz adres powrotny został usunięty).

; $0371 : 881
MATCHING: INC  HL                 ; adresuj następny znak nazwy
          RLA                     ; test na zanegowany bit.

          JR   NC,IN_NAME         ; jeśli go brak, wróć do IN-NAME

; nazwa w całości zgadza się. Przejdź do odczytu danych, ale najpierw zwiększ starszy bajt E_LINE, która jest jedną ze zmiennych
; systemowych do załadowania. Ponieważ młodszy bajt jest odczytywany przed starszym, możliwe jest, że w fazie pośredniej błędna wartość
; mogłaby spowodować zbyt wczesne zakończenie ładowania - zobacz na test w LOAD/SAVE.

          INC  (IY+$15)           ; zwiększ starszy bajt zmiennej systemowej E_LINE.
          LD   HL,VERSN           ; rozpocznij ładowanie od zmiennej systemowej VERSN.

; $037B : 891
IN_PROG:  LD   D,B                ; ustaw D na zero jako znacznik.

          CALL IN_BYTE            ; procedura IN-BYTE ładuje bajt

          LD   (HL),C             ; wstaw zebrany bajt do pamięci.

          CALL LOAD_SAVE

          JR   IN_PROG            ; wróć w pętli do IN-PROG

; to odgałęzienie zbiera pełny bajt przed zwykłym opuszczeniem procedury IN-BYTE.

; $0385 : 901
GET_BIT:  PUSH DE                 ; zachowaj
          LD   E,$94              ; wartość licznika czasu.

; $0388 : 904
TRAILER:  LD   B,$1A              ; licznik na dwadzieścia sześć.

; $038A : 906
COUNTER:  DEC  E                  ; zmniejsz stan licznika.
          IN   A,($FE)            ; wczytaj bit z magnetofonu
          RLA
          BIT  7,E
          LD   A,E

          JR   C,TRAILER          ; z ustawionym przeniesieniem wróć do TRAILER

          DJNZ COUNTER            ; inaczej do COUNTER

          POP  DE

          JR   NZ,BIT_DONE        ; do BIT-DONE

          CP   $56

          JR   NC,NEXT_BIT        ; do NEXT-BIT

; $039C : 924
BIT_DONE: CCF                     ; zaneguj znacznik przeniesienia
          RL   C

          JR   NC,NEXT_BIT        ; do NEXT-BIT

          RET                     ; powróć z pełnym bajtem.


; jeśli w trakcie odczytu danych było przerwanie, wykonaj reset. Jeśli przerwanie w czasie oczekiwania na program z taśmy,
; to przerwa dozwolona.

; $03A2 : 930
BREAK_4:  LD   A,D                ; przenieś znacznik do A.
          AND  A                  ; test na zero.

          JR   Z,RESTART          ; jeśli tak, wróć do RESTART


; $03A6 : 934
REPORT_D: RST  08H                ; ERROR-1
         .BYTE $0C                ; Raport błędu: PRZERWANIE - CONT powtarza

; --------------------------
; PROCEDURA 'NAZWY PROGRAMU'
; --------------------------
; Nazwa jest sprawdzana na raport C. Wybrany zostaje tryb FAST oraz ostatnia litera nazwy jest ustawiana w negatywie.

; $03A8 : 936
NAME:     CALL SCANNING

          LD   A,(FLAGS)
          ADD  A,A

          JP   M,REPORT_C

          POP  HL

          RET  NC

          PUSH HL

          CALL SET_FAST

          CALL STK_FETCH

          LD   H,D
          LD   L,E
          DEC  C

          RET  M

          ADD  HL,BC
          SET  7,(HL)             ; ustaw bit 7 ostatniego znaku nazwy - znak w negatywie oznacza koniec łańcucha nazwy

          RET

; -----------------------
; PROCEDURA ROZKAZU 'NEW'
; -----------------------

; $03C3 : 963
NEW:      CALL SET_FAST

          LD   BC,(RAMTOP)        ; pobierz zawartość zmiennej systemowej RAMTOP
          DEC  BC                 ; ustaw na ostatni bajt systemowy

; ---------------------------
; PROCEDURA 'SPRAWDZANIA RAM'
; ---------------------------

; $03CB : 971
RAM_CHECK: LD  H,B
          LD   L,C                ; przenieś BC do HL
          LD   A,$3F

; $03CF : 975
RAM_FILL: LD   (HL),$02           ; wypełnij pamięć liczbą $02
          DEC  HL
          CP   H                  ; sprawdź, czy cała pamięć już wypełniona

          JR   NZ,RAM_FILL        ; jeśli nie, wypełniaj dalej

; $03D5 : 981
RAM_READ: AND  A                  ; wyzeruj przeniesienie
          SBC  HL,BC
          ADD  HL,BC
          INC  HL

          JR   NC,SET_TOP

          DEC  (HL)

          JR   Z,SET_TOP

          DEC  (HL)

          JR   Z,RAM_READ

; $03E2 : 994
SET_TOP:  LD  (RAMTOP),HL         ; ustaw zmienną systemową RAMTOP na pierwszy bajt ponad obszarem systemowym BASICU.

; -------------------------
; PROCEDURA 'INICJALIZACJI'
; -------------------------

; $03E5 : 997
INITIAL:  LD   HL,(RAMTOP)        ; pobierz zmienną systemową RAMTOP.
          DEC  HL                 ; ustaw adres ostatniego bajtu systemowego.
          LD   (HL),$3E           ; ustaw znacznik kończ $3E - zbyt duży dla starszego bajtu numeru wiersza.
          DEC  HL                 ; ustaw adres nieważnego, młodszego bajtu.
          LD   SP,HL              ; i ustaw wskaźnik stosu na ten adres
          DEC  HL                 ; ustaw adres pierwszego bajtu na stosie procesora,
          DEC  HL                 ; który zostanie zapełniony przez następne CALL/PUSH.
          LD   (ERR_SP),HL        ; ustaw wskaźnik stosu błędów ERR_SP na początek obecnie pustego stosu procesora.

; Teraz ustaw rejestr I, aby układy generacji obrazu wiedziały, gdzie odnaleźć zastaw znaków. Ten ROM wykorzystuje zestaw znaków
; tylko do drukowania na ZX Printer. Obraz TV tworzony jest przez zewnętrzne obwody wideo. Ta pamięć ROM 8KB może być używana jako
; rozszerzenie w ZX80 zamiast jego oryginalnej pamięci 4KB ROM, zatem obwody wideo mogą być na ZX80.

          LD   A,$1E              ; dla tego ROM adres wynosi $1E00.
          LD   I,A                ; ustaw rejestr I poprzez rejestr A.
          IM   1                  ; wybierz tryb 1 dla przerwań Z80.
          LD   IY,ERR_NR          ; ustaw IY na początek RAM, aby można było indeksować zmienne systemowe.
          LD   (IY+$3B),$40       ; ustaw CDFLAG na 0100 0000. Bit 6 wskazuje wymagany tryb obliczeń i generacji obrazu.

          LD   HL,$407D           ; pierwsza komórka za Zmiennymi Systemowymi - 16509 dziesiętnie.
          LD   (D_FILE),HL        ; ustaw na tę wartość zmienną systemową D_FILE.
          LD   B,$19              ; ustaw minimalny ekran na 24 znaki NEWLINE, które nastąpią po początkowym NEWLINE.

; $0408 : 1032
LINE:     LD   (HL),$76           ; wstaw NEWLINE (instrukcja HALT)
          INC  HL                 ; zaadresuj następną pozycję.
          DJNZ LINE               ; wróć w pętli do LINE dla wszystkich 25 znaków NEWLINE

          LD   (VARS),HL          ; ustaw zmienną systemową VARS na następny adres

          CALL CLEAR              ; procedura CLEAR ustawia znacznik końca $80 oraz wskaźniki dynamicznej pamięci E_LINE, STKBOT i STKEND.

; $0413 : 1043
N_L_ONLY: CALL CURSOR_IN          ; procedura CURSOR-IN wstawia kursor i znacznik końca w wierszu edycji, ustawiając również rozmiar
                                  ; dolnych dwóch wierszy ekranu.
          CALL SLOW_FAST          ; procedura SLOW/FAST wybiera tryb obliczeń i wyświetlania

; ----------------------
; SEKCJA 'WYDRUK BASICU'
; ----------------------
; 'Górna' część obrazu jest tworzona przez wywołanie najpierw procedury polecenia CLS, a następnie program w języku BASIC jest wyświetlany
; od S-TOP. Użycie klawisza "kursor w dół" również powoduje przebudowę "górnej" części obrazu.

; $0419 : 1049
UPPER:    CALL CLS

          LD   HL,(E_PPC)          ; młodszy bajt zmiennej systemowej E_PPC
          LD   DE,(S_TOP)          ; młodszy bajt zmiennej systemowej S_TOP
          AND  A
          SBC  HL,DE
          EX   DE,HL

          JR   NC,ADDR_TOP

          ADD  HL,DE
          LD   (S_TOP),HL          ; młodszy bajt zmiennej systemowej S_TOP

; $042D : 1069
ADDR_TOP: CALL LINE_ADDR

          JR   Z,LIST_TOP

          EX   DE,HL

; $0433 : 1075
LIST_TOP: CALL LIST_PROG

          DEC  (IY+$1E)            ; zmienna systemowa BERG

          JR   NZ,LOWER

          LD   HL,(E_PPC)          ; młodszy bajt zmiennej systemowej E_PPC

          CALL LINE_ADDR

          LD   HL,(CH_ADD)         ; młodszy bajt zmiennej systemowej CH_ADD
          SCF                      ; ustaw znacznik przeniesienia
          SBC  HL,DE
          LD   HL,S_TOP            ; młodszy bajt zmiennej systemowej S_TOP

          JR   NC,INC_LINE

          EX   DE,HL
          LD   A,(HL)
          INC  HL
          LDI
          LD   (DE),A

          JR   UPPER

; punkt wejścia dla 'kursor w dół'

; $0454 : 1108
DOWN_KEY: LD   HL,E_PPC            ; młodszy bajt zmiennej systemowej E_PPC

; $0457 : 1111
INC_LINE: LD   E,(HL)
          INC  HL
          LD   D,(HL)
          PUSH HL
          EX   DE,HL
          INC  HL

          CALL LINE_ADDR

          CALL LINE_NO

          POP  HL

; $0464 : 1124
KEY_INPUT: BIT 5,(IY+$2D)         ; zmienna systemowa FLAGX

          JR   NZ,LOWER           ; skocz naprzód do LOWER

          LD   (HL),D
          DEC  HL
          LD   (HL),E

          JR   UPPER

; -----------------------------
; SEKCJA 'KOPII WIERSZA EDYCJI'
; -----------------------------
; Procedura ta ustawia wiersz edycji jedynie z kursorem, gdy
; 1) Brakuje pamięci do edycji wiersza BASIC.
; 2) Podczas wprowadzania naciśnieto klawisz EDIT.
; Punktem wejścia jest LOWER

; $046F : 1135
EDIT_INP: CALL CURSOR_IN          ; procedura CURSOR-IN ustawia wiersz edycji jedynie z kursorem.

; $0472 : 1138
LOWER:    LD   HL,(E_LINE)        ; pobierz start wiersza edycji z E_LINE.

; $0475 : 1141
EACH_CHAR: LD  A,(HL)             ; pobierz znak z wiersza edycji.
          CP   $7E                ; porównaj go ze znacznikiem liczby.

          JR   NZ,END_LINE        ; jeśli różny, skocz naprzód do END-LINE

          LD   BC,$0006           ; inaczej sześć niewidocznych bajtów do usunięcia.

          CALL RECLAIM_2

          JR   EACH_CHAR          ; wróć do EACH-CHAR

; $0482 : 1154
END_LINE: CP   $76
          INC  HL

          JR   NZ,EACH_CHAR

; $0487 : 1159
EDIT_LINE: CALL CURSOR            ; procedura CURSOR ustawia kursor K lub L.

; $048A : 1162
EDIT_ROOM: CALL LINE_ENDS

          LD   HL,(E_LINE)        ; pobierz zmienną systemową E_LINE
          LD   (IY+$00),$FF       ; zmienna systemowa ERR_NR

          CALL COPY_LINE

          BIT  7,(IY+$00)         ; zmienna systemowa ERR_NR

          JR   NZ,DISPLAY_6

          LD   A,(DF_SZ)          ; zmienna systemowa DF_SZ
          CP   $18

          JR   NC,DISPLAY_6

          INC  A
          LD   (DF_SZ),A
          LD   B,A
          LD   C,$01

          CALL LOC_ADDR

          LD   D,H
          LD   E,L
          LD   A,(HL)

; $04B1 : 1201
FREE_LINE: DEC HL
          CP   (HL)

          JR   NZ,FREE_LINE

          INC  HL
          EX   DE,HL
          LD   A,($4005)           ; starszy bajt zmiennej systemowej RAMTOP
          CP   $4D

          CALL C,RECLAIM_1

          JR   EDIT_ROOM

; -------------------------------
; SEKCJA 'OCZEKIWANIA NA KLAWISZ'
; -------------------------------

; $04C1 : 1217
DISPLAY_6: LD  HL,$0000           ; zeruj HL
          LD   (X_PTR),HL         ; wyzeruj zmienną systemową X_PTR
          LD   HL,CDFLAG          ; pobierz CDFLAG do HL
          BIT  7,(HL)             ; sprawdź bit 7

          CALL Z,DISPLAY_1        ; jeśli jest wyzerowany, wywołaj procedurę DISPLAY-1

; $04CF : 1231
SLOW_DISP: BIT  0,(HL)            ; sprawdź bit 0

          JR   Z,SLOW_DISP        ; jeśli wyzerowany, skocz do SLOW-DISP

          LD   BC,(LAST_K)        ; pobierz do BC zmienną systemową LAST_K

          CALL DEBOUNCE           ; czekaj na wygaśnięcie drgań klawiatury

          CALL DECODE             ; dekoduj klawisz

          JR   NC,LOWER           ; wróć do LOWER

; -------------------------------
; SEKCJA 'DEKODOWANIA KLAWIATURY'
; -------------------------------
; Zdekodowany kod klawisza jest w E a HL wskazuje na pozycję w tablicy klawiszy. D zawiera zero.

; $04DF : 1247
K_DECODE: LD   A,(MODE)           ; pobierz zawartość zmiennej systemowej MODE
          DEC  A                  ; testuj razem trzy wartości

          JP   M,FETCH_2          ; naprzód przy zerze do FETCH-2

          JR   NZ,FETCH_1         ; naprzód przy  2 do FETCH-1

;  Pierwotną wartością było 1, a teraz jest zero.

          LD   (MODE),A           ; uaktualnij zmienną systemową MODE

          DEC  E                  ; zmniejsz E do zakresu $00 - $7F
          LD   A,E                ; przenieś je do A
          SUB  $27                ; odejmij 39, ustawiając przeniesienie, jeśli w zakresie 00 - 38

          JR   C,FUNC_BASE        ; w takim razie idź do przodu do FUNC-BASE

          LD   E,A                ; inaczej ustaw w E zmniejszoną wartość

; $04F2 : 1266
FUNC_BASE: LD  HL,K_FUNCT         ; adres tablicy K-FUNCT dla klawiszy funkcyjnych.

          JR   TABLE_ADD          ; skocz naprzód do TABLE-ADD

; $04F7 : 1271
FETCH_1:  LD   A,(HL)
          CP   $76

          JR   Z,K_L_KEY

          CP   $40
          SET  7,A

          JR   C,ENTER
 
          LD   HL,$00C7

; $0505 : 1285
TABLE_ADD: ADD HL,DE

          JR   FETCH_3

; $0508 : 1288
FETCH_2:  LD   A,(HL)
          BIT  2,(IY+$01)          ; zmienna systemowa FLAGS  - tryb K lub L ?

          JR   NZ,TEST_CURS

          ADD  A,$C0
          CP   $E6

          JR   NC,TEST_CURS

; $0515 : 1301
FETCH_3:  LD   A,(HL)

; $0516 : 1302
TEST_CURS: CP  $F0

          JP   PE,KEY_SORT

; $051B : 1307
ENTER:    LD   E,A

          CALL CURSOR

          LD   A,E

          CALL ADD_CHAR

; $0523 : 1315
BACK_NEXT: JP  LOWER

; ---------------------------
; PROCEDURA 'DODAWANIA ZNAKU'
; ---------------------------

; $0526 : 1318
ADD_CHAR:  CALL ONE_SPACE

          LD   (DE),A

          RET

; ----------------------------
; PROCEDURA 'KLAWISZY KURSORA'
; ----------------------------

; $052B : 1323
K_L_KEY:  LD   A,$78

; $052D : 1325
KEY_SORT: LD   E,A
          LD   HL,$0482            ; adres bazowy ED-KEYS
          ADD  HL,DE
          ADD  HL,DE
          LD   C,(HL)
          INC  HL
          LD   B,(HL)
          PUSH BC

; $0537 : 1335
CURSOR:   LD   HL,(E_LINE)         ; zmienna systemowa E_LINE
          BIT  5,(IY+$2D)          ; zmienna systemowa FLAGX

          JR   NZ,L_MODE

; $0540 : 1344
K_MODE:   RES  2,(IY+$01)          ; zmienna systemowa FLAGS  - sygnalizuj użycie trybu K

; $0544 : 1348
TEST_CHAR: LD  A,(HL)
          CP   $7F

          RET  Z

          INC  HL

          CALL NUMBER

          JR   Z,TEST_CHAR

          CP   $26

          JR   C,TEST_CHAR

          CP   $DE

          JR   Z,K_MODE

; $0556 : 1366
L_MODE:   SET  2,(IY+$01)          ; zmienna systemowa FLAGS  - sygnalizuj użycie trybu L

          JR   TEST_CHAR

; --------------------------
; PROCEDURA 'WYCZYŚĆ-JEDEN'
; --------------------------

; $055C : 1372
CLEAR_ONE: LD  BC,$0001

          JP   RECLAIM_2

; -----------------------------
; TABLICA 'KLAWISZY EDYCYJNYCH'
; -----------------------------

; $0562 : 1378
ED_KEYS: .WORD UP_KEY             ; Adres: $059F
         .WORD DOWN_KEY           ; Adres: $0454
         .WORD LEFT_KEY           ; Adres: $0576
         .WORD RIGHT_KEY          ; Adres: $057F
         .WORD FUNCTION           ; Adres: $05AF
         .WORD EDIT_KEY           ; Adres: $05C4
         .WORD N_L_KEY            ; Adres: $060C
         .WORD RUBOUT             ; Adres: $058B
         .WORD FUNCTION           ; Adres: $05AF
         .WORD FUNCTION           ; Adres: $05AF

; -------------------------
; PROCEDURA 'KURSOR W LEWO'
; -------------------------

; $0576 : 1398
LEFT_KEY: CALL LEFT_EDGE

          LD   A,(HL)
          LD   (HL),$7F
          INC  HL

          JR   GET_CODE

; --------------------------
; PROCEDURA 'KURSOR W PRAWO'
; --------------------------

; $057F : 1407
RIGHT_KEY: INC HL
          LD   A,(HL)
          CP   $76

          JR   Z,ENDED_2

          LD   (HL),$7F
          DEC  HL

; $0588 : 1416
GET_CODE: LD   (HL),A

; $0589 : 1417
ENDED_1:  JR   BACK_NEXT

; -----------------------
; PROCEDURA 'WYMAZYWANIA'
; -----------------------

; $058B : 1419
RUBOUT:   CALL LEFT_EDGE

          CALL CLEAR_ONE

          JR   ENDED_1

; ------------------------
; PROCEDURA 'LEWA KRAWĘDŹ'
; ------------------------

; $0593 : 1427
LEFT_EDGE: DEC HL
          LD   DE,(E_LINE)
          LD   A,(DE)
          CP   $7F

          RET  NZ

          POP  DE

; $059D : 1437
ENDED_2:  JR   ENDED_1

; -------------------------
; PROCEDURA 'KURSOR W GÓRĘ'
; -------------------------

; $059F : 1439
UP_KEY:   LD   HL,(E_PPC)

          CALL LINE_ADDR

          EX   DE,HL

          CALL LINE_NO

          LD   HL,$400B           ; ustaw HL na starszy bajt zmiennej systemowej E_PPC

          JP   KEY_INPUT          ; skocz wstecz do KEY-INPUT

; -----------------------------
; PROCEDURA 'KLAWISZ FUNKCYJNY'
; -----------------------------

; $05AF : 1455
FUNCTION: LD   A,E
          AND  $07
          LD   (MODE),A

          JR   ENDED_2

; --------------------------------
; PROCEDURA 'ZBIERZ NUMER WIERSZA'
; --------------------------------

; $05B7 : 1463
ZERO_DE:  EX   DE,HL
          LD   DE,DISPLAY_6 + 1    ; $04C2 - miejsce adresujące dwa zera

; $05BB : 1467
LINE_NO:  LD   A,(HL)
          AND  $C0

          JR   NZ,ZERO_DE

          LD   D,(HL)
          INC  HL
          LD   E,(HL)

          RET

; ------------------------
; PROCEDURA 'KLAWISZ EDIT'
; ------------------------

; $05C4 : 1476
EDIT_KEY: CALL LINE_ENDS          ; procedura LINE-ENDS czyści spód ekranu.

          LD   HL,EDIT_INP
          PUSH HL                 ; ** umieszczane na stosie jako adres pętli w przypadku błędu.

          BIT  5,(IY+$2D)         ; testuj FLAGX

          RET  NZ                 ; w trybie wprowadzania skocz pośrednio do do $046F, EDIT-INP (zacznij jeszcze raz).

          LD   HL,(E_LINE)        ; pobierz E_LINE
          LD   (DF_CC),HL         ; i użyj do uaktualnienia kursora ekranowego DF_CC

; teraz RST $10 wydrukuje numery wierszy do wiersza edycji zamiast na ekran. Najpierw jednak należy się upewnić, że żaden znak newline
; nie pojawi się poza ekranem podczas drukowania numerów wierszy do tego wiersza edycyjnego.

          LD   HL,$1821           ; przygotuj wiersz 0, kolumnę 0
          LD   (S_POSN),HL        ; uaktualnij S_POSN tymi podstawionymi wartościami.

          LD   HL,(E_PPC)         ; pobierz bieżący wiersz z E_PPC, może to być nieistniejący wiersz, tj. ostatnio usunięty.

          CALL LINE_ADDR          ; procedura LINE-ADDR pobiera adres wiersza lub, gdy go brak, adres następnego wiersza.

          CALL LINE_NO            ; procedura LINE-NO pobiera numer wiersza, jeśli taki jest, do DE, pozostawiając HL wskazujące
                                  ; na drugi młodszy bajt.

          LD   A,D                ; sprawdź, czy numer wiersza wynosi zero.
          OR   E

          RET  Z                  ; wróć, jeśli brak numeru wiersza - brak programu do edycji.

          DEC  HL                 ; wskazuj starszy bajt.

          CALL OUT_NO             ; procedura OUT-NO zapisuje numer do wiersza edycji.

          INC  HL                 ; wskazuj na bajty długości.
          LD   C,(HL)             ; młodszy baj do C.
          INC  HL
          LD   B,(HL)             ; starszy bajt do B.

          INC  HL                 ; wskazuj pierwszy znak w wierszu.
          LD   DE,(DF_CC)         ; pobierz kursor pliku wyświetlania DF_CC

          LD   A,$7F              ; przygotuj znak kursora.
          LD   (DE),A             ; i wstaw go do wiersza edycji.
          INC  DE                 ; zwiększ adres przeznaczenia.

          PUSH HL                 ; * zapisz początek BASIC.

          LD   HL,$001D           ; 29 bajtów nadmiarowych.
          ADD  HL,DE              ; dodaj adres kursora.
          ADD  HL,BC              ; dodaj długość wiersza.
          SBC  HL,SP              ; odejmij wskaźnik stosu.

          POP  HL                 ; * odtwórz wskaźnik początku BASIC.

          RET  NC                 ; jeśli brak miejsca, wróć do L046F EDIT-INP. Klawisz EDIT nie będzie działał.

          LDIR                    ; inaczej skopiuj bajty z programu do wiersza edycji. Uwaga, ukryte wartości zmiennoprzecinkowe
                                  ; również są kopiowane do wiersza edycji
          EX   DE,HL              ; przenieś wskaźnik wolnego miejsca do HL

          POP  DE                 ; ** usuń adres EDIT-INP ze stosu.

          CALL SET_STK_B          ; procedura SET-STK-B ustawia STKEND z HL.

          JR   ENDED_2            ; wstecz do ENDED-2 i po kolejnych 3 skokach do $0472, LOWER.
                                  ; Uwaga. Procedura LOWER usuwa ukryte wartości zmiennoprzecinkowe z wiersza edycji.

; ---------------------------
; PROCEDURA 'KLAWISZ NEWLINE'
; ---------------------------

; $060C : 1548
N_L_KEY:  CALL LINE_ENDS

          LD   HL,LOWER            ; przygotuj adres: LOWER
          BIT  5,(IY+$2D)          ; zmienna systemowa FLAGX

          JR   NZ,NOW_SCAN

          LD   HL,(E_LINE)

          LD   A,(HL)
          CP   $FF

          JR   Z,STK_UPPER

          CALL CLEAR_PRB

          CALL CLS

; $0626 : 1574
STK_UPPER: LD  HL,UPPER

; $0629 : 1577
NOW_SCAN: PUSH HL                  ; zapisz na stosie adres procedury (LOWER lub UPPER).

          CALL LINE_SCAN

          POP  HL

          CALL CURSOR

          CALL CLEAR_ONE

          CALL E_LINE_NO

          JR   NZ,N_L_INP

          LD   A,B
          OR   C

          JP   NZ,N_L_LINE

          DEC  BC
          DEC  BC
          LD   (PPC),BC
          LD   (IY+$22),$02        ; zmienna systemowa DF_SZ
          LD   DE,(D_FILE)

          JR   TEST_NULL

; $064E : 1614
N_L_INP:  CP   $76

          JR   Z,N_L_NULL          ; to N/L-NULL

          LD   BC,(T_ADDR)

          CALL LOC_ADDR

          LD   DE,(NXTLIN)
          LD   (IY+$22),$02        ; zmienna systemowa DF_SZ

; $0661 : 1633
TEST_NULL: RST 18H                 ; POBIERZ-ZNAK

          CP   $76

; $0664 : 1636
N_L_NULL: JP   Z,N_L_ONLY

          LD   (IY+$01),$80        ; zmienna systemowa FLAGS
          EX   DE,HL

; $066C : 1644
NEXT_LINE: LD  (NXTLIN),HL
          EX   DE,HL

          CALL TEMP_PTR2

          CALL LINE_RUN

          RES  1,(IY+$01)          ; zmienna systemowa FLAGS  - sygnalizuj, że drukarka nie jest używana
          LD   A,$C0
          LD   (IY+$19),A          ; młodszy bajt zmiennej systemowej X_PTR

          CALL X_TEMP

          RES  5,(IY+$2D)          ; zmienna systemowa FLAGX
          BIT  7,(IY+$00)          ; zmienna systemowa ERR_NR

          JR   Z,STOP_LINE

          LD   HL,(NXTLIN)
          AND  (HL)

          JR   NZ,STOP_LINE

          LD   D,(HL)
          INC  HL
          LD   E,(HL)
          LD   (PPC),DE
          INC  HL
          LD   E,(HL)
          INC  HL
          LD   D,(HL)
          INC  HL
          EX   DE,HL
          ADD  HL,DE

          CALL BREAK_1

          JR   C,NEXT_LINE

          LD   HL,ERR_NR
          BIT  7,(HL)

          JR   Z,STOP_LINE

          LD   (HL),$0C

; $06AE : 1710
STOP_LINE: BIT 7,(IY+$38)          ; zmienna systemowa PR_CC

          CALL Z,COPY_BUFF

          LD   BC,$0121

          CALL LOC_ADDR

          LD   A,(ERR_NR)
          LD   BC,(PPC)
          INC  A

          JR   Z,REPORT

          CP   $09

          JR   NZ,CONTINUE

          INC  BC

; $06CA : 1738
CONTINUE: LD   (OLDPPC),BC

          JR   NZ,REPORT

          DEC  BC

; $06D1 : 1745
REPORT:   CALL OUT_CODE

          LD   A,$18

          RST  10H                 ; PISZ-AKUMULATOR

          CALL OUT_NUM

          CALL CURSOR_IN

          JP   DISPLAY_6

; $06E0 : 1760
N_L_LINE: LD   (E_PPC),BC
          LD   HL,(CH_ADD)
          EX   DE,HL
          LD   HL,N_L_ONLY         ; adresuj: N/L-ONLY
          PUSH HL
          LD   HL,(STKBOT)
          SBC  HL,DE
          PUSH HL
          PUSH BC

          CALL SET_FAST

          CALL CLS

          POP  HL

          CALL LINE_ADDR

          JR   NZ,COPY_OVER

          CALL NEXT_ONE

          CALL RECLAIM_2

; $0705 : 1797
COPY_OVER: POP BC
          LD   A,C
          DEC  A
          OR   B

          RET  Z

          PUSH BC
          INC  BC
          INC  BC
          INC  BC
          INC  BC
          DEC  HL

          CALL MAKE_ROOM

          CALL SLOW_FAST

          POP  BC
          PUSH BC
          INC  DE
          LD   HL,(STKBOT)
          DEC  HL
          LDDR                    ; kopiuj bajty
          LD   HL,(E_PPC)
          EX   DE,HL
          POP  BC
          LD   (HL),B
          DEC  HL
          LD   (HL),C
          DEC  HL
          LD   (HL),E
          DEC  HL
          LD   (HL),D

          RET

; ----------------------------------
; PROCEDURY POLECEŃ 'LIST' I 'LLIST'
; ----------------------------------

; $072C : 1836
LLIST:    SET  1,(IY+$01)         ; zmienna systemowa FLAGS  - sygnalizuj uzywanie drukarki

; $0730 : 1840
LIST:     CALL FIND_INT

          LD   A,B                ; pobierz starszy bajt numeru wiersza dostarczonego przez użytkownika.
          AND  $3F                ; i ogranicz go do zakresu 1-16383.
          LD   H,A
          LD   L,C
          LD   (E_PPC),HL         ; wynik umieść w zmiennej systemowej E_PPC

          CALL LINE_ADDR

; $073E : 1854
LIST_PROG: LD  E,$00

; $0740 : 1856
UNTIL_END: CALL OUT_LINE          ; procedura OUT-LINE tworzy listing jednego wiersza w BASIC wracając wcześniej, gdy ekran staje się
                                  ; pełny lub napotka koniec programu.
          JR   UNTIL_END          ; pętla do UNTIL-END

; ---------------------------------
; PROCEDURA 'WYDRUKU WIERSZA BASIC'
; ---------------------------------

; $0745 : 1861
OUT_LINE: LD   BC,(E_PPC)

          CALL CP_LINES

          LD   D,$92

          JR   Z,TEST_END

          LD   DE,$0000
          RL   E

; $0755 : 1877
TEST_END: LD   (IY+$1E),E          ; zmienna systemowa BERG
          LD   A,(HL)
          CP   $40
          POP  BC

          RET  NC

          PUSH BC

          CALL OUT_NO

          INC  HL
          LD   A,D

          RST  10H                 ; PISZ-AKUMULATOR

          INC  HL
          INC  HL

; $0766 : 1894
COPY_LINE: LD  (CH_ADD),HL
          SET  0,(IY+$01)          ; zmienna systemowa FLAGS  - usuń wiodącą spację

; $076D : 1901
MORE_LINE: LD  BC,(X_PTR)
          LD   HL,(CH_ADD)
          AND  A
          SBC  HL,BC

          JR   NZ,TEST_NUM

          LD   A,$B8

          RST  10H                 ; PISZ-AKUMULATOR

; $077C : 1916
TEST_NUM: LD   HL,(CH_ADD)
          LD   A,(HL)
          INC  HL

          CALL NUMBER

          LD   (CH_ADD),HL

          JR   Z,MORE_LINE

          CP   $7F

          JR   Z,OUT_CURS

          CP   $76

          JR   Z,OUT_CH

          BIT  6,A

          JR   Z,NOT_TOKEN

          CALL TOKENS

          JR   MORE_LINE          ; wróć w pętli do MORE-LINE

; $079A : 1946
NOT_TOKEN: RST 10H                ; PISZ-AKUMULATOR

          JR   MORE_LINE          ; wróć w pętli do MORE-LINE

; $079D : 1949
OUT_CURS: LD   A,(MODE)           ; pobierz zawartość zmiennej systemowej MODE
          LD   B,$AB              ; przygotuj negatywowe F dla kursora funkcyjnego.

          AND  A                  ; test na zero

          JR   NZ,FLAGS_2         ; jeśli nie, skocz naprzód do FLAGS-2

          LD   A,(FLAGS)          ; pobierz zmienną systemową FLAGS.
          LD   B,$B0              ; przygotuj negatywowe K dla kursora.

; $07AA : 1962
FLAGS_2:  RRA                     ; 00000?00 -> 000000?0
          RRA                     ; 000000?0 -> 0000000?
          AND  $01                ; 0000000?    0000000x

          ADD  A,B                ; [F] -> [G]  lub  [K] -> [L]

          CALL PRINT_SP           ; procedura PRINT-SP drukuje znak

          JR   MORE_LINE          ; wróć do MORE-LINE

; ------------------
; PROCEDURA 'LICZBA'
; ------------------
; Ta procedura sprawdza, czy znak w rejestrze jest równy znacznikowi liczby. Jeśli tak, to wartość w parze rejestrów HL jest zwiększana o 5,
; aby albo przeskoczyć liczbę zmiennoprzecinkową, albo zarezerwować pięć bajtów na taką liczbę.
 
; $07B4 : 1972
NUMBER:   CP   $7E                ; znacznik liczby?

          RET  NZ                 ; wróć, jeśli nie

          INC  HL                 ; przesuń HL o pięć bajtów
          INC  HL
          INC  HL
          INC  HL
          INC  HL

          RET

; -----------------------------------
; PROCEDURA 'DEKODOWANIA KLAWIATURY'
; -----------------------------------
; Różne 'wartości klawiszy' przechowywane w parze rejestrów BC są 'dekodowane' na normalne kody znakowe komputera ZX81 poprzez wyszukiwanie ich
; w tablicy klawiszy spod adresu $007E ($007D+1) - KUNSHIFT. Kod znaku jest określony przez (HL).
 
; $07BD : 1981
DECODE:   LD   D,$00
          SRA  B
          SBC  A,A
          OR   $26
          LD   L,$05
          SUB  L

; $07C7 : 1991
KEY_LINE: ADD  A,L
          SCF
          RR   C

          JR   C,KEY_LINE

          INC  C

          RET  NZ

          LD   C,B
          DEC  L
          LD   L,$01

          JR   NZ,KEY_LINE

          LD   HL,$007D
          LD   E,A
          ADD  HL,DE
          SCF

          RET

; -----------------------
; PROCEDURA 'DRUKOWANIA'
; -----------------------
; Dwie procedurki WRITE-CH i WRITE stanowią istotne części procedury drukującej. Jednakże zanim znak będzie mógł zostać wydrukowany, należy pobrać
; S-POSN, sprawdzić i w razie konieczności poszerzyć ekran. Stosowane są różne punkty wejścia do tej procedury, które związane są z zamianą
; kodów binarnych na kody znakowe komputera ZX81.

; $07DC : 2012
LEAD_SP:  LD   A,E
          AND  A

          RET  M

          JR   PRINT_CH

; $07E1 : 2017
OUT_DIGIT: XOR A

; $07E2 : 2018
DIGIT_INC: ADD HL,BC
          INC  A

          JR   C,DIGIT_INC

          SBC  HL,BC
          DEC  A

          JR   Z,LEAD_SP

; $07EB : 2027
OUT_CODE: LD   E,$1C
          ADD  A,E

; $07EE : 2030
OUT_CH:   AND  A

          JR   Z,PRINT_SP

; $07F1 : 2033
PRINT_CH: RES  0,(IY+$01)      ; uaktualnij zmienną FLAGS - sygnalizuj zezwolenia na wiodącą spację

; $07F5 : 2037
PRINT_SP: EXX
          PUSH HL
          BIT  1,(IY+$01)      ; testuj zmienną FLAGS - czy drukarka w użyciu ?

          JR   NZ,LPRINT_A     ; jeśli tak, drukuj do drukarki

          CALL ENTER_CH

          JR   PRINT_EXX

; $0802 : 2050
LPRINT_A: CALL LPRINT_CH

; $0805 : 2053
PRINT_EXX: POP HL
          EXX

          RET

; $0808 : 2056
ENTER_CH: LD   D,A
          LD   BC,(S_POSN)
          LD   A,C
          CP   $21

          JR   Z,TEST_LOW

; $0812 : 2066
TEST_N_L: LD   A,$76
          CP   D

          JR   Z,WRITE_N_L

          LD   HL,(DF_CC)
          CP   (HL)
          LD   A,D

          JR   NZ,WRITE_CH

          DEC  C

          JR   NZ,EXPAND_1

          INC  HL
          LD   (DF_CC),HL
          LD   C,$21
          DEC  B
          LD   (S_POSN),BC

; $082C : 2092
TEST_LOW: LD   A,B
          CP   (IY+$22)        ; zmienna systemowa DF_SZ

          JR   Z,REPORT_5

          AND  A

          JR   NZ,TEST_N_L

; $0835 : 2101
REPORT_5: LD   L,$04           ; 'brak miejsca na ekranie'

          JP   ERROR_3

; $083A : 2106
EXPAND_1: CALL ONE_SPACE

          EX   DE,HL

; $083E : 2110
WRITE_CH: LD   (HL),A
          INC  HL
          LD   (DF_CC),HL
          DEC  (IY+$39)        ; zmienna systemowa S_POSN_x

          RET

; $0847 : 2119
WRITE_N_L: LD  C,$21
          DEC  B
          SET  0,(IY+$01)      ; zmienna systemowa FLAGS  - unieważnij wiodącą spację

          JP   LOC_ADDR

; ----------------------
; PROCEDURA 'LPRINT-CH'
; ----------------------
; Ten podprogram wysyła znak do drukarki ZX-Printer, umieszczając kod znaku w buforze drukarki.
; Uwaga. PR-CC zawiera młodszy bajt adresu bufora. Starszy bajt ma zawsze wartość stałą. 

; $0851 : 2129
LPRINT_CH: CP  $76            ; porównaj z NEWLINE.

          JR   Z,COPY_BUFF    ; jeśli równe, skocz naprzód do COPY-BUFF

          LD   C,A            ; kopię znaku umieść w C.
          LD   A,(PR_CC)      ; pobierz adres bufora z PR_CC
          AND  $7F            ; zignoruj bit 7, aby utworzyć prawdziwy adres.
          CP   $5C            ; Porównaj z 33 kolumną
          LD   L,A            ; utwórz młodszy bajt adresu bufora
          LD   H,$40          ; starszy bajt ma wartość stałą.

          CALL Z,COPY_BUFF    ; wywołaj procedurę COPY-BUFF, aby wysłać pełny bufor do drukarki, jeśli pierwsze 32 bajty są użyte.
                              ; (to zresetuje HL na początek)
          LD   (HL),C         ; umieść znak w buforze.
          INC  L              ; zwiększ pozycję - nie będzie przekroczenia granicy 256.
          LD   (IY+$38),L     ; uaktualnij zmienną systemową PR_CC automatycznie resetując bit 7, aby pokazać, że bufor nie jest pusty.

          RET

; --------------------------
; PROCEDURA POLECENIA 'COPY'
; --------------------------
; Cały ekran znakowy jest kopiowany do drukarki ZX-Printer. Drukowane są wszystkie 24 wiersze tekstu/grafiki.

; $0869 : 2153
COPY:     LD   D,$16           ; przygotuj się do kopiowania 24 wierszy tekstu.
          LD   HL,(D_FILE)     ; ustaw HL na poczatek pliku wideo ze zmiennej D_FILE.
          INC  HL 

          JR   COPY_D          ; naprzód do COPY_D

; Pojedynczy bufor znakowy jest kopiowany do drukarki ZX-Printer.

; $0871 : 2161
COPY_BUFF: LD  D,$01           ; przygotuj się do kopiowania pojedynczego wiersza tekstu.
          LD   HL,PRBUFF       ; ustaw HL na start bufora drukarki PRBUFF.

; obie ścieżki zbiegają się tutaj.

; $0876 : 2166
COPY_D:   CALL SET_FAST

          PUSH BC             ; przechowaj BC, może być wiszący znak w C z LPRINT-CH

; $087A : 2170
COPY_LOOP: PUSH HL            ; zachowaj wskaźnik pierwszego znaku. (*)
          XOR  A              ; wyzeruj akumulator.
          LD   E,A            ; ustaw licznik wierszy pikseli na zero, zakres 0-7.

; ta wewnętrzna pętla zajmuje się każdą poziomą linią pikseli.

; $087D : 2173
COPY_TIME: OUT ($FB),A        ; wyzerowany bit 2 włącza silnik drukarki z nieaktywnym pisakiem - wyzerowany bit 7.
          POP  HL             ; pobierz wskaźnik pierwszego znaku (*) dla pętli wewnętrznej.

; $0880 : 2176
COPY_BRK: CALL BREAK_1        ; sprawdź, czy użytkownik przerwał operację

          JR   C,COPY_CONT    ; jeśli nie było naciśniętego klawisza, idź naprzód do COPY-CONT

; inaczej rejestr A będzie zawierał 11111111 0

          RRA                 ; 0111 1111
          OUT  ($FB),A        ; zatrzymaj silnik drukarki, wyłącz pisak.

; $0888 : 2184
REPORT_D2: RST 08H            ; ERROR-1
         .BYTE $0C            ; Raport błędu: PRZERWANIE - CONT powtarza

; $088A : 2186
COPY_CONT: IN  A,($FB)        ; czytaj port drukarki.
          ADD  A,A            ; testuj bity 6 i 7

          JP   M,COPY_END     ; jeśli brak drukarki, skocz naprzód do COPY-END

          JR   NC,COPY_BRK    ; wróć do COPY-BRK, jeśli pisak nie jest na pozycji

          PUSH HL             ; zachowaj wskaźnik pierwszego znaku (*)
          PUSH DE             ; zachowaj wiersz znaków i wiersz pikseli.

          LD   A,D            ; do A licznik linii ?
          CP   $02            ; przy ostatniej linii ustawia przeniesienie.
          SBC  A,A            ; teraz $FF przy ostatniej linii lub zero w innym przypadku.

; teraz sprytnie przygotuj maskę kontrolną dla drukarki, ustawiając bit 2(później przesunięty do 1) rejestru D, aby zwolnić drukarkę
; dla ostatnich dwóch linii pikseli( E = 6 i 7)

          AND  E              ; AND z numerem linii 0-7
          RLCA                ; przesuń w lewo.
          AND  E              ; AND jeszcze raz.
          LD   D,A            ; zapisz maskę sterującą w D.

; $089C : 2204
COPY_NEXT: LD  C,(HL)         ; załaduj znak z ekranu lub z bufora.
          LD   A,C            ; zapisz kopię w C dla późniejszego testu na negatyw.
          INC  HL             ; uaktualnij wskaźnik dla następnego obiegu.
          CP   $76            ; czy znakiem jest NEWLINE ?

          JR   Z,COPY_N_L     ; naprzód do COPY-N/L, jeśli tak

          PUSH HL             ; * inaczej zachowaj wskaźnik znaku.
          SLA  A              ; (?) pomnóż przez 2
          ADD  A,A            ; pomnóż przez 4
          ADD  A,A            ; pomnóż przez 8
          LD   H,$0F          ; załaduj do H połówkę adresu matryc znakowych.
          RL   H              ; teraz $1E lub $1F (z przeniesieniem)
          ADD  A,E            ; dodaj numer linii 0-7
          LD   L,A            ; teraz HL adresuje bajt źródłowy w matrycy
          RL   C              ; testuj znak, ustawiając przeniesienie, jeśli jest negatywem.
          SBC  A,A            ; akumulator teraz ma zawartość $00 dla normalnych znaków lub $FF dla negatywów.
          XOR  (HL)           ; połącz ze wzorem bitowym z końca ROM.
          LD   C,A            ; przenieś bajt do  C.
          LD   B,$08          ; licznik 8 bitów do wyprowadzenia.

; $08B5 : 2229
COPY_BITS: LD  A,D            ; pobierz maskę sterowania szybkością z D.
          RLC  C              ; umieść bit do wyprowadzenia w przeniesieniu.
          RRA                 ; umieść go w bicie 7, bit prędkości w bicie 1
          LD   H,A            ; zapisz przygotowaną maskę w rejestrze H.

; $08BA : 2234
COPY_WAIT: IN  A,($FB)        ; czytaj port drukarki
          RRA                 ; czekaj na sygnał wyrównania z enkodera.

          JR   NC,COPY_WAIT   ; jeśli brak, czekaj w pętli

          LD   A,H            ; bajt kontrolny do A.
          OUT  ($FB),A        ; i wyprowadź go do portu drukarki.
          DJNZ COPY_BITS      ; w pętli wyprowadź wszystkie 8 bitów

          POP  HL             ; odzyskaj wskaźnik znaku.

          JR   COPY_NEXT      ; skocz wstecz do COPY-NEXT, aby skopiować przyległy znak

; Napotkany został znak NEWLINE, który albo występuje za wierszem tekstu, albo jest pierwszym znakiem ekranu lub wiersza drukarki.

; $08C7 : 2247
COPY_N_L: IN   A,($FB)        ; czytaj port drukarki.
          RRA                 ; czekaj na sygnał z enkodera.

          JR   NC,COPY_N_L    ; jeśli go brak, czekaj w pętli

          LD   A,D            ; przenieś maskę prędkości do A.
          RRCA                ; przesuń bit prędkości na pozycję 1. Bit 7 jest ustawiony na 0 - sterowanie pisakiem.
          OUT  ($FB),A        ; ustaw prędkość drukarki.

          POP  DE             ; odtwórz wiersz znaku oraz wiersz pikseli.
          INC  E              ; zwiększ wiersz pikseli 0-7.
          BIT  3,E            ; sprawdź, czy osiągnięto wartość 8.

          JR   Z,COPY_TIME    ; jeśli nie, wróć do COPY-TIME

; skończono 8 linii pikseli, wiersz tekstu.

          POP  BC             ; pozbądź się niepotrzebnego już znacznika pierwszego znaku 
          DEC  D              ; zmniejsz licznik wiersza tekstu.

          JR   NZ,COPY_LOOP   ; jeśli nie zero, cofnij się do COPY-LOOP

          LD   A,$04          ; zatrzymaj silnik drukarki, który już pracuje wolno.
          OUT  ($FB),A        ; zapisz do portu drukarki.

; $08DE : 2270
COPY_END: CALL SLOW_FAST

          POP  BC             ; odzyskaj zachowaną parę rejestrów BC.

; ----------------------------------------
; PROCEDURA 'CZYSZCZENIA BUFORA DRUKARKI'
; ----------------------------------------
; Ten podprogram ustawia 32 bajty bufora drukarki na zero (spacje), a 33-cim znakiem staje się NEWLINE. Wykonywane to jest po przesłaniu
; zawartości bufora do drukarki, lecz dodatkowo również po wydrukowaniu na niej 24 wierszy ekranowych.
; Uwaga. To jest błąd logiczny, ponieważ ostatnia operacja wcale nie wymaga bufora. Logicznie ujmując, powinno być możliwe takie użycie: 
; 10 LPRINT "HELLO ";
; 20 COPY
; 30 LPRINT ; "WORLD"
; i oczekiwanie, że cała wiadomość pojawi się na drukarce. Co zadziwiające, ten błąd logiczny nigdy nie został wykryty, a chociaż można się
; kłócić, czy powyższy program daje błąd, to powtórzenie tego błędu na Spectrum już jest bez żadnych wątpliwości błędem oprogramowania.
; Ponieważ bufor drukarki ma stały adres na końcu obszaru zmiennych systemowych, a pozycja druku jest w zakresie od $3C do $5C, to bit 7
; zmiennej systemowej jest ustawiany na 1, aby zasygnalizować pusty bufor i automatycznie zresetować się, gdy zmienna ta jest uaktualniana
; jakąkolwiek pozycją druku - sprytnie.

; $08E2 : 2274
CLEAR_PRB: LD  HL,$405C       ; adres ustawiony na koniec PRBUFF
          LD   (HL),$76       ; umieść NEWLINE na ostatniej pozycji.
          LD   B,$20          ; przygotuj się do wyzerowania 32 poprzedzających znaków. 

; $08E9 : 2281
PRB_BYTES: DEC HL             ; zmniejsz adres - mogłoby być DEC L.
          LD   (HL),$00       ; umieść bajt zero.
          DJNZ PRB_BYTES      ; pętla do PRB-BYTES dla wszystkich 32 bajtów

          LD   A,L            ; pobierz pozycję wydruku znaku.
          SET  7,A            ; zasygnalizuj, że bufor jest pusty.
          LD   (PR_CC),A      ; uaktualnij jednobajtową zmienną PR_CC

          RET

; --------------------
; PROCEDURA 'PISZ NA'
; --------------------
; Procedura sprawdza poprawność parametrów dostarczonych poleceniu PRINT AT. Jeśli parametry są złe, sygnalizowany jest błąd B, inaczej otrzymywane są
; poprawne wartości S-POSN i DF-CC poprzez użycie procedury LOC_ADDR.

; $08F5 : 2293
PRINT_AT: LD   A,$17          ; sprawdź, czy współrzędna wierszowa jest w zakresie
          SUB  B              ; od 0 do 23

          JR   C,WRONG_VAL    ; jeśli nie, skocz do WRONG-VAL

; $08FA : 2298
TEST_VAL: CP    (IY+$22)       ; porównaj wynik z liczbą wierszy w dolnej części ekranu

          JP    C,REPORT_5     ; jeśli pozycja na nie wkracza, zgłoś błąd skacząc do REPORT-5

          INC   A
          LD    B,A
          LD    A,$1F          ; teraz sprawdź tak samo współrzędną kolumnową  
          SUB   C              ; powinna być w zakresie od 0 do 31

; $0905 : 2309
WRONG_VAL: JP   C,REPORT_B     ; jeśli nie jest, skocz do REPORT-B

          ADD   A,$02
          LD    C,A

; $090B : 2315
SET_FIELD: BIT 1,(IY+$01)      ; zmienna systemowa FLAGS  - drukarka w użyciu

          JR    Z,LOC_ADDR

          LD    A,$5D
          SUB   C
          LD    (PR_CC),A

          RET

; -------------------------------------
; PROCEDURA 'ADRESU POZYCJI NA EKRANIE'
; -------------------------------------
; Ta ważna procedura ustawia wartość DF-CC dla zadanej pozycji na ekranie. Jeśli obraz jest zwinięty i z tego powodu nie zawiera tej pozycji,
; to pożądana linia zostaje rozwinięta.

; $0918 : 2328
LOC_ADDR: LD   (S_POSN),BC
          LD   HL,(VARS)
          LD   D,C
          LD   A,$22
          SUB  C
          LD   C,A
          LD   A,$76
          INC  B

; $0927 : 2343
LOOK_BACK: DEC HL
          CP   (HL)

          JR   NZ,LOOK_BACK

          DJNZ LOOK_BACK

          INC  HL
          CPIR
          DEC  HL
          LD   (DF_CC),HL
          SCF

          RET  PO

          DEC  D

          RET  Z

          PUSH BC

          CALL MAKE_ROOM

          POP  BC
          LD   B,C
          LD   H,D
          LD   L,E

; $0940 : 2368
EXPAND_2: LD   (HL),$00
          DEC  HL
          DJNZ EXPAND_2

          EX   DE,HL
          INC  HL
          LD   (DF_CC),HL

          RET

; ---------------------------------------------
; PROCEDURA 'ROZWIJANIA NAZW POLECEŃ I FUNKCJI'
; ---------------------------------------------
; Kody znaków odnoszące się do nazw poleceń i funkcji są rozwijane za pomocą tej procedury. Adres każde 'rozwiniętej nazwy' w tablicy nazw jest
; znajdowany przy pomocy procedury TOKEN_ADD. Wiodąca spacja zostaje wydrukowana, jeśli określa ją bit 0 zmiennej FLAGS, następnie zostają
; wydrukowane litery nazwy i na końcu jest dodawana spacja, jeśli jest potrzebna.

; $094B : 2379
TOKENS:   PUSH AF             ; zachowaj kod znaku

          CALL TOKEN_ADD      ; procedura TOKEN_ADD wyszukuje adres nazwy w tablicy nazw wg kodu znaku. Adres w BC.

          JR   NC,ALL_CHARS   ; jeśli wiodąca spacja nie występuje, przejdź do drukowania liter nazwy

          BIT  0,(IY+$01)     ; zmienna systemowa FLAGS  - jeśli ustawione, wiodąca spacja

          JR   NZ,ALL_CHARS

          XOR  A              ; zeruj akumulator otrzymując kod znaku spacji

          RST  10H            ; PISZ-AKUMULATOR - wypisz spację wiodącą

; $0959 : 2393
ALL_CHARS: LD  A,(BC)         ; pobierz znak nazwy do akumulatora
          AND  $3F            ; jeśli jest to ostatni znak nazwy, to pozbądź się bitu negatywu

          RST  10H            ; PISZ-AKUMULATOR - wypisz znak

          LD   A,(BC)         ; ponownie pobierz znak
          INC  BC             ; przesuń wskaźnik na następną literę nazwy w tablicy
          ADD  A,A            ; testuj bit negatywowy, jeśli ustawiony, to był to ostatni znak nazwy

          JR   NC,ALL_CHARS   ; jeśli bit nie ustawiony, kontynuuj wyświetlanie liter nazwy

          POP  BC
          BIT  7,B

          RET  Z

          CP   $1A

          JR   Z,TRAIL_SP

          CP   $38

          RET  C

; $096D : 2413
TRAIL_SP: XOR  A
          SET  0,(IY+$01)      ; zmienna systemowa FLAGS  - Usuń wiodącą wiodącą spację

          JP   PRINT_SP

; $0975 : 2421
TOKEN_ADD: PUSH HL
          LD   HL,TOKENST      ; Adres TOKENÓW
          BIT  7,A             ; sprawdź kod TOKENA

          JR   Z,TEST_HIGH

          AND  $3F

; $097F : 2431
TEST_HIGH: CP  $43

          JR   NC,FOUND

          LD   B,A
          INC  B

; $0985 : 2437
WORDS:    BIT  7,(HL)
          INC  HL

          JR   Z,WORDS

          DJNZ WORDS

          BIT  6,A

          JR   NZ,COMP_FLAG

          CP   $18

; $0992 : 2450
COMP_FLAG: CCF

; $0993 : 2451
FOUND:    LD   B,H
          LD   C,L
          POP  HL

          RET  NC

          LD   A,(BC)
          ADD  A,$E4

          RET

; --------------------------
; PROCEDURA 'JEDNO MIEJSCE'
; --------------------------
; Procedura ta jest wywoływana zawsze, gdy jest potrzebne jedno miejsce w obszarze programu lub w obrębie ekranu.

; $099B : 2459
ONE_SPACE: LD  BC,$0001        ; liczba bajtów do zarezerwowania

; -------------------------
; PROCEDURA 'ZRÓB MIEJSCE'
; -------------------------
; Procedura ta tworzy BC miejsc od pozycji (HL)

; $099E : 2462
MAKE_ROOM: PUSH HL            ; zachowaj HL

          CALL TEST_ROOM      ; sprawdź, czy jest tyle wolnej pamięci

          POP  HL             ; odzyskaj HL

          CALL POINTERS

          LD   HL,(STKEND)    ; pobierz adres końca używanej pamięci
          EX   DE,HL          ; adres ten będzie źródłem
          LDDR                ; przesuń bajty w górę robiąc miejsce

          RET

; ----------------------
; PROCEDURA 'WSKAŹNIKI'
; ----------------------
; Jeśli jakieś wskaźniki muszą być zmieniane, zostaje wywołana ta procedura z wielkością zmiany w BC, a HL określającym wskaźniki do zmiany. Wszystkie
; wskaźniki wskazujące poniżej HL nie zostaną zmienione.

; $09AD : 2477
POINTERS: PUSH AF
          PUSH HL
          LD   HL,D_FILE
          LD   A,$09

; $09B4 : 2484
NEXT_PTR: LD   E,(HL)
          INC  HL
          LD   D,(HL)
          EX   (SP),HL
          AND  A
          SBC  HL,DE
          ADD  HL,DE
          EX   (SP),HL

          JR   NC,PTR_DONE

          PUSH DE
          EX   DE,HL
          ADD  HL,BC
          EX   DE,HL
          LD   (HL),D
          DEC  HL
          LD   (HL),E
          INC  HL
          POP  DE

; $09C8 : 2504
PTR_DONE: INC  HL
          DEC  A

          JR   NZ,NEXT_PTR

          EX   DE,HL
          POP  DE
          POP  AF
          AND  A
          SBC  HL,DE
          LD   B,H
          LD   C,L
          INC  BC
          ADD  HL,DE
          EX   DE,HL

          RET

; -------------------------
; PROCEDURA 'ADRES WIERSZA'
; -------------------------
; Dla danego numeru wiersza w HL procedura wyznacza jego adres w obszarze programu lub adres następnego wiersza, jeśli wskazany wiersz
; nie występuje w programie.

; $09D8 : 2520
LINE_ADDR: PUSH HL            ; zachowaj numer wiersza
          LD   HL,$407D       ; umieść w HL początek obszaru programu w języku BASIC
          LD   D,H            ; skopiuj HL do DE
          LD   E,L

; $09DE : 2526
NEXT_TEST: POP  BC            ; odtwórz numer wiersza w BC

          CALL CP_LINES       ; porównaj numer w BC z numerem w programie, wskazywanym przez HL

          RET  NC             ; jeśli BC <= HL, zakończ - HL wskazuje wiersz

          PUSH BC             ; zachowaj na stosie numer wiersza

          CALL NEXT_ONE       ; przesuń się na początek następnego wiersza

          EX   DE,HL          

          JR   NEXT_TEST      ; kontynuuj szukanie

; -----------------------------------
; PROCEDURA 'PORÓWNAJ NUMERY WIERSZY'
; -----------------------------------
; Numer wiersza w (HL) jest porównywany z numerem w BC. Numery wierszy są przechowywane w porządku odwrotnym do normalnego przechowywania
; liczb 16 bitowych w Z80 - MSB LSB. Dzięki temu procedura porównania nieco się upraszcza.

; $09EA : 2538
CP_LINES: LD   A,(HL)         ; porównaj starsze bajty (HL) z BC
          CP   B

          RET  NZ             ; jeśli różne, wróć

          INC  HL             ; przejdź do młodszych bajtów
          LD   A,(HL)         ; porównaj je
          DEC  HL             ; przywróć HL
          CP   C

          RET

; ---------------------------------------
; PROCEDURA 'NASTĘPNY WIERSZ LUB ZMIENNA'
; ---------------------------------------
; Ta procedura bardzo sprytnie znajduje początek kolejnego wiersza języka BASIC lub początek następnej zmiennej w obszarze zmiennych.
; Numery wierszy są rozpoznawane przez wartość starszego bajtu mniejszą od $40, a różne typy zmiennych przez bity 6 i 7 w ich nazwach.

; $09F2 : 2546
NEXT_ONE: PUSH HL
          LD   A,(HL)
          CP   $40

          JR   C,LINES

          BIT  5,A

          JR   Z,NEXT_O_4

          ADD  A,A

          JP   M,NEXT_FIVE

          CCF

; $0A01 : 2561
NEXT_FIVE: LD  BC,$0005

          JR   NC,NEXT_LETT

          LD   C,$11

; $0A08 : 2568
NEXT_LETT: RLA
          INC  HL
          LD   A,(HL)

          JR   NC,NEXT_LETT

          JR   NEXT_ADD

; $0A0F : 2575
LINES:    INC  HL

; $0A10 : 2576
NEXT_O_4: INC  HL
          LD   C,(HL)
          INC  HL
          LD   B,(HL)
          INC  HL

; $0A15 : 2581
NEXT_ADD: ADD  HL,BC
          POP  DE

; -------------------
; PROCEDURA 'RÓŻNICA'
; -------------------
; Ta procedura znajduje różnicę wartości w parach rejestrów HL i DL. Wynik jest zwracany w parze rejestrów BC

; $0A17 : 2583
DIFFER:   AND  A              ; zeruj przeniesienie
          SBC  HL,DE          ; HL = HL - DE
          LD   B,H            ; różnica do BC
          LD   C,L
          ADD  HL,DE          ; przywróć poprzednią wartość HL
          EX   DE,HL

          RET

; -------------------------
; PROCEDURA 'DOLNE WIERSZE'
; -------------------------
; Procedura czyści dolne wiersze ekranu.

; $0A1F : 2591
LINE_ENDS: LD   B,(IY+$22)    ; zmienna systemowa DF_SZ
          PUSH BC

          CALL B_LINES

          POP  BC
          DEC  B

          JR   B_LINES

; -----------------------
; PROCEDURA ROZKAZU 'CLS'
; -----------------------
; Procedura czyści zawartość ekranu

; $0A2A : 2602
CLS:      LD   B,$18          ; do B załaduj liczbę wierszy na ekranie $18 = 24

; Znajdowany jest adres części ekranu do wyczyszczenia oraz wykonany zostaje test, czy system zawiera mniej, czy więcej 3 1/4 KB pamięci RAM.

; $0A2C : 2604
B_LINES:  RES  1,(IY+$01)     ; zmienna systemowa FLAGS  - Sygnalizuj brak drukarki
          LD   C,$21
          PUSH BC

          CALL LOC_ADDR

          POP  BC
          LD   A,($4005)      ; starszy bajt zmiennej systemowej RAMTOP
          CP   $4D            ; sprawdź, czy ekran jest zwinięty

          JR   C,COLLAPSED    ; jeśli tak, skocz naprzód do COLLAPSED

; W przypadku rozwiniętego pliku obrazu odpowiednia liczba spacji zostaje wydrukowana, aby wyczyścić założoną liczbę wierszy

          SET  7,(IY+$3A)     ; zmienna systemowa S_POSN_y

; $0A42 : 2626
CLEAR_LOC: XOR A              ; przygotuj spację

          CALL PRINT_SP       ; wydrukuj spację

          LD   HL,(S_POSN)
          LD   A,L
          OR   H
          AND  $7E

          JR   NZ,CLEAR_LOC

          JP   LOC_ADDR

; Jeśli plik obrazu jest zwinięty, zostaje użyta instrukcja LDIR do skopiowania znaku nowego wiersza - N/L tyle razy, ile przechowuje rejestr C
; (poprzednio B). Następnie zostaje pobrana zmienna VARS i zwrócona nadmiarowa pamięć w obszarze obrazu.
 
; $0A52 : 2642
COLLAPSED: LD  D,H
          LD   E,L
          DEC  HL
          LD   C,B
          LD   B,$00
          LDIR
          LD   HL,(VARS)

; ------------------------
; PROCEDURA 'ODZYSKIWANIA'
; ------------------------
; Najpierw zmieniane są wskaźniki, a następnie określony obszar pamięci RAM zostaje odzyskany przez użycie instrukcji LDIR do nadpisania
; niechcianej części pamięci RAM.

; $0A5D : 2653
RECLAIM_1: CALL DIFFER

; $0A60 : 2656
RECLAIM_2: PUSH BC
          LD   A,B
          CPL
          LD   B,A
          LD   A,C
          CPL
          LD   C,A
          INC  BC

          CALL POINTERS

          EX   DE,HL
          POP  HL
          ADD  HL,DE
          PUSH DE
          LDIR
          POP  HL

          RET

; ---------------------------------
; PROCEDURA 'NUMERU WIERSZA EDYCJI'
; ---------------------------------
; Ta procedura jest wykorzystywana do określenia, czy bieżący wiersz edycji rozpoczyna się poprawnym numerem od 1 do 9999. Wskaźnik CH_ADD
; jest tymczasowo używany do wskazywania wzdłuż wiersza edycji. Powrót następuje, jeśli jest wykonywany rozkaz INPUT. Do pobrania numeru wiersza
; jest najpierw wywoływana procedura INT_TO_FP, a następnie procedura FP_TO_BC do stworzenia wartości całkowitej w BC. Wartość ta jest dalej
; sprawdzana na zakres 1-9999. Procedura wychodzi poprzez procedurę SET_MEM, która zeruje STKEND.

; $0A73 : 2675
E_LINE_NO: LD  HL,(E_LINE)

          CALL TEMP_PTR2

          RST  18H             ; POBIERZ-ZNAK

          BIT  5,(IY+$2D)      ; zmienna systemowa FLAGX

          RET  NZ

          LD   HL,MEMBOT
          LD   (STKEND),HL

          CALL INT_TO_FP       ; przekształć numer wiersza w liczbę zmiennoprzecinkową na stosie kalkulatora

          CALL FP_TO_BC        ; pobierz liczbę zmiennoprzecinkową ze stosu kalkulatora i umieść ją w BC jako liczbę całkowitą

          JR   C,NO_NUMBER     ; jeśli nie jest to poprawna liczba, skocz do raportu błędu

          LD   HL,$D8F0        ; wartość '-10000'
          ADD  HL,BC           ; sprawdź, czy numer mieści się w zakresie 1-9999

; $0A91 : 2705
NO_NUMBER: JP  C,REPORT_C      ; jeśli zły numer, zgłoś błąd C

          CP   A

          JP   SET_MIN

; -------------------------------------------------
; PROCEDURY WYŚWIETLANIA 'RAPORTU I NUMERU WIERSZA'
; -------------------------------------------------
; Punkt wejścia OUT_NUM jest używany do wyświetlania numerów wierszy z raportem błędu

; $0A98 : 2712
OUT_NUM:  PUSH DE
          PUSH HL
          XOR  A
          BIT  7,B

          JR   NZ,UNITS

          LD   H,B
          LD   L,C
          LD   E,$FF

          JR   THOUSAND

; Punkt wejścia OUT_NO jest używany do wyświetlania numerów wierszy na początku wierszy języka BASIC. 

; $0AA5 : 2725
OUT_NO:   PUSH DE
          LD   D,(HL)
          INC  HL
          LD   E,(HL)
          PUSH HL
          EX   DE,HL
          LD   E,$00          ; ustaw E na wiodącą spację

; $0AAD : 2733
THOUSAND: LD   BC,$FC18

          CALL OUT_DIGIT

          LD   BC,$FF9C

          CALL OUT_DIGIT

          LD   C,$F6

          CALL OUT_DIGIT

          LD   A,L

; $0ABF : 2751
UNITS:    CALL OUT_CODE

          POP  HL
          POP  DE

          RET

; --------------------------
; PROCEDURA 'USUŃ ZE STOSU'
; --------------------------
; Ten podprogram jest używany do wcześniejszego powrotu z procedury, gdy sprawdzana jest składnia. W ZX-81 te same procedury, które wykonują
; polecenia, również sprawdzają składnie w wierszu edycyjnym. Pozwala to dokładnie umieścić znacznik błędu w miejscu, gdzie naruszona jest składnia.
; Sekwencja CALL SYNTAX-Z ; RET Z może być zastąpiona przez wywołanie tego podprogramu, chociaż nie zastąpił on wszystkich wystąpień powyższych
; dwóch instrukcji.

; $0AC5 : 2757
UNSTACK_Z: CALL SYNTAX_Z      ; procedura SYNTAX-Z zwraca ustawiony znacznik zera, gdy sprawdza składnię.

          POP  HL             ; pobierz adres powrotny.

          RET  Z              ; jeśli jest sprawdzana składnia, wróć do poprzedniej procedury wywołującej

          JP   (HL)           ; inaczej skocz do wywołującej procedury, jak zrobiłby to rozkaz RET.

; ----------------------------
; PROCEDURA POLECENIA 'LPRINT'
; ----------------------------
; Bit 1 zmiennej FLAGS jest zawsze ustawiony na 1 przy drukowaniu na drukarce.

; $0ACB : 2763
LPRINT:   SET  1,(IY+$01)     ; zmienna systemowa FLAGS  - informuj o używaniu drukarki

; ---------------------------
; PROCEDURA POLECENIA 'PRINT'
; ---------------------------

; Test, czy jest sam rozkaz PRINT

; $0ACF : 2767
PRINT:    LD   A,(HL)          ; pobierz znak do drukowania
          CP   $76             ; NEWLINE?

          JP   Z,PRINT_END     ; jeśli tak, skocz na koniec procedury

; Tworzona jest teraz pętla, która zajmie się kolejnymi elementami wiersza polecenia PRINT. Najpierw sprawdzane jest, czy kolejny znak
; to przecinek lub średnik - oba posiadają specyficzną funkcję w instrukcji PRINT. 

; $0AD5 : 2773
PRINT_1:  SUB  $1A
          ADC  A,$00

          JR   Z,SPACING

; Teraz sprawdzane jest, czy następnym znakiem jest znak AT.

          CP   $A7

          JR   NZ,NOT_AT       ; jeśli nie, przeskocz naprzód do NOT_AT   

          RST  20H             ; pobierz następny znak

          CALL CLASS_6         ; oblicz następne wyrażenie - numer wiersza

          CP   $1A             ; sprawdź, czy separatorem jest przecinek  

          JP   NZ,REPORT_C     ; jeśli nie, zgłoś błąd C

          RST  20H             ; pobieramy kolejny znak
 
          CALL CLASS_6         ; oblicz następne wyrażenie - numer kolumny

          CALL SYNTAX_ON       ; wykonaj test, czy wiersz jest wykonywany lub czy jest sprawdzana składnia. Jeśli jest tylko sprawdzana
                               ; składnia, zostanie wykonany skok pośredni do PRINT_ON
 
; Numer kolumny i wiersza znajduje się na stosie kalkulatora, jednakże muszą one zostać zamienione miejscami.

          RST  28H             ; KALKULATOR
         .BYTE $01             ; zamień
         .BYTE $34             ; koniec-obliczeń

          CALL STK_TO_BC       ; pobierz do pary rejestrów BC dwie wartości ze stosu kalkulatora 

          CALL PRINT_AT        ; ustaw pozycję wydruku

          JR   PRINT_ON        ; kontynuuj drukowanie

; $0AFA : 2810
NOT_AT:   CP   $A8             ; sprawdź, czy drukowany znak to TAB

          JR   NZ,NOT_TAB      ; jeśli nie, przeskocz wprzód do NOT_TAB 

          RST  20H             ; pobierz kolejny znak
 
          CALL CLASS_6         ; oblicz wartość wyrażenia

          CALL SYNTAX_ON       ; sprawdź, czy jest sprawdzana składnia. Jeśli tak, skocz do PRINT_ON

          CALL STK_TO_A        ; pobierz ze stosu kalkulatora wartość tabulatora do akumulatora
 
          JP   NZ,REPORT_B     ; w przypadku błędu, wyjdź przez RAPORT_B

          AND  $1F             ; inaczej sprawdź poprawność argumentu TAB
          LD   C,A
          BIT  1,(IY+$01)      ; zmienna systemowa FLAGS  - drukarka w użyciu?

          JR   Z,TAB_TEST

          SUB  (IY+$38)        ; zmienna systemowa PR_CC
          SET  7,A
          ADD  A,$3C

          CALL NC,COPY_BUFF

; $0B1E : 2846
TAB_TEST: ADD  A,(IY+$39)      ; zmienna systemowa S_POSN_x
          CP   $21
          LD   A,($403A)       ; zmienna systemowa S_POSN_y
          SBC  A,$01

          CALL TEST_VAL        ; znajdź nowe wartości dla DF_CC i S_POSN

          SET  0,(IY+$01)      ; zmienna systemowa FLAGS  - zlikwiduj wiodącą spację

          JR   PRINT_ON        ; kontynuuj wydruk

; $0B31 : 2865
NOT_TAB:  CALL SCANNING        ; oblicz wartość wyrażenia, wynik umieść na stosie kalkulatora

          CALL PRINT_STK       ; wyświetl ostatnią wartość ze stosu kalkulatora  

; Procedura teraz sprawdza, czy w wierszu polecenia PRINT występuje kolejne wyrażenie

; $0B37 : 2871
PRINT_ON: RST  18H             ; POBIERZ-ZNAK

          SUB  $1A
          ADC  A,$00

          JR   Z,SPACING

          CALL CHECK_END

          JP   PRINT_END

; Tutaj rozdzielane są dwa znaki sterujące wydrukiem - przecinek i średnik

; $0B44 : 2884
SPACING:  CALL NC,FIELD

          RST  20H             ; NASTĘPNY-ZNAK

          CP   $76

          RET  Z

          JP   PRINT_1

; Ten podprogram powoduje skok do PRINT_ON w czasie sprawdzania składni

; $0B4E : 2894
SYNTAX_ON: CALL SYNTAX_Z       ; czy jest sprawdzana składnia?

          RET  NZ              ; jeśli nie, wróć

          POP  HL              ; usuń ze stosu adres powrotu

          JR   PRINT_ON        ; kontynuuj przeglądanie wiersza wydruku

; Procedura drukuje zawartość szczytu stosu

; $0B55 : 2901
PRINT_STK: CALL UNSTACK_Z      ; jeśli jest sprawdzana składnia, nastąpi wyjście z procedury

          BIT  6,(IY+$01)      ; zmienna systemowa FLAGS  - wynik liczbowy czy znakowy?

          CALL Z,STK_FETCH     ; - pobierz ze stosu parametry łańcucha. Łańcuchy i liczby obsługuj osobno 

          JR   Z,PR_STR_4      ; jeśli się udało, skocz do obsługi łańcuchów

          JP   PRINT_FP        ; inaczej obsłuż wydruk liczby.

; Długość łańcucha jest umieszczona w parze rejestrów BC, a adres początku łańcucha znajduje się w parze rejestrów DE.

; $0B64 : 2916
PR_STR_1: LD   A,$0B           ; znak cudzysłowu

; $0B66 : 2918
PR_STR_2: RST  10H             ; PISZ-AKUMULATOR

; $0B67 : 2919
PR_STR_3: LD   DE,(X_PTR)      ; pobierz wskaźnik łańcucha ze zmiennej systemowej X_PTR

; $0B6B : 2923
PR_STR_4: LD   A,B             ; sprawdź, czy koniec łańcucha
          OR   C
          DEC  BC              ; zmniejsz długość łańcucha

          RET  Z               ; powróć, jeśli wydrukowano wszystkie znaki w łańcuchu

          LD   A,(DE)          ; pobierz znak z łańcucha
          INC  DE              ; zwiększ wskaźnik łańcucha  
          LD   (X_PTR),DE      ; zachowaj go w zmiennej systemowej X_PTR
          BIT  6,A             ; sprawdź, czy znak jednoliterowy

          JR   Z,PR_STR_2      ; jeśli tak, drukuj go

          CP   $C0             ; podwójny cudzysłów - drukuj jako zwykły cudzysłów

          JR   Z,PR_STR_1

          PUSH BC              ; zachowaj długość łańcucha

          CALL TOKENS          ; wydrukuj znak wieloliterowy

          POP  BC              ; odtwórz długość łańcucha

          JR   PR_STR_3        ; kontynuuj drukowanie łańcucha

; $0B84 : 2948
PRINT_END: CALL UNSTACK_Z      ; jeśli sprawdzana jest składnia, nastąpi wyjście z procedury

          LD   A,$76           ; inaczej drukuj znak końca wiersza

          RST  10H             ; PISZ-AKUMULATOR

          RET

; Tutaj znajdowana jest właściwa wartość zmiennej systemowej S_POSN oraz w razie potrzeby również PR_CC.

; $0B8B : 2955
FIELD:    CALL UNSTACK_Z       ; wróć przy sprawdzaniu składni

          SET  0,(IY+$01)      ; zmienna systemowa FLAGS  - usuń wiodącą spację
          XOR  A               ; kod spacji

          RST  10H             ; wyświetl spację

          LD   BC,(S_POSN)
          LD   A,C
          BIT  1,(IY+$01)      ; zmienna systemowa FLAGS  - drukarka w użyciu?

          JR   Z,CENTRE

          LD   A,$5D
          SUB  (IY+$38)        ; zmienna systemowa PR_CC

; $0BA4 : 2980
CENTRE:   LD   C,$11
          CP   C

          JR   NC,RIGHT

          LD   C,$01

; $0BAB : 2987
RIGHT:    CALL SET_FIELD

          RET

; ---------------------------------
; PROCEDURY POLECEŃ 'PLOT I UNPLOT'
; ---------------------------------

; $0BAF : 2991
PLOT_UNP: CALL STK_TO_BC

          LD   (COORDS),BC
          LD   A,$2B
          SUB  B

          JP   C,REPORT_B

          LD   B,A
          LD   A,$01
          SRA  B

          JR   NC,COLUMNS

          LD   A,$04

; $0BC5 : 3013
COLUMNS:  SRA  C

          JR   NC,FIND_ADDR

          RLCA

; $0BCA : 3018
FIND_ADDR: PUSH AF

          CALL PRINT_AT

          LD   A,(HL)
          RLCA
          CP   $10

          JR   NC,TABLE_PTR

          RRCA

          JR   NC,SQ_SAVED

          XOR  $8F

; $0BD9 : 3033
SQ_SAVED: LD   B,A

; $0BDA : 3034
TABLE_PTR: LD  DE,P_UNPLOT
          LD   A,(T_ADDR)
          SUB  E

          JP   M,PLOT

          POP  AF
          CPL
          AND  B

          JR   UNPLOT

; $0BE9 : 3049
PLOT:     POP  AF
          OR   B

; $0BEB : 3051
UNPLOT:   CP   $08

          JR   C,PLOT_END

          XOR  $8F

; $0BF1 : 3057
PLOT_END: EXX

          RST  10H            ; PISZ-AKUMULATOR

          EXX

          RET

; -----------------------
; PROCEDURA 'STACK-TO-BC'
; -----------------------
; Procedura pobiera dwie liczby zmiennoprzecinkowe ze stosu kalkulatora, zamienia je na liczby całkowite o zakresie 0-255 i umieszcza
; w parze rejestrów BC

; $0BF5 : 3061
STK_TO_BC: CALL STK_TO_A

          LD   B,A
          PUSH BC
 
          CALL STK_TO_A        

          LD   E,C
          POP  BC
          LD   D,C
          LD   C,A

          RET

; ----------------------
; PROCEDURA 'STACK-TO-A'
; ----------------------
; Procedura pobiera liczbę zmiennoprzecinkową ze stosu kalkulatora, zamienia ją na liczbę całkowitą o zakresie 0-255 i umieszcza w rejestrze A

; $0C02 : 3074
STK_TO_A: CALL FP_TO_A

          JP   C,REPORT_B

          LD   C,$01

          RET  Z

          LD   C,$FF

          RET

; ------------------------------
; PROCEDURA 'PRZEWIJANIA EKRANU'
; ------------------------------

; $0C0E : 3086
SCROLL:   LD   B,(IY+$22)      ; zmienna systemowa DF_SZ
          LD   C,$21

          CALL LOC_ADDR

          CALL ONE_SPACE

          LD   A,(HL)
          LD   (DE),A
          INC  (IY+$3A)        ; zmienna systemowa S_POSN_y
          LD   HL,(D_FILE)
          INC  HL
          LD   D,H
          LD   E,L
          CPIR

          JP   RECLAIM_1

; -----------------
; TABLICE 'SKŁADNI'
; -----------------

; i) TAblica przesunięć

; $0C29 : 3113
OFFSET_T:.BYTE P_LPRINT - $    ; 8B przesunięcie pod adres P-LPRINT
         .BYTE P_LLIST  - $    ; 8D przesunięcie pod adres P-LLIST
         .BYTE P_STOP   - $    ; 2D przesunięcie pod adres P-STOP
         .BYTE P_SLOW   - $    ; 7F przesunięcie pod adres P-SLOW
         .BYTE P_FAST   - $    ; 81 przesunięcie pod adres P-FAST
         .BYTE P_NEW    - $    ; 49 przesunięcie pod adres P-NEW
         .BYTE P_SCROLL - $    ; 75 przesunięcie pod adres P-SCROLL
         .BYTE P_CONT   - $    ; 5F przesunięcie pod adres P-CONT
         .BYTE P_DIM    - $    ; 40 przesunięcie pod adres P-DIM
         .BYTE P_REM    - $    ; 42 przesunięcie pod adres P-REM
         .BYTE P_FOR    - $    ; 2B przesunięcie pod adres P-FOR
         .BYTE P_GOTO   - $    ; 17 przesunięcie pod adres P-GOTO
         .BYTE P_GOSUB  - $    ; 1F przesunięcie pod adres P-GOSUB
         .BYTE P_INPUT  - $    ; 37 przesunięcie pod adres P-INPUT
         .BYTE P_LOAD   - $    ; 52 przesunięcie pod adres P-LOAD
         .BYTE P_LIST   - $    ; 45 przesunięcie pod adres P-LIST
         .BYTE P_LET    - $    ; 0F przesunięcie pod adres P-LET
         .BYTE P_PAUSE  - $    ; 6D przesunięcie pod adres P-PAUSE
         .BYTE P_NEXT   - $    ; 2B przesunięcie pod adres P-NEXT
         .BYTE P_POKE   - $    ; 44 przesunięcie pod adres P-POKE
         .BYTE P_PRINT  - $    ; 2D przesunięcie pod adres P-PRINT
         .BYTE P_PLOT   - $    ; 5A przesunięcie pod adres P-PLOT
         .BYTE P_RUN    - $    ; 3B przesunięcie pod adres P-RUN
         .BYTE P_SAVE   - $    ; 4C przesunięcie pod adres P-SAVE
         .BYTE P_RAND   - $    ; 45 przesunięcie pod adres P-RAND
         .BYTE P_IF     - $    ; 0D przesunięcie pod adres P-IF
         .BYTE P_CLS    - $    ; 52 przesunięcie pod adres P-CLS
         .BYTE P_UNPLOT - $    ; 5A przesunięcie pod adres P-UNPLOT
         .BYTE P_CLEAR  - $    ; 4D przesunięcie pod adres P-CLEAR
         .BYTE P_RETURN - $    ; 15 przesunięcie pod adres P-RETURN
         .BYTE P_COPY   - $    ; 6A przesunięcie pod adres P-COPY

; ii) Tablica parametrów

; $0C48 : 3144
P_LET:   .BYTE $01            ; Klasa-01 - wymagana zmienna
         .BYTE $14            ; Separator:  '='
         .BYTE $02            ; Klasa-02 - musi wystąpić wyrażenie liczbowe lub łańcuchowe

; $0C4B : 3147
P_GOTO:  .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD GOTO           ; Adres: $0E81; Adres: GOTO

; $0C4F : 3151
P_IF:    .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $DE            ; Separator:  'THEN'
         .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD IF             ; Adres: $0DAB; Adres: IF

; $0C54 : 3156
P_GOSUB: .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD GOSUB          ; Adres: $0EB5; Adres: GOSUB

; $0C58 : 3160
P_STOP:  .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD STOP           ; Adres: $0CDC; Adres: STOP

; $0C5B : 3163
P_RETURN:.BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD RETURN         ; Adres: $0ED8; Adres: RETURN

; $0C5E : 3166
P_FOR:   .BYTE $04            ; Klasa-04 - musi wystąpić zmienna jednoliterowa
         .BYTE $14            ; Separator:  '='
         .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $DF            ; Separator:  'TO'
         .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD FOR            ; Adres: $0DB9; Adres: FOR

; $0C66 : 3174
P_NEXT:  .BYTE $04            ; Klasa-04 - musi wystąpić zmienna jednoliterowa
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD NEXT           ; Adres: $0E2E; Adres: NEXT

; $0C6A : 3178
P_PRINT: .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD PRINT          ; Adres: $0ACF; Adres: PRINT

; $0C6D : 3181
P_INPUT: .BYTE $01            ; Klasa-01 - wymagana zmienna
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD INPUT          ; Adres: $0EE9; Adres: INPUT

; $0C71 : 3185
P_DIM:   .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD DIM            ; Adres: $1409; Adres: DIM

; $0C74 : 3188
P_REM:   .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD REM            ; Adres: $0D6A; Adres: REM

; $0C77 : 3191
P_NEW:   .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD NEW            ; Adres: $03C3; Adres: NEW

; $0C7A : 3194
P_RUN:   .BYTE $03            ; Klasa-03 - może wystąpić wyrażenie liczbowe, inaczej wartość zero
         .WORD RUN            ; Adres: $0EAF; Adres: RUN

; $0C7D : 3197
P_LIST:  .BYTE $03            ; Klasa-03 - może wystąpić wyrażenie liczbowe, inaczej wartość zero
         .WORD LIST           ; Adres: $0730; Adres: LIST

; $0C80 : 3200
P_POKE:  .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $1A            ; Separator:  ','
         .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD POKE           ; Adres: $0E92; Adres: POKE

; $0C86 : 3206
P_RAND:  .BYTE $03            ; Klasa-03 - może wystąpić wyrażenie liczbowe, inaczej wartość zero
         .WORD RAND           ; Adres: $0E6C; Adres: RAND

; $0C89 : 3209
P_LOAD:  .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD LOAD           ; Adres: $0340; Adres: LOAD

; $0C8C : 3212
P_SAVE:  .BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD SAVE           ; Adres: $02F6; Adres: SAVE

; $0C8F : 3215
P_CONT:  .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD CONT           ; Adres: $0E7C; Adres: CONT

; $0C92 : 3218
P_CLEAR: .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD CLEAR          ; Adres: $149A; Adres: CLEAR

; $0C95 : 3221
P_CLS:   .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD CLS            ; Adres: $0A2A; Adres: CLS

; $0C98 : 3224
P_PLOT:  .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $1A            ; Separator:  ','
         .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD PLOT_UNP       ; Adres: $0BAF; Adres: PLOT/UNP

; $0C9E : 3230
P_UNPLOT:.BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $1A            ; Separator:  ','
         .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD PLOT_UNP       ; Adres: $0BAF; Adres: PLOT/UNP

; $0CA4 : 3236
P_SCROLL:.BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD SCROLL         ; Adres: $0C0E; Adres: SCROLL

; $0CA7 : 3239
P_PAUSE: .BYTE $06            ; Klasa-06 - musi wystąpić wyrażenie liczbowe
         .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD PAUSE          ; Adres: $0F32; Adres: PAUSE

; $0CAB : 3243
P_SLOW:  .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD SLOW           ; Adres: $0F2B; Adres: SLOW

; $0CAE : 3246
P_FAST:  .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD FAST           ; Adres: $0F23; Adres: FAST

; $0CB1 : 3249
P_COPY:  .BYTE $00            ; Klasa-00 - brak dalszych parametrów
         .WORD COPY           ; Adres: $0869; Adres: COPY

; $0CB4 : 3252
P_LPRINT:.BYTE $05            ; Klasa-05 - zmienna składnia w całości sprawdzana przez procedurę
         .WORD LPRINT         ; Adres: $0ACB; Adres: LPRINT

; $0CB7 : 3255
P_LLIST: .BYTE $03            ; Klasa-03 - może wystąpić wyrażenie liczbowe, inaczej wartość zero
         .WORD LLIST          ; Adres: $072C; Adres: LLIST

; ------------------------------
; PROCEDURA 'SKANOWANIE WIERSZA'
; ------------------------------

; $0CBA : 3258
LINE_SCAN: LD   (IY+$01),$01   ; zmienna systemowa FLAGS

          CALL E_LINE_NO

; $0CC1 : 3265
LINE_RUN:  CALL SET_MIN

          LD   HL,ERR_NR
          LD   (HL),$FF
          LD   HL,FLAGX
          BIT  5,(HL)

          JR   Z,LINE_NULL

          CP   $E3            ; 'STOP' ?
          LD   A,(HL)

          JP   NZ,INPUT_REP

          CALL SYNTAX_Z

          RET  Z


          RST  08H            ; ERROR-1
         .BYTE $0C            ; Raport Błędu: PRZERWANIE - CONT powtarza

; --------------------------
; PROCEDURA POLECENIA 'STOP'
; --------------------------

; $0CDC : 3292
STOP:     RST  08H            ; ERROR-1
         .BYTE $08            ; Raport Błędu: polecenie STOP

; przetwarzanie wiersza jest kontynuowane sprawdzeniem, czy następują jedynie spacje z kończącym je znakiem NEWLINE. Rozkaz IF również zagląda tutaj,
; jeśli wyrażenie testowe ma wartość true, aby wykonać polecenie za THEN, lecz polecenia tego wcale nie musi być, zatem
; 10 IF 1=1 THEN
; przechodzi test składniowy na wszystkich komputerach ZX.

; $0CDE : 3294
LINE_NULL: RST 18H            ; POBIERZ-ZNAK

          LD   B,$00          ; przygotuj wcześniej indeks
          CP   $76            ; porównaj z NEWLINE.

          RET  Z              ; wróć, jeśli jest równe.

          LD   C,A            ; przenieś znak do C.

          RST  20H            ; NASTĘPNY-ZNAK - przesuwa na kolejną pozycję.

          LD   A,C            ; znak do A
          SUB  $E1            ; odejmij kod 'LPRINT' - najmniejszy kod rozkazu.

          JR   C,REPORT_C2    ; jeśli mniejszy, skocz do REPORT-C2

          LD   C,A            ; zmniejszony kod do C
          LD   HL,OFFSET_T    ; ustaw w HL adres tablicy przesunięć.
          ADD  HL,BC          ; indeksuj w tablicy.
          LD   C,(HL)         ; pobierz przesunięcie
          ADD  HL,BC          ; indeksuj w tablicy parametrów.

          JR   GET_PARAM

; $0CF4 : 3316
SCAN_LOOP: LD  HL,(T_ADDR)

; -> Punkt wejścia do pętli skanującej

; $0CF7 : 3319
GET_PARAM: LD  A,(HL)
          INC  HL
          LD   (T_ADDR),HL

          LD   BC,SCAN_LOOP    ; Adres: SCAN-LOOP
          PUSH BC              ; jest umieszczany na stosie maszynowym.

          LD   C,A
          CP   $0B

          JR   NC,SEPARATOR

          LD   HL,CLASS_TBL    ; adres tablicy klas.
          LD   B,$00
          ADD  HL,BC
          LD   C,(HL)
          ADD  HL,BC
          PUSH HL

          RST  18H             ; POBIERZ-ZNAK

          RET                  ; pośredni skok do procedury klas a poprzez późniejszy RET do SCAN-LOOP

; ---------------------
; PROCEDURA 'SEPARATOR'
; ---------------------

; $0D10 : 3344
SEPARATOR: RST  18H            ; POBIERZ-ZNAK

          CP   C

          JR   NZ,REPORT_C2    ; REPORT-C2 - Nonsens w języku BASIC

          RST  20H             ; NASTĘPNY-ZNAK

          RET


; ----------------------
; TABLICA 'KLAS POLECEŃ'
; ----------------------
;

; $0D16 : 3350
CLASS_TBL:.BYTE CLASS_0 - $     ; 17 przesunięcie pod adres CLASS-0
          .BYTE CLASS_1 - $     ; 25 przesunięcie pod adres CLASS-1
          .BYTE CLASS_2 - $     ; 53 przesunięcie pod adres CLASS-2
          .BYTE CLASS_3 - $     ; 0F przesunięcie pod adres CLASS-3
          .BYTE CLASS_4 - $     ; 6B przesunięcie pod adres CLASS-4
          .BYTE CLASS_5 - $     ; 13 przesunięcie pod adres CLASS-5
          .BYTE CLASS_6 - $     ; 76 przesunięcie pod adres CLASS-6

; --------------------------
; PROCEDURA 'SPRAWDŹ KONIEC'
; --------------------------
; Sprawdź koniec polecenia i czy nie ma nadmiarowych znaków za poprawnie sparsowanym poleceniem. Ponieważ w wierszu dozwolone jest tylko jedno
; polecenie, to jedynym dozwolonym znakiem za rozkazem może być NEWLINE.

; $0D1D : 3357
CHECK_END: CALL SYNTAX_Z

          RET  NZ             ; w czasie wykonania wróć.

          POP  BC             ; inaczej usuń adres powrotny.

; $0D22 : 3362
CHECK_2:  LD   A,(HL)         ; pobierz znak.
          CP   $76            ; sprawdź, czy NEWLINE.

          RET  Z              ; wróć, jeśli tak.

; $0D26 : 3366
REPORT_C2: JR  REPORT_C       ; REPORT-C2 - Nonsens w języku BASIC

; -------------------------
; KLASY ROZKAZÓW 03, 00, 05
; -------------------------

; $0D28 : 3368
CLASS_3:  CP   $76

          CALL NO_TO_STK

; $0D2D : 3373
CLASS_0:  CP   A

; $0D2E : 3374
CLASS_5:  POP  BC

          CALL Z,CHECK_END

          EX   DE,HL
          LD   HL,(T_ADDR)
          LD   C,(HL)
          INC  HL
          LD   B,(HL)
          EX   DE,HL

; $0D3A : 3386
CLASS_END: PUSH BC

          RET

; -----------------------------
; KLASY ROZKAZÓW 01, 02, 04, 06
; -----------------------------

; $0D3C : 3388
CLASS_1:  CALL LOOK_VARS

; $0D3F : 3391
CLASS_4_2: LD  (IY+$2D),$00    ; zmienna systemowa FLAGX

          JR   NC,SET_STK

          SET  1,(IY+$2D)      ; zmienna systemowa FLAGX

          JR   NZ,SET_STRLN

; $0D4B : 3403
REPORT_2: RST  08H             ; ERROR-1
         .BYTE $01             ; Raport Błędu: Zmienna nie znaleziona

; $0D4D : 3405
SET_STK:  CALL Z,STK_VAR

          BIT  6,(IY+$01)      ; zmienna systemowa FLAGS  - wynik liczbowy czy znakowy?

          JR   NZ,SET_STRLN

          XOR  A

          CALL SYNTAX_Z

          CALL NZ,STK_FETCH

          LD   HL,FLAGX
          OR   (HL)
          LD   (HL),A
          EX   DE,HL

; $0D63 : 3427
SET_STRLN: LD  (STRLEN),BC
          LD   (DEST),HL

; PROCEDURA POLECENIA 'REM'

; $0D6A : 3434
REM:      RET

; $0D6B : 3435
CLASS_2:  POP  BC
          LD   A,(FLAGS)

; $0D6F : 3439
INPUT_REP: PUSH AF

          CALL SCANNING

          POP  AF
          LD   BC,LET
          LD   D,(IY+$01)      ; zmienna systemowa FLAGS
          XOR  D
          AND  $40

          JR   NZ,REPORT_C

          BIT  7,D

          JR   NZ,CLASS_END

          JR   CHECK_2

; $0D85 : 3461
CLASS_4:  CALL LOOK_VARS

          PUSH AF
          LD   A,C
          OR   $9F
          INC  A

          JR   NZ,REPORT_C

          POP  AF

          JR   CLASS_4_2

; $0D92 : 3474
CLASS_6:  CALL SCANNING

          BIT  6,(IY+$01)      ; zmienna systemowa FLAGS  - wynik liczbowy czy znakowy?

          RET  NZ

; $0D9A : 3482
REPORT_C: RST  08H             ; ERROR-1
         .BYTE $0B             ; Raport błędu - Nonsens w języku BASIC

; --------------------------
; PROCEDURA 'LICZBA NA STOS'
; --------------------------

; $0D9C : 3484
NO_TO_STK: JR  NZ,CLASS_6      ; wróć do CLASS-6 z niezerową liczbą.

          CALL SYNTAX_Z

          RET  Z               ; wróć, jeśli sprawdza się składnię.

; w czasie wykonania umieszczane jest na stosie kalkulatora zero, jako wartość standardowa.

          RST  28H             ; KALKULATOR
         .BYTE $A0             ; na-stos-zero
         .BYTE $34             ; koniec-obliczeń

          RET

; ----------------------
; PROCEDURA 'SKŁADNIA-Z'
; ----------------------
; Ta procedura wraca z ustawionym znacznikiem Z, jeśli sprawdzana jest składnia. Wywołanie tej procedury zajmuje 3 bajty w porównaniu z 4,
; gdyby test był wykonywany na miejscu. Oczywiście cierpi na tym szybkość działania ZX-81.

; $0DA6 : 3494
SYNTAX_Z: BIT  7,(IY+$01)      ; testuj FLAGS  - jedynie sprawdzana składnia?

          RET

; ------------------------
; PROCEDURA POLECENIA 'IF'
; ------------------------
; W czasie wykonania procedury klas wyliczyły wartość warunku i wynik, prawda lub fałsz, znajduje się na stosie kalkulatora.

; $0DAB : 3499
IF:       CALL SYNTAX_Z        ; wyjdź przy sprawdzaniu składni

          JR   Z,IF_END        ; naprzód do IF-END w przypadku sprawdzania składni

; inaczej usuń wartość logiczną ze stosu kalkulatora.

          RST  28H             ; KALKULATOR
         .BYTE $02             ; usuń
         .BYTE $34             ; koniec-obliczeń

; rejestr DE wskazóje wykładnik wartości zmiennoprzecinkowej.

          LD   A,(DE)          ; pobierz wykładnik
          AND  A               ; sprawdź, czy zero - FALSE.

          RET  Z               ; wróć, jeśli tak.

; $0DB6 : 3510
IF_END:   JP   LINE_NULL       ; skocz wstecz do LINE-NULL

; -------------------------
; PROCEDURA POLECENIA 'FOR'
; -------------------------

; $0DB9 : 3513
FOR:      CP   $E0             ; czy bieżący znak jest poleceniem 'STEP' ?

          JR   NZ,F_USE_ONE    ; jeśli nie, to naprzód do F-USE-ONE

          RST  20H             ; NASTĘPNY-ZNAK

          CALL CLASS_6         ; procedura CLASS-6 umieszcza liczbę na stosie

          CALL CHECK_END

          JR   F_REORDER

; $0DC6 : 3526
F_USE_ONE: CALL CHECK_END

          RST  28H             ; KALKULATOR
         .BYTE $A1             ; jeden-na-stos
         .BYTE $34             ; koniec-obliczeń

; $0DCC : 3532
F_REORDER: RST 28H             ; KALKULATOR            v, l, s.
         .BYTE $C0             ; stos-do-pamięci-0      v, l, s.
         .BYTE $02             ; usuń                  v, l.
         .BYTE $01             ; zamień                l, v.
         .BYTE $E0             ; na-stos-paimięć-0      l, v, s.
         .BYTE $01             ; zamień                l, s, v.
         .BYTE $34             ; koniec-obliczeń        l, s, v.

          CALL LET

          LD   (MEM),HL        ; ustaw MEM na adresowaną zmienną.
          DEC  HL              ; wskaż na znak.
          LD   A,(HL)
          SET  7,(HL)
          LD   BC,$0006
          ADD  HL,BC
          RLCA

          JR   C,F_LMT_STP

          SLA  C

          CALL MAKE_ROOM

          INC  HL

; $0DEA : 3562
F_LMT_STP: PUSH HL
          RST  28H             ; KALKULATOR
         .BYTE $02             ; usuń
         .BYTE $02             ; usuń
         .BYTE $34             ; koniec-obliczeń

          POP  HL
          EX   DE,HL

          LD   C,$0A           ; ma być przesunięte dziesięć bajtów.
          LDIR                 ; kopiuj bajty

          LD   HL,(PPC)        ; ustaw HL na zmienną systemową PPC - bieżący wiersz.
          EX   DE,HL           ; przenieś do DE, wskaźnik zmiennej do HL.
          INC  DE              ; początek pętli będzie na następnym wierszu
          LD   (HL),E
          INC  HL
          LD   (HL),D

          CALL NEXT_LOOP       ; procedura NEXT-LOOP zajmuje się wstępnym obiegiem.
 
          RET  NC              ; jeśli możliwe, wróć.

; inaczej program wykonuje się od punktu za pierwszym pasującym rozkazem NEXT.

          BIT  7,(IY+$08)      ; sprawdź starszy bajt PPC

          RET  NZ              ; wróć, jeśli powyżej 32767 ???

          LD   B,(IY+$2E)      ; pobierz nazwę zmiennej ze STRLEN
          RES  6,B             ; zrób ją prawdziwą literą.
          LD   HL,(NXTLIN)     ; ustaw HL z NXTLIN

; teraz wejdź do pętli szukającej pasującego NEXT.

; $0E0E : 3598
NXTLIN_NO: LD  A,(HL)          ; pobierz starszy bajt numeru wiersza.
          AND  $C0             ; wymaskuj dolne bity $3F

          JR   NZ,FOR_END      ; skocz na koniec do FOR-END

          PUSH BC              ; zachowaj literę

          CALL NEXT_ONE        ; procedura NEXT-ONE znajdzie następny wiersz.

          POP  BC              ; odzyskaj literę

          INC  HL              ; przejdź nad numerem wiersza
          INC  HL              ; aż do długości
          INC  HL              ; wiersza

          CALL TEMP_PTR1       ; procedura TEMP-PTR1 ustawia CH_ADD

          RST  18H             ; POBIERZ-ZNAK

          CP   $F3             ; porównaj z 'NEXT'.
          EX   DE,HL           ; następny wiersz do HL.

          JR   NZ,NXTLIN_NO    ; jeśli brak zgodności, wstecz do NXTLIN-NO

          EX   DE,HL           ; odtwórz wskaźnik

          RST  20H             ; NASTĘPNY-ZNAK idzie naprzód i pobiera literę do A.

          EX   DE,HL           ; zachowaj wskaźnik
          CP   B               ; porównaj z nazwą zmiennej.

          JR   NZ,NXTLIN_NO    ; jeśli nie pasuje, wróć do NXTLIN-NO

; $0E2A : 3626
FOR_END:  LD   (NXTLIN),HL     ; uaktualnij zmienną systemową NXTLIN

          RET

; --------------------------
; PROCEDURA POLECENIA 'NEXT'
; --------------------------

; $0E2E : 3630
NEXT:     BIT  1,(IY+$2D)      ; zmienna systemowa FLAGX

          JP   NZ,REPORT_2

          LD   HL,(DEST)
          BIT  7,(HL)

          JR   Z,REPORT_1

          INC  HL
          LD   (MEM),HL

          RST  28H            ; KALKULATOR
         .BYTE $E0            ; na-stos-paimięć-0
         .BYTE $E2            ; na-stos-paimięć-2
         .BYTE $0F            ; dodaj
         .BYTE $C0            ; stos-do-pamięci-0
         .BYTE $02            ; usuń
         .BYTE $34            ; koniec-obliczeń

          CALL NEXT_LOOP

          RET  C

          LD   HL,(MEM)
          LD   DE,$000F
          ADD  HL,DE
          LD   E,(HL)
          INC  HL
          LD   D,(HL)
          EX   DE,HL

          JR   GOTO_2

; $0E58 : 3672
REPORT_1: RST  08H            ; ERROR-1
         .BYTE $00            ; Raport Błędu: NEXT bez FOR

; ----------------------
; PROCEDURA 'PĘTLA NEXT'
; ----------------------

; $0E5A : 3674
NEXT_LOOP: RST 28H            ; KALKULATOR
         .BYTE $E1            ; na-stos-paimięć-1
         .BYTE $E0            ; na-stos-paimięć-0
         .BYTE $E2            ; na-stos-paimięć-2
         .BYTE $32            ; mniej-niż-0
         .BYTE $00            ; skocz-przy-prawdzie
         .BYTE $02            ; do $0E62, LMT-V-VAL

         .BYTE $01            ; zamień

; $0E62 : 3682
LMT_V_VAL: .BYTE $03          ; odejmij
         .BYTE $33            ; większe-niż-0
         .BYTE $00            ; skocz-przy-prawdzie
         .BYTE $04            ; do $0E69, IMPOSS

         .BYTE $34            ; koniec-obliczeń

          AND  A              ; zeruj znacznik przeniesienia

          RET

; $0E69 : 3689
IMPOSS:  .BYTE $34            ; koniec-obliczeń

          SCF

          RET

; --------------------------
; PROCEDURA POLECENIA 'RAND'
; --------------------------
; Z ZX-81 rozkaz nazywa się RAND, w ZX-Spectrum jest to Randomize. W obu tych przypadkach procedura obsługi jest identyczna - ustawia zmienną
; systemową SEED dostarczoną wartością lub wartością opartą na czasie, jeśli nie dostarczono żadnej liczby lub liczba ta jest równa zero.

; $0E6C : 3692
RAND:     CALL FIND_INT

          LD   A,B             ; sprawdź, czy wartość jest równa zero
          OR   C

          JR   NZ,SET_SEED     ; naprzód do SET-SEED, jeśli różne od zera

          LD   BC,(FRAMES)     ; inaczej pobierz zmienną systemową FRAMES

; $0E77 : 3703
SET_SEED: LD   (SEED),BC       ; uaktualnij zmienną systemową SEED

          RET

; --------------------------
; PROCEDURA POLECENIA 'CONT'
; --------------------------
; Kolejny skrócony rozkaz. Miejsca w ROM musiało bardzo brakować. Kontynuuje od wiersza, który był ustawiony w momencie naciśnięcia klawisza BREAK.
; Po STOP jest to następny wiersz, inaczej program by się od razu zatrzymał.

; $0E7C : 3708
CONT:     LD   HL,(OLDPPC)     ; ustaw HL ze zmiennej systemowej OLDPPC

          JR   GOTO_2

; --------------------------
; PROCEDURA POLECENIA 'GOTO'
; --------------------------
; Nazwa również ucierpiała z powodu braku miejsca w ROM i nie ma w niej spacji pomiędzy GO i TO, jak w ZX-Spectrum. To samo dotyczy również
; polecenia GOSUB.

; $0E81 : 3713
GOTO:     CALL FIND_INT

          LD   H,B
          LD   L,C

; $0E86 : 3718
GOTO_2:   LD   A,H
          CP   $F0

          JR   NC,REPORT_B

          CALL LINE_ADDR

          LD   (NXTLIN),HL

          RET

; --------------------------
; PROCEDURA POLECENIA 'POKE'
; --------------------------

; $0E92 : 3730
POKE:     CALL FP_TO_A

          JR   C,REPORT_B      ; naprzód z nadmiarem do REPORT-B

          JR   Z,POKE_SAVE     ; jeśli dodatnie, naprzód do POKE-SAVE

          NEG                  ; zmień znak na przeciwny

; $0E9B : 3739
POKE_SAVE: PUSH AF             ; zachowaj wartość

          CALL FIND_INT        ; procedura FIND-INT pobiera adres do BC wywołując procedurę błędu przy nadmiarze lub wartości ujemnej

          POP  AF              ; odzyskaj wartość

; Uwaga, następne dwie instrukcje są pozostałością po ZX80 i nie powinno ich tytaj być, ale są.

          BIT  7,(IY+$00)      ; sprawdź ERR_NR - czy wciąż $FF ?

          RET  Z               ; jeśli nie, wróć z błędem.

          LD   (BC),A          ; wpisz wartość pod wskazany adres.

          RET

; -----------------------------------
; PROCEDURA 'ZNAJDŹ LICZBĘ CAŁKOWITĄ'
; -----------------------------------

; $0EA7 : 3751
FIND_INT: CALL FP_TO_BC

          JR   C,REPORT_B     ; naprzód z nadmiarem do REPORT-B

          RET  Z              ; wróć, jeśli dodatnie (0-65535).

; $0EAD : 3757
REPORT_B: RST  08H            ; ERROR-1
         .BYTE $0A            ; Raport Błędu: Liczba całkowita poza zakresem

; -------------------------
; PROCEDURA POLECENIA 'RUN'
; -------------------------

; $0EAF : 3759
RUN:      CALL GOTO

          JP   CLEAR

; ---------------------------
; PROCEDURA POLECENIA 'GOSUB'
; ---------------------------

; $0EB5 : 3765
GOSUB:    LD   HL,(PPC)
          INC  HL
          EX   (SP),HL
          PUSH  HL
          LD   (ERR_SP),SP     ; ustaw wskaźnik stosu błędu - ERR_SP

          CALL GOTO

          LD   BC,$0006

; ---------------------------
; PROCEDURA 'SPRAWDŹ MIEJSCE'
; ---------------------------
;

; $0EC5 : 3781
TEST_ROOM: LD  HL,(STKEND)
          ADD  HL,BC

          JR   C,REPORT_4

          EX   DE,HL
          LD   HL,$0024
          ADD  HL,DE
          SBC  HL,SP

          RET  C

; $0ED3 : 3795
REPORT_4: LD   L,$03

          JP   ERROR_3

; ----------------------------
; PROCEDURA POLECENIA 'RETURN'
; ----------------------------

; $0ED8 : 3800
RETURN:   POP  HL
          EX   (SP),HL
          LD   A,H
          CP   $3E

          JR   Z,REPORT_7

          LD   (ERR_SP),SP

          JR   GOTO_2         ; wstecz do GOTO-2

; $0EE5 : 3813
REPORT_7: EX   (SP),HL
          PUSH HL

          RST  08H            ; ERROR-1
         .BYTE $06            ; Raport Błędu: RETURN bez GOSUB

; ---------------------------
; PROCEDURA POLECENIA 'INPUT'
; ---------------------------

; $0EE9 : 3817
INPUT:    BIT  7,(IY+$08)     ; starszy bajt zmiennej systemowej PPC_hi

          JR   NZ,REPORT_8

          CALL X_TEMP

          LD   HL,FLAGX
          SET  5,(HL)
          RES  6,(HL)
          LD   A,(FLAGS)
          AND  $40
          LD   BC,$0002

          JR   NZ,PROMPT

          LD   C,$04

; $0F05 : 3845
PROMPT:   OR   (HL)
          LD   (HL),A

          RST  30H            ; BC-MIEJSC

          LD   (HL),$76
          LD   A,C
          RRCA
          RRCA

          JR   C,ENTER_CUR

          LD   A,$0B
          LD   (DE),A
          DEC  HL
          LD   (HL),A

; $0F14 : 3860
ENTER_CUR: DEC HL
          LD   (HL),$7F
          LD   HL,(S_POSN)
          LD   (T_ADDR),HL
          POP  HL

          JP   LOWER

; $0F21 : 3873
REPORT_8: RST  08H            ; ERROR-1
         .BYTE $07            ; Raport Błędu: Koniec pliku

; ---------------------------
; PROCEDURA POLECENIA 'PAUSE'
; ---------------------------

; $0F23 : 3875
FAST:     CALL SET_FAST

          RES  6,(IY+$3B)      ; zmienna systemowa CDFLAG

          RET

; --------------------------
; PROCEDURA POLECENIA 'SLOW'
; --------------------------
;

; $0F2B : 3883
SLOW:     SET  6,(IY+$3B)      ; zmienna systemowa CDFLAG

          JP   SLOW_FAST

; ---------------------------
; PROCEDURA POLECENIA 'PAUSE'
; ---------------------------

; $0F32 : 3890
PAUSE:    CALL FIND_INT

          CALL SET_FAST

          LD   H,B
          LD   L,C

          CALL DISPLAY_P

          LD   (IY+$35),$FF    ; starszy bajt zmiennej systemowej FRAMES

          CALL SLOW_FAST

          JR   DEBOUNCE

; -------------------
; PROCEDURA 'PRZERWA'
; -------------------
;

; $0F46 : 3910
BREAK_1:  LD   A,$7F          ; czytaj port $7FFE - klawisze B,N,M,.,SPACJA.
          IN   A,($FE)
          RRA                 ; jeśli naciśnięto spację, będzie ustawione przeniesienie

; --------------------
; PROCEDURA 'DEBOUNCE'
; --------------------
;

; $0F4B : 3915
DEBOUNCE: RES  0,(IY+$3B)     ; uaktualnij zmienną systemową CDFLAG
          LD   A,$FF
          LD   (DBOUNC),A

          RET

; ----------------------
; PROCEDURA 'SKANOWANIA'
; ----------------------
; To ta procedura rekurencyjna daje ZX81 jego moc. O ile w systemie jest wystarczająca ilość pamięci, może on obliczać wartości wyrażeń
; o nieograniczonej złożoności.
; Uwaga. Ponieważ nie ma jednoargumentowego plusa, więc PRINT +1 daje błąd składniowy. Na spektrum to działa, lecz również działa PRINT + "STRING".

; $0F55 : 3925
SCANNING:  RST 18H            ; POBIERZ-ZNAK

          LD   B,$00          ; wyzeruj rejestr B
          PUSH BC             ; umieść zero na stosie jako priorytetowy znacznik końca

; $0F59 : 3929
S_LOOP_1:  CP   $40           ; sprawdź ze znakiem 'RND'

          JR   NZ,S_TEST_PI   ; jeśli się nie zgadza, naprzód do S-TEST-PI

; -------------
; FUNKCJA 'RND'
; -------------

          CALL SYNTAX_Z       ; wyjdź, jeśli jest sprawdzana składnia

          JR   Z,S_JPI_END    ; przy sprawdzaniu składni skocz naprzód do S-JPI-END

          LD   BC,(SEED)      ; pobierz zmienną systemową SEED

          CALL STACK_BC       ; i umieść ją na stosie kalkulatora

          RST  28H            ; KALKULATOR                  seed.
         .BYTE $A1            ; jeden-na-stos               seed,1.
         .BYTE $0F            ; dodaj                       seed+1.
         .BYTE $30            ; dane-na-stos                seed+1,75.
         .BYTE $37            ; Wykładnik: $87, Bajty: 1
         .BYTE $16            ;(+00,+00,+00)
         .BYTE $04            ; mnóż                        (seed+1)*75.
         .BYTE $30            ; dane-na-stos                (seed+1)*75,65537.
         .BYTE $80            ; Bajty: 3
         .BYTE $41            ; Wykładnik $91
         .BYTE $00,$00,$80    ;(+00)
         .BYTE $2E            ; n-modulo-m                  reszta,iloraz.
         .BYTE $02            ; usuń                        reszta z dzielenia (seed+1)*75/65537.
         .BYTE $A1            ; jeden-na-stos               reszta,1.
         .BYTE $03            ; odejmij                     reszta-1.
         .BYTE $2D            ; duplikuj                    reszta-1,reszta-1.
         .BYTE $34            ; koniec-obliczeń

          CALL FP_TO_BC

          LD   (SEED),BC      ; uaktualnij zmienną systemową SEED
          LD   A,(HL)         ; HL adresuje wykładnik ostatniej wartości
          AND  A              ; testuj zero

          JR   Z,S_JPI_END    ; jeśli zero, skocz naprzód do S-JPI-END

          SUB  $10            ; inaczej zmniejsz wykładnik o 16
          LD   (HL),A         ; co daje podzielenie ostatniej wartości o 65536

; $0F8A : 3978
S_JPI_END: JR   S_PI_END

; $0F8C : 3980
S_TEST_PI: CP   $42           ; znak 'PI'

          JR   NZ,S_TST_INK   ; jeśli nie, naprzód do S-TST-INK

; ---------------
; OBLICZANIE 'PI'
; ---------------

          CALL SYNTAX_Z       ; wyjdź przy sprawdzaniu składni

          JR   Z,S_PI_END     ; jeśli sprawdzanie składni, naprzód do S-PI-END

          RST  28H            ; KALKULATOR
         .BYTE $A3            ; na-stos-pi/2
         .BYTE $34            ; koniec-obliczeń

          INC  (HL)           ; zwiększ wykładnik, co na stosie da PI.

; $0F99 : 3993
S_PI_END:  RST  20H           ; NASTĘPNY-ZNAK - przesuwa do przodu wskaźnik znaków

          JP   S_NUMERIC      ; skocz naprzód so S-NUMERIC, aby przed kontynuacją ustawić znacznik
                              ; informujący o wyniku liczbowym.
; $0F9D : 3997
S_TST_INK: CP   $41           ; porównaj ze znakiem 'INKEY$'

          JR   NZ,S_ALPHANUM  ; jeśli się nie zgadza, naprzód do S-ALPHANUM

; -------------------
; OBLICZANIE 'INKEY$'
; -------------------

          CALL KEYBOARD

          LD   B,H
          LD   C,L
          LD   D,C
          INC  D

          CALL NZ,DECODE

          LD   A,D
          ADC  A,D
          LD   B,D
          LD   C,A
          EX   DE,HL

          JR   S_STRING

; $0FB2 : 4018
S_ALPHANUM: CALL ALPHANUM

          JR   C,S_LTR_DGT     ; naprzód, gdy alfanumeryczne do S-LTR-DGT

          CP   $1B             ; czy znak to '.' ?

          JP   Z,S_DECIMAL     ; jeśli tak, skocz naprzód do S-DECIMAL

          LD   BC,$09D8        ; przygotuj operację 'odejmowania' o priorytecie 09
          CP   $16            ; czy znak to '-' ?

          JR   Z,S_PUSH_PO     ; jeśli tak, to naprzód do S-PUSH-PO

          CP   $10             ; czy znak to '(' ?

          JR   NZ,S_QUOTE      ; jeśli tak, naprzód do S-QUOTE

          CALL CH_ADD_1        ; procedura CH-ADD+1 przesuwa do przodu wskaźnik znaków.

          CALL SCANNING        ; rekursywnie wywołaj procedurę SCANNING, aby obliczyć wartość podwyrażenia

          CP   $11             ; czy znak to ')' ?

          JR   NZ,S_RPT_C      ; jeśli nie, skocz naprzód do S-RPT-C

          CALL CH_ADD_1        ; procedura CH-ADD+1 przesuwa wskaźnik znaków

          JR   S_J_CONT_3      ; skok względny do S-JP-CONT3, a później do S-CONT3


; rozważ łańcuch w cudzysłowach, np. PRINT "HURA!"
; Uwaga, cudzysłowy nie są dozwolone wewnątrz łańcucha.

; $0FD6 : 4054
S_QUOTE:  CP   $0B             ; czy znakiem jest cudzysłów (") ?

          JR   NZ,S_FUNCTION   ; jeśli nie, naprzód do S-FUNCTION

          CALL CH_ADD_1        ; procedura CH-ADD+1 przesuwa wskaźnik znaków

          PUSH HL              ; * zachowaj początek łańcucha.

          JR   S_QUOTE_S

; $0FE0 : 4064
S_Q_AGAIN: CALL CH_ADD_1       ; procedura CH-ADD+1 przesuwa wskaźnik znaków

; $0FE3 : 4067
S_QUOTE_S: CP   $0B            ; czy znakiem jest '"' ?

          JR   NZ,S_Q_NL       ; jeśli nie, naprzód do S-Q-NL

          POP  DE              ; * odzyskaj poczatek łańcucha
          AND  A               ; przygotuj się do odejmowania
          SBC  HL,DE           ; od bieżącej pozycji odejmij start
          LD   B,H             ; przenieś tą długość
          LD   C,L             ; do pary rejestrów BC

; $0FED : 4077
S_STRING:  LD   HL,FLAGS       ; zaadresuj zmienną systemową FLAGS
          RES  6,(HL)          ; sygnalizuj wynik łańcuchowy
          BIT  7,(HL)          ; sprawdź, czy testowana jest składnia

          CALL NZ,STK_STO      ; w czasie wykonania procedura STK-STO-$ umieszcza na stosie deskryptor łańcucha - start DE, długość BC.

          RST  20H             ; NASTĘPNY-ZNAK - przesuń wskaźnik.

; $0FF8 : 4088
S_J_CONT_3: JP  S_CONT_3

; Należy rozważyć łańcuch bez zamykającego cudzysłowu.

; $0FFB : 4091
S_Q_NL:   CP   $76             ; porównaj z NEWLINE

          JR   NZ,S_Q_AGAIN    ; jeśli różne, wróć z powrotem do S-Q-AGAIN

; $0FFF : 4095
S_RPT_C:  JP   REPORT_C

; $1002 : 4098
S_FUNCTION: SUB $C4            ; odejmij 'CODE' zmniejszając kod znaku
                               ; od CODE do '<>', zakres $00 - $XX
          JR   C,S_RPT_C       ; jeśli mniej, wróć do S-RPT-C

; sprawdź NOT, ostatnią funkcję w zestawie znaków.

          LD   BC,$04EC        ; przygotuj priorytet $04, operacja 'not'
          CP   $13             ; porównaj z 'NOT'  ( - CODE)

          JR   Z,S_PUSH_PO     ; jeśli się zgadza, skocz naprzód do S-PUSH-PO

          JR   NC,S_RPT_C      ; jeśli jest cokolwiek więcej, wstecz do S-RPT-C

; inaczej mamy do czynienia z funkcją od 'CODE' do 'CHR$'

          LD   B,$10           ; priorytet 16 wiąże wszystkie funkcje z argumentami, usuwając potrzebę stosowania nawiasów.

          ADD  A,$D9           ; dodaj $D9, aby uzyskać zakres od $D9 do $EB bit 6 jest ustawiony, aby pokazywać argument liczbowy.
                               ; bit 7 jest ustawiony, aby pokazywać wynik liczbowy.

; teraz wyreguluj te standardowe znaczniki argumentów/wyników.

          LD   C,A             ; zachowaj kod w C

          CP   $DC             ; rozdziel 'CODE', 'VAL', 'LEN'

          JR   NC,S_NO_TO      ; jeśli argument jest łańcuchem, przejdź naprzód do S-NO-TO-$

          RES  6,C             ; sygnalizuj łańcuchowy argument.

; $101A : 4122
S_NO_TO:  CP   $EA             ; wyizoluj górę zakresu: 'STR$' i 'CHR$'

          JR   C,S_PUSH_PO     ; z innymi przejdź naprzód do S-PUSH-PO

          RES  7,C             ; sygnalizuj wynik łańcuchowy.

; $1020 : 4128
S_PUSH_PO: PUSH BC             ; umieść na stosie priorytet/operację

          RST  20H             ; NASTĘPNY-ZNAK

          JP   S_LOOP_1        ; skocz wstecz do S-LOOP-1

; $1025 : 4133
S_LTR_DGT: CP   $26            ; porównaj z 'A'.

          JR   C,S_DECIMAL     ; jeśli poniżej, skocz naprzód do S-DECIMAL

          CALL LOOK_VARS       ; poszukaj zmiennej

          JP   C,REPORT_2      ; jeśli nie znaleziono, wstecz do REPORT-2 przy sprawdzaniu składni, zmienna jest zawsze 'znaleziona'.

          CALL Z,STK_VAR       ; procedura STK-VAR umieszcza na stosie parametry łańcuchowe lub zwraca położenie komórki, jeśli parametry są liczbowe

          LD   A,(FLAGS)       ; pobierz FLAGS
          CP   $C0             ; porównaj z wynikiem/argumentem liczbowym

          JR   C,S_CONT_2      ; jeśli nie jest liczbowy, idź do S-CONT-2

          INC  HL              ; zaadresuj liczbową zawartość zmiennej
          LD   DE,(STKEND)     ; ustaw przeznaczenie na STKEND

          CALL MOVE_FP         ; procedura MOVE-FP umieszcza na stosie pięć bajtów

          EX   DE,HL           ; przenieś nową wolną pozycję z DE do HL.
          LD   (STKEND),HL     ; uaktualnij zmienną systemową STKEND

          JR   S_CONT_2


; Procedura skanowania liczby dziesiętnej jest wywoływana, gdy w wyrażeniu zostanie napotkana cyfra lub znak kropki. Gdy sprawdzana jest składnia,
; to "ukryta" liczba zmiennoprzecinkowa jest umieszczana w wierszu BASIC za zapisem liczby. W czasie wykonywania programu cyfry są pomijane,
; a pobrana zostaje liczba zmiennoprzecinkowa.

; $1047 : 4167
S_DECIMAL: CALL SYNTAX_Z       ; wyjdź przy sprawdzaniu składni

          JR   NZ,S_STK_DEC    ; w czasie wykonania naprzód do S-STK-DEC

          CALL DEC_TO_FP

          RST  18H             ; POBIERZ-ZNAK przesuwa HL poza cyfry

          LD   BC,$0006        ; potrzebne jest sześć komórek.

          CALL MAKE_ROOM       ; zrób na nie miejsce

          INC  HL              ; ustaw HL na pierwszą komórkę
          LD   (HL),$7E        ; wstaw znacznik liczby o kodzie 126
          INC  HL              ; przejdź dalej
          EX   DE,HL           ; przenieś adres docelowy do DE.
          LD   HL,(STKEND)     ; ustaw HL na STKEND, które wskazuje na pierwszą komórkę za "ostatnią wartością"
          LD   C,$05           ; do przesunięcia pięć bajtów
          AND  A               ; wyzeruj znacznik przeniesienia
          SBC  HL,BC           ; odejmij 5, wskazując na "ostatnią wartość"
          LD   (STKEND),HL     ; uaktualnij STKEND, co skutkuje usunięciem liczby

          LDIR                 ; przekopiuj wartość tych pięciu bajtów

          EX   DE,HL           ; wskaźnik BASIC do HL, który może wskazywać biały znak za liczbą
          DEC  HL              ; teraz wskazuje ostatni z pięciu bajtów.

          CALL TEMP_PTR1       ; procedura TEMP-PTR1 przesuwa wskaźnik na kolejny znak pomijając wszystkie znaki białe

          JR   S_NUMERIC       ; naprzód do S-NUMERIC, sygnalizując wynik liczbowy

; w czasie wykonania programu skok trafia w to miejsce, gdy zostanie napotkana cyfra lub kropka.

; $106F : 4207
S_STK_DEC: RST  20H            ; NASTĘPNY-ZNAK

          CP   $7E             ; porównaj ze znacznikiem liczby

          JR   NZ,S_STK_DEC    ; cofnij się w pętli do S-STK-DEC aż znak zostanie odnaleziony pomijając wszystkie cyfry

          INC  HL              ; wskaż pierwszy z pięciu ukrytych bajtów.
          LD   DE,(STKEND)     ; ustaw przeznaczenie ze zmiennej systemowej STKEND

          CALL MOVE_FP         ; procedura MOVE-FP umieszcza liczbę na stosie.

          LD   (STKEND),DE     ; uaktualnij zmienne systemowe STKEND
          LD   (CH_ADD),HL     ; oraz CH_ADD.

; $1083 : 4227
S_NUMERIC: SET  6,(IY+$01)     ; uaktualnij FLAGS  - sygnalizuj wynik liczbowy

; $1087 : 4231
S_CONT_2: RST  18H             ; POBIERZ-ZNAK

; $1088 : 4232
S_CONT_3: CP   $10             ; porównaj z nawiasem otwierającym '('

          JR   NZ,S_OPERTR     ; jeśli nie, skocz naprzód do S-OPERTR

          BIT  6,(IY+$01)      ; testuj FLAGS  - wynik liczbowy czy łańcuchowy?

          JR   NZ,S_LOOP       ; jeśli liczbowy, naprzód do S-LOOP

; inaczej mamy do czynienia z łańcuchem znaków

         CALL SLICING

         RST  20H              ; NASTĘPNY-ZNAK

         JR   S_CONT_3         ; wróć do S-CONT-3


; Znak jest teraz przetwarzany, aby utworzył odpowiednik  w tablicy literałów kalkulatora. Jest to dosyć zawiłe, dlatego w ZX-Spectrum wprowadzono
; w tym miejscu prostą tablicę translacji.

; $1098 : 4248
S_OPERTR: LD   BC,$00C3        ; standardowo przygotuj operator 'odejmowania'. Również ustaw B na zero do późniejszego indeksowania.

          CP   $12             ; czy znakiem jest '>' ?

          JR   C,S_LOOP        ; jeśli mniej, skocz naprzód do S-LOOP, ponieważ osiągnięty został koniec sensownych wyrażeń

          SUB  $16             ; czy znakiem jest '-' ?

          JR   NC,SUBMLTDIV    ; z - * / AND '**' '<>' skocz naprzód do SUBMLTDIV

          ADD  A,$0D           ; pozostałe zwiększ o trzynaście $09 ">' do $0C '+'

          JR   GET_PRIO        ; skocz naprzód do GET-PRIO

; $10A7 : 4263
SUBMLTDIV: CP  $03             ; wyizoluj $00 '-', $01 '*', $02 '/'

          JR   C,GET_PRIO      ; naprzód do GET-PRIO, jeśli tak

; inaczej być może pierwotne do $D8 '**' do $DD '<>' już zmniejszone o $16

          SUB  $C2             ; dając zakres od $00 do $05

          JR   C,S_LOOP        ; naprzód do S-LOOP, jeśli mniej

          CP   $06             ; testuj górną granicę na nonsens, również

          JR   NC,S_LOOP       ; naprzód do S-LOOP, jeśli tak

          ADD  A,$03           ; zwiększ o 3, aby otrzymać połączone operatory

                               ; $00 '-'
                               ; $01 '*'
                               ; $02 '/'

                               ; $03 '**'
                               ; $04 'OR'
                               ; $05 'AND'
                               ; $06 '<='
                               ; $07 ">='
                               ; $08 '<>'

                               ; $09 ">'
                               ; $0A '<'
                               ; $0B '='
                               ; $0C '+'

; $10B5 : 4277
GET_PRIO: ADD  A,C             ; dodaj do standardowej operacji 'sub' ($C3)
          LD   C,A             ; i bajt operatora umieść w C.
          LD   HL,TBL_PRI-$C3  ; teoretyczna podstawa tablicy priorytetów.
          ADD  HL,BC           ; dodaj C ( B jest równe zero)
          LD   B,(HL)          ; pobierz priorytet do B

; $10BC : 4284
S_LOOP:   POP  DE              ; odtwórz poprzednią zawartość
          LD   A,D             ; załaduj A priorytetem.
          CP   B               ; czy jest wyższy priorytet

          JR   C,S_TIGHTER     ; jeśli tak, skocz naprzód do S-TIGHTER

          AND  A               ; czy oba priorytety zero?

          JP   Z,GET_CHAR      ; jeśli zero, wyjdź poprzez GET-CHAR

          PUSH BC              ; zapisz na stosie bieżące wartości
          PUSH DE              ; zapisz na stosie ostatnie wartości

          CALL SYNTAX_Z        ; czy sprawdzana składnia?

          JR   Z,S_SYNTEST     ; jeśli sprawdzana składnia, naprzód do S-SYNTEST

          LD   A,E             ; pobierz ostatnią operację
          AND  $3F             ; zamaskuj bity wskaźnikowe, aby otrzymać prawdziwy literał kalkulatora
          LD   B,A             ; umieść w rejestrze B dla BREG

; wykonaj pojedynczą operację

          RST  28H             ; KALKULATOR
         .BYTE $37             ; fp-calc-2
         .BYTE $34             ; koniec-obliczeń

          JR   S_RUNTEST       ; naprzód do S-RUNTEST

; $10D5 : 4309
S_SYNTEST: LD   A,E            ; przenieś wymaskowany operator do A
          XOR  (IY+$01)        ; wykonaj operację xor z FLAGS, wyniki zresetują bit 6
          AND  $40             ; testuj bit 6

; $10DB : 4315
S_RPORT_C: JP   NZ,REPORT_C    ; wstecz do REPORT-C, jeśli wyniki się nie zgadzają.

; w czasie wykonania przenieś bit 7 operatora do bitu 6 zmiennej FLAGS

; $10DE : 4318
S_RUNTEST: POP  DE             ; przywróć ostatnią operację.
          LD   HL,FLAGS        ; zaadresuj zmienną systemową FLAGS
          SET  6,(HL)          ; załóż wynik liczbowy
          BIT  7,E             ; testuj oczekiwany wynik w operacji

          JR   NZ,S_LOOPEND    ; naprzód do S-LOOPEND, jeśli jest liczbowy

          RES  6,(HL)          ; zeruj, aby zasygnalizować wynik łańcuchowy

; $10EA : 4330
S_LOOPEND: POP  BC             ; odtwórz bieżące wartości

          JR   S_LOOP          ; wstecz do S-LOOP

; $10ED : 4333
S_TIGHTER: PUSH DE             ; zachowaj ostatnie wartości i zajmij się bieżącymi
          LD   A,C             ; pobierz bieżący operator
          BIT  6,(IY+$01)      ; testuj FLAGS  - wynik liczbowy czy łańcuchowy?

          JR   NZ,S_NEXT       ; jeśli liczbowy, naprzód do S-NEXT

          AND  $3F             ; usuń bity znaczników, aby uzyskać czysty literał
          ADD  A,$08           ; dodaj 8 - rozszerzanie literału liczbowego do odpowiadających mu literałów łańcuchowych
          LD   C,A             ; umieść czysty literał z powrotem w C.
          CP   $10             ; porównaj z 'AND'

          JR   NZ,S_NOT_AND    ; jeśli różne, naprzód do S-NOT-AND

          SET  6,C             ; ustaw argument liczbowy wymagany dla 'AND'

          JR   S_NEXT          ; naprzód do S-NEXT

; $1102 : 4354
S_NOT_AND: JR   C,S_RPORT_C    ; jeśli mniej niż 'AND', to wstecz do S-RPORT-C. Nonsens, jeśli '-', '*' itp.

          CP   $17             ; porównaj z literałem 'strs-add'

          JR   Z,S_NEXT        ; jeśli się zgadza, naprzód, sygnalizując wynik łańcuchowy

          SET  7,C             ; dla pozostałych ustaw bit na liczbowe (logiczne)

; $110A : 4362
S_NEXT:   PUSH BC              ; zapisz na stosie 'bieżące' wartości

          RST  20H             ; NASTĘPNY-ZNAK

          JP   S_LOOP_1        ; skocz wstecz do S-LOOP-1

; ---------------------
; 'TABLICA PRIORYTETÓW'
; ---------------------

; $110F : 4367
TBL_PRI: .BYTE $06             ; '-'
         .BYTE $08             ; '*'
         .BYTE $08             ; '/'
         .BYTE $0A             ; '**'
         .BYTE $02             ; 'OR'
         .BYTE $03             ; 'AND'
         .BYTE $05             ; '<='
         .BYTE $05             ; '>='
         .BYTE $05             ; '<>'
         .BYTE $05             ; '>'
         .BYTE $05             ; '<'
         .BYTE $05             ; '='
         .BYTE $06             ; '+'

; ---------------------
; PROCEDURA 'LOOK-VARS'
; ---------------------

; $111C : 4380
LOOK_VARS: SET  6,(IY+$01)     ; zmienna systemowa FLAGS  - sygnalizuj wynik liczbowy

          RST  18H             ; POBIERZ-ZNAK

          CALL ALPHA

          JP   NC,REPORT_C

          PUSH HL
          LD   C,A

          RST  20H             ; NASTĘPNY-ZNAK

          PUSH HL
          RES  5,C
          CP   $10

          JR   Z,V_RUN_SYN

          SET  6,C
          CP   $0D

          JR   Z,V_STR_VAR

          SET  5,C

; $1139 : 4409
V_CHAR:   CALL ALPHANUM

          JR   NC,V_RUN_SYN

          RES  6,C

          RST  20H             ; NASTĘPNY-ZNAK

          JR   V_CHAR          ; z powrotem w pętli do V-CHAR

; $1143 : 4419
V_STR_VAR: RST  20H            ; NASTĘPNY-ZNAK

          RES  6,(IY+$01)      ; zmienna systemowa FLAGS  - sygnalizuj wynik łańcuchowy

; $1148 : 4424
V_RUN_SYN: LD  B,C

          CALL SYNTAX_Z        ; wyjdź przy sprawdzaniu składni

          JR   NZ,V_RUN        ; naprzód do V-RUN

          LD   A,C
          AND  $E0
          SET  7,A
          LD   C,A

          JR   V_SYNTAX        ; naprzód do V-SYNTAX

; $1156 : 4438
V_RUN:    LD   HL,(VARS)

; $1159 : 4441
V_EACH:   LD   A,(HL)
          AND  $7F

          JR   Z,V_80_BYTE

          CP   C

          JR   NZ,V_NEXT

          RLA
          ADD  A,A

          JP   P,V_FOUND_2

          JR   C,V_FOUND_2

          POP  DE
          PUSH DE
          PUSH HL

; $116B : 4459
V_MATCHES: INC HL

; $116C : 4460
V_SPACES: LD   A,(DE)
          INC  DE
          AND  A

          JR   Z,V_SPACES      ; wstecz do V-SPACES

          CP   (HL)

          JR   Z,V_MATCHES     ; wstecz do V-MATCHES

          OR   $80
          CP   (HL)

          JR   NZ,V_GET_PTR    ; naprzód do V-GET-PTR

          LD   A,(DE)

          CALL ALPHANUM

          JR   NC,V_FOUND_1    ; naprzód do V-FOUND-1

; $117F : 4479
V_GET_PTR: POP HL

; $1180 : 4480
V_NEXT:   PUSH BC

          CALL NEXT_ONE

          EX   DE,HL
          POP  BC

          JR   V_EACH          ; wstecz do V-EACH

; $1188 : 4488
V_80_BYTE: SET 7,B

; $118A : 4490
V_SYNTAX:  POP DE

          RST  18H             ; POBIERZ-ZNAK

          CP   $10

          JR   Z,V_PASS        ; naprzód do V-PASS

          SET  5,B

          JR   V_END           ; naprzód do V-END

; $1194 : 4500
V_FOUND_1: POP DE

; $1195 : 4501
V_FOUND_2: POP DE
          POP  DE
          PUSH HL

          RST  18H             ; POBIERZ-ZNAK

; $1199 : 4505
V_PASS:   CALL ALPHANUM

          JR   NC,V_END        ; jeśli alfanumeryczne, naprzód do V-END

          RST  20H             ; NASTĘPNY-ZNAK

          JR   V_PASS          ; wstecz do V-PASS

; $11A1 : 4513
V_END:    POP  HL
          RL   B
          BIT  6,B

          RET

; -------------------
; PROCEDURA 'STK-VAR'
; -------------------

; $11A7 : 4519
STK_VAR:  XOR  A
          LD   B,A
          BIT  7,C

          JR   NZ,SV_COUNT     ; naprzód do SV-COUNT

          BIT  7,(HL) 

          JR   NZ,SV_ARRAYS    ; naprzód do SV-ARRAYS

          INC  A

; $11B2 : 4530
SV_SIMPLE: INC HL
          LD   C,(HL)
          INC  HL
          LD   B,(HL)
          INC  HL
          EX   DE,HL

          CALL STK_STO

          RST  18H             ; POBIERZ-ZNAK

          JP   IS_SV_SLICE     ; skocz naprzód do SV-SLICE?

; $11BF : 4543
SV_ARRAYS: INC HL
          INC  HL
          INC  HL
          LD   B,(HL)
          BIT  6,C

          JR   Z,SV_PTR        ; naprzód do SV-PTR

          DEC  B

          JR   Z,SV_SIMPLE     ; naprzód do SV-SIMPLE$

          EX   DE,HL

          RST  18H             ; POBIERZ-ZNAK

          CP   $10

          JR   NZ,REPORT_3     ; naprzód do REPORT-3

          EX   DE,HL

; $11D1 : 4561
SV_PTR:   EX   DE,HL

          JR   SV_COUNT        ; naprzód do SV-COUNT

; $11D4 : 4564
SV_COMMA: PUSH  HL

          RST  18H             ; POBIERZ-ZNAK

          POP  HL
          CP   $1A

          JR   Z,SV_LOOP       ; naprzód do SV-LOOP

          BIT  7,C

          JR   Z,REPORT_3      ; naprzód do REPORT-3

          BIT  6,C

          JR   NZ,SV_CLOSE     ; naprzód do SV-CLOSE
   
          CP   $11

          JR   NZ,SV_RPT_C     ; naprzód do SV-RPT-C

          RST  20H             ; NASTĘPNY-ZNAK

          RET

; $11E9 : 4585
SV_CLOSE: CP   $11

          JR   Z,SV_DIM        ; naprzód do SV-DIM

          CP   $DF

          JR   NZ,SV_RPT_C     ; naprzód do SV-RPT-C

; $11F1 : 4593
SV_CH_ADD: RST 18H             ; POBIERZ-ZNAK

          DEC  HL
          LD   (CH_ADD),HL

          JR   SV_SLICE        ; naprzód do SV-SLICE

; $11F8 : 4600
SV_COUNT: LD   HL,$0000

; $11FB : 4603
SV_LOOP:  PUSH HL

          RST  20H             ; NASTĘPNY-ZNAK

          POP  HL
          LD   A,C
          CP   $C0

          JR   NZ,SV_MULT      ; naprzód do SV-MULT

          RST  18H             ; POBIERZ-ZNAK

          CP   $11

          JR   Z,SV_DIM        ; naprzód do SV-DIM

          CP   $DF

          JR   Z,SV_CH_ADD     ; wstecz do SV-CH-ADD

; $120C : 4620
SV_MULT:  PUSH BC
          PUSH HL

          CALL DE__DE_1

          EX   (SP),HL
          EX   DE,HL

          CALL INT_EXP1

          JR   C,REPORT_3      ; naprzód do REPORT-3

          DEC  BC

          CALL GET_HL_DE

          ADD  HL,BC
          POP  DE
          POP  BC
          DJNZ SV_COMMA        ; skocz w pętli wstecz do SV-COMMA

          BIT  7,C

; $1223 : 4643
SV_RPT_C: JR   NZ,SL_RPT_C

          PUSH HL
          BIT  6,C

          JR   NZ,SV_ELEM      ; naprzód do SV-ELEM$

          LD   B,D
          LD   C,E

          RST  18H             ; POBIERZ-ZNAK

          CP   $11             ; czy znakiem jest ')' ?

          JR   Z,SV_NUMBER     ; jeśli tak, przesuń się naprzód do SV-NUMBER

; $1231 : 4657
REPORT_3: RST  08H             ; ERROR-1
         .BYTE $02             ; Raport Błędu: zły indeks

; $1233 : 4659
SV_NUMBER: RST 20H             ; NASTĘPNY-ZNAK

          POP  HL
          LD   DE,$0005

          CALL GET_HL_DE

          ADD  HL,BC

          RET

; $123D : 4669
SV_ELEM:  CALL DE__DE_1

          EX   (SP),HL

          CALL GET_HL_DE

          POP  BC
          ADD  HL,BC
          INC  HL
          LD   B,D
          LD   C,E
          EX   DE,HL

          CALL STK_ST_0

          RST  18H            ; POBIERZ-ZNAK

          CP   $11            ; czy jest to ')' ?

          JR   Z,SV_DIM       ; jeśli tak, naprzód do SV-DIM

          CP   $1A            ; czy jest to ',' ?

          JR   NZ,REPORT_3    ; jeśli nie, wstecz do REPORT-3

; $1256 : 4694
SV_SLICE: CALL SLICING

; $1259 : 4697
SV_DIM:   RST  20H            ; NASTĘPNY-ZNAK

; $125A : 4698
IS_SV_SLICE: CP $10

          JR   Z,SV_SLICE     ; wstecz do SV-SLICE

          RES  6,(IY+$01)     ; zmienna systemowa FLAGS  - sygnalizuj wynik łańcuchowy

          RET

; -------------------
; PROCEDURA 'SLICING'
; -------------------

; $1263 : 4707
SLICING:  CALL SYNTAX_Z       ; wyjdź przy sprawdzaniu składni

          CALL NZ,STK_FETCH

          RST  20H            ; NASTĘPNY-ZNAK

          CP   $11            ; czy jest to ')' ?

          JR   Z,SL_STORE     ; jeśli tak, naprzód do SL-STORE

          PUSH DE
          XOR  A
          PUSH AF
          PUSH BC
          LD   DE,$0001

          RST  18H            ; POBIERZ-ZNAK

          POP  HL
          CP   $DF            ; czy jest to 'TO' ?

          JR   Z,SL_SECOND    ; jeśli tak, naprzód do SL-SECOND

          POP  AF

          CALL INT_EXP2

          PUSH AF
          LD   D,B
          LD   E,C
          PUSH HL

          RST  18H            ; POBIERZ-ZNAK

          POP  HL
          CP   $DF            ; czy jest to 'TO' ?

          JR   Z,SL_SECOND    ; jeśli tak, naprzód do SL-SECOND

          CP   $11

; $128B : 4747
SL_RPT_C: JP   NZ,REPORT_C

          LD   H,D
          LD   L,E

          JR   SL_DEFINE      ; naprzód do SL-DEFINE

; $1292 : 4754
SL_SECOND: PUSH HL

          RST  20H            ; NASTĘPNY-ZNAK

          POP  HL
          CP   $11            ; czy jest to ')' ?

          JR   Z,SL_DEFINE    ; jeśli tak, naprzód do SL-DEFINE

          POP  AF

          CALL INT_EXP2

          PUSH AF

          RST  18H            ; POBIERZ-ZNAK

          LD   H,B
          LD   L,C
          CP   $11            ; czy jest to ')' ?

          JR   NZ,SL_RPT_C    ; jeśli nie, wstecz do SL-RPT-C

; $12A5 : 4773
SL_DEFINE: POP AF
          EX   (SP),HL
          ADD  HL,DE
          DEC  HL
          EX   (SP),HL
          AND  A
          SBC  HL,DE
          LD   BC,$0000

          JR   C,SL_OVER       ; naprzód do SL-OVER

          INC  HL
          AND  A

          JP   M,REPORT_3      ; wstecz do REPORT-3

          LD   B,H
          LD   C,L

; $12B9 : 4793
SL_OVER:  POP  DE
          RES  6,(IY+$01)      ; zmienna systemowa FLAGS  - sygnalizuj wynik łańcuchowy

; $12BE : 4798
SL_STORE: CALL SYNTAX_Z

          RET  Z               ; wróć przy sprawdzaniu składni

; ----------------------------
; PROCEDURA 'UMIEŚĆ NA STOSIE'
; ----------------------------
; Umieszcza na szczycie stosu liczbę przekazaną w rejestrach:
; A - wykładnik
: DE:BC - mantysa

; $12C2 : 4802
STK_ST_0: XOR  A               ; zeruj wykładnik

; $12C3 : 4803
STK_STO:  PUSH BC              ; zachowaj fragment liczby

          CALL TEST_5_SP       ; sprawdź, czy w pamięci jest miejsce na liczbę

          POP  BC              ; odtwórz fragment liczby
          LD   HL,(STKEND)     ; adresuj koniec stosu
          LD   (HL),A          ; prześlij wykładnik
          INC  HL
          LD   (HL),E          ; prześlij pozostałe 4 bajty liczby DE:BC
          INC  HL
          LD   (HL),D
          INC  HL
          LD   (HL),C
          INC  HL
          LD   (HL),B
          INC  HL              ; teraz HL wskazuje puste miejsce na stosie
          LD   (STKEND),HL     ; uaktualnij STKEND
          RES  6,(IY+$01)      ; uaktualnij FLAGS - sygnalizuj wynik łańcuchowy

          RET

; -------------------
; PROCEDURY 'INT EXP'
; -------------------
;

; $12DD : 4829
INT_EXP1: XOR  A

; $12DE : 4830
INT_EXP2: PUSH DE
          PUSH HL
          PUSH AF

          CALL CLASS_6

          POP  AF

          CALL SYNTAX_Z        ; wyjdź przy sprawdzaniu składni

          JR   Z,I_RESTORE     ; przy sprawdzaniu składni naprzód do I-RESTORE

          PUSH AF

          CALL FIND_INT

          POP  DE
          LD   A,B
          OR   C
          SCF

          JR   Z,I_CARRY       ; naprzód do I-CARRY

          POP  HL
          PUSH HL
          AND  A
          SBC  HL,BC

; $12F9 : 4857
I_CARRY:  LD   A,D
          SBC  A,$00

; $12FC : 4860
I_RESTORE: POP HL
          POP  DE

          RET

; ---------------------
; PROCEDURA 'DE,(DE+1)'
; ---------------------
; INDEXUJ I ŁADUJ
; Jest to emulacja instrukcji procesora 6800 LDX 1,X, która ładuje wartość 2 bajtową z pamięci do rejestru ją indeksującego. Zwykle takich operacji
; nie opłaca się pisać jako podprogramów, a ta nie oszczędza ani miejsca, ani czasu. Widocznie programista był ograniczony czasowo i pamięciowo.

; $12FF : 4863
DE__DE_1: EX   DE,HL          ; przenieś adres indeksu do HL.
          INC  HL             ; zwiększ, aby zaadresować słowo.
          LD   E,(HL)         ; pobierz młodszy bajt słowa.
          INC  HL             ; indeksuj starszy bajt słowa
          LD   D,(HL)         ; i pobierz go

          RET                 ; wróć z DE = słowo

; ---------------------
; PROCEDURA 'GET-HL*DE'
; ---------------------

; $1305 : 4869
GET_HL_DE: CALL SYNTAX_Z      ; czy sprawdzana jest składnia?

          RET  Z              ; jeśli tak, to wróć

          PUSH BC             ; zachowaj BC
          LD   B,$10          ; do B licznik bitów = 16
          LD   A,H            ; starszy bajt do A
          LD   C,L            ; młodszy do C
          LD   HL,$0000

; $1311 : 4881
HL_LOOP:  ADD  HL,HL          ; sprawdź, czy HL nie za duże przesuwając bity w lewo

          JR   C,HL_END       ; jeśli tak, skocz naprzód do HL-END

          RL   C              ; przesuń bity starego HL w lewo
          RLA

          JR   NC,HL_AGAIN    ; jeśli brak przeniesienia, skocz naprzód do HL-AGAIN

          ADD  HL,DE          ; dodaj do HL DE

; $131A : 4890
HL_END:   JP   C,REPORT_4     ; jeśli za duże, skocz do REPORT-4

; $131D : 4893
HL_AGAIN: DJNZ HL_LOOP        ; wstecz w pętli do HL-LOOP

          POP  BC             ; odtwórz BC

          RET

; ---------------
; PROCEDURA 'LET'
; ---------------

; $1321 : 4897
LET:      LD   HL,(DEST)       ; ustaw wskaźnik znaków
          BIT  1,(IY+$2D)      ; zmienna systemowa FLAGX

          JR   Z,L_EXISTS

          LD   BC,$0005

; $132D : 4909
L_EACH_CH: INC  BC

; test

; $132E : 4910
L_NO_SP:  INC  HL              ; przesuń wskaźnik znaków  
          LD   A,(HL)          ; pobierz znak
          AND  A               ; sprawdź, czy spacja

          JR   Z,L_NO_SP       ; jeśli tak, to wstecz do L-NO-SP

          CALL ALPHANUM        ; sprawdź, czy znak lub cyfra

          JR   C,L_EACH_CH

          CP   $0D             ; czy jest to '$' ?

          JP   Z,L_NEW         ; jeśli tak, naprzód do L-NEW$

          RST  30H             ; BC-MIEJSC

          PUSH DE
          LD   HL,(DEST)
          DEC  DE
          LD   A,C
          SUB  $06
          LD   B,A
          LD   A,$40

          JR   Z,L_SINGLE      ; naprzód do L-SINGLE

; $134B : 4939
L_CHAR:   INC  HL              ; przesuń wskaźnik znaku
          LD   A,(HL)          ; pobierz znak
          AND  A               ; czy to jest spacja ?

          JR   Z,L_CHAR        ; jeśli tak, wstecz do L-CHAR

          INC  DE
          LD   (DE),A
          DJNZ L_CHAR          ; wstecz w pętli do L-CHAR

          OR   $80             ; ustaw bit 7 - ostatni znak nazwy
          LD   (DE),A          ; zapisz znak
          LD   A,$80

; $1359 : 4953
L_SINGLE: LD   HL,(DEST)
          XOR  (HL)
          POP  HL

          CALL L_FIRST

; $1361 : 4961
L_NUMERIC: PUSH HL

          RST  28H             ; KALKULATOR
         .BYTE $02             ; usuń
         .BYTE $34             ; koniec-obliczeń

          POP  HL
          LD   BC,$0005
          AND  A
          SBC  HL,BC

          JR   L_ENTER         ; naprzód do L-ENTER

; $136E : 4974
L_EXISTS: BIT  6,(IY+$01)      ; zmienna systemowa FLAGS  - wynik liczbowy czy łańcuchowy?

          JR   Z,L_DELETE      ; naprzód do L-DELETE$

          LD   DE,$0006
          ADD  HL,DE

          JR   L_NUMERIC       ; wstecz do L-NUMERIC

; $137A : 4986
L_DELETE: LD   HL,(DEST)
          LD   BC,(STRLEN)
          BIT  0,(IY+$2D)      ; zmienna systemowa FLAGX

          JR   NZ,L_ADD        ; naprzód do L-ADD$

          LD   A,B
          OR   C

          RET  Z

          PUSH HL

          RST  30H             ; BC-MIEJSC

          PUSH DE
          PUSH BC
          LD   D,H
          LD   E,L
          INC  HL
          LD   (HL),$00
          LDDR
          PUSH HL

          CALL STK_FETCH

          POP  HL
          EX   (SP),HL
          AND  A
          SBC  HL,BC
          ADD  HL,BC

          JR   NC,L_LENGTH     ; naprzód do L-LENGTH

          LD   B,H
          LD   C,L

; $13A3 : 5027
L_LENGTH: EX   (SP),HL
          EX   DE,HL
          LD   A,B
          OR   C

          JR   Z,L_IN_W_S      ; naprzód do L_IN_W/S

          LDIR

; $13AB : 5035
L_IN_W_S: POP  BC
          POP  DE
          POP  HL

; -------------------
; PROCEDURA 'L-ENTER'
; -------------------

; $13AE : 5038
L_ENTER:  EX   DE,HL
          LD   A,B
          OR   C

          RET  Z

          PUSH DE
          LDIR
          POP  HL

          RET

; $13B7 : 5047
L_ADD:    DEC  HL
          DEC  HL
          DEC  HL
          LD   A,(HL)
          PUSH HL
          PUSH BC

          CALL L_STRING

          POP  BC
          POP  HL
          INC  BC
          INC  BC
          INC  BC

          JP   RECLAIM_2       ; skocz wstecz i wyjdź poprzez RECLAIM-2

; $13C8 : 5064
L_NEW:    LD   A,$60           ; przygotuj maskę %01100000
          LD   HL,(DEST)       ; załaduj wskaźnik znaków
          XOR  (HL)

; --------------------
; PROCEDURA 'L-STRING'
; --------------------
;

; $13CE : 5070
L_STRING: PUSH AF

          CALL STK_FETCH

          EX   DE,HL
          ADD  HL,BC
          PUSH HL
          INC  BC
          INC  BC
          INC  BC

          RST  30H            ; BC-MIEJSC

          EX   DE,HL
          POP  HL
          DEC  BC
          DEC  BC
          PUSH BC
          LDDR
          EX   DE,HL
          POP  BC
          DEC  BC
          LD   (HL),B
          DEC  HL
          LD   (HL),C
          POP  AF

; $13E7 : 5095
L_FIRST:  PUSH AF

          CALL REC_V80

          POP  AF
          DEC  HL
          LD   (HL),A
          LD   HL,(STKBOT)     ; przenieś TKBOT
          LD   (E_LINE),HL     ; do E_LINE
          DEC  HL              ; przed spodem stosu
          LD   (HL),$80        ; umieść znacznik końca

          RET

; ---------------------
; PROCEDURA 'STK-FETCH'
; ---------------------
; Procedura pobiera 5 bajtową wartość ze stosu kalkulatora, zmniejszając wskaźnik stosu o 5, aby wskazywał na koniec stosu. Przy liczbie
; zmiennoprzecinkowej wykładnik znajduje się w A, a mantysa ma 32 bity i jest umieszczana w EDCB. Przy łańcuchach początek jest w DE, a długość
; w BC. A nie jest używane.

; $13F8 : 5112
STK_FETCH: LD  HL,(STKEND)     ; adres końca stosu kalkulatora do HL
          DEC  HL              ; Pobierz mantysę do EDBC
          LD   B,(HL)
          DEC  HL
          LD   C,(HL)
          DEC  HL
          LD   D,(HL)
          DEC  HL
          LD   E,(HL)
          DEC  HL
          LD   A,(HL)          ; pobierz wykładnik do A
          LD   (STKEND),HL     ; Ustaw nowy adres końca stosu kalkulatora

          RET

; -------------------------
; PROCEDURA POLECENIA 'DIM'
; -------------------------
; Tworzona jest tablica i inicjowana na zero, które na ZX-81 jest także spacją.

; $1409 : 5129
DIM:      CALL LOOK_VARS

; $140C : 5132
D_RPORT_C: JP  NZ,REPORT_C

          CALL SYNTAX_Z        ; wyjdź przy sprawdzaniu składni

          JR   NZ,D_RUN        ; jeśli nie, to naprzód do D-RUN

          RES  6,C

          CALL STK_VAR

          CALL CHECK_END

; $141C : 5148
D_RUN:    JR   C,D_LETTER      ; naprzód do D-LETTER

          PUSH BC

          CALL NEXT_ONE

          CALL RECLAIM_2

          POP  BC

; $1426 : 5158
D_LETTER: SET  7,C
          LD   B,$00
          PUSH BC
          LD   HL,$0001
          BIT  6,C

          JR   NZ,D_SIZE       ; naprzód do D-SIZE

          LD   L,$05

; $1434 : 5172
D_SIZE:   EX   DE,HL

; $1435 : 5173
D_NO_LOOP: RST 20H             ; NASTĘPNY-ZNAK

          LD   H,$40

          CALL INT_EXP1

          JP   C,REPORT_3      ; skocz wstecz do REPORT-3

          POP  HL
          PUSH BC
          INC  H
          PUSH HL
          LD   H,B
          LD   L,C

          CALL GET_HL_DE

          EX   DE,HL

          RST  18H             ; POBIERZ-ZNAK

          CP   $1A

          JR   Z,D_NO_LOOP     ; wstecz do D-NO-LOOP

          CP   $11             ; czy jest to ')' ?

          JR   NZ,D_RPORT_C    ; jeśli nie, wstecz do D-RPORT-C

          RST  20H             ; NASTĘPNY-ZNAK

          POP  BC
          LD   A,C
          LD   L,B
          LD   H,$00
          INC  HL
          INC  HL
          ADD  HL,HL
          ADD  HL,DE

          JP   C,REPORT_4

          PUSH DE
          PUSH BC
          PUSH HL
          LD   B,H
          LD   C,L
          LD   HL,(E_LINE)
          DEC  HL

          CALL MAKE_ROOM

          INC  HL
          LD   (HL),A
          POP  BC
          DEC  BC
          DEC  BC
          DEC  BC
          INC  HL
          LD   (HL),C
          INC  HL
          LD   (HL),B
          POP  AF
          INC  HL
          LD   (HL),A
          LD   H,D
          LD   L,E
          DEC  DE
          LD   (HL),$00
          POP  BC
          LDDR

; $147F : 5247
DIM_SIZES: POP BC
          LD   (HL),B
          DEC  HL
          LD   (HL),C
          DEC  HL
          DEC  A

          JR   NZ,DIM_SIZES    ; wstecz do DIM-SIZES

          RET

; -------------------
; PROCEDURA 'RESERVE'
; -------------------

; $1488 : 5256
RESERVE:  LD   HL,(STKBOT)     ; pobierz do HL adres spodu stosu kalkulatora
          DEC  HL              ; HL wskazuje teraz ostatni bajt w obszarze roboczym

          CALL MAKE_ROOM

          INC  HL
          INC  HL
          POP  BC
          LD   (E_LINE),BC
          POP  BC
          EX   DE,HL
          INC  HL

          RET

; ---------------------------
; PROCEDURA POLECENIA 'CLEAR'
; ---------------------------

; $149A : 5274
CLEAR:    LD   HL,(VARS)
          LD   (HL),$80
          INC  HL
          LD   (E_LINE),HL

; ------------------
; PROCEDURA 'X-TEMP'
; ------------------

; $14A3 : 5283
X_TEMP:   LD   HL,(E_LINE)

; ----------------------
; PROCEDURY 'USTAW-STOS'
; ----------------------

; $14A6 : 5286
SET_STK_B: LD  (STKBOT),HL

; $14A9 : 5289
SET_STK_E: LD  (STKEND),HL

          RET

; ------------------------
; PROCEDURA 'TYLKO KURSOR'
; ------------------------
; Ta procedura jest wywoływana w celu stworzenia minimalnego wiersza z kursorem i NEWLINE oraz do ustawienia STKEND na początek wolnej przestrzeni
; na następnej pozycji.

; $14AD : 5293
CURSOR_IN: LD  HL,(E_LINE)     ; pobierz adres początku wiersza edycyjnego z E_LINE
          LD   (HL),$7F        ; wstaw znak kursora
          INC  HL              ; przejdź na następną pozycję
          LD   (HL),$76        ; wstaw znak NEWLINE
          INC  HL              ; przejdź na następną wolną komórkę.
          LD   (IY+$22),$02    ; ustaw wielkość spodu ekranu w DF_SZ

          JR   SET_STK_B       ; wyjdź poprzez SET-STK-B

; ---------------------
; PROCEDURA 'USTAW-MIN'
; ---------------------

; $14BC : 5308
SET_MIN:  LD   HL,MEMBOT       ; zwykła pozycja obszaru pamięci kalkulatora
          LD   (MEM),HL        ; uaktualnij zmienną systemową MEM
          LD   HL,(STKBOT)     ; pobierz STKBOT

          JR   SET_STK_E       ; wstecz do SET-STK-E

; ------------------------------------
; PROCEDURA 'ODZYSKAJ ZNACZNIK KOŃCA'
; ------------------------------------

; $14C7 : 5319
REC_V80:  LD   DE,(E_LINE)

          JP   RECLAIM_1

; -----------------
; PROCEDURA 'ALPHA'
; -----------------

; $14CE : 5326
ALPHA:    CP   $26

          JR   ALPHA_2          ; przeskocz naprzód do ALPHA-2

; --------------------
; PROCEDURA 'ALPHANUM'
; --------------------

; $14D2 : 5330
ALPHANUM: CP   $1C

; $14D4 : 5332
ALPHA_2:  CCF

          RET  NC

          CP   $40

          RET

; -----------------------------------------------------
; PROCEDURA 'LICZBA DZIESIĘTNA DO ZMIENNO-PRZECINKOWEJ'
; -----------------------------------------------------

; $14D9 : 5337
DEC_TO_FP: CALL INT_TO_FP      ; procedura INT-TO-FP pobiera pierwszą część

          CP   $1B             ; czy znak jest '.' ?

          JR   NZ,E_FORMAT     ; jeśli nie, naprzód do E-FORMAT

          RST  28H             ; KALKULATOR
         .BYTE $A1             ; jeden-na-stos
         .BYTE $C0             ; stos-do-pamięci-0
         .BYTE $02             ; usuń
         .BYTE $34             ; koniec-obliczeń

; $14E5 : 5349
NXT_DGT_1: RST 20H             ; NASTĘPNY-ZNAK

          CALL STK_DIGIT

          JR   C,E_FORMAT      ; naprzód do E-FORMAT

          RST  28H             ; KALKULATOR
         .BYTE $E0             ; na-stos-paimięć-0
         .BYTE $A4             ; na-stos-dziesięć
         .BYTE $05             ; dziel
         .BYTE $C0             ; stos-do-pamięci-0
         .BYTE $04             ; mnóż
         .BYTE $0F             ; dodaj
         .BYTE $34             ; koniec-obliczeń

          JR   NXT_DGT_1       ; wróć w pętli do NXT-DGT-1 aż do wyczerpania cyfr

; $14F5 : 5365
E_FORMAT: CP   $2A             ; czy znakiem jest 'E' ?

          RET  NZ              ; wróć, jeśli nie

          LD   (IY+$5D),$FF    ; inicjuj zmienną systemową MEM-0-1st na $FF TRUE

          RST  20H             ; NASTĘPNY-ZNAK

          CP   $15             ; czy znakiem jest '+' ?

          JR   Z,SIGN_DONE     ; jeśli tak, naprzód do SIGN-DONE

          CP   $16             ; czy jest to '-' ?

          JR   NZ,ST_E_PART    ; jeśli nie, naprzód do ST-E-PART

          INC  (IY+$5D)        ; zmień MEM-0-1st na FALSE

; $1508 : 5384
SIGN_DONE: RST  20H            ; NASTĘPNY-ZNAK

; $1509 : 5385
ST_E_PART: CALL INT_TO_FP

          RST  28H             ; KALKULATOR             m, e.
         .BYTE $E0             ; na-stos-paimięć-0      m, e, (1/0) TRUE/FALSE
         .BYTE $00             ; skocz-przy-prawdzie
         .BYTE $02             ; do L1511, E-POSTVE
         .BYTE $18             ; zmień-znak             m, -e

; $1511 : 5393
E_POSTVE:.BYTE $38             ; e-do-potęgi            x.
         .BYTE $34             ; koniec-obliczeń        x.

          RET

; -------------------------
; PROCEDURA 'CYFRA NA STOS'
; -------------------------

; $1514 : 5396
STK_DIGIT: CP  $1C

          RET  C

          CP   $26
          CCF

          RET  C

          SUB  $1C

; ---------------------
; PROCEDURA 'A NA STOS'
; ---------------------

; $151D : 5405
STACK_A:  LD   C,A            ; przenieś A do BC
          LD   B,$00          ; zerując starszy bajt

; ----------------------
; PROCEDURA 'BC NA STOS'
; ----------------------
; ZX81 nie posiada wydzielonego formatu dla liczb całkowitych, zatem zawartość rejestru BC musi być zamieniona na pełną postać zmiennoprzecinkową.

; $1520 : 5408
STACK_BC: LD   IY,ERR_NR      ; ponownie ustaw wskaźnik zmiennych systemowych.
          PUSH BC             ; zachowaj wartość całkowitą.

; teraz zapisz na stosie zero - pięć zerowych bajtów jako punkt startowy.

          RST  28H            ; KALKULATOR
         .BYTE $A0            ; na-stos-zero                0.
         .BYTE $34            ; koniec-obliczeń

          POP  BC             ; odtwórz wartość całkowitą
          LD   (HL),$91       ; umieść $91 w wykładniku      65536.
                              ; jest to największa dozwolona wartość
          LD   A,B            ; pobierz starszy bajt
          AND  A              ; sprawdź, czy jest równy zero.

          JR   NZ,STK_BC_2    ; jeśli nie, to naprzód do STK-BC-2

          LD   (HL),A         ; inaczej wyzeruj z powrotem wykładnik
          OR   C              ; sprawdź młodszy bajt

          RET  Z              ; jeśli BC było równe 0, wróć - koniec roboty.

; inaczej ma być ustawiony bit, jeśli wartością jest tylko jeden.

          LD   B,C            ; zachowaj C w B.
          LD   C,(HL)         ; pobierz zero do C
          LD   (HL),$89       ; ustaw wykładnik $89          256.

; $1536 : 5430
STK_BC_2: DEC  (HL)           ; zmniejsz wykładnik - dzieląc liczbę przez 2
          SLA  C              ;  C<-76543210<-0
          RL   B              ;  C<-76543210<-C

          JR   NC,STK_BC_2    ; jeśli brak przeniesienia, wróć w pętli do STK-BC-2

          SRL  B              ;  0->76543210->C
          RR   C              ;  C->76543210->C

          INC  HL             ; zaadresuj pierwszy bajt mantysy
          LD   (HL),B         ; wstaw B
          INC  HL             ; zaadresuj drugi bajt mantysy
          LD   (HL),C         ; wstaw C

          DEC  HL             ; wskaż ponownie
          DEC  HL             ; na wykładnik

          RET

; --------------------------------------------------
; PROCEDURA 'LICZBA CAŁKOWITA NA ZMIENNOPRZECINKOWĄ'
; --------------------------------------------------

; $1548 : 5448
INT_TO_FP: PUSH AF

          RST  28H            ; KALKULATOR
         .BYTE $A0            ; na-stos-zero
         .BYTE $34            ; koniec-obliczeń

          POP  AF

; $154D : 5453
NXT_DGT_2: CALL STK_DIGIT

          RET  C

          RST  28H            ; KALKULATOR
         .BYTE $01            ; zamień
         .BYTE $A4            ; na-stos-dziesięć
         .BYTE $04            ; mnóż
         .BYTE $0F            ; dodaj
         .BYTE $34            ; koniec-obliczeń

          RST  20H            ; NASTĘPNY-ZNAK

          JR   NXT_DGT_2


; ------------------------------------------
; PROCEDURA 'E-FORMAT NA ZMIENNOPRZECINKOWĄ'
; ------------------------------------------
; (przesunięcie $38: 'e-to-fp')
; wywoływana z DEC-TO-FP i PRINT-FP.
; np. 2.3E4 to 23000.
; Ta procedura oblicza wartość xEm, gdzie m jest dodatnią lub ujemną liczbą całkowitą. Na prostym poziomie x jest mnożone przez 10 dla każdej
; jednostki w m. Jeśli wykładnik dziesiętny jest ujemny, to x jest dzielone przez dziesięć dla każdej jednostki w m. Skrót powstaje, jeśli wykładnik
; jest większy od siedmiu i w takim przypadku jest on zmniejszany o 7, a x zostaje pomnożone lub podzielone przez dziesięć milionów.
; Uwaga, w ZX-Spectrum zastosowano nawet sprytniejszą metodę wykorzystującą przesunięcia bitów poza wykładnik, w której wynik był osiągany w co
; najwyżej sześciu przesunięciach. Poniższa procedura musiała zostać całkowicie przepisana, w większości w kodzie maszynowym Z80. Chociaż już nie
; używany, literał kalkulatora pozostał ze względów kompatybilności wstecznej, natomiast nowa procedura była wywoływana bezpośrednio z kodu
; maszynowego.

; Na wejściu w ZX-81 wykładnik m jest na szczycie stosu, a zmiennoprzecinkowa mantysa leży na stosie poniżej wykładnika.

; $155A : 5466
E_TO_FP:  RST  28H            ; KALKULATOR              x, m.
         .BYTE $2D            ; duplikuj                x, m, m.
         .BYTE $32            ; mniej-niż-0             x, m, (1/0).
         .BYTE $C0            ; stos-do-pamięci-0       x, m, (1/0).
         .BYTE $02            ; usuń                    x, m.
         .BYTE $27            ; wartość-bezwzględna     x, +m.

; $1560 : 5472
E_LOOP:  .BYTE $A1            ; jeden-na-stos           x, m,1.
         .BYTE $03            ; odejmij                 x, m-1.
         .BYTE $2D            ; duplikuj                x, m-1,m-1.
         .BYTE $32            ; mniej-niż-0             x, m-1, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie     x, m-1.
         .BYTE $22            ; do L1587, E-END         x, m-1.
         .BYTE $2D            ; duplikuj                x, m-1, m-1.
         .BYTE $30            ; dane-na-stos
         .BYTE $33            ; Wykładnik: $83, Bajty: 1
         .BYTE $40            ;(+00,+00,+00)            x, m-1, m-1, 6.
         .BYTE $03            ; odejmij                 x, m-1, m-7.
         .BYTE $2D            ; duplikuj                x, m-1, m-7, m-7.
         .BYTE $32            ; mniej-niż-0             x, m-1, m-7, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie     x, m-1, m-7.
         .BYTE $0C            ; do L157A, E-LOW

; lecz jeśli wykładnik jest większy od 7, to zastosuj większe mnożenie lub dzielenie (przy ujemnym m) przez 10 milionów - 1e7.

         .BYTE $01            ; zamień                  x, m-7, m-1.
         .BYTE $02            ; usuń                    x, m-7.
         .BYTE $01            ; zamień                  m-7, x.
         .BYTE $30            ; dane-na-stos
         .BYTE $80            ; Bajty: 3
         .BYTE $48            ; Wykładnik $98
         .BYTE $18,$96,$80    ;(+00)                    m-7, x, 10,000,000 (=f)
         .BYTE $2F            ; skocz
         .BYTE $04            ; do L157D, E-CHUNK

; $157A : 5498
E_LOW:   .BYTE $02            ; usuń                    x, m-1.
         .BYTE $01            ; zamień                  m-1, x.
         .BYTE $A4            ; na-stos-dziesięć        m-1, x, 10 (=f).

; $157D : 5501
E_CHUNK: .BYTE $E0            ; na-stos-paimięć-0       m-1, x, f, (1/0)
         .BYTE $00            ; skocz-przy-prawdzie     m-1, x, f
         .BYTE $04            ; do L1583, E-DIVSN
         .BYTE $04            ; mnóż                    m-1, x*f.
         .BYTE $2F            ; skocz
         .BYTE $02            ; do L1584, E-SWAP

; $1583 : 5507
E_DIVSN: .BYTE $05            ; dziel                   m-1, x/f (= new x).

; $1584 : 5508
E_SWAP:  .BYTE $01            ; zamień                  x, m-1 (= new m).
         .BYTE $2F            ; skocz                   x, m.
         .BYTE $DA            ; do L1560, E-LOOP

; $1587 : 5511
E_END:   .BYTE $02            ; usuń                    x. (-1)
         .BYTE $34            ; koniec-obliczeń         x.

          RET

; ------------------------------------
; PROCEDURA 'ZMIENNOPRZECINKOWA DO BC'
; ------------------------------------
; Liczba zmiennoprzecinkowa zostaje pobrana ze stosu i umieszczona w parze rejestrów BC, w razie konieczności z zaokrągleniem.
; Dopuszczalny zakres od 0 do 65535.4999

; $158A : 5514
FP_TO_BC: CALL STK_FETCH      ; procedura STK-FETCH - wykładnik do A, mantysa do EDCB.

          AND  A              ; testuj zero

          JR   NZ,FPBC_NZRO   ; jeśli nie zero, skocz naprzód do FPBC-NZRO

; inaczej wartość jest zero

          LD   B,A            ; zeruj B
          LD   C,A            ; i także C
          PUSH AF             ; zachowaj znaczniki na stosie maszynowym

          JR   FPBC_END       ; naprzód do FPBC-END

; EDCB  =>  BCE

; $1595 : 5525
FPBC_NZRO: LD  B,E            ; przenieś mantysę z EDCB
          LD   E,C            ; do BCE. Bit 7 rejestru E jest 17-tym bitem, który będzie
          LD   C,D            ; znaczący przy zaokrąglaniu, jeśli liczba już jest znormalizowana.
          SUB  $91            ; odejmij 65536
          CCF                 ; wymień bit przeniesienia na przeciwny
          BIT  7,B            ; testuj bit znaku
          PUSH AF             ; wynik na stos
          SET  7,B            ; ustaw implikowany bit

          JR   C,FPBC_END     ; naprzód z przeniesieniem z SUB/CCF do FPBC-END, liczba jest za duża.

          INC  A              ; zwiększ wykładnik i
          NEG                 ; zaneguj, aby otrzymać zakres $00 - $0F
          CP   $08            ; testuj, czy jest jeden lub dwa bajty

          JR   C,BIG_INT      ; z dwoma bajtami naprzód do BIG-INT

          LD   E,C            ; przesuń mantysę
          LD   C,B            ; 8 bitów w prawo
          LD   B,$00          ; do B wstaw zero
          SUB  $08            ; zmniejsz wykładnik o 8

; $15AF : 5551
BIG_INT:  AND  A              ; testuj wykładnik
          LD   D,A            ; zachowaj wykładnik w D.
          LD   A,E            ; bity ułamkowe do A
          RLCA                ; obróć najbardziej znaczący bit do przeniesienia, aby zaokrąglić już znormalizowaną liczbę.

          JR   Z,EXP_ZERO     ; jeśli wykładnik jest zerem, naprzód do EXP-ZERO
                              ; liczba jest znormalizowana
; $15B5 : 5557
FPBC_NORM: SRL B              ;   0->76543210->C
          RR   C              ;   C->76543210->C
          DEC  D              ; zmniejsz wykładnik

          JR   NZ,FPBC_NORM   ; wstecz w pętli do FPBC-NORM, aż będzie zerowy wykładnik

; $15BC : 5564
EXP_ZERO: JR   NC,FPBC_END    ; bez przeniesienia naprzód do NO-ROUND

          INC  BC             ; zaokrąglij w górę.
          LD   A,B            ; testuj wynik
          OR   C              ; na zero

          JR   NZ,FPBC_END    ; jeśli różny od zera, naprzód do GRE-ZERO

          POP  AF             ; odtwórz znacznik znaku
          SCF                 ; ustaw przeniesienie, aby zaznaczyć przepełnienie
          PUSH AF             ; ponownie zachowaj połączone znaczniki

; $15C6 : 5574
FPBC_END: PUSH BC             ; zachowaj wartość BC

; ustaw HL i DE na stos kalkulatora.

          RST  28H            ; KALKULATOR
         .BYTE $34            ; koniec-obliczeń

          POP  BC             ; odtwórz wartość BC
          POP  AF             ; odtwórz znaczniki
          LD   A,C            ; również skopiuj młodszy bajt do A.

          RET

; -----------------------------------
; PROCEDURA 'ZMIENNOPRZECINKOWA DO A'
; -----------------------------------

; $15CD : 5581
FP_TO_A:  CALL FP_TO_BC       ; pobierz liczbę do BC i A

          RET  C              ; jeśli za duża, wróć z ustawionym przeniesieniem

          PUSH AF             ; zachowaj wynik
          DEC  B              ; sprawdź, czy starszy bajt jest równy zero
          INC  B

          JR   Z,FP_A_END     ; jeśli tak, to naprzód do FP-A-END

          POP  AF             ; odtwórz wynik
          SCF                 ; ustaw znacznik przeniesienia, sygnalizując przepełnienie

          RET

; $15D9 : 5593
FP_A_END: POP  AF             ; odtwórz wynik

          RET

; ------------------------------------------
; PROCEDURA 'PISZ LICZBĘ ZMIENNOPRZECINKOWĄ'
; ------------------------------------------
; wypisuje 'ostatnią wartość' x na stosie kalkulatora.
; Istnieje wiele różnych formatów: 
; PI            wypisuje jako       3.1415927
; .123          wypisuje jako       0.123
; .0123         wypisuje jako       .0123
; 999999999999  wypisuje jako       1000000000000
; 9876543210123 wypisuje jako       9876543200000

; Zaczyna od wyizolowania zera i wypisania dla tego przypadku znaku '0'. Liczby ujemne wypisują wiodący znak '-', a następnie wartość bezwzględną z x.

; $15DB : 5595
PRINT_FP: RST  28H            ; KALKULATOR              x.
         .BYTE $2D            ; duplikuj                x, x.
         .BYTE $32            ; mniej-niż-0             x, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie
         .BYTE $0B            ; do L15EA, PF-NGTVE      x.
         .BYTE $2D            ; duplikuj                x, x
         .BYTE $33            ; większe-niż-0           x, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie
         .BYTE $0D            ; do L15F0, PF-POSTVE     x.
         .BYTE $02            ; usuń                    .
         .BYTE $34            ; koniec-obliczeń         .

          LD   A,$1C          ; załaduj akumulator znakiem '0'

          RST  10H            ; PISZ-AKUMULATOR

          RET

; $15EA : 5610
PF_NEGTVE:.BYTE $27           ; wartość-bezwzględna     +x.
         .BYTE $34            ; koniec-obliczeń         +x.

          LD   A,$16          ; załaduj akumulator znakiem '-'

          RST  10H            ; PISZ-AKUMULATOR

          RST  28H            ; KALKULATOR              x.

; $15F0 : 5616
PF_POSTVE: .BYTE $34          ; koniec-obliczeń         x.

; rejestr HL adresuje wykładnik liczby zmiennoprzecinkowej. Jeśli jest dodatnia i przecinek znajduje się na lewo, to bit 7 ma wartość 1.

          LD   A,(HL)         ; pobierz bajt wykładnika

          CALL STACK_A        ; i umieść go na stosie kalkulatora

; teraz zgrubnie wyznacz ilość cyfr n przed przecinkiem, odejmując połowę od właściwego wykładnika i mnożąc przez logarytm dziesiętny z 2. 
; Właściwa ilość może być o jeden wyższa jako wynik całkowity.

          RST  28H            ; KALKULATOR              x, e.
         .BYTE $30            ; dane-na-stos
         .BYTE $78            ; Wykładnik: $88, Bajty: 2
         .BYTE $00,$80        ;(+00,+00)                x, e, 128.5.
         .BYTE $03            ; odejmij                 x, e -.5.
         .BYTE $30            ; dane-na-stos
         .BYTE $EF            ; Wykładnik: $7F, Bajty: 4
         .BYTE $1A,$20,$9A,$85 ; 0.30103 (log10 2)
         .BYTE $04            ; mnóż                    x,
         .BYTE $24            ; na-liczbę-całkowitą
         .BYTE $C1            ; stos-do-pamięci-1       x, n.
         .BYTE $30            ; dane-na-stos
         .BYTE $34            ; Wykładnik: $84, Bajty: 1
         .BYTE $00            ;(+00,+00,+00)            x, n, 8.
         .BYTE $03            ; odejmij                 x, n-8.
         .BYTE $18            ; zmień-znak              x, 8-n.
         .BYTE $38            ; e-do-potęgi             x * (10^n)

; ostatecznie ósma lub dziewiąta cyfra dziesiętna jest zaokrąglana. Dziesięciocyfrowa liczba całkowita może wzrosnąć w tym przypadku, powiedzmy,
; od 999999999.5 do 1000000000.

         .BYTE $A2            ; na-stos-1/2
         .BYTE $0F            ; dodaj
         .BYTE $24            ; na-liczbę-całkowitą      i.
         .BYTE $34            ; koniec-obliczeń

; Jeśli było tylko 8 cyfr, to ostateczne zaokrąglenie będzie miało miejsce na stosie kalkulatora powyżej, a następne dwie instrukcje wprowadzą
; zamaskowane zero, aby już nie było dalszych zaokrągleń. Jeśli wynik jest 9 cyfrową liczbą całkowitą, to zaokrąglenie odbywa się wewnątrz bufora.

          LD   HL,$406B       ; zaadresuj zmienną systemową MEM-2-5th,
                              ; która może być 'dziewiątą' cyfrą.
          LD   (HL),$90       ; wstaw wartość $90  10010000

; teraz, rozpoczynając od najniższej cyfry, wprowadź 8, 9 lub 10 cyfrową liczbę całkowitą, która reprezentuje znaczącą część liczby.
; Np. PI będzie liczbą 9 cyfrową 314159265

          LD   B,$0A          ; licznik na 10 cyfr.

; $1615 : 5653
PF_LOOP:  INC  HL             ; zwiększ wskaźnik

          PUSH HL             ; zachowaj adres bufora
          PUSH BC             ; zachowaj licznik

          RST  28H            ; KALKULATOR              i.
         .BYTE $A4            ; na-stos-dziesięć        i, 10.
         .BYTE $2E            ; n-modulo-m              i mod 10, i/10
         .BYTE $01            ; zamień                  i/10, reszta.
         .BYTE $34            ; koniec-obliczeń

          CALL FP_TO_A        ; pobierz do wynik do A  $00-$09

          OR   $90            ; ustaw lewe 4 bity na 9 

          POP  BC             ; odtwórz licznik
          POP  HL             ; odtwórz adres bufora

          LD   (HL),A         ; wstaw wymaskowaną cyfrę do bufora
          DJNZ PF_LOOP        ; wróć w pętli do PF-LOOP dla wszystkich 10 cyfr

; najbardziej znacząca cyfra będzie ostatnia, lecz gdy liczba została wyczerpana, to jedna lub dwie ostatnie pozycje mogą zawierać zera ($90).
; Np. dla 'jeden' mamy zero jako oszacowanie wiodących cyfr.
; 1*10^8 100000000 jako wartość całkowita
; 90 90 90 90 90   90 90 90 91 90 jako zawartość bufora mem3/mem4

          INC  HL             ; zwiększ wskaźnik o 1 poza bufor 
          LD   BC,$0008       ; ustaw C na 8 (B i tak jest 0)
          PUSH HL             ; zachowaj wskaźnik

; $162C : 5676
PF_NULL:  DEC  HL             ; zmniejsz wskaźnik
          LD   A,(HL)         ; pobierz maskowaną cyfrę
          CP   $90            ; czy jest to wiodące zero ?

          JR   Z,PF_NULL      ; jeśli tak, skocz w pętli wstecz do PF-NULL

; w tym punkcie znaleziono znaczącą cyfrę. Przeniesienie jest wyzerowane.

          SBC  HL,BC          ; odejmij osiem od adresu.
          PUSH HL             ; ** również ten wskaźnik zachowaj
          LD   A,(HL)         ; pobierz adresowany bajt
          ADD  A,$6B          ; dodaj $6B - co zaokrągli cyfrę rozpływowo, jeśli ma wartość $95 lub więcej
          PUSH AF             ; zachowaj wynik przeniesienia.

; teraz wejdź do pętli zaokrąglającej liczbę. Po wykonaniu zaokrąglenia zero powstałe z niego lub będące wcześniej na tej pozycji zostaje zmienione
; z $90 na $80.

; $1639 : 5689
PF_RND_LP: POP AF             ; odzyskaj przeniesienie ze stosu maszynowego.
          INC  HL             ; zwiększ adres
          LD   A,(HL)         ; pobierz nowy bajt
          ADC  A,$00          ; dodaj do niego przeniesienie
          DAA                 ; wyrównaj dziesiętnie akumulator przeniesienie rozpłynie się po cyfrach '9'
          PUSH AF             ; zachowaj przeniesienie na stosie maszynowym.
          AND  $0F            ; wydobądź cyfry 0 - 9 i ustaw znacznik zera, jeśli zero
          LD   (HL),A         ; wstaw z powrotem do bufora
          SET  7,(HL)         ; ustaw bit 7, aby uczynić znak drukowalnym. lecz nie w przypadku końcowego zera za przecinkiem dziesiętnym

          JR   Z,PF_RND_LP    ; jeśli zero, wstecz do PF-RND-LP aby rozważyć dalsze zaokrąglanie i identyfikację końcowych zer.

          POP  AF             ; usuń zbędne dane ze stosu
          POP  HL             ; odzyskaj dolny wskaźnik

; teraz wstaw 6 końcowych zer, które są drukowane, jeśli znajdują się przed przecinkiem dziesiętnym, lecz zaznacz koniec wydruku, jeśli są po
; przecinku dziesiętnym. Np.:
; 9876543210123 jest drukowane jako 9876543200000
; 123.456001    jest drukowane jako 123.456

          LD   B,$06          ; licznik na sześć.

; $164B : 5707
PF_ZERO_6: LD  (HL),$80       ; wstaw maskowane zero
          DEC  HL             ; zmniejsz wskaźnik
          DJNZ PF_ZERO_6      ; dla wszystkich sześciu zer cofnij się w pętli do PF-ZERO-6

; n-mod-m zredukowało liczbę do zera i zostaje ono obecnie usunięte ze stosu kalkulatora przed pobraniem pierwotnego oszacowania wiodących cyfr.

          RST  28H            ; KALKULATOR                0.
         .BYTE $02            ; usuń                      .
         .BYTE $E1            ; na-stos-paimięć-1         n.
         .BYTE $34            ; koniec-obliczeń           n.

          CALL FP_TO_A        ; pobierz liczbę do A

          JR   Z,PF_POS       ; jeśli dodatnia, przeskocz naprzód do PF-POS

          NEG                 ; z ujemnych robimy dodatnie

; $165B : 5723
PF_POS:   LD   E,A            ; przenieś licznik cyfr do E
          INC  E              ; zwiększ dwukrotnie
          INC  E
          POP  HL             ; odzyskaj wskaźnik pozycji o jeden poza buforem

; $165F : 5727
GET_FIRST: DEC HL             ; zmniejsz adres
          DEC  E              ; zmniejsz licznik cyfr
          LD   A,(HL)         ; pobierz wymaskowany bajt
          AND  $0F            ; wyizoluj prawe cztery bity.

          JR   Z,GET_FIRST    ; jeśli jest to zero wiodące, wstecz do GET-FIRST

; teraz ustal, czy będzie potrzebny format E do wydruku

          LD   A,E            ; przenieś teraz właściwą liczbę cyfr do A.
          SUB  $05            ; odejmij pięć
          CP   $08            ; porównaj z 8, skoro maksymalna liczba cyfr wynosi 13.

          JP   P,PF_E_FMT     ; jeśli dodatnie, naprzód do PF-E-FMT

          CP   $F6            ; testuj na więcej niż cztery zera za przecinkiem.

          JP   M,PF_E_FMT     ; jeśli są, naprzód do PF-E-FMT

          ADD  A,$06          ; testuj na zero wiodących cyfr, np. 0.5

          JR   Z,PF_ZERO_1    ; jeśli tak, naprzód do PF-ZERO-1 

          JP   M,PF_ZEROS     ; jeśli jest więcej niż jedno zero, skocz do PF-ZEROS

; w przeciwnym razie cyfry przed przecinkiem mają zostać wydrukowane

          LD   B,A            ; liczba wiodących znaków do B.

; $167B : 5755
PF_NIB_LP: CALL PF_NIBBLE

          DJNZ PF_NIB_LP      ; wstecz w pętli dla kolejnych cyfr do PF-NIB-LP


          JR   PF_DC_OUT      ; naprzód do PF-DC-OUT w celu przetworzenia części ułamkowej

; $1682 : 5762
PF_E_FMT: LD   B,E            ; licznik do B

          CALL PF_NIBBLE      ; procedura PF-NIBBLE drukuje jedną cyfrę.

          CALL PF_DC_OUT      ; procedura PF-DC-OUT obsługuje część ułamkową.

          LD   A,$2A          ; przygotuj znak 'E'

          RST  10H            ; PISZ-AKUMULATOR

          LD   A,B            ; przenieś wykładnik do A
          AND  A              ; sprawdź znak.

          JP   P,PF_E_POS     ; jeśli dodatnie, skocz naprzód do PF-E-POS

          NEG                 ; zmień ujemny wykładnik na dodatni.
          LD   B,A            ; zachowaj dodatni wykładnik w B.

          LD   A,$16          ; przygotuj znak '-'

          JR   PF_E_SIGN      ; przeskocz naprzód do PF-E-SIGN

; $1698 : 5784
PF_E_POS: LD   A,$15          ; przygotuj znak '+'

; $169A : 5786
PF_E_SIGN: RST 10H            ; PISZ-AKUMULATOR

; teraz zamień całkowity wykładnik w B na dwie cyfry. Będzie miał wartość mniejszą od 99.

          LD   A,B            ; pobierz dodatni wykładnik.
          LD   B,$FF          ; rozpocznij od lewej cyfry równej minus jeden.

; $169E : 5790
PF_E_TENS: INC B              ; zwiększ licznik dziesiątek
          SUB  $0A            ; odejmij dziesięć od wykładnika

          JR   NC,PF_E_TENS   ; skocz wstecz w pętli do PF-E-TENS, jeśli większe od dziesięć 

          ADD  A,$0A          ; anuluj efekt ostatniego odejmowania
          LD   C,A            ; przenieś resztę do C
          LD   A,B            ; wartość dziesiątek przenieś do A.
          AND  A              ; testuj zero.

          JR   Z,PF_E_LOW     ; przeskocz naprzód do PF-E-LOW, jeśli tak, 

          CALL OUT_CODE       ; procedura OUT-CODE drukuje jako cyfry '1' - '9'

; $16AD : 5805
PF_E_LOW: LD   A,C            ; młodszy bajt do A

          CALL OUT_CODE        ; procedura OUT-CODE drukuje ostatnią cyfrę wykładnika.

          RET

; ta odnoga zajmuje się zerami po przecinku dziesiętnym. Np. .01 lub .0000999

; $16B2 : 5810
PF_ZEROS: NEG                 ; zmiana znaku czyni liczbę dodatnią od 1 do 4.
          LD   B,A            ; licznik zer do B.

          LD   A,$1B          ; przygotuj znak '.'

          RST  10H            ; PISZ-AKUMULATOR

          LD   A,$1C          ; przygotuj '0'

; $16BA : 5818
PF_ZRO_LP: RST 10H            ; PISZ-AKUMULATOR

          DJNZ PF_ZRO_LP      ; w pętli skocz wstecz do PF-ZRO-LP

          JR   PF_FRAC_LP     ; naprzód do PF-FRAC-LP

; istnieje potrzeba wyświetlenia zera wiodącego, np. przy 0.1, lecz nie przy .01

; $16BF : 5823
PF_ZERO_1: LD  A,$1C          ; przygotuj znak '0'.

          RST  10H            ; PISZ-AKUMULATOR

; ten podprogram obsługuje przecinek dziesiętny oraz cyfry końcowe. Jeśli kolejnym znakiem jest znaczone zero, $80, to nic więcej nie ma do wydrukowania.

; $16C2 : 5826
PF_DC_OUT: DEC (HL)           ; zmniejsz adresowany znak
          INC  (HL)           ; zwiększ go z powrotem

          RET  PE             ; wróć z przepełnieniem (miał wartość 128), ponieważ brak części ułamkowej

; inaczej część ułamkowa występuje, zatem wydrukuj kropkę dziesiętną.

          LD   A,$1B          ; przygotuj znak '.'

          RST  10H            ; PISZ-AKUMULATOR

; teraz wejdź do pętli, aby wydrukować końcowe cyfry

; $16C8 : 5832
PF_FRAC_LP: DEC (HL)          ; test na znaczone zero.
          INC  (HL)

          RET  PE             ; wróć po wyczerpaniu cyfr

          CALL PF_NIBBLE      ; drukuj cyfrę

          JR   PF_FRAC_LP     ; wstecz do PF-FRAC-LP dla wszystkich cyfr ułamkowych.

; procedura do wydruku prawych czterech bitów

; $16D0 : 5840
PF_NIBBLE: LD  A,(HL)         ; pobierz adresowany bajt
          AND  $0F            ; wymaskuj 4 najmłodsze bity

          CALL OUT_CODE       ; wydrukuj je jako cyfrę

          DEC  HL             ; zmniejsz wskaźnik

          RET

; --------------------------------------
; PROCEDURA 'PRZYGOTOWANIA DO DODAWANIA'
; --------------------------------------
; Ta procedura jest wywoływana dwukrotnie do przygotowania każdej z liczb zmiennoprzecinkowych do dodawania w miejscu na stosie kalkulatora.
; Wykładnik zostaje pobrany z pierwszego bajtu, który następnie jest czyszczony w celu odgrywania roli bajtu znaku i znacznika przepełnienia.
; Jeśli wykładnik ma wartość zero, to liczba również ma wartość 0 i wykonany zostaje wczesny powrót. Teraz zostaje ustawiony nadmiarowy bit znaku
; mantysy i w przypadku liczby ujemnej wszystkie pięć bajtów zostają zanegowane w kodzie U2 w celu przygotowania liczby do dodawania. Przy drugim
; wywołaniu wykładnik pierwszej liczby jest w rejestrze B. 

; $16D8 : 5848
PREP_ADD: LD   A,(HL)         ; pobierz wykładnik.
          LD   (HL),$00       ; ustaw ten bajt na zero, aby przyjął wszelkie przepełnienia i określał liczbę standardowo jako dodatnią.
          AND  A              ; testuj pobrany wykładnik na zero.

          RET  Z              ; wróć z ustawionym znacznikiem Z, jeśli liczba jest zerem.

          INC  HL             ; wskaż pierwszy bajt mantysy.
          BIT  7,(HL)         ; testuj bit znaku.
          SET  7,(HL)         ; ustaw go na jego wynikową wartość.
          DEC  HL             ; ustaw wskaźnik ponownie na pierwszy bajt.

          RET  Z              ; wróć, jeśli bit oznaczał liczbę dodatnią.

; jeśli jest ujemna, to wszystkie pięć bajtów zostanie zanegowane w U2, poczynając od najmłodszego.

          PUSH BC             ; zachowaj zawartość rejestru B.
          LD   BC,$0005       ; ustaw BC na pięć.
          ADD  HL,BC          ; wskaż na komórkę poza piątym bajtem.
          LD   B,C            ; ustaw licznik B na pięć.
          LD   C,A            ; umieść oryginalny wykładnik w C.
          SCF                 ; ustaw znacznik przeniesienia, aby była dodawana jedynka.

; teraz wejdź do pętli zmieniającej znak liczby na ujemny. Pierwszy z pięciu bajtów otrzyma wartość $FF oznaczającą liczbę ujemną.

; $16EC : 5868
NEG_BYTE: DEC  HL             ; wskaż na pierwszy, lub bardziej znaczący bajt.
          LD   A,(HL)         ; pobierz go do akumulatora.
          CPL                 ; zaneguj.
          ADC  A,$00          ; dodaj początkowe przeniesienie lub dalsze przeniesienia.
          LD   (HL),A         ; wstaw liczbę z powrotem na swoje miejsce.
          DJNZ NEG_BYTE       ; w pętli skocz wstecz pięć razy do NEG-BYTE

          LD   A,C            ; odtwórz wykładnik w akumulatorze.
          POP  BC             ; odtwórz zawartość rejestru B.

          RET

; --------------------------------
; PROCEDURA 'POBRANIA DWÓCH LICZB'
; --------------------------------
; Procedurę tę wykorzystują operacje dodawania, mnożenia i dzielenia do pobierania dwóch pięciobajtowych liczb adresowanych przez HL i DE
; ze stosu kalkulatora do rejestrów Z80. Rejestr HL nie może już wskazywać na pierwszą z tych dwóch liczb. Ponieważ 32-bitowe dodawanie
; wykonywane jest przy pomocy 16 bitowych instrukcji Z80, istotne jest, aby młodsze dwa bajty każdej mantysy znajdowały się w jednym zestawie
; rejestrów, a pozostałe bajty w zestawie alternatywnym.

; We: HL = najwyższa liczba, DE= najniższa liczba

;        : alt':   :
; Wy:    :H,B-C:C,B: num1
;        :L,D-E:D-E: num2

; $16F7 : 5879
FETCH_TWO: PUSH HL            ; zachowaj HL 
          PUSH AF             ; zachowaj A - wynikowy znak, gdy używane przy dzieleniu.

          LD   C,(HL)
          INC  HL
          LD   B,(HL)
          LD   (HL),A         ; wstaw znak, gdy używane przy mnożeniu.
          INC  HL
          LD   A,C            ; m1
          LD   C,(HL)
          PUSH BC             ; na stos m2 m3

          INC  HL
          LD   C,(HL)         ; m4
          INC  HL
          LD   B,(HL)         ; m5  BC zawiera m5 m4

          EX   DE,HL          ; ustaw HL na początek drugiej liczby.

          LD   D,A            ; m1
          LD   E,(HL)
          PUSH DE             ; na stos   m1 n1

          INC  HL
          LD   D,(HL)
          INC  HL
          LD   E,(HL)
          PUSH DE             ; na stos   n2 n3

          EXX

          POP  DE             ; ze stosu  n2 n3
          POP  HL             ; ze stosu  m1 n1
          POP  BC             ; ze stosu  m2 m3

          EXX

          INC  HL
          LD   D,(HL)
          INC  HL
          LD   E,(HL)         ; DE zawiera n4 n5

          POP  AF             ; odtwórz zachowane rejestry
          POP  HL

          RET

; --------------------------------
; PROCEDURA 'PRZESUWANIA SKŁADNIKA'
; --------------------------------
; Akumulator zawiera różnicę pomiędzy dwoma wykładnikami. Dodana ma być najmniejsza liczba.

; $171A : 5914
SHIFT_FP: AND  A              ; testuj różnicę pomiędzy dwoma wykładnikami.

          RET  Z              ; wróć, gdy zero - oba są znormalizowane.

          CP   $21            ; porównaj z 33 bitami.

          JR   NC,ADDEND_0    ; jeśli większe niż 32, skocz naprzód do ADDEND-0

          PUSH BC             ; zachowaj część w BC
          LD   B,A            ; licznik przesunięć do B.

; Teraz wykonaj B przesunięć na składniku L'D'E'D E w celu zrównania go z dodajną H'B'C'C B

; $1722 : 5922
ONE_SHIFT: EXX
          SRA  L              ;    76543210->C    bit 7 bez zmian.
          RR   D              ; C->76543210->C
          RR   E              ; C->76543210->C
          EXX 
          RR   D              ; C->76543210->C
          RR   E              ; C->76543210->C
          DJNZ ONE_SHIFT      ; w pętli wykonuj B razy od ONE-SHIFT

          POP  BC             ; odzyskaj BC

          RET  NC             ; wróć, jeśli w ostatnim przesuwie nie było przeniesienia.

; jeśli ustawiony został znacznik przeniesienia, to nastąpiła utrata dokładności, zatem zaokrąglij składnik.

          CALL ADD_BACK

          RET  NZ             ; wróć, jeśli nie FF 00 00 00 00

; to odgałęzienie ustawia wszystkie pięć bajtów składnika na zero i wykonywane jest, podczas dodawania, gdy wykładniki są zbyt oddalone od siebie,
; aby bity składnika mogły wpłynąć na wynik dodawania.

; $1736 : 5942
ADDEND_0: EXX                 ; wybierz alternatywny zestaw rejestrów dla bardziej znaczących bajtów.
          XOR    A            ; wyzeruj akumulator.

; ten punkt wejścia (z mnożenia) ustawia wszystkie cztery bajty na zero lub przy kontynuowaniu od poprzedniego adresu, podczas dodawania,
; ustawia wszystkie pięć bajtów na zero.

; $1738 : 5944
ZEROS_4_5: LD  L,$00          ; ustaw bajt 1 na zero.
          LD   D,A            ; ustaw bajt 2 na A.
          LD   E,L            ; ustaw bajt 3 na zero.
          EXX                 ; wybierz główny zestaw rejestrów 
          LD   DE,$0000       ; ustaw niższe bajty 4 i 5 na zero.

          RET

; ----------------------------
; PROCEDURA 'DODAJ-Z-POWROTEM'
; ----------------------------
; Wywoływana z SHIFT-FP powyżej podczas dodawania i po normalizacji z mnożenia. W rzeczywistości jest to 32 bitowa procedura zwiększania o 1,
; która ustawia znacznik zera zgodnie z 32 bitowym wynikiem. Podczas dodawania jedynie liczby ujemne, typu FF FF FF FF FF, wersje dopełnieniowe
; liczb powiedzmy xx 80 00 00 01 dadzą w wyniku pełną kaskadową zamianę na FF 00 00 00 00. Liczba FF FF FF FF FF przy przesuwaniu w prawo nie jest
; zmieniana przez SHIFT-FP, lecz ustawia przeniesienie, co powoduje wywołanie tej procedury.

; $1741 : 5953
ADD_BACK: INC  E

          RET  NZ

          INC  D

          RET  NZ

          EXX
          INC  E

          JR   NZ,ALL_ADDED   ; jeśli brak przepełnienia, skocz naprzód do ALL-ADDED

          INC  D

; $174A : 5962
ALL_ADDED: EXX

          RET                 ; wróć z ustawionym znacznikiem zera przy zerowej mantysie.


; ----------------------
; OPERACJA 'ODEJMOWANIA'
; ----------------------
; po prostu zmień znak odjemnej i wykonaj dodawanie.

; $174C : 5964
SUBTRACT: LD   A,(DE)         ; pobierz bajt wykładnika drugiej liczby - odjemnej. 
          AND  A              ; testuj zero

          RET  Z              ; jeśli zero, wróć - pierwsza liczba jest wynikiem.

          INC  DE             ; adresuj pierwszy bajt mantysy.
          LD   A,(DE)         ; pobierz go do akumulatora.
          XOR  $80            ; zmień na przeciwny bit znaku.
          LD   (DE),A         ; umieść z powrotem na stosie kalkulatora.
          DEC  DE             ; wskaż bajt wykładnika. Przejdź do procedury dodawania.

; --------------------
; OPERACJA 'DODAWANIA'
; --------------------
; Operacja dodawania używa większość rejestrów Z80 do dodania dwóch liczb zmiennoprzecinkowych. Jest to operacja dwuargumentowa, a na wejściu HL
; wskazuje pierwszą liczbę i DE drugą.

; $1755 : 5973
ADDITION: EXX
          PUSH HL             ; zachowaj wskaźnik do następnego literału.
          EXX

          PUSH DE             ; zachowaj wskaźnik do drugiej liczby
          PUSH HL             ; zachowaj wskaźnik do pierwszej liczby - stanie się
                              ; wskaźnikiem wyniku na stosie kalkulatora.

          CALL PREP_ADD

          LD   B,A            ; zachowaj pierwszy wykładnik w B.
          EX   DE,HL          ; zamień ze sobą wskaźniki liczb.

          CALL PREP_ADD

          LD   C,A            ; zachowaj drugi wykładnik w C.
          CP   B              ; porównaj bajty wykładników.

          JR   NC,SHIFT_LEN   ; jeśli drugi większy, skocz naprzód do SHIFT-LEN

          LD   A,B            ; inaczej większy wykładnik do A
          LD   B,C            ; mniejszy do B
          EX   DE,HL          ; zamień ze sobą wskaźniki liczb.

; $1769 : 5993
SHIFT_LEN: PUSH AF            ; zachowaj starszy wykładnik
          SUB  B              ; odejmij mniejszy wykładnik

          CALL FETCH_TWO

          CALL SHIFT_FP

          POP  AF             ; odtwórz większy wykładnik.
          POP  HL             ; odtwórz wskaźnik wyniku.
          LD   (HL),A         ; wstaw bajt wykładnika.
          PUSH HL             ; ponownie zachowaj wskaźnik wyniku.

; teraz wykonaj 32-bitowe dodawanie, wykorzystując 16-bitowe instrukcje dodawania Z80

          LD   L,B            ; przenieś indywidualnie młodsze bajty mantysy do
          LD   H,C            ; rejestru HL
          ADD  HL,DE          ; operacja dodawania młodszych bajtów

; teraz dwie starsze pary bajtów, które są przechowywane w zapasowym zestawie rejestrów.

          EXX                 ; przełącz się na zapasowe rejestry 
          EX   DE,HL          ; przenieś starsze bajty mantysy do rejestru HL.
          ADC  HL,BC          ; dodawanie starszych bajtów z przeniesieniem z poprzedniej operacji.
          EX   DE,HL          ; wynik w DE, bajty znaku ($FF lub $00) do HL

; teraz zajmiemy się dwoma bajtami znaków

          LD   A,H            ; pobierz bajt znaku z num1
          ADC  A,L            ; dodaj z przeniesieniem z dodawania mantys 00 lub 01 lub FE lub FF
          LD   L,A            ; wynik w L.

; możliwe wyniki znaków i nadmiaru z mantysy
;
;  H +  L + carry =  L    RRA  XOR L  RRA
; ------------------------------------------------------------
; 00 + 00         = 00    00   00
; 00 + 00 + carry = 01    00   01     carry
; FF + FF         = FE C  FF   01     carry
; FF + FF + carry = FF C  FF   00
; FF + 00         = FF    FF   00
; FF + 00 + carry = 00 C  80   80

          RRA                 ; C->76543210->C
          XOR L               ; ustaw bit 0, jeśli wymagane jest przesunięcie.
          EXX                 ; przełącz na główny zestaw rejestrów
          EX   DE,HL          ; pełny wynik mantysy teraz w rejestrach D'E'D E.
          POP  HL             ; odtwórz wskaźnik do wynikowego wykładnika na stosie kalkulatora.
          RRA                 ; czy wystąpił nadmiar ?

          JR   NC,TEST_NEG    ; jeśli nie, przeskocz naprzód do TEST-NEG

; jeśli dodawanie dwóch dodatnich mantys wywołało nadmiar lub jeśli dodawanie dwóch ujemnych mantys nie wywołało nadmiaru, to wynikowy wykładnik
; musi być zwiększony o 1, a mantysa przesunięta jedną pozycję w prawo.

          LD   A,$01          ; wymagane jedno przesunięcie.

          CALL SHIFT_FP       ; procedura SHIFT-FP wykonuje pojedyncze przesunięcie zaokrąglając stracone bity

          INC  (HL)           ; zwiększ wykładnik.

          JR   Z,ADD_REP_6    ; naprzód do ADD-REP-6, jeśli wykładnik przewija się z FF na zero, ponieważ liczba jest wtedy zbyt duża dla systemu.

; na tym etapie wykładnik na stosie kalkulatora jest poprawny.

; $1790 : 6032
TEST_NEG: EXX                 ; przełącz się na alternatywny zestaw rejestrów.
          LD   A,L            ; załaduj znak wyniku do akumulatora.
          AND  $80            ; izoluj bit 7 z bajtu znaku, ustawiając znacznik zera, jeśli liczba jest dodatnia.
          EXX                 ; wróć do głównego zestawu rejestrów.
          INC  HL             ; wskaż pierwszy bajt mantysy
          LD   (HL),A         ; wstaw $00 dla liczby dodatniej lub $80 dla liczby ujemnej na tej pozycji na stosie kalkulatora
          DEC  HL             ; wskaż ponownie wykładnik.

          JR   Z,GO_NC_MLT    ; jeśli liczba jest dodatnia, skocz naprzód do GO-NC-MLT

; liczba ujemna musi być uzupełniona do podstawy 2, zanim zostanie umieszczona na stosie.

          LD   A,E            ; pobierz najniższy (pierwszy z prawej) bajt mantysy.
          NEG                 ; neguj
          CCF                 ; zmień przeniesienie na przeciwne
          LD   E,A            ; umieść z powrotem w rejestrze
          LD   A,D
          CPL
          ADC  A,$00
          LD   D,A
          EXX                 ; przełącz się do wyższych (pierwszych z lewej) 16 bitów.
          LD   A,E
          CPL
          ADC  A,$00
          LD   E,A
          LD   A,D
          CPL
          ADC  A,$00

          JR   NC,END_COMPL   ; bez przepełnienia, naprzód do END-COMPL

; inaczej cała mantysa jest zerem.  00 00 00 00

          RRA                 ; ustaw mantysę na 80 00 00 00
          EXX                 ; przełącz.
          INC  (HL)           ; zwiększ wykładnik.

; $17B3 : 6067
ADD_REP_6: JP  Z,REPORT_6     ; jeśli wykładnik się wyzerował, skocz naprzód do REPORT-6 'Liczba zbyt duża'

          EXX                 ; przełącz się z powrotem na alternatywny zestaw rejestrów.

; $17B7 : 6071
END_COMPL: LD  D,A            ; wstaw pierwszy bajt mantysy z powrotem do DE.
          EXX                 ; przełącz się na główny zestaw rejestrów.

; $17B9 : 6073
GO_NC_MLT: XOR  A             ; wyzeruj przeniesienie i akumulator, aby nie zostały przeniesione naprzód żadne dodatkowe bity, co zdarza się w mnożeniu.

          JR   TEST_NORM      ; naprzód do wspólnego kodu pod adresem TEST-NORM 

; ---------------------------------------------------
; PROCEDURA 'PRZYGOTOWANIA DO MNOŻENIA LUB DZIELENIA'
; ---------------------------------------------------
; ta procedura jest wywoływana dwukrotnie z mnożenia i z dzielenia, aby przygotować każdą z dwóch liczb do tych operacji. Początkowo akumulator
; przechowuje zero, a po drugim wywołaniu bit 7 akumulatora stanie się bitem znaku wyniku.

; $17BC : 6076
PREP_M_D: SCF                 ; ustaw znacznik przeniesienia, aby zasygnalizować, że liczba jest zerem.
          DEC  (HL)           ; testuj wykładnik
          INC  (HL)           ; na wartość zero.

          RET  Z              ; jeśli jest zero, wróć z ustawionym znacznikiem przeniesienia.

          INC  HL             ; adresuj pierwszy bajt mantysy.
          XOR  (HL)           ; suma modulo 2 bitów znaku.
          SET  7,(HL)         ; ustaw wynikowy bit.
          DEC  HL             ; wskaż bajt wykładnika.

          RET

; -------------------
; OPERACJA 'MNOŻENIA'
; -------------------

; $17C6 : 6086
MULTIPLY: XOR  A              ; zeruj bit 7 - bieżącego znacznika znaku.

          CALL PREP_M_D

          RET  C              ; wróć, jeśli liczba jest zerem. zero * cokolwiek = zero.

          EXX
          PUSH HL             ; zachowaj wskaźnik do 'następnego literału'
          EXX
          PUSH DE             ; zachowaj wskaźnik do drugiej liczby 
          EX   DE,HL          ; ustaw HL na adres drugiej liczby.

          CALL PREP_M_D

          EX   DE,HL          ; HL pierwsza liczba, DE - druga liczba

          JR   C,ZERO_RSLT    ; z przeniesieniem naprzód do ZERO-RSLT cokolwiek * zero = zero.

          PUSH HL             ; zachowaj wskaźnik do pierwszej liczby.

          CALL FETCH_TWO      ; procedura FETCH-TWO pobiera dwie mantysy ze stosu kalkulatora do B'C'C,B  D'E'D E
                              ; (HL będzie nadpisane, lecz wynikowy znak w A zostaje wstawiony na stos kalkulatora)
          LD   A,B            ; przenieś pierwszy bajt mantysy pierwszej liczby
          AND  A              ; wyzeruj przeniesienie.
          SBC  HL,HL          ; skrót dla LD HL,$0000 w celu ustawienia młodszych dwóch bajtów wyniku. (2 bajty programu)
          EXX                 ; przełącz na zapasowe rejestry
          PUSH HL             ; zachowaj HL
          SBC  HL,HL          ; ustaw HL na zero również w celu ustawienia starszych dwóch bajtów wyniku i wyzeruj przeniesienie.
          EXX                 ; przełącz na zwykłe rejestry.
          LD   B,$21          ; rejestr B może teraz zliczać trzydzieści trzy przesunięcia

          JR   STRT_MLT       ; naprzód do punktu wejścia pętli STRT-MLT

; Wejście do pętli mnożenia znajduje się pod adresem STRT-LOOP.

; $17E7 : 6119
MLT_LOOP: JR   NC,NO_ADD      ; jeśli brak przeniesienia, naprzód do NO-ADD inaczej dodaj mnożnik.

          ADD  HL,DE          ; dodaj dwa najmłodsze bajty do wyniku
          EXX                 ; przełącz się na starsze bajty.
          ADC  HL,DE          ; dodaj starsze bajty mnożnika oraz przeniesienie.
          EXX                 ; przełącz na główny zestaw rejestrów.

; w każdym przypadku przesuń wynik w prawo do B'C'C A

; $17EE : 6126
NO_ADD:   EXX                 ; przełącz na rejestry zapasowe
          RR   H              ; C > 76543210 > C
          RR   L              ; C > 76543210 > C
          EXX
          RR   H              ; C > 76543210 > C
          RR   L              ; C > 76543210 > C

; $17F8 : 6136
STRT_MLT: EXX                 ; przełącz na rejestry zapasowe.
          RR   B              ; C > 76543210 > C
          RR   C              ; C > 76543210 > C
          EXX                 ; teraz główny zestaw rejestrów
          RR   C              ; C > 76543210 > C
          RRA                 ; C > 76543210 > C
          DJNZ MLT_LOOP       ; wykonuj 33 razy w pętli od MLT-LOOP

          EX   DE,HL
          EXX
          EX   DE,HL
          EXX
          POP  BC
          POP  HL
          LD   A,B
          ADD  A,C

          JR   NZ,MAKE_EXPT

          AND  A

; $180E : 6158
MAKE_EXPT: DEC A
          CCF                 ; Zaneguj znacznik przeniesienia

; $1810 : 6160
DIVN_EXPT: RLA
          CCF                 ; Zaneguj znacznik przeniesienia
          RRA

          JP   P,OFLW1_CLR

          JR   NC,REPORT_6

          AND  A

; $1819 : 6169
OFLW1_CLR: INC A

          JR   NZ,OFLW2_CLR

          JR   C,OFLW2_CLR

          EXX
          BIT  7,D
          EXX

          JR   NZ,REPORT_6

; $1824 : 6180
OFLW2_CLR: LD  (HL),A
          EXX
          LD   A,B
          EXX

; dodawanie łączy się tutaj z wyzerowanym znacznikiem przeniesienia.

; $1828 : 6184
TEST_NORM: JR   NC,NORMALIZE

          LD   A,(HL)
          AND  A

; $182C : 6188
NEAR_ZERO: LD  A,$80          ; przygotuj się do ratowania najbardziej znaczącego bitu mantysy, jeśli jest ustawiony.

          JR   Z,SKIP_ZERO    ; skocz naprzód do SKIP-ZERO

; $1830 : 6192
ZERO_RSLT: XOR  A             ; stwórz maskę zerową bajtu, aby zasygnalizować ustawienie pięciu bajtów na zero.

; $1831 : 6193
SKIP_ZERO: EXX                ; przełącz na rejestry zapasowe
          AND  D              ; wyizoluj najbardziej znaczący bit, jeśli A ma wartość $80.

          CALL ZEROS_4_5      ; procedura ZEROS-4/5 ustawia mantysę bez zmiany znaczników.

          RLCA                ; testuj ustawienie MSB. Bit 7 idzie do bitu 0 albo $00 -> $00, albo $80 -> $01
          LD   (HL),A         ; utwórz wykładnik $01 (najmniejszy) lub $00 dla zero

          JR   C,OFLOW_CLR    ; w pierwszym przypadku skocz naprzód do OFLOW-CLR

          INC  HL             ; adresuj pierwszy bajt mantysy na stosie kalkulatora.
          LD   (HL),A         ; wstaw zero dla bitu znaku.
          DEC  HL             ; wskaż zerowy wykładnik

          JR   OFLOW_CLR      ; naprzód do OFLOW-CLR

; ta gałąź jest wspólna dla dodawania i mnożenia, gdy wynik mantysy jest wciąż w rejestrach D'E'D E .

; $183F : 6207
NORMALIZE: LD   B,$20         ; będzie potrzeba co najmniej 32 przesuwy w lewo.

; $1841 : 6209
SHIFT_ONE: EXX                ; adresuj starsze 16 bitów.
          BIT  7,D            ; testuj pierwszy bit od lewej
          EXX                 ; adresuj młodsze 16 bitów.

          JR   NZ,NORML_NOW   ; jeśli pierwszy od lewej bit był ustawiony, skocz naprzód do NORML-NOW

          RLCA                ; to przechowuje zero z dodawania, 33-ci bit dla mnożenia 
          RL   E              ; C < 76543210 < C
          RL   D              ; C < 76543210 < C
          EXX                 ; adresuj starsze 16 bitów.
          RL   E              ; C < 76543210 < C
          RL   D              ; C < 76543210 < C
          EXX                 ; przełącz na główne rejestry.
          DEC  (HL)           ; zmniejsz bajt wykładnika na stosie kalkulatora.

          JR   Z,NEAR_ZERO    ; jeśli wykładnik osiąga zero, wróć do NEAR-ZERO, jest możliwe, że ostatnia rotacja ustawiła bit 7 rejestru D.
                              ; Sprawdzimy to.
          DJNZ SHIFT_ONE      ; wróć wstecz w pętli do SHIFT-ONE

; Jeśli wykonano trzydzieści dwa przesuwy w lewo bez ustawienia najbardziej znaczącego bitu, to wynik jest zerem.

          JR   ZERO_RSLT      ; wstecz do ZERO-RSLT

; $1859 : 6233
NORML_NOW: RLA                ; dla ścieżki dodawania A ma zawsze wartość zero. Dla ścieżki mnożenia ...

          JR   NC,OFLOW_CLR   ; naprzód do OFLOW-CLR

; ta gałąź jest wykonywana tylko przy mnożeniu.

          CALL ADD_BACK

          JR   NZ,OFLOW_CLR   ; naprzód do OFLOW-CLR

          EXX
          LD   D,$80
          EXX
          INC  (HL)

          JR   Z,REPORT_6     ; naprzód do REPORT-6

; teraz przenosimy mantysę ze zestawu rejestrów na stos kalkulatora dołączając do niej bit znaku, który już się tam znajduje.

; $1868 : 6248
OFLOW_CLR: PUSH HL           ; zachowaj wskaźnik wykładnika na stosie.
          INC  HL            ; adresuj pierwszy bajt mantysy, który został poprzednio załadowany bitem znaku $00 lub $80.
          EXX
          PUSH DE            ; umieść na stosie dwa najbardziej znaczące bajty.
          EXX
          POP  BC            ; pobierz ze stosu - właściwa mantysa jest teraz w BCDE.

; teraz bit znaku.

          LD   A,B           ; pierwszy bajt mantysy do A 
          RLA                ; wyprowadź bit 7, który jest ustawiony na 1
          RL   (HL)          ; wprowadź bit znaku ze stosu do znacznika przeniesienia.
          RRA                ; wprowadź bit znaku do 7 bitu bajtu mantysy.

; przenosimy mantysę z głównych rejestrów na stos kalkulatora.

          LD   (HL),A
          INC  HL
          LD   (HL),C
          INC  HL
          LD   (HL),D
          INC  HL
          LD   (HL),E
          POP  HL            ; odtwórz wskaźnik do num1, które jest teraz wynikiem.
          POP  DE            ; odtwórz wskaźnik do num2, który jest teraz STKEND.
          EXX
          POP  HL            ; odtwórz wskaźnik do następnego literału kalkulatora.
          EXX

          RET

; $1880 : 6272
REPORT_6: RST  08H           ; ERROR-1
         .BYTE $05           ; Raport Błędu: Przepełnienie arytmetyczne.

; --------------------
; OPERACJA 'DZIELENIE'
; --------------------
; "Ze wszystkich operacji arytmetycznych dzielenie jest najbardziej skomplikowane oraz najmniej zrozumiałe. Szczególnie interesujące jest to,
; że programista w firmie Sinclair sam popełnił błąd w swoim kodzie (lub skopiował czyjś błąd!), ponieważ  PRINT PEEK 6352 [ $18D0 ]
; ('niepoprawiony' ROM, 6351 [ $18CF ] ) powinno dawać 218 a nie 225." - Dr Ian Logan, czasopismo Syntax sierpień/wrzesień 1982.
; [ tj. skok powinien być wykonywany do div-34th ]

; Najpierw sprawdź dzielenie przez zero

; $1882 : 6274
DIVISION: EX   DE,HL          ; zajmij się najpierw drugą liczbą
          XOR  A              ; ustaw znacznik znaku

          CALL PREP_M_D

          JR   C,REPORT_6     ; wstecz do REPORT-6, jeśli zero 'Przepełnienie arytmetyczne'

          EX   DE,HL          ; teraz przygotuj drugą liczbę i sprawdź ją na zero.

          CALL PREP_M_D

          RET  C              ; jeśli zero, wróć

          EXX
          PUSH HL             ; zachowaj wskaźnik do następnego literału kalkulatora.
          EXX
          PUSH DE             ; zachowaj wskaźnik do dzielnika - będzie to STKEND.
          PUSH HL             ; zachowaj wskaźnik do dzielnej - będzie to wynik.

          CALL FETCH_TWO      ; procedura FETCH-TWO pobiera te dwie liczby
                              ; do rejestrów H'B'C'C B
                              ;              L'D'E'D E
          EXX
          PUSH HL             ; zachowaj oba wykładniki.
          LD   H,B            ; przenieś dzielną do H'L'H L
          LD   L,C
          EXX
          LD   H,C
          LD   L,B
          XOR  A              ; wyzeruj przeniesienie oraz akumulator.
          LD   B,$DF          ; licz wprzód od -33 dziesiętnie

          JR   DIV_START      ; naprzód do punktu wewnątrz pętli pod adres DIV-START

; $18A2 : 6306
DIV_LOOP: RLA                 ; wymnóż częściowy iloraz przez dwa,
          RL   C              ; ustawiając bit wynikowy z przeniesienia.
          EXX
          RL   C
          RL   B
          EXX

; $18AB : 6315
DIV_34TH: ADD  HL,HL
          EXX
          ADC  HL,HL
          EXX

          JR   C,SUBN_ONLY    ; naprzód do SUBN-ONLY

; $18B2 : 6322
DIV_START: SBC HL,DE          ; odejmij część dzielnika.
          EXX
          SBC  HL,DE
          EXX

          JR   NC,NO_RSTORE   ; jeśli da się odejmować, naprzód do NO-RSTORE

          ADD  HL,DE          ; inaczej odtwórz
          EXX
          ADC  HL,DE
          EXX
          AND  A              ; wyczyść przeniesienie

          JR   COUNT_ONE      ; naprzód do COUNT-ONE

; $18C2 : 6338
SUBN_ONLY: AND A
          SBC  HL,DE
          EXX
          SBC  HL,DE
          EXX

; $18C9 : 6345
NO_RSTORE: SCF                ; ustaw znacznik przeniesienia

; $18CA : 6346
COUNT_ONE: INC B              ; zwiększ licznik

          JP   M,DIV_LOOP     ; jeśli wciąż minus, wróć do DIV-LOOP

          PUSH AF

          JR   Z,DIV_START    ; wstecz do DIV-START

; "Ten skok jest wykonywany w złe miejsce. 34-ty bit nigdy nie zostanie osiągnięty bez wcześniejszego przesunięcia dzielnej. Dlatego ważne wyniki,
; takie jak 1/10 i 1/1000, nie są zaokrąglane tak jak powinny być. Zaokrąglenie nigdy nie zachodzi, jeśli zależy od 34-tego bitu. Skok powinien być
; wykonywany do DIV-34th powyżej." - Dr Frank O'Hara, "The Complete Spectrum ROM Disassembly", 1983, wydane przez Melbourne House.

; Jednakże, gdy dokona się tej zmiany, to (1/2=.5) będzie teraz dawało wynik true, natomiast (.25=1/4), które dawało true, już nie będzie tak działać.

          LD   E,A
          LD   D,C
          EXX
          LD   E,C
          LD   D,B

          POP  AF
          RR   B
          POP  AF
          RR   B

          EXX
          POP  BC
          POP  HL
          LD   A,B
          SUB  C

          JP   DIVN_EXPT      ; skocz wstecz do DIVN-EXPT

; -------------------------------------------------------
; PROCEDURA 'OBCINANIA LICZBY CAŁKOWITEJ W KIERUNKU ZERA'
; -------------------------------------------------------

; $18E4 : 6372
TRUNCATE: LD   A,(HL)         ; pobierz wykładnik
          CP   $81            ; porównaj z +1  

          JR   NC,T_GR_ZERO   ; jeśli 1 lub więcej, skocz naprzód do T-GR-ZERO

; inaczej ta liczba jest mniejsza niż plus lub minus jeden i można uczynić ją zerem

          LD   (HL),$00       ; zrób wykładnik zero.
          LD   A,$20          ; przygotuj się na wyzerowanie 32 bitów mantysy.

          JR   NIL_BYTES      ; naprzód do NIL-BYTES

; $18EF : 6383
T_GR_ZERO: SUB $A0            ; odejmij +32 od wykładnika

          RET  P              ; wróć, jeśli wynik dodatni, ponieważ wszystkie 32 bity mantysy odnoszą się do części całkowitej.
                              ; Pływający przecinek jest gdzieś na prawo od mantysy
          NEG                 ; inaczej zaneguj, aby utworzyć liczbę, której prawe bity będą wyczyszczone.

; przykładowo, zaniedbując bit znaku, liczba 3.5 jest przechowywana jako wykładnik $82 mantysa .11100000 00000000 00000000 00000000
; Potrzebujemy ustawić $82 - $A0 = $E2 NEG = $1E (trzydzieści) bitów na zero, aby utworzyć liczbę całkowitą.
; Znak liczby nigdy nie jest rozważany, ponieważ pierwszy bit mantysy musi być częścią liczby całkowitej.

; $18F4 : 6388
NIL_BYTES: PUSH DE            ; zachowaj wskaźnik do STKEND
          EX   DE,HL          ; HL wskazuje na STKEND
          DEC  HL             ; teraz na ostatni bajt mantysy.
          LD   B,A            ; Przenieś licznik bitów do rejestru B.
          SRL  B              ; podziel 
          SRL  B              ; przez
          SRL  B              ; osiem

          JR   Z,BITS_ZERO    ; jeśli zero, naprzód do BITS-ZERO

; inaczej pierwotny licznik zawierał osiem lub więcej i całe bajty można wyczyścić.

; $1900 : 6400
BYTE_ZERO: LD  (HL),$00       ; ustaw osiem bitów na zero.
          DEC  HL             ; wskaż bardziej znaczący bajt mantysy.
          DJNZ BYTE_ZERO      ; skocz w pętli wstecz do BYTE-ZERO

; teraz rozważ bity resztowe.

; $1905 : 6405
BITS_ZERO: AND $07            ; wyizoluj pozostałe bity

          JR   Z,IX_END       ; jeśli ich brak, skocz naprzód do IX-END

          LD   B,A            ; przenieś licznik bitów do rejestru B.
          LD   A,$FF          ; utwórz maskę 11111111

; $190C : 6412
LESS_MASK: SLA A              ; 1 <- 76543210 <- o     przesuń maskę w lewo.
          DJNZ LESS_MASK      ; w pętli powtarzaj aż do wyzerowania licznika

          AND  (HL)           ; usuń niechciane prawe bity
          LD   (HL),A         ; i umieść w bajcie mantysy.

; $1912 : 6418
IX_END:   EX   DE,HL          ; odtwórz wskaźnik wyniku z DE. 
          POP  DE             ; odtwórz STKEND ze stosu.

          RET


;************************************
;**  KALKULATOR ZMIENNOPRZECINKOWY **
;************************************

; Ogólnie kalkulator unika używania rejestru IY.
; Wyjątkami są val i str$.
; Więc programista w asemblerze, który wyłączył przerwania w celu używania IY do innych celów, może wciąż korzystać z kalkulatora do celów matematycznych.


; -----------------
; 'TABLICA STAŁYCH'
; -----------------
; ZX81 posiada tylko liczby zmiennoprzecinkowe. Zarówno ZX80 jak i ZX Spectrum posiadają również liczby całkowite w pewnej postaci.

; $1915 : 6421
STK_ZERO: .BYTE $00           ; Bajty: 1
          .BYTE $B0           ; Wykładnik $00
          .BYTE $00           ;(+00,+00,+00)

; $1918 : 6424
STK_ONE:  .BYTE $31           ; Wykładnik $81, Bajty: 1
          .BYTE $00           ;(+00,+00,+00)

; $191A : 6426
STK_HALF: .BYTE $30           ; Wykładnik: $80, Bajty: 1
          .BYTE $00           ;(+00,+00,+00)

; $191C : 6428
STK_PI_2: .BYTE $F1           ; Wykładnik: $81, Bajty: 4
          .BYTE $49,$0F,$DA,$A2

; $1921 : 6433
STK_TEN:  .BYTE $34           ; Wykładnik: $84, Bajty: 1
          .BYTE $20           ;(+00,+00,+00)

; -----------------
; 'TABLICA ADRESÓW'
; -----------------
; rozpoczyna się od operacji dwuargumentowych, które posiadają dwa argumenty i jeden wynik. Na początku trzy pseudooperacje dwuargumentowe.

; $1923 : 6435
TBL_ADDRS: .WORD JUMP_TRUE    ; $00 Adres: $1C2F - skocz-true
          .WORD EXCHANGE      ; $01 Adres: $1A72 - wymień
          .WORD DELETE        ; $02 Adres: $19E3 - usuń

; prawdziwe operacje dwuargumentowe

          .WORD SUBTRACT      ; $03 Adres: $174C - odejmij
          .WORD MULTIPLY      ; $04 Adres: $176C - mnóż
          .WORD DIVISION      ; $05 Adres: $1882 - dziel
          .WORD TO_POWER      ; $06 Adres: $1DE2 - potęguj
          .WORD OR_LOGIC      ; $07 Adres: $1AED - logiczne-lub

          .WORD NO_AND_NO     ; $08 Adres: $1B03 - no-&-no
          .WORD NO_L_EQL      ; $09 Adres: $1B03 - no-l-eql
          .WORD NO_L_EQL      ; $0A Adres: $1B03 - no-gr-eql
          .WORD NO_L_EQL      ; $0B Adres: $1B03 - nos-neql
          .WORD NO_L_EQL      ; $0C Adres: $1B03 - no-grtr
          .WORD NO_L_EQL      ; $0D Adres: $1B03 - no-less
          .WORD NO_L_EQL      ; $0E Adres: $1B03 - nos-eql
          .WORD ADDITION      ; $0F Adres: $1755 - dodaj

          .WORD STR_AND_NO    ; $10 Adres: $1AF8 - str-&-no
          .WORD NO_L_EQL      ; $11 Adres: $1B03 - str-l-eql
          .WORD NO_L_EQL      ; $12 Adres: $1B03 - str-gr-eql
          .WORD NO_L_EQL      ; $13 Adres: $1B03 - strs-neql
          .WORD NO_L_EQL      ; $14 Adres: $1B03 - str-grtr
          .WORD NO_L_EQL      ; $15 Adres: $1B03 - str-less
          .WORD NO_L_EQL      ; $16 Adres: $1B03 - strs-eql
          .WORD STRS_ADD      ; $17 Adres: $1B62 - strs-add

; operacje jednoargumentowe

          .WORD NEGATE        ; $18 Adres: $1AA0 - neguj

          .WORD CODE          ; $19 Adres: $1C06 - code
          .WORD VAL           ; $1A Adres: $1BA4 - val
          .WORD LEN           ; $1B Adres: $1C11 - len
          .WORD SIN           ; $1C Adres: $1D49 - sin
          .WORD COS           ; $1D Adres: $1D3E - cos
          .WORD TAN           ; $1E Adres: $1D6E - tan
          .WORD ASN           ; $1F Adres: $1DC4 - asn
          .WORD ACS           ; $20 Adres: $1DD4 - acs
          .WORD ATN           ; $21 Adres: $1D76 - atn
          .WORD LN            ; $22 Adres: $1CA9 - ln
          .WORD EXP           ; $23 Adres: $1C5B - exp
          .WORD INT           ; $24 Adres: $1C46 - int
          .WORD SQR           ; $25 Adres: $1DDB - sqr
          .WORD SGN           ; $26 Adres: $1AAF - sgn
          .WORD ABS           ; $27 Adres: $1AAA - abs
          .WORD PEEK          ; $28 Adres: $1A1B - peek
          .WORD USR_NO        ; $29 Adres: $1AC5 - usr-no
          .WORD STR           ; $2A Adres: $1BD5 - str$
          .WORD CHRS          ; $2B Adres: $1B8F - chrs
          .WORD NOT_LOGIC     ; $2C Adres: $1AD5 - logiczne-nie

; koniec operacji jednoargumentowych

          .WORD MOVE_FP       ; $2D Adres: $19F6 - duplikuj
          .WORD N_MOD_M       ; $2E Adres: $1C37 - n-modulo-m

          .WORD JUMP          ; $2F Adres: $1C23 - skocz
          .WORD STK_DATA      ; $30 Adres: $19FC - dane-na-stos

          .WORD DEC_JR_NZ     ; $31 Adres: $1C17 - dec-jr-nz
          .WORD LESS_0        ; $32 Adres: $1ADB - mniej-niż-0
          .WORD GREATER_0     ; $33 Adres: $1ACE - więcej-niż-0
          .WORD END_CALC      ; $34 Adres: $002B - koniec-liczenia
          .WORD GET_ARGT      ; $35 Adres: $1D18 - pobierz-argt
          .WORD TRUNCATE      ; $36 Adres: $18E4 - obetnij
          .WORD FP_CALC_2     ; $37 Adres: $19E4 - fp-calc-2
          .WORD E_TO_FP       ; $38 Adres: $155A - e-do-fp

; kolejne adresy są po prostu następnymi dostępnymi slotami dla złożonych literałów o zakresie od $80 do $FF.

          .WORD SERIES_XX     ; $39 Adres: $1A7F - series-xx $80 - $9F.
          .WORD STK_CONST_XX  ; $3A Adres: $1A51 - stk-const-xx $A0 - $BF.
          .WORD ST_MEM_XX     ; $3B Adres: $1A63 - st-mem-xx $C0 - $DF.
          .WORD GET_MEM_XX    ; $3C Adres: $1A45 - get-mem-xx   $E0 - $FF.

; Na boku: 3D - 7F są stąd nieużywanymi literałami kalkulatora.
;          39 - 7B byłyby dostępne dla rozszerzeń.

; -----------------------------
; KALKULATOR ZMIENNOPRZECINKOWY
; -----------------------------

; $199D : 6557
CALCULATE: CALL STK_PNTRS    ; procedura ta jest wywoływana w celu ustawienia wskaźników kalkulatora dla standardowej operacji jednoargumentowej.
                             ; HL wskazuje ostatnią wartość na stosie, DE wskazuje pierwszą pozycję po stosie

; w tym punkcie procedura kalkulatora jest wywoływana przez generator ciągów funkcyjnych ...

; $19A0 : 6560
GEN_ENT_1: LD  A,B           ; przechowaj zawartość rejestru B mikroprocesora Z80
          LD   (BREG),A      ; w zmiennej systemowej BREG, będzie on służył jako licznik dla rozkazu djnz lub za instrukcję dla kalkulatora

; ... a później od tego miejsca

; $19A4 : 6564
GEN_ENT_2: EXX               ; przełącz rejestry
          EX   (SP),HL       ; i zachowaj adres następnej instrukcji, adres powrotny w H'L'.
                             ; Jeśli jest to wywołanie rekurencyjne, to H'L' z poprzedniego wywołania idzie na stos c.f. koniec obliczeń.
          EXX                ; przełącz z powrotem na główny zestaw rejestrów.

; to jest punkt wejścia pętli przy obsłudze literałów łańcuchowych.

; $19A7 : 6567
RE_ENTRY: LD   (STKEND),DE    ; zachowaj koniec stosu w zmiennej systemowej STKEND
          EXX                 ; przełącz na zapasowe rejestry
          LD   A,(HL)         ; pobierz kolejny literał
          INC  HL             ; zwiększ wskaźnik w HL'

; przy pojedynczej operacji wykonywany jest skok wstecz do tego miejsca

; $19AE : 6574
SCAN_ENT: PUSH HL             ; zachowaj wskaźnik na stosie
          AND  A              ; teraz sprawdź, czy literał

          JP   P,FIRST_3D     ; jeśli w zakresie $00 - $3D, skocz naprzód do FIRST-3D wszystko z ustawionym bitem 7 będzie jednym ze złożonych literałów.

; Literały złożone posiadają następujący format.
; bit 7 ustawiony - oznacza literał złożony.
; bity 6-5 są podgrupą 0-3
; bity 4-0 są osadzonym parametrem $00 - $1F.
; Podgrupa 0-3 musi być obsłużona w celu utworzenia dostępnych dalej czterech miejsc adresowych po prostych literałach w tablicy adresów.

          LD   D,A            ; zachowaj literał w rejestrze D
          AND  $60            ; dokonaj koniunkcji z 01100000, aby wyizolować podgrupę
          RRCA                ; obróć bity
          RRCA                ; 4 pozycje w prawo
          RRCA                ; nie pięć, ponieważ potrzebne nam jest przesunięcie * 2
          RRCA                ; 00000xx0
          ADD  A,$72          ; dodaj ($39 * 2), aby otrzymać poprawne przesunięcie.
          LD   L,A            ; umieść w L późniejsze indeksowanie.
          LD   A,D            ; odtwórz literał złożony
          AND  $1F            ; użyj maski do wyizolowania bitów parametru

          JR   ENT_TABLE      ; naprzód do ENT-TABLE

; tutaj następuje skok przy literałach prostych.

; $19C2 : 6594
FIRST_3D: CP   $18            ; porównaj z pierwszymi operacjami jednoargumentowymi.

          JR   NC,DOUBLE_A    ; przy operacjach dwuargumentowych skocz do DOUBLE-A

; operacja jednoargumentowa, więc ustaw wskaźniki.

          EXX
          LD   BC,$FFFB       ; wartość -5
          LD   D,H            ; przenieś HL, ostatnią wartość, do DE.
          LD   E,L
          ADD  HL,BC          ; odejmij 5, aby HL wskazywało na drugą wartość.
          EXX

; $19CE : 6606
DOUBLE_A: RLCA                ; podwój literał
          LD   L,A            ; i umieść w L do indeksowania

; $19D0 : 6608
ENT_TABLE: LD  DE,TBL_ADDRS   ; Adres: tbl-addrs
          LD   H,$00          ; przygotuj indeks
          ADD  HL,DE          ; dodaj, aby otrzymać adres procedury
          LD   E,(HL)         ; młodszy bajt do E
          INC  HL
          LD   D,(HL)          ; starszy bajt do D

          LD   HL,RE_ENTRY    ; Adres: RE-ENTRY
          EX   (SP),HL        ; idzie na stos maszynowy adres następnego literału idzie do HL.
          PUSH DE             ; teraz na stos trafia adres procedury.
          EXX                 ; przełącz na główne rejestry unikaj używania rejestru IY.
          LD   BC,($401D)     ; STKEND_hi do C nic nie trafia, ale do B idzie BREG i przejdź do następnej instrukcji RET,
                              ; która posiada podwójną tożsamość.

; ------------------
; PROCEDURA 'USUŃ'
; ------------------
; offset $02: 'delete'
; Prosty powrót, lecz przy użyciu jako literał kalkulatora usuwa on ostatnią wartość ze stosu. Na wejściu, jak zwykle z operacjami dwuargumentowymi,
; HL=pierwsza liczba, DE=druga liczba
; Na wyjściu, HL=wynik, DE=STKEND.
; Więc nic do roboty

; $19E3 : 6627
DELETE:   RET                 ; powróć - skocz pośrednio, jeśli kontynuuje się powyższą procedurę.

; --------------------------------
; PROCEDURA 'POJEDYNCZEJ OPERACJI'
; --------------------------------
; offset $37: 'fp-calc-2'
; Ta pojedyncza operacja jest używana do obliczania wartości większości funkcji matematycznych i łańcuchowych, które znajdują się w wyrażeniach
; języka BASIC.

; $19E4 : 6628
FP_CALC_2: POP AF             ; porzuć adres powrotny.
          LD   A,(BREG)       ; załaduj akumulator ze zmiennej systemowej BREG wartością będzie literał, np. 'tan'
          EXX                 ; przełącz na rejestry zapasowe

          JR   SCAN_ENT       ; wstecz do SCAN-ENT, następnym literałem będzie end-calc

; ----------------------------
; PROCEDURA "TEST NA 5 MIEJSC'
; ----------------------------
; Procedura ta jest wywoływana z MOVE-FP, STK-CONST i STK-STORE w celu sprawdzenia, czy jest wystarczająco miejsca pomiędzy stosem kalkulatora a
; stosem maszynowym na wartość 5-cio bajtową. Wraca z parą BC zawierającą wartość 5, gotową dla ewentualnej instrukcji LDIR.

; $19EB : 6635
TEST_5_SP: PUSH DE            ; zachowaj
          PUSH HL             ; rejestry na stosie maszynowym
          LD   BC,$0005       ; potrzeba 5 bajtów

          CALL TEST_ROOM      ; procedura TEST-ROOM testuje wolną pamięć RAM, generując, jeśli jej brak.

          POP   HL            ; inaczej odtwórz
          POP   DE            ; rejestry

          RET                 ; wróć z parą BC ustawioną na 5.

; ---------------------------------------------
; PROCEDURA 'PRZESUŃ LICZBĘ ZMIENNOPRZECINKOWĄ'
; ---------------------------------------------
; offset $2D: 'duplicate'
; Ta prosta procedura jest instrukcją LDIR przesuwającą 5 bajtów, która wykorzystuje testy pamięci. Gdy używa się jej jako literał kalkulatora,
; duplikuje ostatnią wartość na stosie kalkulatora. Jednoargumentowa, więc na wejściu HL wskazuje na ostatnią wartość, DE na STKEND.

; $19F6 : 6646
MOVE_FP:  CALL TEST_5_SP       ; procedura TEST-5-SP sprawdza wolną pamięć i ustawia BC na 5

          LDIR                 ; kopiuj te pięć bajtów.

          RET                  ; wróć z parą DE adresującą nowe STKEND i HL adresującą nową ostatnią wartość.

; ---------------------------------
; PROCEDURA 'UMIEŚĆ DANE NA STOSIE'
; ---------------------------------
; offset $30: 'stk-data'
; Gdy jakiś podprogram kalkulatora potrzebuje umieścić jakąś wartość na jego stosie, a nie jest ona typową stałą, to zostaje wywołana ta
; procedura ze zmienną liczbą następujących za nią bajtów danych, które przenoszą do tej procedury pożądaną wartość zmiennoprzecinkową
; przedstawioną w sposób najbardziej treściwy

; $19FC : 6652
STK_DATA: LD   H,D            ; prześlij STKEND
          LD   L,E            ; do HL dla wyniku.

; $19FE : 6654
STK_CONST: CALL TEST_5_SP     ; procedura TEST-5-SP sprawdza, czy jest miejsce i ustawia BC na $05.

          EXX                 ; przełącz na zapasowe rejestry
          PUSH HL             ; zachowaj na stosie wskaźnik do następnego literału
          EXX                 ; przełącz na główne rejestry
          EX   (SP),HL        ; wskaźnik do HL, adres przeznaczenia na stos.
          PUSH BC             ; zachowaj BC - wartość 5 z testowania miejsca??.
          LD   A,(HL)         ; pobierz bajt za kodem 'stk-data'
          AND  $C0            ; wyizoluj bity 7 i 6
          RLCA                ; obróć
          RLCA                ; na bity 1 i 0  zakres $00 - $03.
          LD   C,A            ; przenieś do C
          INC  C              ; i zwiększ o 1, aby otrzymać liczbę bajtów do odczytania $01 - $04
          LD   A,(HL)         ; ponownie załaduj pierwszy bajt
          AND  $3F            ; wymaskuj, aby otrzymać możliwy wykładnik.

          JR   NZ,FORM_EXP    ; jeśli dało się dołączyć wykładnik, skocz naprzód do FORM-EXP

; inaczej ten bajt podaje jedynie liczbę bitów, a wykładnik jest w następnym bajcie.

          INC  HL             ; adresuj następny bajt
          LD   A,(HL)         ; i pobierz wykładnik ( - $50).

; $1A14 : 6676
FORM_EXP: ADD  A,$50          ; teraz dodaj $50, aby utworzyć właściwy wykładnik
          LD   (DE),A         ; i załaduj go do pierwszego bajtu docelowego.
          LD   A,$05          ; umieść w akumulatorze $05 i
          SUB  C              ; odejmij C, aby otrzymać liczbę końcowych zer plus jeden.
          INC  HL             ; zwiększ adres źródła
          INC  DE             ; zwiększ adres przeznaczenia
          LD   B,$00          ; przygotuj się do kopiowania
          LDIR                ; przekopiuj C bajtów
          POP   BC            ; odtwórz licznik 5 w BC ??.
          EX   (SP),HL        ; umieść HL na stosie jako wskaźnik następnego literału, a wartość ze stosu - wskaźnik wyniku - pobierz do HL.
          EXX                 ; przełącz na rejestry zapasowe.
          POP  HL             ; odtwórz ze stosu w H'L' wskaźnik następnego literału
          EXX                 ; przełącz z powrotem na rejestry główne
          LD   B,A            ; licznik zer do B
          XOR  A              ; wyczyść akumulator

; $1A27 : 6695
STK_ZEROS: DEC B              ; zmniejsz o 1 licznik w B

          RET  Z              ; wróć przy zerze, DE wskazuje na nowe STKEND, HL wskazuje na nową liczbę.

          LD   (DE),A         ; inaczej umieść zero w miejscu docelowym
          INC  DE             ; zwiększ wskaźnik przeznaczenia

          JR   STK_ZEROS      ; cofnij się w pętli wstecz do STK-ZEROS, aż zadanie zostanie wykonane.

; -------------------------
; PROCEDURA 'POMIJAJ STAŁE'
; -------------------------
; Procedura ta przechodzi przez elementy tablicy stałych o zmiennej długości, umieszczając pośrednie, niechciane stałe na fikcyjnym stosie kalkulatora,
; który znajduje się w pierwszych pięciu bajtach pamięci ROM w ZX81.

; $1A2D : 6701
SKIP_CONS: AND A              ; testuj, czy początkowo jest zero.

; $1A2E : 6702
SKIP_NEXT: RET Z              ; Jeśli jest zero, powróć.

          PUSH AF             ; zachowaj licznik.
          PUSH DE             ; i normalny adres STKEND

          LD   DE,$0000       ; fikcyjna wartość dla STKEND na początku ROM. Uwaga, nie jest to błąd, ale ten adres trzeba przenieść gdzieś indziej,
                              ; jeśli program działa w RAM.

          CALL STK_CONST      ; procedura STK-CONST przechodzi przez rekordy o zmiennej długości.

          POP  DE             ; odtwórz prawdziwy STKEND
          POP  AF             ; odtwórz licznik
          DEC  A              ; zmniejsz go o 1

          JR   SKIP_NEXT      ; skocz wstecz w pętli do SKIP-NEXT

; -----------------------------
; PROCEDURA 'POZYCJA W PAMIĘCI'
; -----------------------------
; Procedura ta po otrzymaniu adresu bazowego w HL i indeksu w A oblicza adres A-tego elementu, gdzie każdy z tych elementów zajmuje w pamięci
; pięć bajtów. Używana jest do adresowania liczb zmiennoprzecinkowych w obszarze pamięci kalkulatora.

; $1A3C : 6716
LOC_MEM:  LD   C,A            ; zachowaj oryginalny numer $00-$1F.
          RLCA                ; A x 2
          RLCA                ; A x 4
          ADD  A,C            ; dodaj oryginalny numer, otrzymując pomnożenie przez pięć.
          LD   C,A            ; umieść wynik w C.
          LD   B,$00          ; ustaw B na 0.
          ADD  HL,BC          ; dodaj w celu otrzymania w HL adresu startu elementu.

          RET

; -------------------------------------
; PROCEDURA 'POBIERZ Z OBSZARU PAMIĘCI'
; -------------------------------------
; offsets $E0 to $FF: 'get-mem-0', 'get-mem-1' itd.
; A zawiera przesunięcie $00-$1F. Stos kalkulatora rośnie o 5 bajtów.

; $1A45 : 6725
GET_MEM_XX: PUSH DE           ; zachowaj STKEND
          LD   HL,(MEM)       ; MEM jest adresem bazowym komórek pamięci.

          CALL LOC_MEM        ; ustaw w HL adres pierwszego z 5 bajtów

          CALL MOVE_FP        ; przenieś 5 bajtów ze sprawdzeniem dostępności pamięci, DE teraz wskazuje na nowy STKEND.

          POP  HL             ; oryginalny STKEND jest teraz wskaźnikiem wyniku.

          RET

; -------------------------
; PROCEDURA 'STAŁA NA STOS'
; -------------------------
; offset $A0: 'stk-zero'  - 0 na stos
; offset $A1: 'stk-one'   - 1 na stos
; offset $A2: 'stk-half'  - 1/2 na stos
; offset $A3: 'stk-pi/2'  - pi/2 na stos
; offset $A4: 'stk-ten'   - 10 na stos
; Procedura ta pozwala jednobajtowej instrukcji umieścić na stosie do 32 stałych przechowywanych w skróconej postaci w tablicy stałych.
; W rzeczywistości potrzebne jest tylko 5 stałych. Na wejściu rejestr A zawiera literał poddany operacji AND z $1F. Nie jest to specjalnie
; efektywne i byłoby lepiej przechowywać te liczby w pełnej, 5 bajtowej postaci i umieszczać je na stosie w podobny sposób do tego, który
; później będzie używany dla tablicy wartości półtonów.

; $1A51 : 6737
STK_CONST_XX: LD H,D          ; zachowaj STKEND - potrzebne dla wyniku
          LD   L,E
          EXX                 ; przełącz na zapasowe rejestry
          PUSH HL             ; zachowaj wskaźnik do kolejnego literału
          LD   HL,STK_ZERO    ; początek tablicy stałych do H'L'
          EXX                 ; przełącz na główne rejestry

          CALL SKIP_CONS      ; przejdź do pożądanej stałej

          CALL STK_CONST      ; umieść stałą na stosie

          EXX
          POP  HL             ; odtwórz wskaźnik do następnego literału.
          EXX

          RET

; -------------------------------------
; PROCEDURA 'ZAPISZ W OBSZARZE PAMIĘCI'
; -------------------------------------
; Offsets $C0 to $DF: 'st-mem-0', 'st-mem-1' etc.
; Chociaż mogą być adresowane 32 lokacje pamięci, to dla ROM potrzebne jest tylko sześć od $C0 do $C5 i dla nich przeznaczono trzydzieści
; bajtów (6*5). Programiści ZX81, którzy chcą używać procedur zmiennoprzecinkowych z poziomu asemblera, mogą zmienić zmienną systemową
; MEM, aby wskazywała na obszar 160 bajtów RAM w celu pełnego wykorzystania całego zakresu. A zawiera wyprowadzone przesunięcie $00-$1F.
; Jednoargumentowa, zatem na wejściu HL wskazuje na ostatnią wartość, DE na STKEND.

; $1A63 : 6755
ST_MEM_XX: PUSH HL            ; zachowaj wskaźnik wyniku.
          EX   DE,HL          ; przenieś do DE.
          LD   HL,(MEM)       ; pobierz z MEM adres bazowy obszaru pamięci.

          CALL LOC_MEM        ; procedura LOC-MEM ustawia HL na adres przeznaczenia.

          EX   DE,HL          ; zamień - HL jest początkiem, DE jest przeznaczeniem.

          CALL MOVE_FP        ; Uwaga: krótkie LD BC,5; LDIR
                              ; test pamięci nie jest potrzebny, zatem te instrukcje byłyby szybsze!
          EX   DE,HL          ; DE = STKEND
          POP  HL             ; odtwórz oryginalny wskaźnik wyniku

          RET

; ------------------
; PROCEDURA 'ZAMIEŃ'
; ------------------
; offset $01: 'exchange'
; Procedura ta zamienia dwie ostatnie wartości na stosie kalkulatora. Na wejściu jak zawsze przy operacjach dwuargumentowych,
; HL=pierwsza liczba, DE=druga liczba
; Na wyjściu: HL=wynik, DE=STKEND.

; $1A72 : 6770
EXCHANGE: LD   B,$05          ; należy zamienić pięć bajtów

; początek pętli.

; $1A74 : 6772
SWAP_BYTE: LD  A,(DE)         ; każdy bajt drugiej liczby
          LD   C,(HL)         ; każdy bajt pierwszej liczby
          EX   DE,HL          ; zamień wskaźniki
          LD   (DE),A         ; zapisz każdy bajt pierwszej liczby
          LD   (HL),C         ; zapisz każdy bajt drugiej liczby
          INC  HL             ; przesuń oba wskaźniki
          INC  DE
          DJNZ SWAP_BYTE      ; skocz wstecz w pętli do SWAP-BYTE, aż wszystkie 5 bajtów będzie przesłane.

          EX   DE,HL         ; parzysta liczba zamian przywraca stan wskaźników, aby DE adresowało STKEND.

          RET

; -----------------------------
; PROCEDURA 'GENERATORA CIĄGÓW'
; -----------------------------
; offset $86: 'series-06'
; offset $88: 'series-08'
; offset $8C: 'series-0C'
; ZX81 wykorzystuje wielomiany Czybyszewa do tworzenia przybliżeń dla SIN, ATN, LN i EXP. Ich nazwa pochodzi od nazwiska rosyjskiego matematyka,
; Pafunty Czybyszewa, urodzonego w 1821, który dokonał wielu prac pionierskich w dziedzinie ciągów liczbowych. w przypadku kalkulatorów
; wielomiany Czybyszewa posiadają taką zaletę nad innymi ciągami, przykładowo nad ciągami Taylora, iż szybciej osiągają przybliżenia funkcji:
; SIN w 6 iteracjach, EXP w 8, a LN i ATN w 12. Sposób pracy tej procedury jest interesujący, lecz pełne jej wyjaśnienie wraz z demonstracją
; w BASIC'u ZX81 znajduje się "The Complete Spectrum ROM Disassembly" autorstwa dr Iana Logana i dr Franka O'Hary, opublikowanym w 1983 przez
; Melbourne House.

; $1A7F : 6783
SERIES_XX: LD  B,A            ; parametr $00 - $1F do licznika B
          CALL GEN_ENT_1      ; Rekurencyjne wywołanie specjalnego punktu wejścia w kalkulatorze, który umieszcza rejestr B w zmiennej systemowej BREG.
                              ; Adres powrotny jest następną pozycją, gdzie kalkulator oczekuje swojej pierwszej instrukcji - obecnie wskazywanej
                              ; przez H'L'. Poprzedni wskaźnik ciągów pięciobajtowych liczb zostaje umieszczony na stosie maszynowym.
; Faza wstępna.

         .BYTE $2D            ; duplikuj                x,x.
         .BYTE $0F            ; dodaj                   x+x.
         .BYTE $C0            ; stos-do-pamięci-0       2x.
         .BYTE $02            ; usuń                    .
         .BYTE $A0            ; na-stos-zero            0.
         .BYTE $C2            ; stos-do-pamięci-2       0.

; teraz następuje wejście do pętli w celu wykonania obliczeń algebraicznych dla każdej z liczb w ciągu

; $1A89 : 6793
G_LOOP:  .BYTE $2D            ; duplikuj                v,v.
         .BYTE $E0            ; na-stos-paimięć-0       v,v,2x
         .BYTE $04            ; mnóż                    v,v*2x
         .BYTE $E2            ; na-stos-paimięć-2       v,v*2x,v'
         .BYTE $C1            ; stos-do-pamięci-1
         .BYTE $03            ; odejmij                 v,v*2x-v'
         .BYTE $34            ; koniec-obliczeń

; na stosie kalkulatora umieszczona zostaje kolejna stała

          CALL STK_DATA       ; procedura STK-DATA jest wywoływana, aby bezpośrednio wstawić tą stałą na stos i zwiększyć wskaźnik H'L'.

          CALL GEN_ENT_2      ; procedura GEN-ENT-2 rekurencyjnie wchodzi do kalkulatora bez zmian w zmiennej systemowej BREG
                              ; zawartość H'L' idzie na stos maszynowy i zostaje załadowana jak zwykle następnym adresem.

         .BYTE $0F            ; dodaj                   v,2*v*x-v'+v''
         .BYTE $01            ; zamień                  2*v*x-v'+v'',v
         .BYTE $C2            ; stos-do-pamięci-2
         .BYTE $02            ; usuń                    2*v*x-v'+v''

         .BYTE $31            ; zmniejsz-skocz-jeśli-nie-zero
         .BYTE $EE            ; wstecz do $1A89, G-LOOP

; gdy wyliczana pętla zostanie zakończona, ostatnie odejmowanie da nam wynik, np. SIN X.

         .BYTE $E1            ; na-stos-paimięć-1
         .BYTE $03            ; odejmij
         .BYTE $34            ; koniec-obliczeń

          RET                 ; wróć z H'L' wskazującym na pozycję za ostatnią liczbą w ciągu.

; --------------------------------------
; Obsługa jednoargumentowego minusa ($18)
; --------------------------------------
; Procedura zmienia znak liczby na szczycie stosu kalkulatora. Operacja jednoargumentowa, zatem na wejściu HL wskazuje ostatnią wartość,
; DE wskazuje STKEND.

; $1AA0 : 6816
NEGATE:   LD   A,(HL)         ; pobierz wykładnik ostatniej wartości na stosie kalkulatora.
          AND  A              ; testuj go.

          RET  Z              ; wróć, jeśli zero - liczba jest zerem.

          INC  HL             ; adres bajtu z bitem znaku.
          LD   A,(HL)         ; pobierz go do akumulatora.
          XOR  $80            ; zmień bit znaku na przeciwny.
          LD   (HL),A         ; włóż z powrotem pobrany bajt.
          DEC  HL             ; ponownie wskaż ostatnią wartość.

          RET

; -----------------------
; Wartość bezwzględna ($27)
; -----------------------
; Ta procedura oblicza wartość bezwzględną liczby na szczycie stosu kalkulatora.

; $1AAA : 6826
ABS:      INC  HL             ; wskaż bajt z bitem znaku.
          RES  7,(HL)         ; ustaw znak na plus.
          DEC  HL             ; wskaż z powrotem ostatnią wartość.

          RET

; -----------
; Signum ($26)
; -----------
; Ta procedura zastępuje ostatnią wartość na stosie kalkulatora jedną z liczb:
; -1, jeśli liczba jest ujemna
;  1, jeśli jest dodatnia
;  0, jeśli jest równa 0 - wtedy liczba zostaje pozostawiona bez zmian

; $1AAF : 6831
SGN:      INC  HL              ; wskaż na pierwszy bajt 4-bajtowej mantysy.
          LD   A,(HL)          ; pobierz bajt z bitem znaku.
          DEC  HL              ; wskaż na wykładnik.
          DEC  (HL)            ; testuj wykładnik na wartość zero
          INC  (HL)
          SCF                  ; Ustaw znacznik przeniesienia.

          CALL NZ,FP_0_1       ; procedura FP-0/1 zastępuje ostatnią wartość liczbą 1, jeśli wykładnik wskazuje, iż wartość jest różna od zera.
                               ; W każdym przypadku mantysa składa się teraz z czterech zer.
          INC  HL              ; wskaż pierwszy bajt mantysy.
          RLCA                 ; wstaw oryginalny bit znaku do przeniesienia.
          RR   (HL)            ; wstaw przeniesienie do bitu znaku wyniku.
          DEC  HL              ; wskaż na ostatnią wartość.

          RET

; -------------------------
; obsługa funkcji PEEK ($28)
; -------------------------
; Ta funkcja zwraca zawartość komórki pamięci o podanym adresie. Można pobrać komórkę z całego obszaru adresowego, łącznie z ROM.

; $1ABE : 6846
PEEK:     CALL FIND_INT        ; procedura FIND-INT umieszcza adres w BC.

          LD   A,(BC)          ; pobierz zawartość do rejestru A.

; $1AC2 : 6850
IN_PK_STK: JP  STACK_A         ; wyjdź poprzez STACK-A, aby umieścić A na stosie kalkulatora.

; ---------------
; USR liczba ($29)
; ---------------
; Funkcja USR, za którą następuje liczba od 0 do 65535, pozwala wywołać komputerowi ZX81 program w kodzie maszynowym. Funkcja ta zwraca jako swoją
; wartość parę rejestrów BC.
; Uwaga: procedura STACK-BC odtwarza stan rejestru IY na $4000, jeśli program użytkownika go zmienił.

; $1AC5 : 6853
USR_NO:   CALL FIND_INT         ; procedura FIND-INT umieszcza dostarczony adres w BC.

          LD   HL,STACK_BC      ; na stosie maszynowym zostaje umieszczony adres STACK-BC
          PUSH HL
          PUSH BC               ; a następnie adres procedury w kodzie maszynowym.

          RET                   ; wykonany zostanie skok pośredni do tej procedury a przy powrocie z niej również do STACK-BC.

; -----------------------
; Większe od zera ($33)
; -----------------------
; Test, czy ostatnia wartość na stosie kalkulatora jest większa od zera. Ta procedura jest również wywoływana z końcowych testów procedury porównania.

; $1ACE : 6862
GREATER_0: LD  A,(HL)          ; pobierz wykładnik.
          AND  A               ; test na zero.

          RET  Z               ; jeśli tak, wróć.

          LD   A,$FF           ; przygotuj maskę XOR na bit znaku

          JR   SIGN_TO_C       ; naprzód do SIGN-TO-C, aby wstawić znak do przeniesienia (przeniesienie zostanie ustawione, jeśli znak jest dodatni)
                               ; a następnie zapisz tę lokację 1 lub 0 zgodnie z wynikiem

; ---------------------------
; Obsługa operatora NOT ($2C)
; ---------------------------
; Powoduje zapisanie ostatniej wartości 1, jeśli była równa 0, lub 0 dla każdej innej wartości.

; tj. NOT 0 zwraca 1, NOT 1 zwraca 0, NOT -3 zwraca 0.

; Ta procedura jest również bezpośrednio wywoływana z końcowych testów operatora porównania.

; $1AD5 : 6869
NOT_LOGIC: LD  A,(HL)          ; pobierz bajt wykładnika.
          NEG                  ; zaneguj - ustawia przeniesienie, jeśli był różny od zera.
          CCF                  ; zaneguj przeniesienie, aby było ustawione, gdy liczba była zerem, inaczej wyzerowane

          JR   FP_0_1          ; naprzód do FP-0/1.

; ----------------------
; Mniejsze od zera ($32)
; ----------------------
; Niszcząco sprawdź, czy ostatnia wartość na stosie kalkulatora jest mniejsza od 0. Jeśli tak, bit nr 7 drugiego bajtu będzie ustawiony na 1.

; $1ADB : 6875
LESS_0:   XOR  A               ; zeruj maskę XOR (przeniesienie zostanie ustawione, jeśli znak był ujemny).

; przenieś znak mantysy do znacznika przeniesienia.

; $1ADC : 6876
SIGN_TO_C: INC HL              ; zaadresuj drugi bajt.
          XOR (HL)             ; jeśli liczba jest ujemna, bit 7 rejestru A będzie ustawiony na 1.
          DEC  HL              ; adresuj ponownie pierwszy bajt.
          RLCA                 ; obróć bit 7 rejestru A do przeniesienia.

; --------------
; Zero lub jeden
; --------------
; Ta procedura umieszcza liczbę całkowitą o wartości 0 lub 1 na adresowanej lokacji stosu kalkulatora lub obszaru MEM. Wartość 1 jest wpisywana,
; jeśli ustawione jest przeniesienie, inaczej wpisywane jest zero.

; $1AE0 : 6880
FP_0_1:   PUSH HL              ; zachowaj wskaźnik pierwszego bajtu
          LD   B,$05           ; pięć bajów do roboty.

; $1AE3 : 6883
FP_LOOP:  LD   (HL),$00        ; w pętli wstaw 5 zer.
          INC  HL              ; adres kolejnego bajtu
          DJNZ FP_LOOP         ; powtarzaj

          POP  HL              ; odzyskaj adres pierwszego bajtu

          RET  NC              ; jeśli brak przeniesienia, zero jest gotowe

          LD   (HL),$81        ; inaczej wpisz 1

          RET


; --------------------------
; Obsługa operatora OR ($07)
; --------------------------
; Operator logiczny OR, np. X OR Y
; Wynikiem jest zero, jeśli obie wartości są zerami, inaczej wynik jest niezerowy.

; np.  0 OR 0  zwraca  0.
;     -3 OR 0  zwraca -3.
;      0 OR -3 zwraca  1.
;     -3 OR 2  zwraca  1.

; Operacja dwuargumentowa.
; Na wejściu HL wskazuje na pierwszy argument (X) a DE na drugi (Y).

; $1AED : 6893
OR_LOGIC: LD   A,(DE)          ; pobierz wykładnik drugiej liczby
          AND  A               ; testuj go.

          RET  Z               ; jeśli zero, wróć.

          SCF                  ; ustaw znacznik przeniesienia

          JR   FP_0_1          ; wstecz do FP-0/1 w celu nadpisania pierwszego argumentu wartością 1

; -----------------------------------------
; Obsługa operatora liczba AND liczba ($08)
; -----------------------------------------
; Operator logiczny AND. Zwraca zero, jeśli jeden z argumentów jest zerem.
; inaczej zwraca pierwszy argument.

; np. -3 AND 2  zwraca -3.
;     -3 AND 0  zwraca 0.
;      0 AND -2 zwraca 0.
;      0 AND 0  zwraca 0.

; Porównaj z procedurą OR powyżej

; $1AF3 : 6899
NO_AND_NO: LD  A,(DE)          ; pobierz wykładnik drugiej liczby
          AND  A               ; testuj go.

          RET  NZ              ; wróć, jeśli różne od zera

          JR   FP_0_1          ; wstecz do FP-0/1 w celu nadpisania pierwszego argumentu zerem.

; ------------------------------------------
; Obsługa operatora łańcuch AND liczba ($10)
; ------------------------------------------
; np. "WYGRYWASZ" AND WYNIK>99 zwróci ten łańcuch, jeśli warunek będzie prawdziwy lub pusty łańcuch, jeśli warunek będzie fałszywy.

; $1AF8 : 6904
STR_AND_NO: LD A,(DE)          ; pobierz wykładnik drugiej liczby.
          AND  A               ; testuj go.

          RET  NZ              ; wróć, jeśli liczba była różna od zero - wynikiem będzie łańcuch.

; jeśli liczba była równa zero (fałsz), to musi być zwrócony pusty łańcuch przez zmianę długości łańcucha na stosie kalkulatora na zero.

          PUSH DE              ; zachowaj wskaźnik do już zbędnej liczby (który stanie się nowym STKEND)

          DEC  DE              ; wskaż piąty bajt deskryptora łańcucha.
          XOR  A               ; wyczyść akumulator.
          LD   (DE),A          ; umieść zero w starszym bajcie długości.
          DEC  DE              ; zaadresuj młodszy bajt długości.
          LD   (DE),A          ; umieść tam zero - teraz łańcuch będzie pusty.

          POP  DE              ; odtwórz wskaźnik - nowe STKEND.

          RET

; -------------------------------------
; Wykonaj porównanie ($09-$0E, $11-$16)
; -------------------------------------
; Operacje dwuargumentowe.

; Ta procedura używana jest do wykonania dwunastu możliwych operacji porównań. Na wejściu rejestr B zawiera literał operacji porównania.

; $1B03 : 6915
NO_L_EQL: LD   A,B             ; przenieś literał do akumulatora
          SUB  $08             ; teraz zakres jest od 01-06 lub 09-0E
          BIT  2,A             ; wyodrębnij ">', '<', '='.

          JR   NZ,EX_OR_NOT    ; z tymi operatorami przeskocz do EX-OR-NOT.

          DEC  A               ; inaczej zmień na $00-$02, $08-$0A, 0C-0E, aby zgadzały się bity 0-2.

; $1B0B : 6923
EX_OR_NOT: RRCA                ; pierwsze RRCA ustawia przeniesienie dla wymiany.

          JR   NC,NU_OR_STR    ; naprzód do NU-OR-STR w ośmiu pozostałych przypadkach

; dla 4 innych przypadków dwie wartości na stosie kalkulatora są zamieniane miejscami.

          PUSH AF              ; zachowaj A i przeniesienie.
          PUSH HL              ; zachowaj HL - wskaźnik do pierwszego argumentu. (DE wskazuje na drugi argument).

          CALL EXCHANGE        ; procedura zamienia te dwie wartości. (HL = drugi argument, DE = STKEND)

          POP  DE              ; DE = pierwszy argument
          EX   DE,HL           ; jak było wcześniej.
          POP  AF              ; odtwórz A i przeniesienie.

; Uwaga, byłoby lepiej, jeśli drugie RRCA poprzedzałoby test łańcuchowy. Zachowałoby to dwa zdublowane bajty i jeślibyśmy również pozbyli się
; tego SUB 8 na początku, nie musielibyśmy zamieniać miejscami testowanych bitów.

; $1B16 : 6934
NU_OR_STR: BIT 2,A             ; test na porównanie łańcuchowe.

          JR   NZ,STRINGS      ; jeśli tak, naprzód do STRINGS.

; kontynuuj z porównaniami liczbowymi.

          RRCA                 ; drugie RRCA powoduje ustawienie przeniesienia przez eql/neql.
          PUSH AF              ; zachowaj A i przeniesienie.

          CALL SUBTRACT        ; procedura odejmowania pozostawia wynik na stosie.

          JR   END_TESTS       ; naprzód do END-TESTS

; $1B21 : 6945
STRINGS:  RRCA                 ; drugie RRCA powoduje ustawienie przeniesienia przez eql/neql.
          PUSH AF              ; zachowaj A i przeniesienie.

          CALL STK_FETCH       ; procedura STK-FETCH pobiera parametry drugiego łańcucha

          PUSH DE              ; zachowaj początek drugiego łańcucha.
          PUSH BC              ; oraz jego długość.

          CALL STK_FETCH       ; procedura STK-FETCH pobiera parametry pierwszego łańcucha początek w DE, długość w BC.

          POP  HL              ; odtwórz długość drugiego łańcucha w HL.

; Teraz następuje wejście do pętli w celu porównania przez odejmowanie kolejnych znaków w obu łańcuchach. Jeśli znaki są zgodne, wskaźniki
; zostają zwiększone o 1, a długość zmniejsza się o 1 i wykonywany jest skok względny do tego miejsca. Jeśli oba łańcuchy zostaną przeglądnięte
; i będą one zgodne, to są równe.

; $1B2C : 6956
BYTE_COMP: LD  A,H             ; testuj, czy drugi łańcuch jest pusty
          OR   L
          EX   (SP),HL         ; umieść długość 2 na stosie, a początek 2 w  HL.
          LD   A,B             ; starszy bajt długości do A

          JR   NZ,SEC_PLUS     ; jeśli drugi łańcuch nie jest pusty, naprzód do SEC-PLUS.

          OR   C               ; testuj długość pierwszego łańcucha.

; $1B33 : 6963
SECND_LOW: POP BC              ; pobierz długość drugiego ze stosu.

          JR   Z,BOTH_NULL     ; naprzód do BOTH-NULL, jeśli pierwszy łańcuch jest również pusty.

; warunek prawdy - pierwszy łańcuch jest dłuższy od drugiego (SECND-LESS)

          POP  AF              ; odtwórz przeniesienie (ustawione, gdy eql/neql)
          CCF                  ; Zaneguj znacznik przeniesienia.
                               ; Uwaga. Równość staje się fałszywa. Nierówność jest prawdziwa. Poprzez zamianę lub zastosowanie końcowego NOT,
                               ; wszystkie porównania zostały przetworzone, jest to zatem ścieżka sukcesu.
          JR   STR_TEST        ; wyjdź poprzez STR-TEST

; Skok następuje tutaj przy zgodności

; $1B3A : 6970
BOTH_NULL: POP AF              ; odtwórz przeniesienie - ustawione dla eql/neql

          JR   STR_TEST        ; naprzód do STR-TEST

; skok tutaj jest wtedy, gdy drugi łańcuch nie jest pusty, a młodszy bajt pierwszego musi zostać przetestowany.

; $1B3D : 6973
SEC_PLUS: OR   C               ; sprawdź długość pierwszego łańcucha.

          JR   Z,FRST_LESS     ; jeśli długość wynosi zero, skocz naprzód do FRST-LESS.

; w obu łańcuchach pozostało przynajmniej po jednym znaku.

          LD   A,(DE)          ; pobierz znak z pierwszego łańcucha.
          SUB  (HL)            ; odejmij od niego znak z drugiego łańcucha.

          JR   C,FRST_LESS     ; jeśli ustawione przeniesienie, naprzód do FRST-LESS

          JR   NZ,SECND_LOW    ; wstecz do SECND-LOW a następnie do STR-TEST, jeśli brak zgodności

          DEC  BC              ; zmniejsz długość pierwszego łańcucha.
          INC  DE              ; zwiększ wskaźnik pierwszego łańcucha.
          INC  HL              ; zwiększ wskaźnik drugiego łańcucha.
          EX   (SP),HL         ; zamień go z długością na stosie
          DEC  HL              ; zmniejsz długość drugiego łańcucha

          JR   BYTE_COMP       ; wstecz do BYTE-COMP

; fałszywy warunek.

; $1B4D : 6989
FRST_LESS: POP BC              ; usuń długość
          POP  AF              ; pobierz A
          AND  A               ; wyzeruj przeniesienie dla wyniku false.

; zgodność oraz x$>y$ spotykają się tutaj

; $1B50 : 6992
STR_TEST: PUSH AF              ; dla testów łańcuchowych na stosie kalkulatora umieszczane jest zero

          RST  28H             ; KALKULATOR
         .BYTE $A0             ; zero-na-stos
         .BYTE $34             ; koniec-obliczeń

; ścieżka numeryczna i łańcuchowa schodzą się tutaj.

; $1B54 : 6996
END_TESTS: POP AF              ; te trzy testy, wywoływane wg konieczności
          PUSH AF              ; dają poprawny wynik dla wszystkich dwunastu porównań. Wstępne przeniesienie jest ustawiane dla '<>' i '=',

          CALL C,NOT_LOGIC     ; a końcowe przeniesienie jest ustawiane dla '>', '<' i '='.

          CALL GREATER_0

          POP  AF              ; odtwórz literał
          RRCA                 ; trzecie RRCA - test na '<=', ">=' lub '<>'.

          CALL NC,NOT_LOGIC    ; jeśli tak, zastosuj końcowe NOT.

          RET

; -----------------------
; Łączenie łańcuchów($17)
; -----------------------
; Ten literał łączy dwa łańcuchy w jeden, np. LET A$ = B$ + C$. Parametry dwóch łańcuchów do złączenia są na stosie.

; $1B62 : 7010
STRS_ADD: CALL STK_FETCH       ; procedura STK-FETCH pobiera parametry pierwszego łańcucha i usuwa je ze stosu kalkulatora.

          PUSH DE              ; zachowaj adres startu.
          PUSH BC              ; i długość.

          CALL STK_FETCH       ; procedura STK-FETCH dla drugiego łańcucha

          POP  HL              ; ponownie pobierz pierwszą długość
          PUSH HL              ; i zachowaj ponownie na stosie
          PUSH DE              ; zachowaj początek drugiego łańcucha
          PUSH BC              ; i jego długość.
          ADD  HL,BC           ; dodaj obie długości.
          LD   B,H             ; przenieś do BC
          LD   C,L             ; i stwórz

          RST  30H             ; BC-miejsc w obszarze roboczym. DE wskazuje na start tego obszaru.

          CALL STK_STO         ; procedura STK-STO-$ umieszcza parametry nowego łańcucha na stosie, uaktualniając STKEND.

          POP  BC              ; długość pierwszego
          POP  HL              ; adres początku
          LD   A,B             ; test na zerową długość
          OR   C

          JR   Z,OTHER_STR     ; jeśli zerowa długość, idź do OTHER-STR

          LDIR                 ; skopiuj łańcuch do przestrzeni roboczej.

; $1B7D : 7037
OTHER_STR: POP BC              ; teraz druga długość
          POP  HL              ; i początek łańcucha
          LD   A,B             ; test na zerową długość
          OR   C

          JR   Z,STK_PNTRS     ; przeskocz naprzód do STK-PNTRS, jeśli długość zerowa.

          LDIR                 ; inaczej kopiuj bajty i kontynuuj w następnej procedurze, która ustawia wskaźniki stosu kalkulatora.

; ---------------------------
; Wskaźniki stosu kalkulatora
; ---------------------------
; Rejestr DE jest ustawiony na STKEND a HL, wskaźnik wyniku, jest ustawiony na 5 komórek poniżej. Procedura jest używana, gdy zapis tych
; wartości jest niewygodny w czasie używania stosu kalkulatora podczas innych operacji na stosie maszynowym. Procedura jest również wykorzystywana
; do zakończenia procedury VAL z tego samego powodu i do inicjowania stosu kalkulatora na początku procedury CALCULATE.

; $1B85 : 7045
STK_PNTRS: LD  HL,(STKEND)     ; pobierz wartość STKEND ze zmiennej systemowej.
          LD   DE,$FFFB        ; wartość -5
          PUSH HL              ; zachowaj wartość STKEND.
          ADD  HL,DE           ; odejmij 5 od HL.
          POP  DE              ; pobierz STKEND do DE.

          RET

; -----------------
; Obsługa CHR$ (2B)
; -----------------
; Funkcja zwraca jednoznakowy łańcuch, który jest wynikiem zamiany liczby z zakresu 0-255 na łańcuch, np. CHR$ 38 = "A".
; Uwaga. ZX81 nie posiada zestawu znaków ASCII.

; $1B8F : 7055
CHRS:     CALL FP_TO_A         ; procedura FP-TO-A umieszcza tę liczbę w A.

          JR   C,REPORT_BD     ; jeśli nadmiar, naprzód do REPORT-BD

          JR   NZ,REPORT_BD    ; jeśli ujemna, naprzód do REPORT-BD

          PUSH AF              ; zachowaj argument.
          LD   BC,$0001        ; potrzebne jedno miejsce.

          RST  30H             ; BC-MIEJSC ustawia DE na początek obszaru

          POP  AF              ; odtwórz liczbę ze stosu.
          LD   (DE),A          ; i umieść ją w obszarze roboczym.

          CALL STK_STO         ; procedura STK-STO-$ umieszcza na stosie deskryptor.

          EX   DE,HL           ; ustaw HL na wskazywanie wyniku a DE na STKEND.

          RET

; $1BA2 : 7074
REPORT_BD: RST 08H             ; ERROR-1
         .BYTE $0A             ; Raport Błędu: Liczba całkowita poza zakresem

; -----------------
; Obsługa VAL ($1A)
; -----------------
;   VAL traktuje znaki w łańcuchu jak wyrażenie liczbowe.
;       np. VAL "2.3" = 2.3; VAL "2+4" = 6, VAL ("2" + "4") = 24.

; $1BA4 : 7076
VAL:      LD   HL,(CH_ADD)     ; pobierz wartość zmiennej systemowej CH_ADD
          PUSH HL              ; i zapisz ją na stosie maszynowym.

          CALL STK_FETCH       ; procedura STK-FETCH pobiera argument łańcuchowy ze stosu kalkulatora.

          PUSH DE              ; zachowaj adres początku łańcucha.
          INC  BC              ; zwiększ długość na znak nowego wiersza.

          RST  30H             ; BC-MIEJSC tworzy miejsce w obszarze roboczym.

          POP  HL              ; odtwórz początek łańcucha w HL.
          LD   (CH_ADD),DE     ; załaduj CH_ADD początkiem DE w obszarze roboczym.

          PUSH DE              ; zachowaj początek w obszarze roboczym
          LDIR                 ; skopiuj łańcuch z programu, zmiennych lub obszaru roboczego do zarezerwowanego miejsca.
          EX   DE,HL           ; do HL koniec łańcucha + 1
          DEC  HL              ; zmniejsz HL, aby wskazywało na koniec nowego obszaru.
          LD   (HL),$76        ; wstaw na końcu znak końca wiersza - ZX81 nie używa kodu ASCII.
          RES  7,(IY+$01)      ; uaktualnij FLAGS  - sygnalizuj sprawdzanie składni.

          CALL CLASS_6         ; procedura CLASS-06 - sprawdza składnię wyrażenia.

          CALL CHECK_2         ; procedura CHECK-2 sprawdza osiągnięcie końca wiersza.

          POP  HL              ; odtwórz początek łańcucha w obszarze roboczym.
          LD   (CH_ADD),HL     ; ustaw ponownie CH_ADD na początek łańcucha.
          SET  7,(IY+$01)      ; uaktualnij FLAGS  - sygnalizuj wykonywanie programu.

          CALL SCANNING        ; procedura SCANNING oblicza w całości wyrażenie w łańcuchu, pozostawiając wynik na stosie kalkulatora.

          POP  HL              ; odtwórz oryginalną wartość CH_ADD.
          LD   (CH_ADD),HL

          JR   STK_PNTRS       ; wyjdź poprzez STK-PNTRS, co resetuje wskaźniki stosu kalkulatora.

; -----------------
; Obsługa STR$ (2A)
; -----------------
; Ta funkcja zwraca reprezentację łańcuchową argumentu liczbowego. Użyta metoda polega na oszukaniu procedury PRINT-FP, tak aby sądziła
; ona, że zapisuje do ściśniętego bufora wideo, gdy w rzeczywistości zapisuje do obszaru roboczego łańcucha.
; Jeśli na pozycji druku znajduje się znak newline a liczba kolumn nie została zredukowana do zera, to procedura wydruku zakłada, że w systemie
; jest tylko 1KB pamięci RAM i pamięć ekranu, jak i reszta pamięci dynamicznej, rozszerza się według potrzeb za pomocą wywołań do procedury
; ONE-SPACE. Ekran jest odzwierciedlony znakowo, nie bitowo.

; $1BD5 : 7125
STR:      LD   BC,$0001        ; utwórz początkowy bajt w obszarze roboczym

          RST  30H             ; wykorzystując procedurę BC-SPACES.

          LD   (HL),$76        ; umieść tam znak końca wiersza.
          LD   HL,(S_POSN)     ; pobierz wartość S_POSN - kolumna i wiersz
          PUSH HL              ; zachowaj je na stosie.

          LD   L,$FF           ; ustaw wartość kolumny na 255, co da wymyślony bufor o długości 254 znaków
          LD   (S_POSN),HL     ; i zapisz go w zmiennej systemowej S_POSN.

          LD   HL,(DF_CC)      ; pobierz wartość DF_CC
          PUSH HL              ; i również zachowaj na stosie.

          LD   (DF_CC),DE      ; teraz wstaw adres początku obszaru roboczego do DF_CC, które zwykle wskazuje adres gdzieś wewnątrz bufora ekranu.
          PUSH DE              ; zachowaj adres nowego łańcucha.

          CALL PRINT_FP        ; wydrukuj wartość argumentu w obszarze roboczym.

          POP  DE              ; odtwórz początek łańcucha.

          LD   HL,(DF_CC)      ; pobierz adres końca łańcucha z DF_CC.
          AND  A               ; przygotuj się do odejmowania.
          SBC  HL,DE           ; odejmij, aby otrzymać długość.

          LD   B,H             ; i przenieś ją do BC
          LD   C,L             ; register.

          POP  HL              ; odtwórz pierwotną wartość DF_CC
          LD   (DF_CC),HL

          POP  HL              ; odtwórz pierwotne wartości S_POSN
          LD   (S_POSN),HL

          CALL STK_STO         ; procedura STK-STO-$ umieszcza deskryptor łańcucha na stosie kalkulatora.

          EX   DE,HL           ; HL = ostatnia wartość, DE = STKEND.

          RET

; --------------
; FUNKCJA 'CODE'
; --------------
; (offset $19: 'code')
; Zwraca kod znaku lub kod pierwszego znaku w łańcuchu. Np. CODE "AARDVARK" = 38  (nie 65, ponieważ ZX81 nie stosuje kodu ASCII).

; $1C06 : 7174
CODE:     CALL STK_FETCH       ; procedura STK-FETCH pobiera parametry łańcucha i usuwa je ze stosu kalkulatora.
                               ; DE wskazuje na początek, BC zawiera długość.
          LD   A,B             ; test na długość łańcucha
          OR   C

          JR   Z,STK_CODE      ; jeśli pusty łańcuch, przeskocz do STK-CODE z zerem.

          LD   A,(DE)          ; inaczej pobierz pierwszy znak.

; $1C0E : 7182
STK_CODE: JP   STACK_A         ; skocz wstecz do STACK-A (z testem pamięci)

; ----------------
; PODPROGRAM 'LEN'
; ----------------
; (offset $1b: 'len')
; Zwraca długość łańcucha. W BASICu firmy Sinclair łańcuchy mogą posiadać długość przekraczającą 20.000 znaków, więc do przechowania długości
; wymagany jest rejestr szesnastobitowy.

; $1C11 : 7185
LEN:      CALL STK_FETCH       ; procedura STK-FETCH pobiera parametry łańcucha i usuwa je ze stosu kalkulatora.
                               ; para rejestrów BC zawiera teraz długość łańcucha.

          JP   STACK_BC        ; skocz wstecz do STACK-BC, aby umieścić wynik na stosie kalkulatora (z testem pamięci).

; -----------------------------
; PODPROGRAM 'ZMNIEJSZ LICZNIK'
; -----------------------------
; (offset $31: 'dec-jr-nz')
; Kalkulator posiada instrukcję, która zmniejsza jednobajtowy pseudorejestr i wykonuje wynikłe z tego skoki względne w identyczny sposób,
; jak instrukcja DJNZ mikroprocesora Z80.

; $1C17 : 7191
DEC_JR_NZ: EXX                 ; przełącz na zestaw adresujący kod
          PUSH HL              ; zachowaj wskaźnik do bajtu z przesunięciem
          LD   HL,BREG         ; zaadresuj BREG w zmiennych systemowych
          DEC  (HL)            ; zmniejsz go
          POP  HL              ; odtwórz wskaźnik

          JR   NZ,JUMP_2       ; jeśli nie było zera, skocz do JUMP-2

          INC  HL              ; idź poza bajt z długością skoku.
          EXX                  ; wróć do głównego zestawu rejestrów

          RET

; -----------------
; PODPROGRAM 'SKOCZ'
; -----------------
; (Offset $2F; 'jump')
; Procedura umożliwia kalkulatorowi wykonywanie skoków względnych, podobnych do instrukcji JR obecnej w zestawie poleceń mikroprocesora Z80.

; $1C23 : 7203
JUMP:     EXX                  ; przełącz na zestaw wskazujący

; $1C24 : 7204
JUMP_2:   LD   E,(HL)          ; bajt skoku 0-127 naprzód, 128-255 wstecz.
          XOR  A               ; wyczyść akumulator.
          BIT  7,E             ; sprawdź, czy skok wstecz

          JR   Z,JUMP_3        ; jeśli dodatni, przeskocz do JUMP-3.

          CPL                  ; inaczej zmień na przeciwny.

; $1C2B : 7211
JUMP_3:   LD   D,A             ; przenieś do starszego bajtu.
          ADD  HL,DE           ; przesuń wskaźnik kalkulatora naprzód lub wstecz.
          EXX                  ; wyjdź z zestawu wskaźnikowego.

          RET

; --------------------------------
; PODPROGRAM 'SKOCZ PRZY PRAWDZIE'
; --------------------------------
; (Offset $00; 'jump-true')
; Procedura pozwala kalkulatorowi wykonywać warunkowe skoki względne zależne od wyniku ostatniego testu. W ZX81 wykładnik będzie równy 0 dla zera
; lub $81 dla wyniku jeden.

; $1C2F : 7215
JUMP_TRUE: LD  A,(DE)          ; pobierz bajt wykładnika
          AND  A               ; wynik 0 czy 1 ?

          JR   NZ,JUMP         ; jeśli 1, wstecz do JUMP.

          EXX                  ; inaczej przełącz na zestaw wskaźnikowy.
          INC  HL              ; przejdź ponad bajtem z długością skoku.
          EXX                  ; wróć do głównego zestawu rejestrów.

          RET

; -------------------
; PODPROGRAM 'MODULO'
; -------------------
; ( Offset $2E: 'n-mod-m' )
; ( i1, i2 -- i3, i4 )
; Ten podprogram oblicza wartość N mod M, gdzie M jest liczbą naturalną, ostatnią wartością na stosie kalkulatora, a N jest liczbą naturalną
; leżącą poniżej. Procedura zwraca wynik dzielenia jako ostatnią wartość oraz leżącą pod nią resztę z dzielenia.
; Np.    17 MOD 3 = 5 i reszta 2
; Podprogram jest wywoływany podczas obliczania liczby pseudolosowej oraz również przez procedurę PRINT-FP.

; $1C37 : 7223
N_MOD_M:  RST  28H             ; KALKULATOR           17, 3.
         .BYTE $C0             ; stos-do-pamięci-0    17, 3.
         .BYTE $02             ; usuń                 17.
         .BYTE $2D             ; duplikuj             17, 17.
         .BYTE $E0             ; pobierz-pamięć-0     17, 17, 3.
         .BYTE $05             ; dziel                17, 17/3.
         .BYTE $24             ; zamień-na-całkowitą  17, 5.
         .BYTE $E0             ; pobierz-pamięć-0     17, 5, 3.
         .BYTE $01             ; zamień               17, 3, 5.
         .BYTE $C0             ; stos-do-pamięci-0    17, 3, 5.
         .BYTE $04             ; mnóż                 17, 15.
         .BYTE $03             ; odejmij              2.
         .BYTE $E0             ; pobierz-pamięć-0     2, 5.
         .BYTE $34             ; koniec-obliczeń      2, 5.

          RET

; --------------------------
; FUNKCJA 'LICZBA CAŁKOWITA'
; --------------------------
; (offset $24: 'int')
; Funkcja ta zwraca część całkowitą z x, która dla liczb dodatnich jest taka sama jak dla zaokrąglania. Literał zaokrąglij
; obcina liczby ujemne w górę, zatem -3.4 daje wynik -3, natomiast funkcja INT w języku BASIC musi zaokrąglać liczby ujemne w dół, aby otrzymać
; INT -3.4 równe -4. Najlepiej przejść przez polecenia, używając jako przykładowych wartości liczb 3.4 i -3.4

; $1C46 : 7238
INT:      RST  28H            ; KALKULATOR             x.    (= 3.4 lub -3.4).
         .BYTE $2D            ; duplikuj               x, x.
         .BYTE $32            ; mniej-niż-0            x, (1/0)
         .BYTE $00            ; skocz-przy-prawdzie    x, (1/0)
         .BYTE $04            ; do L1C46, X-NEG
         .BYTE $36            ; zaokrąglij             trunc 3.4 = 3.
         .BYTE $34            ; koniec-obliczeń        3.

          RET                 ; wróć z wynikiem INT x na stosie kalkulatora.

; $1C4E : 7246
X_NEG:   .BYTE $2D            ; duplikuj               -3.4, -3.4.
         .BYTE $36            ; zaokrąglij             -3.4, -3.
         .BYTE $C0            ; stos-do-pamięci-0      -3.4, -3.
         .BYTE $03            ; odejmij                -.4
         .BYTE $E0            ; na-stos-paimięć-0      -.4, -3.
         .BYTE $01            ; zamień                 -3, -.4.
         .BYTE $2C            ; neguj-logicznie        -3, (0).
         .BYTE $00            ; skocz-przy-prawdzie    -3.
         .BYTE $03            ; do $1C59, EXIT         -3.
         .BYTE $A1            ; jeden-na-stos          -3, 1.
         .BYTE $03            ; odejmij                -4.

; $1C59 : 7257
EXIT:    .BYTE $34            ; koniec-obliczeń        -4.

          RET

; ----------------
; Potęgowanie (23)
; ----------------

; $1C5B : 7259
EXP:      RST  28H            ; KALKULATOR
         .BYTE $30            ; dane-na-stos
         .BYTE $F1            ; Wykładnik: $81, Bajty: 4
         .BYTE $38,$AA,$3B,$29
         .BYTE $04            ; mnóż
         .BYTE $2D            ; duplikuj
         .BYTE $24            ; na-liczbę-całkowitą
         .BYTE $C3            ; stos-do-pamięci-3
         .BYTE $03            ; odejmij
         .BYTE $2D            ; duplikuj
         .BYTE $0F            ; dodaj
         .BYTE $A1            ; jeden-na-stos
         .BYTE $03            ; odejmij
         .BYTE $88            ; serie-08
         .BYTE $13            ; Wykładnik: $63, Bajty: 1
         .BYTE $36            ;(+00,+00,+00)
         .BYTE $58            ; Wykładnik: $68, Bajty: 2
         .BYTE $65,$66        ;(+00,+00)
         .BYTE $9D            ; Wykładnik: $6D, Bajty: 3
         .BYTE $78,$65,$40    ;(+00)
         .BYTE $A2            ; Wykładnik: $72, Bajty: 3
         .BYTE $60,$32,$C9    ;(+00)
         .BYTE $E7            ; Wykładnik: $77, Bajty: 4
         .BYTE $21,$F7,$AF,$24
         .BYTE $EB            ; Wykładnik: $7B, Bajty: 4
         .BYTE $2F,$B0,$B0,$14
         .BYTE $EE            ; Wykładnik: $7E, Bajty: 4
         .BYTE $7E,$BB,$94,$58
         .BYTE $F1            ; Wykładnik: $81, Bajty: 4
         .BYTE $3A,$7E,$F8,$CF
         .BYTE $E3            ; na-stos-paimięć-3
         .BYTE $34            ; koniec-obliczeń

          CALL FP_TO_A

          JR   NZ,N_NEGTV

          JR   C,REPORT_6B

          ADD  A,(HL)

          JR   NC,RESULT_OK

; $1C99 : 7321
REPORT_6B: RST  08H           ; ERROR-1
         .BYTE $05            ; Raport Błędu: Liczba zbyt duża

; $1C9B : 7323
N_NEGTV:  JR   C,RSLT_ZERO

          SUB  (HL)

          JR   NC,RSLT_ZERO

          NEG

; $1CA2 : 7330
RESULT_OK: LD  (HL),A

          RET

; $1CA4 : 7332
RSLT_ZERO: RST 28H            ; KALKULATOR
         .BYTE $02            ; usuń
         .BYTE $A0            ; na-stos-zero
         .BYTE $34            ; koniec-obliczeń

          RET

; ----------------------------
; FUNKCJA 'LOGARYTM NATURALNY'
; ----------------------------
; (offset $22: 'ln')
; Jak sam ZX81, logarytmy 'naturalne' pochodzą ze Szkocji. Zostały wymyślone w 1614 roku przez obytego w podróżach Szkota o nazwisku John Napier,
; który zapisał "Nic nie jest bardziej dokuczliwe i utrudniające w obliczeniach od mnożeń, dzieleń, kwadratów i sześcianów dużych liczb".

; Logarytmy Napiera umożliwiły wykonywanie powyższych operacji przez proste dodawanie i odejmowanie, ułatwiając obliczenia nawigacyjne i astronomiczne,
; które dręczyły jego erę. Logarytmy naturalne zostały szybko zastąpione logarytmami przy podstawie 10, które wraz z Napierem wynalazł Henry Briggs,
; wyuczony w Cambridge profesor geometrii na Uniwersytecie Oksfordzkim. Uprościły one układanie tablic, które pozwalały ludziom łatwo skalować
; obliczenia.

; Dopiero niedawno, wraz z pojawieniem się kalkulatorów kieszonkowych i komputerów takich jak ZX81, logarytmy naturalne odzyskały swoją pozycję,
; chociaż niektóre komputery wciąż zachowują logarytmy dziesiętne. Logarytmy naturalne są potęgami podstawy 'e', która, podobnie jak liczba pi,
; w sposób naturalny pojawia się w różnych dziedzinach matematyki. Również jak 'pi' liczba 'e' jest niewymierna i zaczyna się jako 2.718281828...

; Tabelaryczne używanie logarytmów polegało na tym, iż aby pomnożyć przez siebie dwie liczby a i b, należało znaleźć ich logarytmy, następnie
; znalezione logarytmy dodać i otrzymaną sumę odszukać w tablicy antylogarytmów, w której dostawaliśmy pożądany iloczyn.

; Funkcja EXP jest odpowiednikiem antylogarytmu w języku BASIC. Biorąc dwie dowolne liczby, powiedzmy 1.72 i 6.89, uruchom poniższy program:
; 10 PRINT EXP ( LN 1.72 + LN 6.89 )
; dostaniesz taki sam wynik jak:
; 20 PRINT 1.72 * 6.89.
; Dzielenie wykonuje się za pomocą odejmowania dwóch logarytmów.

; Napier wspominał również o rachunkach związanych z kwadratowymi i sześciennymi potęgami oraz pierwiastkami. Aby podnieść pewną liczbę do 3 potęgi,
; znajdź jej logarytm naturalny, pomnóż go przez 3 i znajdź antylogarytm wyniku, np.
; PRINT EXP( LN 4 * 3 )
; daje 64.
; Podobnie, aby znaleźć n-ty pierwiastek podziel logarytm przez 'n'. ROM komputera ZX81 wykorzystuje następujący wzór do wyszukiwania wartości
; pierwiastków kwadratowych (tutaj pierwiastka z liczby 9):
; PRINT EXP ( LN 9 / 2 )
; Funkcja Napiera dotycząca pierwiastka kwadratowego jest jedynie specjalnym przypadkiem funkcji 'potęgowej'. Pierwiastek sześcienny lub
; dowolny inny liczy się równie prosto.

; Najpierw sprawdzane jest, czy argument LN jest liczbą większą od zera.

; $1CA9 : 7337
LN:       RST  28H            ; KALKULATOR                 x.
         .BYTE $2D            ; duplikuj                   x,x.
         .BYTE $33            ; większe-niż-0              x,(0/1).
         .BYTE $00            ; skocz-przy-prawdzie        x.
         .BYTE $04            ; do L1CB1, VALID
         .BYTE $34            ; koniec-obliczeń

; $1CAF : 7343
REPORT_AB: RST 08H            ; ERROR-1
         .BYTE $09            ; Raport Błędu: zły argument

; $1CB1 : 7345
VALID:    .BYTE $A0           ; na-stos-zero               x,0.  - usunięte ze stosu 1 zostaje nadpisane zerem
          .BYTE $02           ; usuń                       x.    - operacja jest zbędna
          .BYTE $34           ; koniec-obliczeń

          LD   A,(HL)         ; pobierz wykładnik e
          LD   (HL),$80       ; zredukuj x do mantysy - x'

          CALL STACK_A        ; stos zawiera teraz         x',e.

          RST  28H            ; KALKULATOR                 x',e.
         .BYTE $30            ; dane-na-stos               x',e,128.
         .BYTE $38            ; Wykładnik: $88, Bajty: 1
         .BYTE $00            ;(+00,+00,+00)
         .BYTE $03            ; odejmij                    x',e-128.   - zredukuj do prawdziwego wykładnika
         .BYTE $01            ; zamień                     e',x'.
         .BYTE $2D            ; duplikuj                   e',x',x'.
         .BYTE $30            ; dane-na-stos               e',x',x',0.8.
         .BYTE $F0            ; Wykładnik: $80, Bajty: 4
         .BYTE $4C,$CC,$CC,$CD ;
         .BYTE $03            ; odejmij                    e',x',x'-0.8.
         .BYTE $33            ; większe-niż-0              e',x'(0/1).
         .BYTE $00            ; skocz-przy-prawdzie        e',x'.
         .BYTE $08            ; do L1CD2, GRE_8
         .BYTE $01            ; zamień                     x',e'.
         .BYTE $A1            ; jeden-na-stos              x',e',1.
         .BYTE $03            ; odejmij                    x',e'-1.
         .BYTE $01            ; zamień                     e'-1,x'.
         .BYTE $34            ; koniec-obliczeń

          INC  (HL)           ; powiększ x' dwa razy       e'-1,2x'.
          RST  28H            ; KALKULATOR                 e'-1,2x'.

; $1CD2 : 7378                                             (x' <= 0.8)                      (x' > 0.8)   - tutaj zbiegają się obie wersje   
GRE_8:   .BYTE $01            ; zamień                     2x',e'-1.                      | x',e'.
         .BYTE $30            ; dane-na-stos               2x',e'-1,LN 2.                 | x',e',LN 2.
         .BYTE $F0            ; Wykładnik: $80, Bajty: 4
         .BYTE $31,$72,$17,$F8 ;
         .BYTE $04            ; mnóż                       2x',(e'-1)LN 2.                | x',e'LN 2.
         .BYTE $01            ; zamień                     (e'-1)LN 2,2x'.                | e'LN 2,x'.
         .BYTE $A2            ; na-stos-1/2                (e'-1)LN 2,2x',0.5.            | e'LN 2,x',0.5.
         .BYTE $03            ; odejmij-1/2                (e'-1)LN 2,2x'-0.5.            | e'LN 2,x'-0.5.
         .BYTE $A2            ; na-stos-1/2                (e'-1)LN 2,2x'-0.5,0.5.        | e'LN 2,x'-0.5,0.5.
         .BYTE $03            ; odejmij                    (e'-1)LN 2,2x'-1.              | e'LN 2,x'-1.
         .BYTE $2D            ; duplikuj                   (e'-1)LN 2,2x'-1,2x'-1.        | e'LN 2,x'-1,x'-1.
         .BYTE $30            ; dane-na-stos               (e'-1)LN 2,2x'-1,2x'-1,2.5.    | e'LN 2,x'-1,x'-1,2.5.
         .BYTE $32            ; Wykładnik: $82, Bajty: 1
         .BYTE $20            ;(+00,+00,+00)
         .BYTE $04            ; mnóż                       (e'-1)LN 2,2x'-1,5x'-2.5.      | e'LN 2,x'-1,2.5x'-2.5.
         .BYTE $A2            ; na-stos-1/2                (e'-1)LN 2,2x'-1,5x'-2.5,0.5.  | e'LN 2,x'-1,2.5x'-2.5,0.5.
         .BYTE $03            ; odejmij                    (e'-1)LN 2,2x'-1,5x'-3.        | e'LN 2,x'-1,2.5x'-3.
         .BYTE $8C            ; serie-0C                   uruchom generator szeregów
         .BYTE $11            ; Wykładnik: $61, Bajty: 1
         .BYTE $AC            ;(+00,+00,+00)
         .BYTE $14            ; Wykładnik: $64, Bajty: 1
         .BYTE $09            ;(+00,+00,+00)
         .BYTE $56            ; Wykładnik: $66, Bajty: 2
         .BYTE $DA,$A5        ;(+00,+00)
         .BYTE $59            ; Wykładnik: $69, Bajty: 2
         .BYTE $30,$C5        ;(+00,+00)
         .BYTE $5C            ; Wykładnik: $6C, Bajty: 2
         .BYTE $90,$AA        ;(+00,+00)
         .BYTE $9E            ; Wykładnik: $6E, Bajty: 3
         .BYTE $70,$6F,$61    ;(+00)
         .BYTE $A1            ; Wykładnik: $71, Bajty: 3
         .BYTE $CB,$DA,$96    ;(+00)
         .BYTE $A4            ; Wykładnik: $74, Bajty: 3
         .BYTE $31,$9F,$B4    ;(+00)
         .BYTE $E7            ; Wykładnik: $77, Bajty: 4
         .BYTE $A0,$FE,$5C,$FC ;
         .BYTE $EA            ; Wykładnik: $7A, Bajty: 4
         .BYTE $1B,$43,$CA,$36 ;
         .BYTE $ED            ; Wykładnik: $7D, Bajty: 4
         .BYTE $A7,$9C,$7E,$5E ;
         .BYTE $F0            ; Wykładnik: $80, Bajty: 4
         .BYTE $6E,$23,$80,$93 ;
         .BYTE $04            ; mnóż
         .BYTE $0F            ; dodaj
         .BYTE $34            ; koniec-obliczeń

          RET

; --------------------------
; FUNKCJE 'TRYGONOMETRYCZNE'
; --------------------------
; Trygonometria to technika kosmiczna. Używali jej również stolarze i budowniczowie piramid. Niektóre zastosowania trygonometrii mogą być
; zupełnie abstrakcyjne, lecz jej zasady można zaobserwować w prostych trójkątach prostokątnych. Trójkąty posiadają kilka specjalnych własności:

; 1) Suma wszystkich trzech kątów wynosi zawsze PI radianów (180 stopni). Bardzo pomocne, gdy znasz dwa kąty i chcesz znaleźć trzeci.
; 2) W każdym trójkącie prostokątnym suma kwadratów przyprostokątnych jest równa kwadratowi przeciwprostokątnej. Bardzo pomocne, gdy znasz
;    długości dwóch boków trójkąta prostokątnego i chcesz znaleźć długość boku trzeciego.
; 3) Funkcje sinus, cosinus i tangens umożliwiają wyliczenie nieznanej długości boku, jeśli znamy długość innego boku oraz kąt pomiędzy
;    przyprostokątną a przeciwprostokątną.
; 4) Funkcje arcus sinus, arcus cosinus i arcus tangens pozwalają wyliczyć nieznany kąt, jeśli są znane długości dwóch boków.

; -----------------------------
; PROCEDURA 'ZREDUKUJ ARGUMENT'
; -----------------------------
; (offset $35: 'get-argt')

; Ta funkcja wykonuje dwie funkcje na kącie wyrażonym w radianach, które przygotowują go jako argument dla funkcji sinus i cosinus.
; Najpierw upewnia się, czy kąt redukuje się do normalnego zakresu. Np. jeśli statek zawraca o kąt, powiedzmy, 3PI radianów (540 stopni),
; to efektywny obrót wyniesie PI radianów (180 stopni).
; Następnie zamienia kąt w radianach na ułamek kąta prostego w zależności od tego, w której ćwiartce układu współrzędnych leży ten kąt.
; wynikiem jest liczba z zakresu od -1 do 1.          

;                       90 stopni

;                         (pi/2)
;                  II       +1        I
;                            |
;             sin+      |\   |   /|    sin+
;             cos-      | \  |  / |    cos+
;             tan-      |  \ | /  |    tan+
;                       |   \|/)  |          
;   180 stopni  (pi) 0 -|----+----|-- 0  (0)   0 stopni
;                       |   /|\   |
;             sin-      |  / | \  |    sin-
;             cos-      | /  |  \ |    cos+
;             tan+      |/   |   \|    tan-
;                            |
;                  III      -1       IV
;                        (3pi/2)

;                        270 stopni

; $1D18 : 7448
GET_ARGT: RST  28H            ; KALKULATOR                 x.
         .BYTE $30            ; dane-na-stos
         .BYTE $EE            ; Wykładnik: $7E, Bajty: 4
         .BYTE $22,$F9,$83,$6E ;                           x, 1/(2*PI).
         .BYTE $04            ; mnóż                       x/(2*PI).
         .BYTE $2D            ; duplikuj                   x/(2*PI),x/(2*PI).  
         .BYTE $A2            ; na-stos-1/2                x/(2*PI),x/(2*PI),0.5.
         .BYTE $0F            ; dodaj                      x/(2*PI),x/(2*PI)+0.5.
         .BYTE $24            ; na-liczbę-całkowitą        x/(2*PI),x/INT((2*PI)+0.5).
         .BYTE $03            ; odejmij                    x/(2*PI)-x/INT((2*PI)+0.5) = y
         .BYTE $2D            ; duplikuj                   y,y.
         .BYTE $0F            ; dodaj                      2y.
         .BYTE $2D            ; duplikuj                   2y,2y.
         .BYTE $0F            ; dodaj                      4y.
         .BYTE $2D            ; duplikuj                   4y,4y.
         .BYTE $27            ; wartość-bezwzględna        4y,ABS(4y).
         .BYTE $A1            ; jeden-na-stos              4y,ABS(4y),1.
         .BYTE $03            ; odejmij                    4y,ABS(4y)-1 = z
         .BYTE $2D            ; duplikuj                   4y,z,z.
         .BYTE $33            ; większe-niż-0              4y,z,(0/1).
         .BYTE $C0            ; stos-do-pamięci-0          mem-0 zawiera wynik testu
         .BYTE $00            ; skocz-przy-prawdzie        4y,z
         .BYTE $04            ; do L1D35, ZPLUS
         .BYTE $02            ; usuń                       4y.
         .BYTE $34            ; koniec-obliczeń            4y.

          RET

; Jeśli skok nastąpił do tego miejsca, kontynuuj.

; $1D35 : 7477
ZPLUS:   .BYTE $A1            ; jeden-na-stos              4y,z,1.
         .BYTE $03            ; odejmij                    4y,z-1.
         .BYTE $01            ; zamień                     z-1,4y.
         .BYTE $32            ; mniej-niż-0                z-1,(1/0).
         .BYTE $00            ; skocz-przy-prawdzie        z-1.
         .BYTE $02            ; do $1D3C, YNEG
         .BYTE $18            ; zmień-znak                 1-z.

; $1D3C : 7484
YNEG:    .BYTE $34            ; koniec-obliczeń

          RET

; -----------------
; FUNKCJA 'COSINUS'
; -----------------
; (offset $1D: 'cos')
; Cosinus jest obliczany jako sinus przeciwnego kąta w trójkącie prostokątnym z poprawą znaku w zależności od numeru ćwiartki, w której
; ten kąt się znajduje.

;             /|
;          h /y|
;           /  |o
;          /x  |
;         /----|    
;          a

; Cosinus kąta x jest równy długości boku a podzielonej przez długość przeciwprostokątnej h. Jednakże, gdy rozważymy kąt y, to okaże się, że
; a/h jest równe jego sinusowi. Ponieważ kąty x i y sumują się do kata prostego, kąt y możemy znaleźć przez odjęcie kąta x od pi/2. Jednakże
; równie łatwe jest wstępne zredukowanie argumentu, a następnie odjęcie go od wartości 1 (zredukowany kąt prosty). Jest jeszcze prościej odjąć
; 1 od tego kąta i skorygować znak. W rzeczywistości po zredukowaniu argumentu wykorzystywana jest jego wartość bezwzględna, a następnie sprawdzany
; jest wynik redukcji, zachowany w obszarze pamięci kalkulatora w mem-0. Na podstawie tego wyniku dokonuje się korekcji znaku argumentu przed
; obliczeniem sinusa.

; $1D3E : 7486
COS:      RST  28H            ; KALKULATOR                 x.                  - kąt w radianach.
         .BYTE $35            ; get-argt                   x.                  - zredukuj do -1 to +1
         .BYTE $27            ; wartość-bezwzględna        ABS(x)
         .BYTE $A1            ; jeden-na-stos              ABS(x),1.
         .BYTE $03            ; odejmij                    ABS(x)-1.           - teraz kąt przeciwny 
         .BYTE $E0            ; na-stos-paimięć-0          ABS(x)-1,(0/1).     - pobierz wskaźnik znaku.
         .BYTE $00            ; skocz-przy-prawdzie        ABS(x)-1.           - jeśli zgodny, skocz do obliczeń sinusa
         .BYTE $06            ; naprzód do $1D4B, C-ENT
         .BYTE $18            ; zmień-znak                 1-ABS(x).           - inaczej zmień znak na przeciwny  
         .BYTE $2F            ; skocz                      1-ABS(x).           - i teraz skocz do obliczania sinusa
         .BYTE $03            ; naprzód do $1D4B, C-ENT

; ---------------
; FUNKCJA 'SINUS'
; ---------------
; (offset $1C: 'sin')
; Jest to podstawowa funkcja, z której są wyliczane bezpośrednio lub pośrednio pozostałe funkcje trygonometryczne - cos i tg.
; Wykorzystuje ona generator szeregów do wyznaczenia wartości wielomianów Czybyszewa.

;             /|
;          1 / |
;           /  |x
;          /a  |
;         /----|    
;          y

; $1D49 : 7497
SIN:      RST  28H            ; KALKULATOR                 x.                  - kąt w radianach
         .BYTE $35            ; get-argt                   x.                  - zredukuj do -1 to +1

; $1D4B : 7499
C_ENT:   .BYTE $2D            ; duplikuj                   x,x.
         .BYTE $2D            ; duplikuj                   x,x,x.
         .BYTE $04            ; mnóż                       x,x^2.
         .BYTE $2D            ; duplikuj                   x,x^2,x^2.
         .BYTE $0F            ; dodaj                      x,2x^2.
         .BYTE $A1            ; jeden-na-stos              x,2x^2,1.
         .BYTE $03            ; odejmij                    x,2x^2-1.
         .BYTE $86            ; serie-06                   uruchom generator szeregów
         .BYTE $14            ; Wykładnik: $64, Bajty: 1
         .BYTE $E6            ;(+00,+00,+00)
         .BYTE $5C            ; Wykładnik: $6C, Bajty: 2
         .BYTE $1F,$0B        ;(+00,+00)
         .BYTE $A3            ; Wykładnik: $73, Bajty: 3
         .BYTE $8F,$38,$EE    ;(+00)
         .BYTE $E9            ; Wykładnik: $79, Bajty: 4
         .BYTE $15,$63,$BB,$23 ;
         .BYTE $EE            ; Wykładnik: $7E, Bajty: 4
         .BYTE $92,$0D,$CD,$ED ;
         .BYTE $F1            ; Wykładnik: $81, Bajty: 4
         .BYTE $23,$5D,$1B,$EA ;
         .BYTE $04            ; mnóż
         .BYTE $34            ; koniec-obliczeń

          RET


; -----------------
; FUNKCJA 'TANGENS'
; -----------------
; (offset $1E: 'tan')
; Oblicza tangens z x jako sin(x) / cos(x).

;             /|
;          h / |
;           /  |o
;          /x  |
;         /----|    
;          a

; Tangens kąta x jest ilorazem długości naprzeciwległego boku o przez długość boku przyległego a. Ponieważ długość naprzeciwległego boku można
; obliczyć wykorzystując sin(x), a długość boku przyległego wykorzystując cos(x), to tangens można zdefiniować jak powyżej.

; Błąd nr 6 powstaje, jeśli argument w radianach jest zbyt bliski +/-pi/2 - dla takiego kata tangens osiąga wartość nieskończoną.
; Np.      PRINT TAN (PI/2)  jest obliczane jak 1/0.
; Podobnie PRINT TAN (3*PI/2), TAN (5*PI/2) itd.

; $1D6E : 7534
TAN:      RST  28H            ; KALKULATOR                 x.
         .BYTE $2D            ; duplikuj                   x,x.
         .BYTE $1C            ; sinus                      x,SIN(x).
         .BYTE $01            ; zamień                     SIN(x),x.
         .BYTE $1D            ; cosinus                    SIN(x),COS(x).
         .BYTE $05            ; dziel                      SIN(x)/COS(x) (= TAN(x)).
         .BYTE $34            ; koniec-obliczeń            TAN(x).

          RET

; -----------------------
; FUNKCJA 'ARCUS TANGENS'
; -----------------------
; (Offset $21: 'atn')
; Funkcja odwrotna do tangensa, której wynik jest w radianach.
; Jest to podstawowa funkcja, z której wyprowadzane są pośrednio lub bezpośrednio pozostałe funkcje, takie jak arcus sinus i arcus cosinus. Zwracany
; wynik leży w zakresie od -pi/2 do pi/2.
; Jest ostatnią z czterech procedur, które wykorzystują generator szeregów do utworzenia wielomianów Chybyszewa.

; $1D76 : 7542
ATN:      LD   A,(HL)         ; pobierz wykładnik
          CP   $81            ; porównaj go z wykładnikiem jedynki

          JR   C,SMALL        ; jeśli mniejszy, naprzód do SMALL

          RST  28H            ; KALKULATOR                 x.
         .BYTE $A1            ; jeden-na-stos              x,1.
         .BYTE $18            ; zmień-znak                 x,-1.  
         .BYTE $01            ; zamień                     -1,x.
         .BYTE $05            ; dziel                      -1/x.
         .BYTE $2D            ; duplikuj                   -1/x,-1/x.
         .BYTE $32            ; mniej-niż-0                -1/x,(-1/x<0?).
         .BYTE $A3            ; na-stos-pi/2               -1/x,(0/1),pi/2.
         .BYTE $01            ; zamień                     -1/x,pi/2,(0,1).
         .BYTE $00            ; skocz-przy-prawdzie        -1/x,pi/2.
         .BYTE $06            ; do L1D8B, CASES
         .BYTE $18            ; zmień-znak                 -1/x,-pi/2.
         .BYTE $2F            ; skocz                      -1/x,-pi/2.
         .BYTE $03            ; do L1D8B, CASES

; $1D89 : 7561                                             (x > 0)                      (x <= 0)
SMALL:    RST  28H            ; KALKULATOR                 -1/x,pi/2.                 | -1/x,-pi/2.
         .BYTE $A0            ; na-stos-zero               -1/x,pi/2,0.               | -1/x,-pi/2,0.

; $1D8B : 7563
CASES:   .BYTE $01            ; zamień                     -1/x,0,pi/2.               | -1/x,0,-pi/2.
         .BYTE $2D            ; duplikuj                   -1/x,0,pi/2,pi/2.          | -1/x,0,-pi/2,-pi/2.
         .BYTE $2D            ; duplikuj                   -1/x,0,pi/2,pi/2,pi/2.     | -1/x,0,-pi/2,-pi/2,-pi/2.
         .BYTE $04            ; mnóż                       -1/x,0,pi/2,pi^2/4.        | -1/x,0,-pi/2,pi^2/4.
         .BYTE $2D            ; duplikuj                   -1/x,0,pi/2,pi^2/4,pi^2/4. | -1/x,0,-pi/2,pi^2/4,pi^2/4.
         .BYTE $0F            ; dodaj                      -1/x,0,pi/2,pi^2/2.        | -1/x,0,-pi/2,pi^2/2.
         .BYTE $A1            ; jeden-na-stos              -1/x,0,pi/2,pi^2/2,1.      | -1/x,0,-pi/2,pi^2/2,1.
         .BYTE $03            ; odejmij                    -1/x,0,pi/2,pi^2/2-1.      | -1/x,0,-pi/2,pi^2/2-1.
         .BYTE $8C            ; serie-0C                   uruchom generator szeregów
         .BYTE $10            ; Wykładnik: $60, Bajty: 1
         .BYTE $B2            ;(+00,+00,+00)
         .BYTE $13            ; Wykładnik: $63, Bajty: 1
         .BYTE $0E            ;(+00,+00,+00)
         .BYTE $55            ; Wykładnik: $65, Bajty: 2
         .BYTE $E4,$8D        ;(+00,+00)
         .BYTE $58            ; Wykładnik: $68, Bajty: 2
         .BYTE $39,$BC        ;(+00,+00)
         .BYTE $5B            ; Wykładnik: $6B, Bajty: 2
         .BYTE $98,$FD        ;(+00,+00)
         .BYTE $9E            ; Wykładnik: $6E, Bajty: 3
         .BYTE $00,$36,$75    ;(+00)
         .BYTE $A0            ; Wykładnik: $70, Bajty: 3
         .BYTE $DB,$E8,$B4    ;(+00)
         .BYTE $63            ; Wykładnik: $73, Bajty: 2
         .BYTE $42,$C4        ;(+00,+00)
         .BYTE $E6            ; Wykładnik: $76, Bajty: 4
         .BYTE $B5,$09,$36,$BE ;
         .BYTE $E9            ; Wykładnik: $79, Bajty: 4
         .BYTE $36,$73,$1B,$5D ;
         .BYTE $EC            ; Wykładnik: $7C, Bajty: 4
         .BYTE $D8,$DE,$63,$BE ;
         .BYTE $F0            ; Wykładnik: $80, Bajty: 4
         .BYTE $61,$A1,$B3,$0C ;
         .BYTE $04            ; mnóż
         .BYTE $0F            ; dodaj
         .BYTE $34            ; koniec-obliczeń

          RET

; ---------------------
; FUNKCJA 'ARCUS SINUS'
; ---------------------
; (Offset $1F: 'asn')
; Funkcja odwrotna do sinus z wynikiem w radianach. Obliczana z wykorzystaniem powyższej funkcji arcus tangens. Błąd A jest generowany, jeśli
; argument wykracza poza przedział <-1,1>. Do obliczeń wykorzystana została tożsamość trygonometryczna:

; TAN(x/2) = SIN(x/(1+COS x))

; Z TAN(x/2) wyliczany jest kat x/2 za pomocą wywołania ATN i na koniec samo x przez dodanie do siebie połówki kąta - x/2.

; $1DC4 : 7620
ASN:      RST  28H            ; KALKULATOR                 x.
         .BYTE $2D            ; duplikuj                   x,x.
         .BYTE $2D            ; duplikuj                   x,x,x.
         .BYTE $04            ; mnóż                       x,x^2.
         .BYTE $A1            ; jeden-na-stos              x,x^2,1.
         .BYTE $03            ; odejmij                    x,x^2-1.
         .BYTE $18            ; zmień-znak                 x,1-x^2.
         .BYTE $25            ; pierwiastek                x,sqr(1-x^2) = y.
         .BYTE $A1            ; jeden-na-stos              x,y,1.
         .BYTE $0F            ; dodaj                      x,y+1.
         .BYTE $05            ; dziel                      x/(y+1).
         .BYTE $21            ; arcus tangens              a/2     - połówka kąta
         .BYTE $2D            ; duplikuj                   a/2,a/2.
         .BYTE $0F            ; dodaj                      a.
         .BYTE $34            ; koniec-obliczeń            a.

          RET

; -----------------------
; FUNKCJA 'ARCUS COSINUS'
; -----------------------
; (Offset $20: 'acs')
; Funkcja odwrotna do cosinus z wynikiem w radianach.
; Błąd A, jeśli argument nie jest w zakresie od -1 do 1.
; Wynik w zakresie od 0 do pi.
; Wyprowadzona z powyższego asn, które z kolei jest wyprowadzone z poprzedzającego atn. Mogłoby być wyliczone bezpośrednio z atn wg wzoru
;   acs(x) = atn(sqr(1-x*x)/x).
; Jednakże, ponieważ sinus i cosinus są pionowymi translacjami jednego w drugi, użyto
;   acs(x) = pi/2 - asn(x)
; tj. arcus cosinus znanej wartości x da poszukiwany kąt b w radianach. Z powyższego wiemy, jak policzyć kąt a używając asn(x). Ponieważ trzy
; kąty dowolnego trójkata dodają się do pi radianów, a największym kątem w tym przypadku jest kąt prosty (pi/2 radianów), to możemy obliczyć
; kąt b jako pi/2 (oba katy) minus asn(x) (kąt a). 
;
;            /|
;         1 /b|
;          /  |x
;         /a  |
;        /----|    
;          y

; $1DD4 : 7636
ACS:      RST  28H            ; KALKULATOR           x.
         .BYTE $1F            ; arcus-sinus          asn(x).
         .BYTE $A3            ; na-stos-pi/2         asn(x), pi/2.
         .BYTE $03            ; odejmij              asn(x) - pi/2.
         .BYTE $18            ; zmień-znak           pi/2 - asn(x) = acs(x).
         .BYTE $34            ; koniec-obliczeń      acs(x)

          RET

; ---------------------------------
; OPERACJA 'PIERWIASTEK KWADRATOWY'
; ---------------------------------
; (Offset $25: 'sqr')
; Błąd A, jeśli argument jest ujemny. Ta procedura jest godna uwagi ze względu na jej rozmiar - 7 bajtów. Pierwotnie kod ZX81 zajmował 9KB
; i musiano zastosować różne techniki, aby wcisnąć go w pamięć 8K.

; $1DDB : 7643
SQR:      RST  28H            ; KALKULATOR           x.
         .BYTE $2D            ; duplikuj             x, x.
         .BYTE $2C            ; neguj-logicznie      x, 1/0
         .BYTE $00            ; skocz-przy-prawdzie  x, (1/0).
         .BYTE $1E            ; do L1DFD, LAST, wyjdź przy argumencie równym zero - wynik zero.

; inaczej kontynuuj obliczanie jako x ** .5

         .BYTE $A2            ; na-stos-1/2          x, .5.
         .BYTE $34            ; koniec-obliczeń      x, .5.

; ----------------------
; OPERACJA 'POTĘGOWANIE'
; ----------------------
; (Offset $06: 'to-power')
; Podnosi pierwszą liczbę x do potęgi drugiej liczby y.
; 0 ** +n = 0
; 0 ** -n = nadmiar arytmetyczny.

; $1DE2 : 7650
TO_POWER: RST  28H            ; KALKULATOR            x, y.
         .BYTE $01            ; zamień                y, x.
         .BYTE $2D            ; duplikuj              y, x, x.
         .BYTE $2C            ; neguj-logicznie       y, x, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie
         .BYTE $07            ; naprzód do $1DEE, XISO, jeśli x jest równe zero.

; inaczej X jest niezerowe. Funkcja 'ln' przechwyci ujemne wartości x.

         .BYTE $22            ; logarytm-naturalny     y, LN y.
         .BYTE $04            ; mnóż                   y * LN x.
         .BYTE $34            ; koniec-obliczeń

          JP   EXP            ; skocz wstecz do procedury EXP

; Te procedury tworzą trzy proste wyniki, gdy liczba ma wartość zero. Rozpocznij od usunięcia znanego zera, aby pozostawić y do potęgi czynnika.

; $1DEE : 7662
XISO:    .BYTE $02            ; usuń                   y.
         .BYTE $2D            ; duplikuj               y, y.
         .BYTE $2C            ; neguj-logicznie        y, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie     
         .BYTE $09            ; naprzód do $1DFB, ONE jeśli y jest równe zero.

; czynnik potęgowy nie jest zerem. Jeśli jest ujemny, powstanie błąd.

         .BYTE $A0            ; na-stos-zero           y, 0.
         .BYTE $01            ; zamień                 0, y.
         .BYTE $33            ; większe-niż-0          0, (1/0).
         .BYTE $00            ; skocz-przy-prawdzie    0.
         .BYTE $06            ; do $1DFD, LAST         jeśli y był liczbą dodatnią.

; inaczej wymuś dzielenie przez zero, co spowoduje powstanie błędu nadmiaru arytmetycznego. Istnieją pewne jedno i dwubajtowe zamienniki,
; lecz najbardziej formalnym zakończeniem powinno być end-calc; RST 08 .BYTE 05.

         .BYTE $A1            ; jeden-na-stos          0, 1.
         .BYTE $01            ; zamień                 1, 0.
         .BYTE $05            ; dziel                  1/0    >> błąd 


; $1DFB : 7675
ONE:     .BYTE $02            ; usuń                   .
         .BYTE $A1            ; jeden-na-stos          1.

; $1DFD : 7677
LAST:    .BYTE $34            ; koniec-obliczeń        ostatnia wartość 1 lub 0.

          RET

; ------------------
; 'ZAPASOWE KOMÓRKI'
; ------------------

; $1DFF : 7679
SPARE:   .BYTE $FF           ; to już wszystko

; --------------------
; 'ZESTAW ZNAKÓW ZX81'
; --------------------

; $1E00 : 7680
CHAR_SET:

; $00 - Znak: ' '          CHR$(0)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000

; $01 - Znak: mozaika      CHR$(1)

       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000


; $02 - Znak: mozaika      CHR$(2)

       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000


; $03 - Znak: mozaika      CHR$(3)

       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000

; $04 - Znak: mozaika      CHR$(4)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000

; $05 - Znak: mozaika      CHR$(5)

       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000

; $06 - Znak: mozaika      CHR$(6)

       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %00001111
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000

; $07 - Znak: mozaika      CHR$(7)

       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %11111111
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000
       .BYTE    %11110000

; $08 - Znak: mozaika      CHR$(8)

       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %10101010
       .BYTE    %01010101

; $09 - Znak: mozaika      CHR$(9)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %10101010
       .BYTE    %01010101

; $0A - Znak: mozaika      CHR$(10)

       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %10101010
       .BYTE    %01010101
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000

; $0B - Znak: '"'          CHR$(11)

       .BYTE    %00000000
       .BYTE    %00100100
       .BYTE    %00100100
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000

; $0C - Znak:  L          CHR$(12)

       .BYTE    %00000000
       .BYTE    %00011100
       .BYTE    %00100010
       .BYTE    %01111000
       .BYTE    %00100000
       .BYTE    %00100000
       .BYTE    %01111110
       .BYTE    %00000000

; $0D - Znak: '$'          CHR$(13)

       .BYTE    %00000000
       .BYTE    %00001000
       .BYTE    %00111110
       .BYTE    %00101000
       .BYTE    %00111110
       .BYTE    %00001010
       .BYTE    %00111110
       .BYTE    %00001000

; $0E - Znak: ':'          CHR$(14)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010000
       .BYTE    %00000000

; $0F - Znak: '?'          CHR$(15)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00000000
       .BYTE    %00001000
       .BYTE    %00000000

; $10 - Znak: '('          CHR$(16)

       .BYTE    %00000000
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00000100
       .BYTE    %00000000

; $11 - Znak: ')'          CHR$(17)

       .BYTE    %00000000
       .BYTE    %00100000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00100000
       .BYTE    %00000000

; $12 - Znak: ">'          CHR$(18)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010000
       .BYTE    %00001000
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00010000
       .BYTE    %00000000

; $13 - Znak: '<'          CHR$(19)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00010000
       .BYTE    %00001000
       .BYTE    %00000100
       .BYTE    %00000000

; $14 - Znak: '='          CHR$(20)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00111110
       .BYTE    %00000000
       .BYTE    %00111110
       .BYTE    %00000000
       .BYTE    %00000000

; $15 - Znak: '+'          CHR$(21)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00111110
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00000000

; $16 - Znak: '-'          CHR$(22)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00111110
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000

; $17 - Znak: '*'          CHR$(23)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010100
       .BYTE    %00001000
       .BYTE    %00111110
       .BYTE    %00001000
       .BYTE    %00010100
       .BYTE    %00000000

; $18 - Znak: '/'          CHR$(24)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000010
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00010000
       .BYTE    %00100000
       .BYTE    %00000000

; $19 - Znak: ';'          CHR$(25)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00100000

; $1A - Znak: ','          CHR$(26)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00010000

; $1B - Znak: '"'          CHR$(27)

       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00000000
       .BYTE    %00011000
       .BYTE    %00011000
       .BYTE    %00000000

; $1C - Znak: '0'          CHR$(28)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000110
       .BYTE    %01001010
       .BYTE    %01010010
       .BYTE    %01100010
       .BYTE    %00111100
       .BYTE    %00000000

; $1D - Znak: '1'          CHR$(29)

       .BYTE    %00000000
       .BYTE    %00011000
       .BYTE    %00101000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00111110
       .BYTE    %00000000

; $1E - Znak: '2'          CHR$(30)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %00000010
       .BYTE    %00111100
       .BYTE    %01000000
       .BYTE    %01111110
       .BYTE    %00000000

; $1F - Znak: '3'          CHR$(31)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %00001100
       .BYTE    %00000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $20 - Znak: '4'          CHR$(32)

       .BYTE    %00000000
       .BYTE    %00001000
       .BYTE    %00011000
       .BYTE    %00101000
       .BYTE    %01001000
       .BYTE    %01111110
       .BYTE    %00001000
       .BYTE    %00000000

; $21 - Znak: '5'          CHR$(33)

       .BYTE    %00000000
       .BYTE    %01111110
       .BYTE    %01000000
       .BYTE    %01111100
       .BYTE    %00000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $22 - Znak: '6'          CHR$(34)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000000
       .BYTE    %01111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $23 - Znak: '7'          CHR$(35)

       .BYTE    %00000000
       .BYTE    %01111110
       .BYTE    %00000010
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00000000

; $24 - Znak: '8'          CHR$(36)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $25 - Znak: '9'          CHR$(37)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111110
       .BYTE    %00000010
       .BYTE    %00111100
       .BYTE    %00000000

; $26 - Znak: 'A'          CHR$(38)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01111110
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00000000

; $27 - Znak: 'B'          CHR$(39)

       .BYTE    %00000000
       .BYTE    %01111100
       .BYTE    %01000010
       .BYTE    %01111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01111100
       .BYTE    %00000000

; $28 - Znak: 'C'          CHR$(40)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $29 - Znak: 'D'          CHR$(41)

       .BYTE    %00000000
       .BYTE    %01111000
       .BYTE    %01000100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000100
       .BYTE    %01111000
       .BYTE    %00000000

; $2A - Znak: 'E'          CHR$(42)

       .BYTE    %00000000
       .BYTE    %01111110
       .BYTE    %01000000
       .BYTE    %01111100
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01111110
       .BYTE    %00000000

; $2B - Znak: 'F'          CHR$(43)

       .BYTE    %00000000
       .BYTE    %01111110
       .BYTE    %01000000
       .BYTE    %01111100
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %00000000

; $2C - Znak: 'G'          CHR$(44)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000000
       .BYTE    %01001110
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $2D - Znak: 'H'          CHR$(45)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01111110
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00000000

; $2E - Znak: 'I'          CHR$(46)

       .BYTE    %00000000
       .BYTE    %00111110
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00001000
       .BYTE    %00111110
       .BYTE    %00000000

; $2F - Znak: 'J'          CHR$(47)

       .BYTE    %00000000
       .BYTE    %00000010
       .BYTE    %00000010
       .BYTE    %00000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $30 - Znak: 'K'          CHR$(48)

       .BYTE    %00000000
       .BYTE    %01000100
       .BYTE    %01001000
       .BYTE    %01110000
       .BYTE    %01001000
       .BYTE    %01000100
       .BYTE    %01000010
       .BYTE    %00000000

; $31 - Znak: 'L'          CHR$(49)

       .BYTE    %00000000
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %01111110
       .BYTE    %00000000

; $32 - Znak: 'M'          CHR$(50)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01100110
       .BYTE    %01011010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00000000

; $33 - Znak: 'N'          CHR$(51)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01100010
       .BYTE    %01010010
       .BYTE    %01001010
       .BYTE    %01000110
       .BYTE    %01000010
       .BYTE    %00000000

; $34 - Znak: 'O'          CHR$(52)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $35 - Znak: 'P'          CHR$(53)

       .BYTE    %00000000
       .BYTE    %01111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01111100
       .BYTE    %01000000
       .BYTE    %01000000
       .BYTE    %00000000

; $36 - Znak: 'Q'          CHR$(54)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01010010
       .BYTE    %01001010
       .BYTE    %00111100
       .BYTE    %00000000

; $37 - Znak: 'R'          CHR$(55)

       .BYTE    %00000000
       .BYTE    %01111100
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01111100
       .BYTE    %01000100
       .BYTE    %01000010
       .BYTE    %00000000

; $38 - Znak: 'S'          CHR$(56)

       .BYTE    %00000000
       .BYTE    %00111100
       .BYTE    %01000000
       .BYTE    %00111100
       .BYTE    %00000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $39 - Znak: 'T'          CHR$(57)

       .BYTE    %00000000
       .BYTE    %11111110
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00000000

; $3A - Znak: 'U'          CHR$(58)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00111100
       .BYTE    %00000000

; $3B - Znak: 'V'          CHR$(59)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %00100100
       .BYTE    %00011000
       .BYTE    %00000000

; $3C - Znak: 'W'          CHR$(60)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01000010
       .BYTE    %01011010
       .BYTE    %00100100
       .BYTE    %00000000

; $3D - Znak: 'X'          CHR$(61)

       .BYTE    %00000000
       .BYTE    %01000010
       .BYTE    %00100100
       .BYTE    %00011000
       .BYTE    %00011000
       .BYTE    %00100100
       .BYTE    %01000010
       .BYTE    %00000000

; $3E - Znak: 'Y'          CHR$(62)

       .BYTE    %00000000
       .BYTE    %10000010
       .BYTE    %01000100
       .BYTE    %00101000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00010000
       .BYTE    %00000000

; $3F - Znak: 'Z'          CHR$(63)

       .BYTE    %00000000
       .BYTE    %01111110
       .BYTE    %00000100
       .BYTE    %00001000
       .BYTE    %00010000
       .BYTE    %00100000
       .BYTE    %01111110
       .BYTE    %00000000

       .END                    ;dyrektywa asemblera TASM

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe