Programowanie PMC II


Podrozdziały

 

Najprostszy program

Najprostszy program dla PMC II nawet nie musisz pisać. Po uruchomieniu symulatora w okienku tekstu programu masz:

 

; Program dla PMC II
; Autor:
; Wersja:
; Data:

START: END

 

Oczywiście program ten nic nie robi. Po kompilacji i uruchomieniu program natychmiast się zatrzymuje z powodu instrukcji END.

 

Ładowanie danych do akumulatora

Kolejny program również jest bardzo prosty. Umieszcza ona w rejestrze akumulatora liczbę 133.

 

START: LDA #133 ;umieść w akumulatorze 133
       END      ;zakończ program

 

Gdy go skompilujemy i uruchomimy, to po zatrzymaniu powinniśmy zauważyć, iż akumulator zawiera wartość 133.

 

Akumulator Licznik Rozkazów Rejestr Instrukcji
0000000010000101 : 0085 : 133 0002 : 2 0000 : END

 

Zwróć uwagę, iż zawartość akumulatora jest prezentowana przez symulator PMC II na trzy sposoby:

 

- jako liczba binarna: 0000000010000101
- jako liczba szesnastkowa: 0085
- jako liczba dziesiętna: 133

 

Dzięki temu rozwiązaniu możesz w prosty sposób interpretować zawartość akumulatora wg potrzeb.

Licznik rozkazów zatrzymał się na adresie 2. Adres ten zawiera instrukcję END, co widzimy w rejestrze instrukcji. To właśnie ta instrukcja zatrzymała dalsze wykonywanie programu.

 

Zapis danych do pamięci

Program umieszcza liczbę 125 w pierwszej komórce pamięci.

 

DANE:  DAT    0  ;tutaj umieścimy liczbę 125

START: LDA #125  ;umieszczamy najpierw w akumulatorze liczbę 125
       STA $DANE ;teraz zawartość akumulatora umieszczamy w komórce 1
       END

 

Zwróć uwagę, iż przed uruchomieniem programu komórka 1 (o etykiecie DANE) zawiera wartość 0. Wartość tę umieszcza tam dyrektywa DAT. Po wykonaniu programu w komórce tej powinna znaleźć się wartość 125, czyli to, co program tam umieścił.

 

 Adr  Etykieta Inst  Argument  Pamięć
00  INOUT:      
01 DANE: DAT  125 007D    125
02 START: LDA  #125 147D   5245
03   STA  $DANE 2801  10241
04   END   0000      0

 

Przesłanie danych

Przesłanie danych ma na celu pobranie informacji przechowywanej w jednej komórce i umieszczenie jej w innej. Poniższy program przenosi dane z komórki DANE1 do DANE2:

 

DANE1: DAT 147    ;tę liczbę skopiujemy do komórki następnej
DANE2: DAT   0    ;tutaj będzie skopiowana zawartość komórki poprzedniej

START: LDA $DANE1 ;pobieramy zawartość pierwszej komórki
       STA $DANE2 ;i umieszczamy ją w drugiej komórce
       END

 

Po zakończeniu programu w obu komórkach DANE1 i DANE2 mamy tę samą wartość 147.

 

Adr  Etykieta Inst  Argument  Pamięć
00  INOUT:      
01 DANE1: DAT  147 0093    147
02 DANE2: DAT  147 0093    147
03 START: LDA  $DANE1 1801   6145
04   STA  $DANE2 2802  10242
05   END   0000      0

 

Zamiana zawartości

Operacja zamiany zawartości polega na przesłaniu danych pomiędzy komórkami tak, aby ich zawartości zostały nawzajem zamienione: w komórce pierwszej ma się znaleźć to co było w drugiej, a we drugiej to co było w pierwszej Operacja taka wymaga dodatkowej zmiennej pomocniczej, w której przechowujemy tymczasowo zawartość jednej z komórek. Zamiany dokonujemy w trzech krokach:

  1. Komórkę A przesyłamy do komórki pomocniczej X
  2. Do komórki A przesyłamy komórkę B
  3. Do komórki B przesyłamy komórkę pomocniczą X

Poniższy program zamienia miejscami zawartości komórek DANE1 i DANE2:

 

DANE1: DAT  15     ;zawartości tych dwóch komórek zostaną
DANE2: DAT 188     ;zamienione miejscami
X:     DAT   0     ;to jest zmienna pomocnicza

START: LDA $DANE1  ;przesyłamy DANE1 do X
       STA $X
       LDA $DANE2  ;przesyłamy DANE2 do DANE1
       STA $DANE1
       LDA $X      ;przesyłamy X do DANE1
       STA $DANE2
       END

 

Po wykonaniu programu komórki DANE1 i DANE2 mają zamienioną zawartość.

 

 Adr  Etykieta Inst  Argument  Pamięć
00  INOUT:      
01 DANE1: DAT  188 00BC    188
02 DANE2: DAT  15 000F     15
03 X: DAT  15 000F     15
04 START: LDA  $DANE1 1801   6145
05   STA  $X 2803  10243
06   LDA  $DANE2 1802   6146
07   STA  $DANE1 2801  10241
08   LDA  $X 1803   6147
09   STA  $DANE2 2802  10242
10   END   0000      0

 

Wyprowadzanie znaków

PMC II posiada tylko jedno urządzenie wyjścia - rejestr INOUT, który zajmuje adres 0 w przestrzeni adresowej. Każdy zapis do tego rejestru powoduje przesłanie na wyświetlacz jednego znaku. Poniższy program wyświetla literkę A:

 

START: LDA #"A    ;pobieramy do akumulatora kod literki A
       STA $INOUT ;przesyłamy go do rejestru wyjścia
       END

 

Po wykonaniu tego programu na wyświetlaczu pojawi się literka A.

 

 
A 

 

Pętla nieskończona

Pętla to konstrukcja programowa, w której wybrana grupa instrukcji jest cyklicznie powtarzana. Pętla nieskończona wykonywana jest ciągle, bez końca. Aby zatrzymać program z pętlą nieskończoną musisz posłużyć się przyciskiem STOP. Poniższy program wyświetla ciąg zer i jedynek.

 

START: LDA #"0    ;pobieramy do akumulatora znak 0
       STA $INOUT ;przesyłamy go na wyjście
       LDA #"1    ;pobieramy znak 1
       STA $INOUT ;przesyłamy go na wyjście
       JMP #START ;skaczemy na początek programu - powtarzamy od nowa

 

Cechą charakterystyczną pętli nieskończonej jest instrukcja skoku JMP do początku pętli. Skok ten powoduje ponowne wykonywanie rozkazów zawartych pomiędzy początkiem pętli a instrukcją skoku.

 

 
1010101010101010101010101010101010101010101010101010101010101010 

 

Podejmowanie decyzji

Cechą odróżniającą komputery od prostych liczydeł jest możliwość podejmowania różnych działań w zależności od sytuacji napotkanej w trakcie obliczeń. Obliczenia niejako mogą być wykonywane różnymi drogami w zależności od wyników operacji poprzednich. Dzięki tym cechom komputer może działać celowo - mądrze, inteligentnie.

W repertuarze rozkazów PMC II mamy dwie instrukcje, których wykonanie zależy od spełnienia pewnego warunku:

 

JZR - skok do adresu, gdy akumulator zawiera zero
JMI - skok do adresu, gdy akumulator zawiera wartość ujemną

 

Wbrew pierwszemu wrażeniu te dwie instrukcje pozwalają badać nawet złożone warunki. Poniżej podajemy odpowiednie przykłady:

 

Wyznaczanie znaku liczby

Poniższy program bada liczbę przechowywaną w zmiennej DANE. W zależności od wartości tej liczby wyświetla jeden z napisów <0, =0 lub >0.

 

DANE:  DAT -256

START: LDA $DANE  ;pobieramy liczbę do akumulatora
       JZR #ZERO  ;czy liczba równa zero?
       JMI #MINUS ;czy liczba ujemna?
       LDA #">    ;liczba dodatnia
       JMP #PISZ  ;wyświetlamy tekst
ZERO:  LDA #"=    ;liczba równa zero
       JMP #PISZ
MINUS: LDA #"<    ;liczba ujemna
PISZ:  STA $INOUT ;wypisujemy odpowiedni tekst
       LDA #"0
       STA $INOUT
       END

 

Wartość bezwzględna

Poniższy program bada zawartość komórki DANE. Jeśli jest ona ujemna, to zmienia ją na dodatnią.

 

DANE:  DAT -68    ;komórka z danymi

START: LDA $DANE  ;sprawdzamy, czy liczba jest ujemna
       JMI #MINUS ;jeśli tak, skaczemy do etykiety MINUS
       END        ;jeśli nie, kończymy program. Liczba jest dodatnia

MINUS: LDA #0     ;zmieniamy znak liczby odejmując ją od 0
       SUB $DANE
       STA $DANE
       END

 

Wartość większa

Ten program bada zawartość dwóch komórek DANE1 i DANE2. W komórce MAX umieszcza większą z nich.

 

DANE1:  DAT  139   ;komórki z danymi
DANE2:  DAT  278
MAX:    DAT    0   ;tutaj program umieści większą z liczb

START:  LDA $DANE1 ;pobieramy pierwszą liczbę
        SUB $DANE2 ;testowo odejmujemy od niej drugą liczbę
        JMI #D2    ;jeśli różnica mniejsza od 0, to DANE2 jest większa
        LDA $DANE1 ;tutaj większa jest DANE1
        JMP #KONIEC
D2:     LDA $DANE2 ;tutaj większa jest DANE2
KONIEC: STA $MAX   ;w MAX umieszczamy większą z liczb
        END 

 

Pętla warunkowa

Pętla warunkowa powstaje wtedy, gdy wybrana grupa instrukcji jest powtarzana w zależności od spełnienia pewnego warunku.

Poniższy program odczytuje dane z wejścia PMC II. Jeśli bufor jest pusty, to odczyt rejestru daje wartość 0. W takim przypadku program czeka aż na wejściu pojawi się jakaś dane. To jest pierwsza pętla warunkowa - cykliczny odczyt wejścia aż pojawi się na nim dana.

Gdy na wejściu pojawią się dane program wchodzi w drugą pętle warunkową - odczytuje dane i przesyła je na wyjście aż skończą się. W takim przypadku program jest kończony.

 

START:  LDA $INOUT  ;pobieramy znak z wejścia
        JZR #START  ;jeśli brak znaku, czekamy aż się pojawi
PISZ:   STA $INOUT  ;odczytany znak przesyłamy na wyjście
        LDA $INOUT  ;pobieramy kolejny znak
        JZR #KONIEC ;jeśli dane się skończyły, kończymy
        JMP #PISZ   ;w przeciwnym razie kontynuujemy
KONIEC: END

 

Kolejny program wykorzystuje pośredni tryb adresowania do przesłania zadanego tekstu na wyjście. Tekst jest przesyłany z kolejnych komórek pamięci dotąd, aż zostanie napotkany znak o kodzie 0. Wtedy program kończy swoje działanie.

 

TEKST:  DAT "W      ;w kolejnych komórkach umieszczamy
        DAT "I      ;poszczególne literki tekstu witaj
        DAT "T
        DAT "A
        DAT "J
        DAT 0       ;to jest koniec tekstu
TPTR:   DAT TEKST   ;tutaj mamy adres pierwszego znaku tekstu

START:  LDA *TPTR   ;pobieramy znak tekstu
        JZR #KONIEC ;jeśli koniec tekstu, kończymy
        STA $INOUT  ;znak przesyłamy na wyjście
        INC $TPTR   ;zwiększamy adres tekstu - następny znak
        JMP #START  ;kontynuujemy pętle z następnym znakiem
KONIEC: END

 

Pętla iteracyjna

Pętla iteracyjna jest pętlą warunkową, która wykonuje się zadaną ilość razy. Cechą charakterystyczną pętli iteracyjnej jest licznik zliczający kolejne obiegi. Gdy licznik osiągnie zadaną wartość, pętla kończy działanie.

Poniższy program wyświetla zadaną ilość literek X.

 

LICZNIK: DAT 15       ;liczba obiegów pętli

START:   LDA $LICZNIK ;sprawdzamy, czy licznik osiągnął 0
         JZR #KONIEC  ;jeśli tak, kończymy
         SUB #1       ;zmniejszamy licznik o 1
         STA $LICZNIK
         LDA #"X      ;na wyjście przesyłamy znak X
         STA $INOUT
         JMP #START   ;kontynuujemy pętlę
KONIEC:  END

 

Drugi program wypisuje na wyświetlaczu wszystkie duże literki od A do Z.

 

LICZNIK: DAT "A       ;wartość początkowa licznika - kod literki A

START:   LDA $LICZNIK ;licznik przesyłamy na wyjście
         STA $INOUT
         SUB #"Z      ;sprawdzamy, czy licznik osiągnął wartość Z
         JZR #KONIEC  ;jeśli tak, kończymy
         INC $LICZNIK ;jeśli nie, przechodzimy do kolejnej literki
         JMP #START   ;i kontynuujemy pętlę
KONIEC:  END

 

Wypisywanie liczb

Większość komputerów wypisuje liczby wykonując odpowiedni program. W tym celu zamienia się wartość liczby na odpowiedni ciąg znaków. Algorytm jest następujący:

Kolejne od końca cyfry otrzymujemy jako resztę z dzielenia liczby przez podstawę systemu, w którym chcemy zapisać liczbę. Wartość liczby dzielimy przez podstawę. Operację kontynuujemy dotąd, aż liczba osiągnie wartość 0. Wtedy otrzymane cyfry wyświetlamy. Dokładne algorytmy zamiany liczb na ciągi znaków znajdziesz w artykule Binarne Kodowanie Liczb.

Poniższy program wyświetla dziesiętnie zawartość komórki DANE

 

DANE:   DAT 26541   ;liczba do wyświetlenia - dodatnia!
CYFRY:  DAT 0       ;bufor na 5 cyfr
        DAT 0
        DAT 0
        DAT 0
        DAT 0
CPTR:   DAT 0       ;wskaźnik cyfr w buforze

START:  LDA #CYFRY  ;ustawiamy CPTR na ostatnią cyfrę
        ADD #4
        STA $CPTR   ;CPTR -> CYFRY[4]
LP1:    LDA $DANE   ;pobieramy liczbę
        MOD #10     ;wyznaczamy cyfrę
        ADD #48     ;dodajemy kod ASCII
        STA *CPTR   ;wstawiamy cyfrę do bufora
        LDA $CPTR   ;przesuwamy się na kolejną cyfrę
        SUB #1
        STA $CPTR
        LDA $DANE   ;liczbę dzielimy przez podstawę 10
        DIV #10
        STA $DANE
        JZR #PISZ   ;jeśli koniec, wypisujemy bufor
        JMP #LP1    ;jeśli nie, kontynuujemy pętlę
PISZ:   INC $CPTR   ;CPTR wskazuje o jedną cyfrę wcześniej. Korygujemy
        LDA *CPTR   ;pobieramy cyfrę
        STA $INOUT  ;przesyłamy ją na wyjście
        LDA $CPTR   ;sprawdzamy, czy koniec bufora
        SUB #CYFRY
        SUB #4
        JZR #KONIEC
        JMP #PISZ   ;jeśli nie, kontynuujemy
KONIEC: END  

 

Odczyt liczb

Odczyt liczb dokonuje się w sposób programowy wg tzw. schematu Hornera:

  1. Ustawiamy wartość liczby na 0.
  2. Odczytujemy z wejścia kolejny znak cyfry. Jeśli cyfry się skończyły - kończymy.
  3. Od kodu znaku odejmujemy 48, aby otrzymać wartość cyfry
  4. Liczbę mnożymy przez podstawę systemu i dodajemy do niej cyfrę
  5. Wracamy do punktu 2.

Dokładne algorytmy odczytu liczb w dowolnym systemie pozycyjnym znajdziesz w artykule Binarne Kodowanie Liczb.

Poniższy program odczytuje z wejścia liczbę (musi być zapisana poprawnie) w postaci ciągu znaków i wyznacza jej wartość w komórce DANE. Tam też zobaczymy wynik po zakończeniu programu.

 

DANE:   DAT 0       ;tutaj znajdzie się odczytana z wejścia liczba
X:      DAT 0       ;zmienna pomocnicza

START:  LDA $INOUT  ;czekamy, aż na wejściu pojawią się znaki
        JZR #START
LP1:    SUB #48     ;odejmujemy kod ASCII
        STA $X      ;cyfrę umieszczamy w zmiennej pomocniczej
        LDA $DANE   ;liczbę mnożymy przez 10
        MUL #10
        ADD $X      ;dodajemy cyfrę
        STA $DANE
        LDA $INOUT  ;pobieramy kolejną cyfrę
        JZR #KONIEC ;jeśli koniec cyfr, kończymy
        JMP #LP1    ;w przeciwnym razie kontynuujemy
KONIEC: END

 

Podsumowanie

W rozdziale pokazaliśmy podstawowe techniki programowania w języku maszynowym (w asemblerze) procesora PMC II. Prosty zbiór rozkazów nie jest przeszkodą w pisaniu bardziej złożonych programów. Jednakże program maszynowy jest dla człowieka mało czytelny. W rzeczywistych procesorach jest bardzo podobnie. Wszystkie cechy kodu maszynowego PMC II znajdziemy w jego starszych braciach. Zatem opanowanie pisania prostych programów w asemblerze PMC II znakomicie zwróci się nam w przyszłości przy programowaniu dużych maszyn. Podstawy już mamy.

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.