|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
| SPIS TREŚCI |
| Podrozdziały |
Umówmy się na początku, iż teksty będziemy umieszczać w pamięci PMC ze specjalnym kodem o wartości 0 na końcu. Kod ten nazywa się znacznikiem końca tekstu. W PMC można to osiągnąć następująco:
...
TEKST: DAT "Poznaj swój komputer" ;właściwy tekst
DAT 0 ;znacznik końca tekstu
...

Program odczytujący taki tekst z pamięci po natrafieniu na znak o kodzie 0 będzie wiedział, iż tekst się właśnie mu skończył. Znak zero można w prosty sposób przetestować poleceniem skoku warunkowego JZR.
Poniższy program wypisuje tekst powitalny na wyświetlaczu znakowym. Zasada działania jest bardzo prosta. Kolejne znaki tekstu pobierane są z pamięci przy pomocy polecenia LDA z trybem pośrednim z postinkrementacją. W trybie tym wykorzystywana jest jedna z komórek pamięci PMC do przechowywania adresu danych. Każde zaadresowanie powoduje pobranie danych z pamięci i zwiększenie ich adresu o 1, dzięki czemu wskazywane są kolejne dane (w naszym przypadku kolejne literki tekstu). Pobrany znak zostaje sprawdzony poleceniem JZR na wartość 0, która oznacza koniec tekstu. Jeśli nie jest to znak końca tekstu, to zostaje przesłany na wyświetlacz znakowy do portu CHP, a pozycja na wyświetlaczu w porcie CHI zostaje zwiększona.
RUN START
TXT: DAT "Witamy w PMC" ;tekst do wyświetlenia
DAT 0 ;znacznik końca tekstu
TPTR: DAT TXT ;adres początku tekstu
START: LDA (TPTR++) ;pobieramy kolejny znak tekstu
JZR #EX1 ;kończymy, jeśli kod zero
STA CHP ;przesyłamy na port znakowy
INC CHI ;zwiększamy pozycję na wyświetlaczu
JMP #START
EX1:

Tego typu program potrafi wyświetlać tylko krótkie teksty. Dłuższe spowodują nadpisanie informacji, ponieważ przekroczenie pozycji nr 15 na wyświetlaczu spowoduje przewinięcie się licznika pozycji CHI, który jest 4 bitowy. Innym sposobem prezentacji tekstu może być przewijanie w stylu reklamy lub napisów na giełdzie. W PMC można to w prosty sposób osiągnąć ustawiając na stałe pozycję wyświetlania w CHI na 15, a następnie przesyłanie znaku do CHP, po którym następuje przesłanie kodu kontrolnego o wartości 258. Kod ten powoduje przesunięcie w lewo wszystkich literek na wyświetlaczu z wpisaniem znaku spacji na ostatniej pozycji.
Poniższy program wyświetla w kółko zadany napis. Ponieważ wyświetlanie napisu
jest powtarzane, to przed wejściem do pętli program ustawia na nowo adres tekstu
w zmiennej wskaźnikowej TPTR. W pętli głównej
wprowadziłem małą pętlę opóźniającą, aby tekst był czytelny na szybszym
komputerze. W razie konieczności należy dostosować zawartość akumulatora.
RUN START
TPTR: DAT 0 ;tutaj będzie adres tekstu
TEKST: DAT "W dzisiejszych rozgrywkach klas III w kategorii "
DAT "programowania w języku Pascal pierwsze miejsce "
DAT "zajęła klasa III J. Na miejscu drugim uplasowała "
DAT "się klasa III A. Miejsce trzecie przypadło "
DAT "w udziale klasie III C. GRATULUJEMY!"
DAT " "
DAT 0 ;znacznik końca tekstu
START: LDA #15 ;ustawiamy pozycję na wyświetlaczu
STA CHI
LP1: LDA #TEKST ;ustawiamy adres początku testu
STA TPTR
LP2: LDA (TPTR++) ;pobieramy znak
JZR #LP1 ;jeśli koniec, to od początku
STA CHP ;znak na wyświetlacz
LDA #-10 ;pętla opóźniająca, powtarzana aż
LP3: ADD #1 ;ACR osiągnie wartość 0
JMI #LP3
LDA #258 ;kod przesunięcia w lewo
STA CHP
JMP #LP2
Tekst odczytujemy z portu INP. Brzmi to dosyć prosto, jednak w praktyce takie proste nie jest, ponieważ musimy obsłużyć kilka sytuacji, które mogą się zdarzyć w trakcie odczytu:
Z tego prostego przykładu możesz wyobrazić sobie złożoność operacji wejścia / wyjścia w prawdziwym systemie komputerowym, gdzie mogą wystąpić dodatkowe sytuacje (np. pełny dysk, błąd odczytu, zerwanie transmisji itp.).
Poniższy program obsługuje odczyt tekstu z portu INP. Odczytywany tekst wstawiony zostaje do tablicy o szesnastu elementach. Wielkość tablicy limituje długość tekstu do 15 znaków (dziesiąty znak to znak o kodzie 0). Jeśli użytkownik poda więcej znaków, to zostaną one odczytane, ale będą zignorowane i nie trafią do tablicy, w której będzie tylko pierwszych 15 znaków. Jeśli będzie ich mniej, to tablica nie zostanie zapełniona w całości. W każdym przypadku na końcu wczytanego tekstu zawsze umieszczany jest znak 0. Po wczytaniu tekstu zostanie on następnie wyprowadzony na wyświetlacz znakowy za pomocą metody opisanej w poprzednim rozdziale.
RUN START
TPTR: DAT TEXT ;zmienna wskaźnikowa, przechowuje adres tekstu
TEXT: DAT "0123456789ABCDEF" ;bufor dla tekstu - 16 znaków
I: DAT 15 ;maksymalna liczba znaków do odczytu
START: LDA INP ;odczytujemy pierwszy znak
JZR #START ;bufor zajęty, czekamy
JMI #START ;bufor pusty, też czekamy
LP1: STA (TPTR++) ;jest znak, umieszczamy go w buforze
LDA I ;sprawdzamy, czy bufor pełny, co stanie się,
SUB #1 ;gdy licznik osiągnie zero
STA I
JZR #INPE ;tak, kończymy odczyt
LP2: LDA INP ;czytamy kolejny znak
JZR #LP2 ;jeśli bufor zajęty, to czekamy
JMI #INPE ;jeśli pusty, to kończymy odczyt
JMP #LP1 ;inaczej wykonujemy kolejny obieg
INPE: LDA INP ;pozbywamy się reszty znaków
JMI #EX1
JMP #INPE
EX1: LDA #0 ;na końcu tekstu umieszczamy kod 0
STA (TPTR++)
LDA #TEXT ;odtwarzamy adres początku tekstu
STA TPTR
LP3: LDA (TPTR++) ;wyświetlamy odczytany tekst
JZR #0 ;znak końca tekstu, kończymy
STA CHP ;zwykły znak, wyświetlamy go
INC CHI ;następna pozycja
JMP #LP3
Program produkuje wyniki, które umieszcza w komórkach pamięci. W PMC możemy podglądnąć zawartość dowolnych komórek, nie istnieje więc konieczność wyprowadzania liczb na wyświetlacz. Jednak w prawdziwym komputerze opcja taka nie jest dostępna. Dlatego musimy poznać metody przekształcania wartości liczby na ciąg cyfr w wybranym systemie pozycyjnym. Teoretycznie zadanie to rozwiązaliśmy we wcześniejszych rozdziałach. Teraz nadszedł czas na część praktyczną.
Pierwszy program oblicza kolejne cyfry dziesiętne podanej liczby dodatniej z zakresu od 0 do 32767. Do obliczeń stosujemy odwrotny algorytm Hornera. Polega on na znajdowaniu reszty z dzielenia liczby przez 10. Reszty te tworzą cyfry od ostatniej do pierwszej. Po obliczeniu reszty liczbę należy podzielić przez 10. Obliczenia kontynuujemy aż do otrzymania liczby o wartości zero. Na przykład:
Liczba ma wartość 23756.
| 23756 : | 10 = | 2375 i reszta 6 |
| 2375 : | 10 = | 237 i reszta 5 |
| 237 : | 10 = | 23 i reszta 7 |
| 23 : | 10 = | 2 i reszta 3 |
| 2 : | 10 = | 0 i reszta 2 |
Reszta jest wartością liczbową od 0 do 9. Aby otrzymać kod znaku ASCII przedstawiającego odpowiednią cyfrę, należy do otrzymanej reszty dodać kod znaku "0" równy 48. Ponieważ otrzymujemy cyfry w kolejności odwrotnej, to będą one wstawiane do 6 elementowej tablicy począwszy od 5 elementu (piąty element ma indeks 4 - nie zapominaj o tym, to bardzo ważne!!!) w dół (maksymalnie może być 5 cyfr). Tablica jest wypełniona znakiem spacji przed rozpoczęciem obliczania cyfr. W szóstym elemencie przechowywany jest znak o kodzie 0. Po uzyskaniu cyfr liczba zostaje wyświetlona na wyświetlaczu znakowym.
RUN START
N: DAT 12654 ;liczba do wyświetlenia
NTAB: DAT " " ;tablica 5 spacji
DAT 0 ;znak końca tekstu
NPTR: DAT 0 ;adres poszczególnych cyfr
X: DAT 0 ;zmienna pomocnicza
START: LDA #NTAB ;obliczamy adres 5 elementu + 1
ADD #5
STA NPTR ;adres do zmiennej wskaźnikowej
LP1: LDA N ;obliczamy iloraz N przez 10
DIV #10
STA X ;zapamiętujemy go chwilowo
MUL #10 ;obliczamy resztę z dzielenia
SUB N ;reszta ujemna
XOR #-1 ;obliczamy liczbę przeciwną w kodzie U2
ADD #49 ;obliczamy kod ASCII cyfry
STA (--NPTR) ;umieszczamy ją w tablicy
LDA X ;do N idzie wynik dzielenia przez 10
STA N
JZR #EX1 ;jeśli zero, to koniec przetwarzania
JMP #LP1 ;w przeciwnym razie następna cyfra
EX1: LDA #NTAB ;wyświetlamy cyfry na wyświetlaczu
STA NPTR
LP2: LDA (NPTR++)
JZR #0
STA CHP
INC CHI
JMP #LP2
Przedstawiony powyżej program potrafi wyświetlać poprawnie tylko liczby dodatnie i zero. Nie radzi sobie zupełnie z liczbami ujemnymi. Powodem jest sposób reprezentacji liczb ujemnych w pamięci maszyny - kod U2. Jednak prosta modyfikacja pozwoli wyświetlić również liczby ujemne.
Przed obliczaniem kolejnych cyfr sprawdzamy, czy liczba jest ujemna - jeśli tak, to zapamiętujemy ten fakt w osobnej zmiennej, np. wpisując tam znak "-". Następnie zamieniamy wartość liczby na przeciwną, obliczamy cyfry i na początku zapisu wpisujemy zapamiętany na początku znak "-". Ponieważ zapis liczby składa się teraz z maksymalnie 5 cyfr oraz znaku minus, to musimy powiększyć rozmiar tablicy przechowującej cyfry. Dla sprawdzenia, po wyliczeniu cyfr wyświetlamy je na wyświetlaczy znakowym.
RUN START
N: DAT -2457 ;liczba do wyświetlenia
NTAB: DAT " " ;tablica 6 spacji
DAT 0 ;znak końca tekstu
NPTR: DAT 0 ;adres poszczególnych cyfr
SGN: DAT "+" ;przechowuje informacje o znaku liczby
X: DAT 0 ;zmienna pomocnicza
START: LDA #NTAB ;obliczamy adres 6 elementu + 1
ADD #6
STA NPTR ;adres do zmiennej wskaźnikowej
LDA N ;sprawdzamy, czy N < 0
JMI #MINUS
JMP #LP1
MINUS: XOR #-1 ;obliczamy wartość przeciwną
ADD #1
STA N
LDA #"-" ;do SGN wprowadzamy znak minus
STA SGN
LP1: LDA N ;obliczamy iloraz N przez 10
DIV #10
STA X ;zapamiętujemy go chwilowo
MUL #10 ;obliczamy resztę z dzielenia
SUB N ;reszta ujemna
XOR #-1 ;obliczamy liczbę przeciwną w kodzie U2
ADD #49 ;obliczamy kod ASCII cyfry
STA (--NPTR) ;umieszczamy ją w tablicy
LDA X ;do N idzie wynik dzielenia przez 10
STA N
JZR #EX1 ;jeśli zero, to koniec przetwarzania
JMP #LP1 ;w przeciwnym razie następna cyfra
EX1: LDA SGN ;na początku dopisujemy znak liczby
STA (--NPTR)
LDA #NTAB ;wyświetlamy cyfry na wyświetlaczu
STA NPTR
LP2: LDA (NPTR++)
JZR #0
STA CHP
INC CHI
JMP #LP2
Program wciąż nie radzi sobie z wartością -32768, która jest poprawna w kodzie U2. Spowodowane jest to tym, iż wartości tej nie można poprawnie zapisać jako liczby przeciwnej, dodatniej. Kod U2 jest kodem niesymetrycznym i dla 16 bitowych liczb ma zakres (-32768, 32767). Jedynym sensownym rozwiązaniem jest sprawdzenie tej wartości w programie i jeśli mamy z nią do czynienia, to w tablicy należy bezpośrednio umieścić odpowiednie cyfry i zakończyć obliczenia. Oto kompletny program wyświetlania dowolnych liczb w systemie PMC:
RUN START
N: DAT -2457 ;liczba do wyświetlenia
NTAB: DAT " " ;tablica 6 spacji
DAT 0 ;znak końca tekstu
NPTR: DAT 0 ;adres poszczególnych cyfr
SPCVAL: DAT -32768 ;wartość specjalna -32768
SPCASE: DAT "-32768" ;przechowuje bezpośredni zapis -32768
DAT 0
SPTR: DAT SPCASE ;używane przy kopiowaniu tablic
SGN: DAT "+" ;przechowuje informacje o znaku liczby
X: DAT 0 ;zmienna pomocnicza
START: LDA N ;sprawdzamy, czy N = -32768
SUB SPCVAL
JZR #SPEC
JMP #NORMAL ;jeśli nie, to idziemy normalnym torem
SPEC: LDA #NTAB ;skopiujemy tablicę znaków SPCASE
STA NPTR ;do NTAB
LP0: LDA (SPTR++)
STA (NPTR++)
JZR #EX2
JMP #LP0
NORMAL: LDA #NTAB ;obliczamy adres 6 elementu + 1
ADD #6
STA NPTR ;adres do zmiennej wskaźnikowej
LDA N ;sprawdzamy, czy N < 0
JMI #MINUS
JMP #LP1
MINUS: XOR #-1 ;obliczamy wartość przeciwną
ADD #1
STA N
LDA #"-" ;do SGN wprowadzamy znak minus
STA SGN
LP1: LDA N ;obliczamy iloraz N przez 10
DIV #10
STA X ;zapamiętujemy go chwilowo
MUL #10 ;obliczamy resztę z dzielenia
SUB N ;reszta ujemna
XOR #-1 ;obliczamy liczbę przeciwną w kodzie U2
ADD #49 ;obliczamy kod ASCII cyfry
STA (--NPTR) ;umieszczamy ją w tablicy
LDA X ;do N idzie wynik dzielenia przez 10
STA N
JZR #EX1 ;jeśli zero, to koniec przetwarzania
JMP #LP1 ;w przeciwnym razie następna cyfra
EX1: LDA SGN ;na początku dopisujemy znak liczby
STA (--NPTR)
EX2: LDA #NTAB ;wyświetlamy cyfry na wyświetlaczu
STA NPTR
LP2: LDA (NPTR++)
JZR #0
STA CHP
INC CHI
JMP #LP2
Z podanych przykładów jasno wynika, iż procedury wyprowadzania liczb na wyświetlacze wcale nie są proste. Jest to prawdą również w świecie IBM. Zwróć uwagę, iż procedury wyświetlania liczb można bardzo prosto przystosować do innych systemów liczenia (np. piątkowego). Jednak przy wyświetlaniu liczb w systemie dwójkowym, ósemkowym i szesnastkowym korzysta się z innych metod, które uwzględniają sposób reprezentacji danych w pamięci maszyny, tj. bity.
Zapis dwójkowy zbudowany jest tylko z dwóch cyfr - 0 i 1. Teoretycznie moglibyśmy stosować odwrotny algorytm Hornera do obliczenia poszczególnych cyfr, tylko po co - przecież w komórce pamięci komputer przechowuje wartość w systemie dwójkowym. Wystarczy więc odczytać kolejne bity i wypisywać na wyświetlaczu cyfry 0 lub 1 w zależności od wartości tych bitów. Metody operacji bitowych omówiliśmy w poprzednim rozdziale. Poniżej przedstawiamy prosty program wyświetlający dowolną wartość w systemie dwójkowym. Wyświetlane jest zawsze 16 cyfr.
RUN START
N: DAT 23 ;tutaj umieszczamy liczbę do wyświetlenia
I: DAT 0 ;zlicza bity
START: LDA N ;wydzielamy kolejne bity liczby
RLA #1 ;obracając je w lewo
STA N
AND #1 ;gotowe
ADD #48 ;tworzymy kod ASCII cyfry
STA CHP ;teraz na wyświetlacz
INC CHI ;następna pozycja
INC I ;zwiększamy licznik bitów
LDA I
SUB #16 ;koniec?
JMI #START ;następna cyfra, jeśli nie
Przy wyświetlaniu wartości ósemkowych skorzystamy z faktu, iż licząc od końca kolejne trzy bity wartości dwójkowej przedstawiają jedną cyfrę ósemkową w zakresie od 0 do 7. Jeśli przyjrzymy się komórce pamięci PMC, to stwierdzimy, iż pierwszą cyfrą ósemkową może być tylko cyfra 0 lub 1, a za nią następuje 5 cyfr już dowolnych:
| Komórka pamięci PMC ósemkowo i dwójkowo | |||||||||||||||
| c5 | c4 | c3 | c2 | c1 | c0 | ||||||||||
| b15 | b14 | b13 | b12 | b11 | b10 | b09 | b08 | b07 | b06 | b05 | b05 | b03 | b02 | b01 | b00 |
Poszczególne cyfry uzyskamy obracając bity w lewo i wykonując operację AND z maską 1 dla bitu b15 oraz 7 dla pozostałych bitów.
RUN START
N: DAT 864 ;tutaj podajemy wartość liczby
I: DAT 0 ;licznik obiegów
START: LDA N ;najpierw bit 15
RLA #1 ;bit b15 jest teraz na pozycji b0
STA N
AND #1 ;wydzielamy go
JMP #DIGIT
LP1: LDA N ;wydzielamy po trzy bity
RLA #3
STA N
AND #0B111 ;maska wydzielania bitów
DIGIT: ADD #48 ;tworzymy kod cyfry
STA CHP ;przesyłamy go na wyświetlacz znakowy
INC CHI ;następna pozycja
INC I ;zwiększamy licznik obiegów
LDA I ;koniec?
SUB #6 ;należy wykonać 6 obiegów pętli
JMI #LP1
Przy wyświetlaniu liczb szesnastkowych również wykorzystuje się fakt, iż licząc od końca każde kolejne 4 bity liczby dwójkowej przedstawiają jedną cyfrę szesnastkową. Problemem jest jedynie uzyskanie poprawnego kodu ASCII takiej cyfry. Nie wystarczy dodać do wartości cyfry kodu znaku "0" (48), ponieważ cyfry "A"..."F" będą źle przedstawione (literka A ma kod ASCII równy 65). My pójdziemy zupełnie inną drogą i po prostu umieścimy w pamięci tablicę ze wszystkimi cyframi szesnastkowymi. Otrzymana wartość cyfry będzie indeksem w tej tablicy, według którego pobierzemy odpowiedni znak.
RUN START
N: DAT 14978 ;tutaj umieszczamy liczbę do wyświetlenia
HEXTAB: DAT "0123456789ABCDEF"
HPTR: DAT 0 ;do adresowania cyfr w tablicy
I: DAT 0 ;licznik pętli
START: LDA N ;wydzielamy czwórki bitów obracając wartość
RLA #4 ;o cztery pozycję w lewo i wykonując
STA N ;operację AND z maską 0B0000000000001111
AND #15 ;w ACR wartość cyfry szesnastkowej
ADD #HEXTAB ;obliczamy adres znaku tej cyfry w tablicy
STA HPTR
LDA (HPTR++) ;pobieramy ten znak z tablicy
STA CHP ;i wyświetlamy go na wyświetlaczu znakowym
INC CHI
INC I ;zwiększamy licznik obiegów pętli
LDA I
SUB #4 ;koniec?
JMI #START ;następna cyfra, jeśli nie
Liczby odczytujemy jako kolejne znaki cyfr. Znak cyfry ma kod ASCII (np. cyfra 0 to kod 48). Najpierw więc musimy przekształcać odczytane kody cyfr na ich wartość - polega to na odjęciu od kodu ASCII wartości 48 (kod cyfry 0). Następnie stosujemy algorytm Hornera do obliczenia wartości liczby.
Brzmi to dosyć prosto. Jednak musisz rozważyć kilka ważnych spraw przy opracowaniu poprawnego programu odczytu liczby. Przede wszystkim program będzie współpracował z użytkownikiem, który jest istotą nieprzewidywalną i omylną. Dobrze skonstruowany algorytm powinien działać poprawnie w każdej sytuacji, nawet jeśli użytkownik wprowadzi bezsensowny stek bzdur (są tacy, nawet wśród was, którzy lubią w ten sposób męczyć komputery). Z drugiej strony użytkownik może wprowadzić liczbę za dużą lub za małą, to też musi sprawdzać program Widzisz więc, iż odczyt liczb komplikuje się znacznie, gdy chcemy się zabezpieczyć przed możliwymi błędami ze strony człowieka.

Poniższa wersja programu nie sprawdza poprawności wprowadzonych danych, dlatego nie jest odporna na błędy użytkownika. Najpierw program czeka, aż w buforze pojawią się dane, które musi wprowadzić użytkownik. Gdy dane są dostępne, to program odczytuje je znak po znaku. Zakładamy, iż są to kolejne cyfry liczby. Każdy znak cyfry jest sprowadzany do wartości cyfry przez zmniejszenie kodu o 48. Wartości te są dodawane do wyniku przemnożonego przez 10 (schemat Hornera). Pętla jest kończona, gdy w buforze wyczerpią się znaki. Program działa poprawnie dla liczb z zakresu od 0 do 65535. Ponieważ jednak PMC pracuje w kodzie U2, to liczby większe od 32767 będą przedstawiane jako ujemne (najstarszy bit ma wartość 1).
Program można rozbudować według następujących wskazówek:
Rozbudowę pozostawiamy ambitnym czytelnikom.
RUN START
N: DAT 0 ;tutaj trafi odczytana liczba
X: DAT 0 ;zmienna pomocnicza
START: LDA INP ;odczytujemy znak z bufora
JZR #START ;bufor zajęty?
JMI #START ;bufor pusty?
LP1: SUB #"0" ;obliczamy wartość cyfry
STA X ;i zapamiętujemy ją tymczasowo
LDA N ;N przemnażamy przez 10
MUL #10
ADD X ;dodajemy cyfrę
STA N ;zapisujemy wynik
LP2: LDA INP ;pobieramy kolejny znak
JZR #LP2 ;czekamy na dostępność bufora
JMI #0 ;ale kończymy, gdy pusty. Wynik w N
JMP #LP1 ;inaczej przetwarzamy znak
Odczyt liczb ze znakiem nie różni się zasadniczo od odczytu liczb bez znaku. Jedyną nowością jest dodatkowy znak, który może pojawić się na początku zapisu, mianowicie minus. Program odczytujący powinien sprawdzić, czy pierwszy znak jest minusem. Jeśli tak, to zostaje ustawiony odpowiedni znacznik. Teraz następuje odczyt liczby bez znaku. Po odczytaniu liczby program sprawdza znacznik i jeśli jest on ustawiony, zmienia wartość liczby na przeciwną.
RUN START
N: DAT 0 ;tutaj trafi odczytana liczba
SGN: DAT 0 ;znacznik liczby ujemnej
X: DAT 0 ;zmienna pomocnicza
START: LDA INP ;odczytujemy znak z bufora
JZR #START ;bufor zajęty?
JMI #START ;bufor pusty?
STA X ;zapamiętujemy chwilowo znak
SUB #"-" ;sprawdzamy, czy odczytano minus
JZR #MINUS
LDA X ;jeśli nie, to odtwarzamy znak
JMP #LP1 ;i przetwarzamy go
MINUS: INC SGN ;ustawiamy znacznik
JMP #LP2 ;i przechodzimy do odczytu cyfr
LP1: SUB #"0" ;obliczamy wartość cyfry
STA X ;i zapamiętujemy ją tymczasowo
LDA N ;N przemnażamy przez 10
MUL #10
ADD X ;dodajemy cyfrę
STA N ;zapisujemy wynik
LP2: LDA INP ;pobieramy kolejny znak
JZR #LP2 ;czekamy na dostępność bufora
JMI #EX1 ;ale kończymy, gdy pusty
JMP #LP1 ;inaczej przetwarzamy znak
EX1: LDA SGN ;liczba ujemna?
JZR #0 ;kończymy, jeśli nie. Wynik w N.
LDA #0 ;inaczej zmieniamy znak N
SUB N
STA N
Program odczytujący liczbę dwójkową można skonstruować na bazie poprzednio przedstawionego programu dla liczb dziesiętnych. Jednak chciałbym pokazać wam nieco inne podejście do tego problemu. Ponieważ liczby są przechowywane w pamięci komputera w postaci bitów, to możemy bezpośrednio odczytywać cyfry dwójkowe, zamieniać je na bity o wartości 0 lub 1 i wstawiać do tworzonej liczby, która przed tą operacją jest przesuwana bitowo o jedną pozycję w lewo.
RUN START
N: DAT 0 ;tutaj trafi odczytana liczba dwójkowa
X: DAT 0 ;zmienna pomocnicza
START: LDA INP ;odczytujemy znak z bufora
JZR #START ;bufor zajęty?
JMI #START ;bufor pusty?
LP1: SUB #"0" ;obliczamy wartość cyfry 0 lub 1
STA X ;i zapamiętujemy ją tymczasowo
LDA N ;N przesuwamy o 1 pozycję w lewo
RLA #1
ORA X ;wstawiamy bit
STA N ;zapisujemy wynik
LP2: LDA INP ;pobieramy kolejny znak
JZR #LP2 ;czekamy na dostępność bufora
JMI #0 ;ale kończymy, gdy pusty. Wynik w N
JMP #LP1 ;inaczej przetwarzamy znak
Dla liczb ósemkowych modyfikacja algorytmu jest minimalna. Wystarczy przesuwać bitowo zmienną N o trzy pozycję w lewo - cyfra ósemkowa zastępuje trzy bity liczby dwójkowej.
RUN START
N: DAT 0 ;tutaj trafi odczytana liczba ósemkowa
X: DAT 0 ;zmienna pomocnicza
START: LDA INP ;odczytujemy znak z bufora
JZR #START ;bufor zajęty?
JMI #START ;bufor pusty?
LP1: SUB #"0" ;obliczamy wartość cyfry od 0 do 7
STA X ;i zapamiętujemy ją tymczasowo
LDA N ;N przesuwamy o 3 pozycję w lewo
RLA #3
ORA X ;wstawiamy bity cyfry ósemkowej
STA N ;zapisujemy wynik
LP2: LDA INP ;pobieramy kolejny znak
JZR #LP2 ;czekamy na dostępność bufora
JMI #0 ;ale kończymy, gdy pusty. Wynik w N
JMP #LP1 ;inaczej przetwarzamy znak
Sam algorytm obliczania wartości liczby szesnastkowej nie różni się niczym od opisanych powyżej algorytmów dla liczb dwójkowych i ósemkowych - jedna cyfra szesnastkowa zajmuje cztery bity, więc liczbę przesuwamy w lewo bitowo o cztery pozycje i łączymy bity cyfry szesnastkowej z liczbą. Problemem jednak będzie obliczenie wartości cyfry szesnastkowej. Z bufora wejściowego INP cyfry odczytujemy jako znaki w kodzie ASCII. Dla cyfr "0" ... "9" nie ma problemu. Wystarczy od kodu znaku odjąć wartość 48, aby otrzymać wartość tej cyfry. Jednak cyfry literowe "A" ... "F" mogą początkującemu programiście sprawić nieco kłopotu. Ich kody leżą dalej w zestawie ASCII od kodów cyfr "0" ... "9". Co gorsza, użytkownik może wprowadzić zamiast dużych liter małe znaki "a" ... "f". W poniższej tabelce zebraliśmy kody ASCII wszystkich cyferek szesnastkowych.
| cyfry normalne | cyfry literowe | ||||||||||||||
| 0 48 |
1 49 |
2 50 |
3 51 |
4 52 |
5 53 |
6 54 |
7 55 |
8 56 |
9 57 |
A 65 |
B 66 |
C 67 |
D 68 |
E 69 |
F 70 |
| a 97 |
b 98 |
c 99 |
d 100 |
e 101 |
f 102 |
||||||||||
Aby otrzymać poprawną wartość cyfry musimy wykonać następujące obliczenia:
cyfra ← cyfra - 48
jeśli cyfra > 9, to cyfra ← cyfra - 7
jeśli cyfra >
15, to cyfra ← cyfra - 32
Sprawdźmy: użytkownik podał cyfrę "d" o kodzie 100
cyfra = 100 - 48 = 52
52 > 9, więc cyfra = 52 - 7 = 45
45 > 15, więc
cyfra = 45 - 32 = 13, co jest wartością cyfry
D.
Po tych wyjaśnieniach możemy przejść do programu odczytującego liczby w kodzie szesnastkowym.
RUN START
N: DAT 0 ;tutaj trafi odczytana liczba szesnastkowa
X: DAT 0 ;zmienna pomocnicza
START: LDA INP ;odczytujemy znak z bufora
JZR #START ;bufor zajęty?
JMI #START ;bufor pusty?
LP1: SUB #48 ;cyfra <- cyfra - 48
STA X ;i zapamiętujemy ją tymczasowo
SUB #10 ;cyfra < 9 ?
JMI #CYFRA
ADD #3 ;cyfra <- cyfra - 7
STA X
SUB #16 ;cyfra < 15 ?
JMI #CYFRA
SUB #16 ;cyfra <- cyfra - 32
STA X
CYFRA: LDA N ;N przesuwamy o 4 pozycję w lewo
RLA #4
ORA X ;wstawiamy bity cyfry ósemkowej
STA N ;zapisujemy wynik
LP2: LDA INP ;pobieramy kolejny znak
JZR #LP2 ;czekamy na dostępność bufora
JMI #0 ;ale kończymy, gdy pusty. Wynik w N
JMP #LP1 ;inaczej przetwarzamy znak
Odczytując port IOP dostajemy stan przycisków panelu IOP. Każdy przycisk ma skojarzony ze sobą jeden bit portu. Odczyt będzie więc polegał na sprawdzeniu stanu odpowiedniego bitu. Poniższy program zaprzestaje działania, po kliknięciu przycisku nr 3.
RUN START
START: LDA IOP ;odczytujemy stan przycisków
AND #8 ;sprawdzamy stan bitu nr 3
JZR #START ;jeśli nie jest naciśnięty, to kontynuujemy
A ten prosty program odczytuje stan przycisków IOP i mruga diodami LED nad wciśniętymi przyciskami:
RUN START
MASKA: DAT 0
START: LDA IOP ;odczytujemy stan przycisków
AND MASKA ;bity ustawiamy lub zerujemy
STA IOP ;zaświecamy diody
LDA MASKA ;negujemy bity maski
XOR #-1
STA MASKA
LDA #-5 ;małe opóźnienie
LP1: ADD #1
JMI #LP1
JMP #START
W następnym programie odczytywany jest stan trzech przycisków. W zależności od ich stanu program obraca na wyświetlaczu znakowym literkę A w lewo, gdy naciśnięty jest przycisk 1; w prawo, gdy naciśnięty jest przycisk 0 oraz kończy działanie, gdy naciśnięty jest przycisk 2.
RUN START
START: LDA #"A" ;umieszczamy znak A na wyświetlaczu
STA CHP
LP1: LDA IOP ;sprawdzamy stan przycisku 0
AND #1
JZR #N1 ;jeśli wyciśnięty, to dalej
LDA #261 ;wciśnięty, obrót znaków w prawo
STA CHP
N1: LDA IOP ;sprawdzamy stan przycisku 1
AND #2
JZR #N2 ;jeśli wyciśnięty, to dalej
LDA #260 ;wciśnięty, obrót znaków w lewo
STA CHP
N2: LDA IOP ;sprawdzamy stan przycisku 2
AND #4
JZR #LP1 ;jeśli wyciśnięty, to kontynuujemy pętlę
Kolejny program demonstruje sposób odczytu sekwencji przycisków. Program kończy wykonanie, gdy naciśnięte są jednocześnie trzy przyciski 0, 2 i 5.
RUN START
START: LDA IOP ;odczytujemy stan wszystkich przycisków
AND #0B100101 ;wydzielamy bity 5,2 i 0
XOR #0B100101 ;sprawdzamy, czy są ustawione na 1
JZR #EX1 ;jeśli tak, to kończymy
JMP #START
EX1:

Sterowanie wyświetlaczami 7-mio segmentowymi LED odbywa się podobnie do sterowania portem znakowym. Mamy tutaj port indeksowy DSI, do którego wprowadzamy numer aktywnego wyświetlacza. Port ten jest 4 bitowy. Pierwszy wyświetlacz znajduje się po prawej stronie i ma numer 0. Po wprowadzeniu numeru do DSI komputer uzyskuje dostęp do poszczególnych segmentów LED wybranego wyświetlacza poprzez port DSP. Odczyt tego portu zwraca informację, które z segmentów są zaświecone (skojarzone z nimi bity mają stan 1). Zapis do tego portu powoduje zaświecenie odpowiednich segmentów.
Świeceniem segmentów sterują bity od b0 do b6. Bit b7 steruje świeceniem kropki przy cyfrze. Port DSP jest 8-mio bitowy.
Taki sposób sterowania, chociaż nie pozwala bezpośrednio wyświetlać cyfr (wpisanie wartości cyfry do portu DSP nie spowoduje pojawienia się jej na wyświetlaczu), to jednak daje pełną kontrolę nad świeceniem poszczególnych segmentów. Dzięki temu można również tak wysterować segmenty wyświetlacza, aby pojawiły się na nich niektóre literki lub znaki.
Prezentowany poniżej program zaświeca wszystkie segmenty we wszystkich
wyświetlaczach.
RUN START
START: LDA #0B11111111 ;ustawione wszystkie 8 bitów
STA DSP ;zapalamy wszystkie segmenty
INC DSI ;przechodzimy do następnego wyświetlacza
LDA DSI ;koniec?
JZR #0 ;kończymy, jeśli tak
JMP #START ;następny wyświetlacz, jeśli nie
Poeksperymentuj w tym programie z wartością wprowadzaną na jego początku do rejestru akumulatora. Np. wpisz taką wartość, aby na wszystkich wyświetlaczach pojawiły się cyfry 0, 1, 2, itd.
Kolejny program demonstruje sposób wyświetlania cyfr. Dane dla wyświetlacza LED zgromadzone zostały w tablicy w ten sposób, iż element o indeksie np. 3 zawiera kształt cyfry 3 dla portu DSP. Program zamienia więc wartość cyfry na element z tablicy DSPTAB o indeksie równym tej cyfrze, następnie przesyła ten element do portu DSP. W rezultacie na wyświetlaczu otrzymujemy kształty kolejnych cyfr.
RUN START
N: DAT 0 ;licznik
DSPTAB: DAT 0B0111111 ;cyfra 0
DAT 0B0000011 ;cyfra 1
DAT 0B1101101 ;cyfra 2
DAT 0B1100111 ;cyfra 3
DAT 0B1010011 ;cyfra 4
DAT 0B1110110 ;cyfra 5
DAT 0B1111110 ;cyfra 6
DAT 0B0100011 ;cyfra 7
DAT 0B1111111 ;cyfra 8
DAT 0B1110111 ;cyfra 9
DTPTR: DAT 0 ;do adresowania tablicy
START: LDA N ;N zamieniamy na kod dla portu wyświetlacza
ADD #DSPTAB ;obliczamy adres elementu
STA DTPTR
LDA (DTPTR++) ;pobieramy kod dla wyświetlacza
STA DSP ;zapalamy odpowiednie segmenty LED
LDA #-25 ;pętla opóźniająca
LP1: ADD #1
JMI #LP1
INC N ;zwiększamy N o 1
LDA N ;sprawdzamy, czy N > 9
SUB #10
JMI #START
LDA #0 ;jeśli tak, to zerujemy licznik
STA N
JMP #START
A tutaj mamy przykład licznika liczącego w kodzie szesnastkowym. W tablicy zdefiniowano dodatkowe cyfry A...F.
RUN START
N: DAT 0 ;licznik
DSPTAB: DAT 0B0111111 ;cyfra 0
DAT 0B0000011 ;cyfra 1
DAT 0B1101101 ;cyfra 2
DAT 0B1100111 ;cyfra 3
DAT 0B1010011 ;cyfra 4
DAT 0B1110110 ;cyfra 5
DAT 0B1111110 ;cyfra 6
DAT 0B0100011 ;cyfra 7
DAT 0B1111111 ;cyfra 8
DAT 0B1110111 ;cyfra 9
DAT 0B1111011 ;cyfra A
DAT 0B1011110 ;cyfra b
DAT 0B0111100 ;cyfra C
DAT 0B1001111 ;cyfra d
DAT 0B1111100 ;cyfra E
DAT 0B1111000 ;cyfra F
DTPTR: DAT 0 ;do adresowania tablicy
START: LDA N ;N zamieniamy na kod dla portu wyświetlacza
AND #0B1111 ;pozostawiamy tylko cztery najmłodsze bity
ADD #DSPTAB ;obliczamy adres elementu
STA DTPTR
LDA (DTPTR++) ;pobieramy kod dla wyświetlacza
STA DSP ;zapalamy odpowiednie segmenty LED
LDA #-25 ;pętla opóźniająca
LP1: ADD #1
JMI #LP1
INC N ;zwiększamy N o 1
JMP #START
Kolejny program jest modyfikacją programu wyświetlania liczb dziesiętnych bez znaku. Tym razem liczba zostaje umieszczona na wyświetlaczach 7-mio segmentowych LED. Wyświetlacze są sterowane bezpośrednio bez umieszczania cyfr w pamięci. Program łatwo można dostosować do innych systemów pozycyjnych przez zmianę wartości stałej P.
RUN START
P: EQU 10 ;określa podstawę systemu 2..16
N: DAT 31857 ;liczba do wyświetlenia
X: DAT 0 ;zmienna pomocnicza
DSPTAB: DAT 0B0111111 ;cyfra 0
DAT 0B0000011 ;cyfra 1
DAT 0B1101101 ;cyfra 2
DAT 0B1100111 ;cyfra 3
DAT 0B1010011 ;cyfra 4
DAT 0B1110110 ;cyfra 5
DAT 0B1111110 ;cyfra 6
DAT 0B0100011 ;cyfra 7
DAT 0B1111111 ;cyfra 8
DAT 0B1110111 ;cyfra 9
DAT 0B1111011 ;cyfra A
DAT 0B1011110 ;cyfra b
DAT 0B0111100 ;cyfra C
DAT 0B1001111 ;cyfra d
DAT 0B1111100 ;cyfra E
DAT 0B1111000 ;cyfra F
DTPTR: DAT 0 ;do adresowania tablicy
START: LDA #0 ;ustawiamy wyświetlacz na ostatnią cyfrę
STA DSI
LP1: LDA N ;obliczamy iloraz N przez P
DIV #P
STA X ;zapamiętujemy go chwilowo
MUL #P ;obliczamy resztę z dzielenia
SUB N ;reszta ujemna
XOR #-1 ;obliczamy liczbę przeciwną w kodzie U2
ADD #1
ADD #DSPTAB ;obliczamy adres kształtu cyfry
STA DTPTR
LDA (DTPTR++) ;pobieramy definicję cyfry
STA DSP ;wyświetlamy ją
INC DSI ;ustawiamy kolejną pozycję
LDA X ;do N idzie wynik dzielenia przez 10
STA N
JZR #0 ;jeśli zero, to koniec przetwarzania
JMP #LP1 ;w przeciwnym razie następna cyfra
Oprócz wyświetlania liczb wyświetlacze 7-mio segmentowe LED mogą również służyć do prostych animacji. Poniższy program wyświetla na ostatnim wyświetlaczu biegającą w kółko kreseczkę.
RUN START
MASK: DAT 1
START: LDA #-10 ;małe opóźnienie
LP1: ADD #1
JMI #LP1
LDA MASK ;odczytujemy maskę
STA DSP ;zapalamy segment
RLA #1 ;maskę przesuwamy o 1 bit w lewo
STA MASK
AND #0B1000000
JZR #START ;jeśli bit 7 zero, to powtarzamy
LDA #1 ;inaczej ustawiamy maskę od nowa
STA MASK
JMP #START
Ten program z kolei wyświetla kreseczkę przebiegającą przez kolejne wyświetlacze.
RUN START
START: LDA #0B1000000
STA DSP ;zapalamy kreseczkę (segment g)
LDA #-10 ;małe opóźnienie
LP1: ADD #1
JMI #LP1
STA DSP ;gasimy kreseczkę
INC DSI ;przenosimy się do następnej pozycji
JMP #START
Sprawdźcie osobiście, co robi poniższy program:
RUN START
START: LDA #0B1001110
XOR DSP
STA DSP
INC DSI
JMP #START
PMC wyposażona jest w prosty ekranik graficzny, którym sterujemy za pomocą dwóch portów: GRP i GRI. W pierwszym porcie ustawiamy lub odczytujemy kolor punktu. W drugim porcie ustawiamy lub odczytujemy położenie punktu na ekranie. Współrzędne x i y mają zakres od 0 do 15.
Umieszczenie punktu na ekranie graficznym składać się będzie z następujących operacji:
Poniższy program realizuje wymienione operacje. Umieszcza on punkt o kolorze określonym przez zmienne R (składowa czerwona), G (składowa zielona) oraz B (składowa niebieska) na współrzędnych określonych przez zmienne X oraz Y.
RUN START
R: DAT 15 ;czterobitowa składowa czerwona koloru
G: DAT 0 ;czterobitowa składowa zielona koloru
B: DAT 0 ;czterobitowa składowa niebieska koloru
X: DAT 7 ;współrzędna x
Y: DAT 7 ;współrzędna y
START: LDA Y ;łączymy współrzędne x i y w jedno słowo
RLA #4
ORA X
STA GRI ;ustawiamy pozycję punktu
LDA R ;łączymy składowe kolorów
RLA #4
ORA G
RLA #4
ORA B
STA GRP ;ustawiamy kolor punktu
W niektórych algorytmach graficznych (np. wypełniania obszaru kolorem) istotne jest odczytanie koloru punktu leżącego na zadanych współrzędnych. Polega to na wykonaniu następujących operacji:
Poniższy program odczytuje składowe koloru punktu na zadanych współrzędnych i wpisuje je do zmiennych R (składowa czerwona), G (składowa zielona) i B (składowa niebieska). Przed odczytem ekranik graficzny jest wypełniany zadanym kolorem w celu przetestowania działania procedury.
RUN START
KOL: DAT 0xFF0 ;kolor żółty do testowego wypełnienia
R: DAT 0 ;tutaj trafi składowa czerwona
G: DAT 0 ;tutaj trafi składowa zielona
B: DAT 0 ;tutaj trafi składowa niebieska
X: DAT 5 ;współrzędna X odczytywanego punktu
Y: DAT 2 ;współrzędna Y odczytywanego punktu
START: LDA KOL ;wypełniamy ekranik graficzny kolorem
STA GRP
INC GRI ;następny punkt
LDA GRI
JZR #D1
JMP #START
D1: LDA Y ;łączymy współrzędne
RLA #4
ORA X
STA GRI ;udostępniamy punkt (x,y)
LDA GRP ;pobieramy kolor
STA R ;chwilowo zapamiętujemy go w R
AND #0B1111 ;wydzielamy bity koloru niebieskiego
STA B
LDA R ;odtwarzamy kolor
RLA #-4 ;przesuwamy bity koloru zielonego na pozycję
AND #0B1111 ;wydzielamy je
STA G
LDA R ;i to samo z bitami koloru czerwonego
RLA #-8
AND #0B1111
STA R
Efekty graficzne można uzyskiwać bardzo prostymi środkami. Poniższy program wypełnia ekranik graficzny punktami o coraz wyższych kolorach.
RUN START
START: INC GRP ;zwiększamy kolor punktu na danych współrzędnych
INC GRI ;przechodzimy do następnego punktu
JMP #START
Jeszcze ciekawszy efekt da nam poniższy program:
RUN START
START: LDA #0 ;rozpoczynamy od koloru czarnego
LP1: STA GRP ;ustawiamy kolor punktu
INC GRI ;przechodzimy do następnego punktu
ADD #1 ;zwiększamy kolor w akumulatorze
JMP #LP1 ;kontynuujemy pętlę
Następny program tworzy na ekranie graficznym efekt szachownicy. Kolory punktów jasnych i ciemnych są przechowywane w zmiennych KOL1 i KOL2.
RUN START
KOL1: DAT 0xFF0 ;żółty kolor
KOL2: DAT 0x00F ;niebieski kolor
MASK: DAT 0
START: LDA MASK ;jaki punkt postawić?
JZR #D1 ;0 - KOL2
LDA KOL1 ;1 - KOL1
JMP #D2
D1: LDA KOL2
D2: STA GRP ;ustawiamy kolor punktu
LDA MASK ;zmieniamy bit 0 maski na przeciwny
XOR #1
STA MASK
INC GRI ;przesuwamy się do następnej pozycji
LDA GRI ;sprawdzamy, czy koniec
JZR #0 ;kończymy, jeśli tak
AND #0xF ;sprawdzamy, czy wypełniliśmy 1 wiersz
JZR #D3
JMP #START ;jeśli nie, to kontynuujemy
D3: LDA MASK ;jeśli tak, to w następnym wierszu musimy
XOR #1 ;odwrócić układ kolorów, aby powstawała
STA MASK ;szachownica
JMP #START
Kolejny z programów wnosi nieco animacji na ekranik graficzny. PMC nie pracuje zbyt szybko, więc efekty animacyjne nie będą zaawansowane. Program symuluje odbijającą się piłeczkę. Piłeczka jest punktem, który zmienia współrzędne. Gdy osiągnie jedną z krawędzi ekranu następuje zmiana kierunku ruchu w osi, w której wystąpiła ta krawędź.
RUN START
KOL: DAT 0xF0F ;kolor piłeczki
X: DAT 5 ;współrzędna x
Y: DAT 2 ;współrzędna y
OX: DAT 0 ;stara współrzędna x
OY: DAT 0 ;stara współrzędna y
DX: DAT 1 ;przyrost w osi x
DY: DAT 1 ;przyrost w osi y
START: LDA Y ;łączymy współrzędne i wpisujemy
RLA #4 ;wynik do portu indeksowego grafiki
ORA X
STA GRI
LDA KOL ;ustawiamy kolor punktu (piłeczka)
STA GRP
LDA X ;zapamiętujemy bieżące współrzędne
STA OX
ADD DX ;przesuwamy piłeczkę w osi x
STA X
JZR #MDX ;sprawdzamy, czy piłeczka osiągnęła ścianę
XOR #15 ;w osi x
JZR #MDX
JMP #ON1 ;jeśli nie, to przechodzimy do współrzędnej y
MDX: SUB DX ;jeśli tak, to zmieniamy kierunek ruchu
STA DX ;w osi x (przeciwny przyrost)
ON1: LDA Y ;ze współrzędną y wykonujemy identyczne
STA OY ;operacje
ADD DY
STA Y
JZR #MDY
XOR #15
JZR #MDY
JMP #ON2
MDY: SUB DY
STA DY
ON2: LDA OY ;łączymy stare współrzędne i zapisujemy
RLA #4 ;do portu indeksowego grafiki
ORA OX
STA GRI
LDA #0 ;następnie wymazujemy punkt (piłeczkę)
STA GRP
JMP #START ;i kontynuujemy pętlę
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.