„Kukiełka Marionetkarza: o byciu ekspertem w programowaniu komputerowym”
- CAPUT I NARODZINY TYRANII Z DUCHA SPRAWCZOŚCI
- CAPUT II DŻIHAD USPRAWIEDLIWIA ISKRĘ, OD KTÓREJ ŚWIAT STAJE W OGNIU(04.11.2025)
- CAPUT III STATYSTYCZNIE ISTOTNY POMIAR WŁASNEGO CIENIA(11.11.2025)
- CAPUT IV ANALIZA UKŁADU ZAMKNIĘTEGO Z PERSPEKTYWY WIĘŹNIA(18.11.2025)
- CAPUT V ZWIEDZANIE RAJU UTRACONEGO(25.11.2025)
- CAPUT VI SŁOŃ JAKI JEST KAŻDY WIDZI, WIĘC UPAJAJMY SIĘ!(02.12.2025)
- CAPUT VII TRANSCENDENCJA NIEOSIĄGALNA(09.12.2025)
- CAPUT VIII ENDOMORFIZACJA JAJKA KOLUMBA(16.11.2025)
- CAPUT IX CZŁOWIEK CZŁOWIEKOWI RZEMIEŚLNIKIEM RZECZYWISTOŚCI(23.12.2025)
- CAPUT X KAŻDY PUNKT DROGI TO POCZĄTEK I KONIEC(30.12.2025)
- APPENDIX A WYBRANE FRAGMENTY DOKUMENTACJI WINDRAD
- APPENDIX B WYBRANE FRAGMENTY DOKUMENTACJI WISŁA 64
- APPENDIX C WYBRANE FRAGMENTY DOKUMENTACJI DRZWI
MARJONETKA KVKIEŁKARZA
albo
O BYCIU EKſPERTEM
W ZAUTOMATYZOWANYM
PRZETWARZANIU DANYCH
ZA POMOCĄ PROGRAMOWANYA
MASZYN KALKULUJĄCYCH
F.N.
CAPUT I
NARODZINY TYRANII
Z DUCHA SPRAWCZOŚCI
Kiedy zaczynałem swoją pierwszą pracę jako
programista, najbardziej popularnym
kalkulatorem w naszym kraju była Wisła 64.
Posiadała ona zawrotne 65536 adresowalnych
rejestrów pamięciowych oraz jednostkę
arytmetyczno-logiczną wspierającą operacje na
16-cyfrowych słowach binarnych. Model
programowy był wyjątkowo przyjazny,
ponieważ dla niemal wszystkich operacji adres
rejestru danych był kodowany w ostatnich dwóch oktetach instrukcji.
Był to dramatyczny przeskok względem kalkulatora Orzeł 8, który
dominował tuż przed Wisłą. Mimo 8-cyfrowych binarnych operacji
arytmetycznych Orzeł umożliwiał adresowanie 16384 oktetów pamięci,
ale opierało się to na skomplikowanym systemie banków pamięci.
Dla starych wyg Orła, którzy opanowali jego model, ta zmiana faworyta
była niemal jak śmierć przyjaciela. Koniec końców otrząsnęli się oni z
żałoby i zaczęli wykorzystywać potencjał nowej maszyny.
Miałem to szczęście, że wydział na którym studiowałem matematykę
stosowaną ze specjalizacją w systemach cyfrowych zdążył zaopatrzyć się
w Wisłę 64, gdy byłem na ostatnim roku mojego programu. Dzięki
czemu udało mi się skosztować nieco świeżonki przed wylądowaniem
na rynku pracy.
Co prawda moim szczytem wykorzystania tego systemu było rysowanie
drzewek w konsoli terminala. Uczelniani operatorzy, którym donosiłem
karty z wyperforowanym programem, sarkastycznie pytali, czy
stworzyłem nowy program albo znowu jest to tylko rysowanie
Fryckowych krzaków. Żółć, która mnie od tego zalewała,
odparowywała w kontakcie z entuzjazmem wynikającym z obcowania z
cudem ludzkości, jakim była Wisła 64.
Spółka PolACME, w której zatrudniłem się jako inżynier, dostarczała
rozwiązań obliczeniowych podmiotom w całym kraju oraz powoli
zdobywała zagraniczne rynki. Naszym sztandarowym produktem był
program Drzwi. Dedykowany był on na systemy oparte o Wisła 64 i
stanowił wejście do wirtualnej przestrzeni operatorskiej, która
umożliwiała wykonywanie wielu pomniejszych programów naraz oraz
dostarczała szereg wygodnych narzędzi do zarządzania pamięcią
operacyjną, jak i pamięcią pomocniczą. Wspierała zarówno taśmy
magnetyczne, jak i magazyny talerzowe. Był to produkt tak świetny, że
używali go nawet nasi inżynierowie i projektanci.
Dział, w którym pracowałem, opracowywał innowacyjne urządzenie
rozszerzające do Wisła 64, które miało umożliwić bezpośrednią
wymianę danych między dwiema maszynami na znaczne odległości.
Roboczo zostało nazwane Piast, ponieważ miało połączyć maszyny
kalkulujące, niczym pierwsi królowie Korony Polskiej połączyli
nadwiślańskie plemiona.
Pierwsze prezentacje okazały się nie lada sukcesem. Kierownictwo
zaczęło naciskać, żeby możliwe było podłączenie wielu takich urządzeń
do jednej maszyny Wisła 64, dzięki czemu mogłaby się ona
komunikować w wiele stron naraz. Ponadto dodano wymaganie, aby
komunikacja działała również w trybie pośrednika(coś jak zabawa w
"podaj dalej"). Przekroczeniem Rubikonu była jednak decyzja na
zaadaptowanie produktu pod zagraniczne maszyny liczące. Podjęta ona
została, ponieważ dyrekcja nawiązała współpracę biznesową z
Dortmundzką spółką NWRW(Nordhein-Westfallen Rechenwerke
GmbH) i podpisała kontrakt na ich autorską technologię o nazwie
WindRad. Reklamowana była jako rewolucja w dziedzinie
programowania obliczeniowego, ponieważ miała umożliwić uniwersalny
zapis programu, który będzie możliwy do translacji na dowolny system
obliczeniowy. Z założenia miało to odciążyć od projektowania
programu na bazie konkretnej maszyny matematycznej, której niuanse
wymagały podejmowania wielu decyzji dotyczących mało istotnych
szczegółów.
Symbolika marki opisywała to jako podmuch wiatru na młyn
napędzający inżynierię superwydajnych systemów obliczeniowego
przetwarzania danych. My jednak zrobiliśmy sobie z niej obiekt żartów
o tym, że wyraża ona podświadomą tęsknotę zarządu NWRW za
reżimowym ustrojem, który ich naród sam obalił pokolenie wcześniej.
PolACME utworzyło specjalny dział, który miał pomóc NWRW w
opracowaniu translatorów WindRad na maszyny Wisła 64 oraz Orzeł 8.
Już po kilku miesiącach otrzymaliśmy prototypy, na bazie których
mieliśmy opracowywać WindRadową wersję programu urządzenia
komunikacyjnego Piast.
Czuć było w tym pewną inercję. Dokumentacja techniczna WindRada
była opasła i poruszanie się po niej wymagało nieco wprawy. Pobieżne
zapamiętanie spisu treści nieco przyspieszało ten proces. Sama treść
dokumentacji dawała po sobie znać, że została przetłumaczona przez
kogoś, kto średnio rozumiał język polski.
Wszystkie słowa kluczowe WindRada pochodziły z niemieckiego. Nie
miałem z tym większego problemu, mój ojciec był z pochodzenia
Niemcem. Ożenił się jednak z Polką i z tego powodu w Polsce się
osiedlił. Pracował jako pianista w regionalnej filharmonii. Przekonywał
często matkę, że nadał mi imię na cześć Chopina, jednak pod jej
nieobecność opowiadał mi o chwale Cesarstwa Pruskiego oraz
wielkości Świętego Cesarstwa Rzymskiego za panowania Barbarossy.
Nie omieszkał przy tym wtrącać różne szlacheckie aforyzmy.
"Pamiętaj synu, najpotężniejsza armia nie uczyni z ciebie władcy, jeżeli
kupisz ją za cenę suwerenności."
Nie trafiało to wtedy do mnie, bo byliśmy prostą rodziną z miasta.
Najpotężniejszym żołnierzem naszego domu była matka uzbrojona w
tłuczek do kotletów. I bez tego była w stanie zrobić sobie z ojca
podnóżek. Do końca życia nawijał o Czystości i tym, że liczy się tylko
pismo i każdy ma takie same prawo jego interpretacji. Od czasu do
czasu przebąkiwał coś o rzymskich uzurpatorach, którzy są diabłami
świecącymi w ciemnościach. Jednak dla ukochanej Gracji ugiął się i
ochrzcił jedynego syna po katolicku. Może to właśnie ta rozdwojona
wizja na moje życie zaszczepiła we mnie jakiś dualizm, który
uniemożliwił poważne podejście do obu z rodzimych wyznań. Poza tym
nie potrafił wytrzymać choćby jednego przyjęcia bez tyrady o tym, jaki
to ród von Nischwitzów nie był wpływowy, mimo że nie utrwalił się
szczególnie na kartach historii. Wobec czego był prześmiewczo
nazywany za plecami baronem Terenzem.
Ja również nie podzielałem tej sympatii, więc irytowało mnie gdy
koledzy z pracy przychodzili do mnie z pytaniami o wpływ niuansów
języka niemieckiego na WindRad, bo nie znałem go wcale aż tak
dobrze.
Notacja, którą zapewnił nam WindRad od czasu do czasu pokrywała się
ze schematami powtarzających się przypadków projektu Piast. Te
schematy dokumentowaliśmy w formie biblioteki zawierającej schematy
list instrukcji, które były opisane pod kątem problemu, jaki
rozwiązywały. Notacja WindRada przypominała nieco notatki boczne
tych dokumentów z tym, że nie były one tylko pustymi słowami, bo
translator weryfikował spójność programu pod kątem użytych notacji.
Niestety po przepisaniu bazowej części komunikacyjnej Piasta do
WindRad maksymalna przepustowość danych spadła o niemal 30
procent. Wzbudziło to alarm u kierownictwa działu, bo kampania
marketingowa zaczęła już obiecywać pewne liczby, a teraz okazały się
one nieosiągalne.
Dlatego PolACME wystąpiło z podaniem do NWRW, aby zapewnili
nam szkolenie w kwestii efektywniejszego używania WindRada.
Producent WindRada zebrał wywiad od spółek używających ich
produktu i spisał opasłe kompendium pełne różnorodnych technik i
zasad użycia. Kopia woluminów trafiła do naszego działu i
kierownictwo wymagało od nas ich studiowania i stosowania się do ich
przykazu. Zorganizowanie sobie na to czasu oraz systemu
współdzielenia dostępu do ksiąg pozostało kwestią przemilczaną.
Napięcie wzrosło jeszcze bardziej, gdy dział rozwijający Drzwi zaczął
adaptować konkurencyjną technologię. Ich kierownictwo zdecydowało
się na wschodnie rozwiązanie o nazwie Szczipcy(ros. щипцы).
Reklamowana była jako coś co pozwoli złapać rozgrzaną do bieli ideę
programu i kuć ją póki gorąca. Poza tym miało się to kojarzyć z
pewnym i bezpiecznym chwytem.
W rzeczywistości koledzy, którzy zaczęli je używać byli głównie
uszczypliwi wobec wszystkich dookoła. Zaczęli nam suszyć głowy, że
rozwiązania, które piszemy pod WindRad są podatne na awarie i
manipulacje z zewnątrz, więc przezwaliśmy ich kultem czerwonego
kraba.
Kuriozum osiągnęło punkt krytyczny w momencie, w którym doszło
do sprzeczki między mną, a kolegą z działu o to jaki zapis w
WindRadzie użyć. Popchnęło mnie to do przeprowadzenia iście
szaleńczego badania, którym chciałem wykazać swoją rację, a w
konsekwencji doprowadziło do niebagatelnych wniosków.
Przedstawię to za pomocą zapisów moich kontemplacji, które ukażą je
z perspektywy bliższej temu, co myślałem i czułem w ciągu wydarzeń.
APPENDIX A
WYBRANE FRAGMENTY DOKUMENTACJI WINDRAD
WindRad jest jedną z technologii kalkulatorowych opracowanych przez
Nordhein-Westfallen Rechenwerke GmbH(NWRW).
Jego zadaniem jest dostarczanie sposobu zapisu programów w sposób
uniwersalny i przetłumaczalny na dowolną programowalną maszynę
cyfrową.
Program zgodny z WindRad składa się z wierszy cyfrowego tekstu. Na
wiersz składają się słowa oddzielone przerwami. Przerwa jest dowolnym
znakiem, który w druku robi pustą przestrzeń i jest zależna od
kodowania cyfrowego tekstu użytego do zapisu programu. Przerwy na
początku i na końcu wiersza nie rozróżniają programów, wielokrotne
puste znaki pomiędzy słowami stanowią pojedynczą przerwę.
Wysokość liter jest rozróżnialna w WindRad. Słowa o odgórnie
nadanym znaczeniu składają się z samych wielkich liter.
Wiersze opisują operacje przetwarzania danych, kształt struktur
sterujących oraz zmiany przepływu sterowania. Możliwe zapisy
określone są w postaci składni. Każdy wiersz ma skończoną złożoność
określoną odgórnie, zależną od pierwszorzędnej składni.
Program jest wykonywany wierszami od góry w dół, a każdy wiersz
słowami od lewej do prawej.
Pewne operacje nie są niezgodne z gramatyką WindRad, ale ich skutek
jest niemożliwy do zdefiniowania. Takie przypadki określa się jako
Grauzone(pol. szara strefa) i należy unikać doprowadzenia do nich.
Dane w Windrad podlegają typowaniu. Typy dzielą się na podstawowe i złożone. Typy złożone określa się mianem "agregat".
Typy podstawowe mają określoną wartość zeropodobną oraz porządek
wartości. Wartości znajdujące się dalej w porządku uznaje się za
większe.
Typy podstawowe można używać w formie wartości bezpośredniej.
Typ ZAHL służy do reprezentowania wartości całkowitoliczbowych zapisywanych za pomocą cyfr arabskich.
Typ KOMMA służy do reprezentowania liczb pseudorzeczywistych
zapisywanych w formie dziesiętnej z przecinkiem oddzielającym
wartość całkowitą od ułamkowej.
Bezpośrednia wartość KOMMA podlega błędowi obcięcia
wynikającego z precyzji kodowania liczb przecinkowych na jaki
przetłumaczony zostanie program. Wyniki operacji na wartościach
KOMMA również podlegają błędom precyzji.
Oba typy liczbowe mogą reprezentować wartości ujemne zaczynające się od znaku minusa i nieposiadające przerwy między minusem, a znakami liczby.
Wartość KETTE rozpoczęta i zakończona znakiem cytatu stanowi
jedno słowo.
Porządek wartości KETTE zależy przede wszystkim od długości
wartości. Wartości zawierające więcej znaków są większe.
W przypadku wartości o równej liczbie znaków relacja porządku zależy
od porządku znaków wynikających z użytego kodowania tekstu. Znaki
używane w odgórnie określonych słowach WindRad powinny zajmować
początkowe pozycje porządku.
Sugerowany porządek to:
- duże litery alfabetu łacińskiego
- małe litery alfabetu łacińskiego
- cyfry arabskie
- znaki specjalne używane jako słowa operacji tj. dwukropek, znak równości, znaki mniejsze/większe
Typ LOGIK reprezentuje wartości logiczne. Przyjmuje tylko wartość
WAHR oraz FALSCH oznaczających odpowiednio prawdę oraz fałsz.
Wartością zeropodobną jest fałsz, a prawda jest większa w relacji do
fałszu.
LOGIK_NULL = FALSCH
WAHR > FALSCH
Operacje na wartościach wykonywane są zgodne z typowym
kierunkiem przebiegu programu tj. od lewej do prawej, ale ich wynik
jest przekazywany wstecz, do lewej. Dlatego muszą zostać poprzedzone
składnią, która skorzysta z wyprodukowanej wartości.
Jako operand można użyć wyłącznie wartości bezpośredniej lub
symbolu. Nie można zagnieździć kolejnej operacji jako operandu.
Dla wszystkich typów podstawowych można dokonywać operacji
porównania.
Operacje porównania skutkują wytworzeniem wartości typu LOGIK.
Możliwe porównania to równość(=), lewe większe(>) oraz prawe
większe(<).
Każdy symbol może zostać poddany operacji pobierania adresu.
Polega ono na wykorzystaniu znaku (@) po lewej stronie nazwy
symbolu, bez przerwy.
Operacja wytwarza wartość adresu jako typ ZAHL.
Dla typów liczbowych można używać dwuwartościowych operacji
arytmetycznych takich jak dodawanie(+), odejmowanie(-), mnożenie(*),
dzielenie(/).
Pomiędzy operandami, a znakiem operacji musi występować przerwa.
Odejmowanie może występować w formie jednowartościowej w
którym występuje tylko prawy operand. Produkuje ono wartość
przeciwną.
Wartości KETTE można łączyć ze sobą poprzez operację konkatenacji, która funkcjonuje pod znakiem pionowej kreski(|).
Na wartościach logicznych można dokonywać operacji dwuwartościowych, czyli iloczynu(UND) i sumy(ODER). Jak również jednooperandowego zaprzeczenia logicznego(NICHT), które przyjmuje tylko prawy operand.
Dane można przetwarzać pod postacią symboli. Symbol nadaje danym
semantyczną nazwę oraz umożliwia zapamiętanie wartości.
Użycie symbolu poprzedza jego deklaracja. Deklaracja określa nazwę
symbolu oraz typ danych. Nazwa symbolu może składać się z dużych i
małych liter oraz musi zaczynać się od małej litery.
Wiersz deklaracji symbolu rozpoczyna się słowem specjalnym DATEN.
DATEN *nazwa* *typ*
Symbole typu podstawowego tuż po deklaracji mają niezdefiniowaną
wartość.
Deklarację symbolu można zakończyć słowem specjalnym KONST.
Taki symbol nie może zmienić wartości w dalszym przebiegu programu.
Jego wartość musi zostać nadana w wierszu następującym po deklaracji.
Zmiana wartości symbolu może nastąpić w wyniku operacji przypisania.
Przypisanie z prawej do lewej notuje się wokół operatora :=
przyjmującego z lewej strony symbol, którego wartość jest zmieniana. Z
prawej strony operatora podaje się wartość bezpośrednią, symbol albo
operację zgodną z symbolem z lewej strony.
Wartość wyliczona z prawej strony operatora kopiowana jest do
symbolu po lewej stronie.
Typy złożone agregują określony typ podstawowy.
Każdy element agregatu działa jak osobny symbol, więc może zostać
użyty jako wartość jak i może mu zostać nadana nowa wartość.
Typ FOLGE reprezentuje ciągi wartości. Używa się go poprzez
połączenie z typem podstawowym poprzez znak podkreślenia np.
FOLGE_ZAHL.
Agregaty FOLGE wykorzystują równoodległość elementów wynikającą
ze stałego rozmiaru symboli typów podstawowych oraz przyległości ich
wartości w pamięci.
Deklaracja agregatu typu FOLGE wymaga określenia rozmiaru ciągu w
nazwie zmiennej. Bazową cześć nazwy i liczbę elementów separuje się
znakiem podkreślenia.
W ramach deklaracji wszystkie elementy ciągu uzupełniane są wartością
zeropodobną.
Można ustalić wartość n pierwszych elementów ciągu używając wiersza
ANFANG tuż po deklaracji agregatu FOLGE.
Za wierszem ANFANG następują wiersze z wartościami typu elementu.
Każdy wiersz uzupełnia wartość pod kolejnym indeksem dolnym. Może
być to wartość bezpośrednia jak i symbol.
Za ostatnią wartością wstępnego uzupełnienia umieszcza się wiersz
ENDE.
Odniesienie do konkretnego elementu ciągu następuje poprzez
określenie jego indeksu za znakiem podkreślenia bazowej części nazwy.
Elementy indeksuje się wartościami całkowitoliczbowymi.
Indeks dolny można przekazać jako wartość bezpośrednią lub poprzez
symbol. Wartość bezpośrednia nie może być ujemna. W przypadku
symbolu wartość ujemna w trakcie ewaluacji ulega przesunięciu,
którego wynik jest zależny od rozmiaru liczb całkowitych systemu
docelowego.
Wskazanie na indeks poza rozmiarem ciągu jest przypadkiem
Grauzone.
Typ ZIPP reprezentuje pary danych w relacji klucz-wartość.
Konkretny ZIPP opisuje się formacie zgodnie z przykładem.
Wstępne wartości agregatu można nadać między wierszami ANFANG-
ENDE następującymi tuż po deklaracji. Poszczególne pary podaje się w
wierszach w formacie według przykładu.
DATEN przykladZipp ZIPP[KETTE -> LOGIK]
ANFANG
"abc" -> WAHR
"def" -> FALSCH
"xyz" -> FALSCH
ENDE
Odniesienie do wartości pod kluczem następuje poprzez wskazanie
klucza w nawiasach kwadratowych za nazwą symbolu o typie agregatu.
Dostęp do wartości kluczem powinien mieć złożoność nie wyższą niż
logarytmiczna.
Użycie nieistniejącego klucza do odczytu spowoduje ewaluację do
wartości zeropodobnej typu wartości.
Przepływ sterowania programu można kształtować za pomocą struktur
sterujących i podprogramów.
Symbole zadeklarowane wewnątrz struktur sterujących przestając
funkcjonować za ich zamknięciem. Ich nazwy nie mogą być takie same
jak nazwy symboli zadeklarowanych w wierszach poprzedzających
strukturę sterującą.
Struktury wyboru służą do wybiórczego wykonywania wierszy programu w zależności od jego stanu.
Struktura FLIPPER pozwala na wykonanie operacji od wybranego
wiersza w zależności od wartości wejściowej.
Wejście do struktury FLIPPER może być tylko wartości ZAHL.
Strukturę otwiera wiersz ze słowem specjalnym FLIPPER i następującą
po nim wartością typu ZAHL. Może być ona zarówno symbolem jak i
wartością bezpośrednią.
Wewnątrz struktury znajdują się wiersze operacji oraz wiersze REIN
oznaczające początek operacji dla danej wartości wejścia.
Wiersz REIN wymaga podania bezpośredniej wartości typu ZAHL tuż
za słowem REIN.
Wartości poszczególnych REIN-ów nie mogą się powtarzać. Pierwszy
wiersz wewnątrz FLIPPERA musi być REIN-em.
Po dopasowaniu wejścia do REIN-u wykonane zostaną wszystkie
wiersze za REIN-em aż do końca FLIPPER-a. Wcześniejsze
przekierowanie sterowania na zewnątrz struktury FLIPPER jest
możliwe za pomocą wiersza RAUS.
Opcjonalnie za wartością dla REIN można umieścić drugorzędną
składnię powodującą przepływ sterowania na zewnątrz.
Strukturę FLIPPER zamyka się wierszem z odwróconym słowem
specjalnym - REPPILF.
Struktura WENN pozwala na wykonanie operacji jeżeli spełniony
zostanie warunek.
Struktura rozpoczyna się od wiersza zaczynającego się słowem WENN
po którym występuje wartość bezpośrednia, symbol albo operacja typu
LOGIK.
Warunek uznaje się za spełniony jeżeli ewaluuje się do wartości WAHR.
Blok warunkowy zamyka się wierszem NNEW, DOCH albo DOCH
WENN. Wiersz DOCH otwiera blok, który wykonuje się jeśli
poprzedni warunek nie został spełniony. Wiersz DOCH WENN
pozwala na zdefiniowanie kolejnego bloku, którego sprawdzenie nastąpi
jedynie jeśli poprzedni warunek nie został spełniony.
Struktury iterujące służą do wielokrotnego wykonywania tych samych wierszy.
Struktura BIS służy do n-krotnego wykonania bloku programu.
Podstawowa składnia przyjmuje liczbę iteracji. Wiersz rozpoczynający
można rozszerzyć składnią VON określającą wartość pierwszego
numeru iteracji, domyślnie jest to jeden.
Można również rozszerzyć ją składnią ALS, która określa nazwę
tymczasowego symbolu ZAHL przechowującego wartość aktualnej
iteracji. Nazwa symbolu nie może się pokrywać z wcześniej
zadeklarowanymi i istnieje tylko do końca struktury.
BIS 10
BIS 15 VON 5
BIS 10 ALS iteracja
BIS 9 VON 1 ALS iteracja
Strukturę zamyka się wierszem ze słowem SIB.
Każdy blok składni można wyizolować zamykając go w podprogram.
Deklaracja podprogramu rozpoczyna się słowem
UNTERPROGRAMM. Po nim następuje opcjonalny typ wartości
zwrotnej podprogramu. Dalej jest nazwa podprogramu, która podlega
tym samym regułom co nazwy symboli. Nazwy zarówno symboli jak i
podprogramów nie mogą się dublować.
W kolejnych wierszach deklaruje się symbole stanowiące parametry
programu. Każdy wiersz składa się z nazwy symbolu parametru i jego
typu. Nazwa parametru nie może być tożsama nazwie podprogramu.
Po liście parametrów następuje wiersz STARTE za którymi znajdują się
wiersze instrukcji podprogramu. Za ostatnią instrukcją umieszcza się
wiersz ENDE.
Wewnątrz podprogramu nie można deklarować kolejnych
podprogramów. Nie można deklarować podprogramów wewnątrz
struktur sterujących.
Słowo specjalne ZUR funkcjonuje jako zmiana przepływu sterowania.
Składnia ta powoduje wyjście na zewnątrz wykonywanego
podprogramu, czyli tak zwany powrót.
W przypadku funkcji zwracającej wartość funkcjonuje również jako
symbol. Wartość do niego przypisana stanowi wartość zwrotną funkcji.
W przypadku przypisywania od prawej do lewej ze słowem ZUR po
lewej, po prawej stronie może wystąpić jedynie wartość bezpośrednia
lub symbol.
W podprogramie funkcjonują wyłącznie symbole zadeklarowane jako
jego parametry oraz symbole zadeklarowane wewnątrz wierszy
podprogramu.
Nazwa symbolu w podprogramie może być taka sama jak w innych
podprogramach oraz wierszach głównego programu.
Chcąc wykonać podprogram należy rozpocząć wiersz słowem
specjalnym TUN.
Wywołanie może nastąpić wyłącznie za deklaracją podprogramu.
Za słowem TUN podaje się nazwę podprogramu i bez przerwy otwiera
nawiasy w których podaje się wartości argumentów oddzielone
przerwami.
Jako argumenty podprogramu można przekazać wyłącznie symbole i
wartości bezpośrednie. Wartość symboli przekazanych jako argumenty
jest kopiowana do symboli zadeklarowanych jako parametry
podprogramu.
Wartość zwrotną podprogramu można skopiować do symbolu używając
operatora =: za wywołaniem podprogramu i symbolu po prawej stronie
tego operatora.
Istnieje szereg podprogramów, które powinny być dostępne do wywołania w każdym programie i dostosowane pod system docelowy.
Grupa podprogramów pamięciowych służy do tymczasowego
przydzielania bloków pamięci przez system docelowy.
Wśród nich znajdują się podprogramy do zapisu oraz odczytu wartości
każdego typu podstawowego z adresu wskazanego jako typ ZAHL.
Podprogram ZEIT służy do pobierania czasu, który upłynął od
początku uruchomienia programu.
Podprogram nie deklaruje żadnych parametrów.
Podprogram zwraca ciąg wartości typu FOLGE_ZAHL, którego
rozmiar i znaczenie elementów zależą od systemu docelowego.
Program tłumaczący może udostępniać również podprogramy charakterstyczne dla systemu docelowego.
APPENDIX B
WYBRANE FRAGMENTY DOKUMENTACJI WISŁA 64
Wisła 64 udostępnia ponad 64 tysiące adresowalnych komórek pamięci.
W przypadku wartości całkowitoliczbowych cyfry binarne poszczególnych oktetów są kodowane od prawej do lewej jako od najmniej do najbardziej znaczącej.
Instrukcje programu Wisła 64 kodowane są jako kolejne binarne oktety
w pamięci. Każda instrukcja koduje operację w pierwszym oktecie oraz
może użyć od 0 do 3 następujących oktetów jako operandy.
Cyfry oktetu operacji opisane są od lewej do prawej. Pierwsze cztery
cyfry binarne kodują bazową operację w formie liczby porządkowej.
Kolejne cztery to flagi charakterystyki operacji. Każda bazowa operacja
wspiera inną kombinację charakterystyk.
Model programowy pozwala na użycie dwóch rejestrów. Rejestru
roboczego oraz rejestru szczytu stosu wykonania. Rejestr szczytu stosu
wykonania zawiera adres bloku pamięci przechowującego informacje o
ramkach procedur oraz danych z nimi związanych.
Używany rejestr koduje się na piątej cyfrze binarnej w taki sposób, że 0
to rejestr roboczy, a 1 to rejestr stosu.
Cyfra numer 6 określa w jakim zakresie przetwarza się rejestr. Instrukcja
może działać w trybie pełnym(0) albo połowicznym(1), czyli
odpowiednio dwu albo jednooktetowym.
Cyfra numer 7 oznacza, czy rejestr używany jest w trybie wartości(0) czy
trybie wskaźnika(1). Tryb wartości to operowanie na wartości rejestru
wprost. Tryb wskaźnika oznacza, że wartość w rejestrze wyznacza adres
pod którym znajduje się wartość do użycia.
W trybie wskaźnika wymagane jest podanie dodatkowego oktetu
operandu tuż za oktetem operacji, który koduje przesunięcie względem adresu pod rejestrem. Wartość operandu kodowana jest w formacie
uzupełnień do dwóch.
Ostatnia cyfra oznacza, czy operand główny jest adresem(0) czy
wartością(1). Operand adresowy zawsze zajmuje dwa oktety, operand
wartościowy może być jednooktetowy, jeżeli wybrano przetwarzanie w
trybie połowicznym.
Dokładne działanie zależne jest od operacji bazowej.
Program na Wisłę 64 można zapisywać w postaci notacji pomocniczej.
Istnienie programu przekładającego tę notację na kodowanie obrazu
programu jest zależne od systemu na którym przetwarzany jest zapis.
Każda instrukcja zapisywana jest w osobnym wierszu.
Można tworzyć wiersze funkcjonujące jako alias adresu. Taki wiersz
rozpoczyna się znakiem zakreślonego a - @. Wartość aliasu jest
wyliczana w trakcie kodowania obrazu programu.
Program kodujący powinien umożliwić określenie wartości adresu
pierwszej instrukcji programu. Względem tej wartości przeliczane są
wszystkie aliasy powstałe w ramach oznaczenia wiersza.
Możliwe jest również nadanie stałej wartości aliasu adresowego.
Każda operacja bazowa ma swój mnemonik w notacji pomocniczej.
Mnemoniki pisze się w formie małych liter.
Notacja pomocnicza pozwala na korzystanie z tzw. adresów
pomocniczych - auxilar. Notuje się je w skrócie dużych liter AUX za
którymi znajduje się liczba porządkowa.
Możliwe jest bezpośrednie kodowanie wartości w obrazie programu.
Służą do tego wiersze zaczynające się od znaku krzyżyka(#). Kodują
one tyle oktetów ile jest minimalnie potrzebne dla zapisanej wartości.
Domyślnie wartości są w formie dziesiętnej np. #127, ale mogą być
również zapisywane w formie binarnej np. #b1001 albo
heksadecymalnej np. #hf0a1.
Zakodowany obraz programu powinien zawierać dodatkowe podwójne
sekwencje zerowych oktetów o liczbie równej największej liczbie
porządkowej użytej jako adres pomocniczy. Oktety te powinny znaleźć
się za oktetami kodującymi ostatnią instrukcję.
Wiersz instrukcji rozpoczyna się od mnemonika operacji bazowej.
Po nim następuje mnemonik rejestru(R - roboczy, S - stosu). Nie każda
operacja bazowa używa rejestru.
Chcąc użyć rejestru w trybie adresowym należy tuż za jego
mnemonikiem, bez przerwy umieścić znak zakreślonego a oraz wartość
przesunięcia. Wartość przesunięcia przyjmuje wartości od -128 do 127.
Kolejnym możliwym słowem jest wartość operandu głównego. Tryb
połowiczny wymusza się poprzez prefiks operandu znakiem dużego P.
Wartości bezpośrednie w trybie połowicznym muszą być
jednooktetowe.
Operand adresowy zapisuje się jako wartość liczbową lub wyciąga z
aliasu.
Operand wartościowy poprzedza się znakiem krzyżyka(#). Wartości
można podawać tak samo jak w przypadku wierszy kodujących dane z
tym, że nie mogą być większe niż na dwa oktety.
Możliwe jest użycie aliasu jako operacja na dosłownej wartości adresu, a
nie wartości znajdującej się pod nim.
Notacja pomocnicza udostępnia również specjalną składnię "rel"
służącą do tworzenia wartości względnej do aliasu adresu na potrzeby
skoków. Wartość liczona jest względem końca instrukcji i zmniejszana o
jeden, aby uwzględnić jeden oktet instrukcji skoku, która ma ją
wykorzystać.
lista operacji:
| nazwa | kod | mnemonik | tryby rejestru | tryby operandu |
| pusta operacja | 0 | nic | nie dotyczy | nie dotyczy |
| wstawienie do rejestru | 1 | wst | wartość/wskaźnik | adres/wartość |
| przechowanie w pamięci | 2 | prze | wartość/wskaźnik | adres |
| iloczyn binarny | 3 | oraz | wartość | adres/wartość |
| suma binarna | 4 | lub | wartość | adres/wartość |
| negacja binarna | 5 | nie | wartość | nie dotyczy |
| dodawanie | 6 | dod | wartość | adres/wartość |
| odejmowanie | 7 | ode | wartość | adres/wartość |
| mnożenie | 8 | mn | wartość | adres/wartość |
| Skok bezwarunkowy | 9 | sk | nie dotyczy | nie dotyczy |
| porównanie | 10 | por | wartość/wskaźnik | adres/wartość |
| Skok gdy nierówne | 11 | sgn | nie dotyczy | nie dotyczy |
| Skok gdy mniejsze | 12 | sgm | nie dotyczy | nie dotyczy |
| Wykonanie procedury | 13 | czyn | nie dotyczy | nie dotyczy |
| Powrót z procedury | 14 | pwr | nie dotyczy | nie dotyczy |
| Zatrzymanie maszyny | 15 | stop | nie dotyczy | nie dotyczy |
Pusta operacja skutkuje przejściem do następnej instrukcji. Wykonuje puste cykle zegara bez wpływu na stan pamięci i rejestrów.
Operacje binarne oraz arytmetyczne zapisują otrzymany wynik w użytym rejestrze.
Operacje skoku używają wartości rejestru roboczego jako przesunięcie
względne w oktetach. Przesunięcie następuje względem końca instrukcji
skoku.
Skoki "gdy" bazują na wyniku ostatniej operacji porównania. Operacja
porównania porównuje rejestr do operandu, więc przykładowo skok
gdy mniejsze dokona skoku, gdy w ramach ostatniego porównania
wartość rejestrowa była mniejsza niż wartość operandowa.
Operacja wykonania procedury wykorzystuje wartość w rejestrze
roboczym jako adres pod którym znajduje się pierwsza instrukcja
procedury.
Operacja wykonania procedury powoduje wpisanie adresu początku
następnej instrukcji na wierzch stosu i zwiększenie jego rejestru o dwa.
Analogicznie operacja powrotu korzysta z dwóch oktetów poniżej
wartości rejestru stosu jako adres skoku. Następnie zmniejsza wartość
rejestru stosu o dwa.
Operacja zatrzymania maszyny powoduje całkowite zatrzymanie przebiegu przetwarzania instrukcji.
Pusta operacja skutkuje przejściem do następnej instrukcji. Wykonuje
puste cykle zegara bez wpływu na stan pamięci i rejestrów.
Operacje binarne oraz arytmetyczne zapisują otrzymany wynik w
użytym rejestrze.
Operacje skoku używają wartości rejestru roboczego jako przesunięcie
względne w oktetach. Przesunięcie następuje względem końca instrukcji
skoku.
Skoki "gdy" bazują na wyniku ostatniej operacji porównania. Operacja
porównania porównuje rejestr do operandu, więc przykładowo skok
gdy mniejsze dokona skoku, gdy w ramach ostatniego porównania
wartość rejestrowa była mniejsza niż wartość operandowa.
Operacja wykonania procedury wykorzystuje wartość w rejestrze
roboczym jako adres pod którym znajduje się pierwsza instrukcja
procedury.
Operacja wykonania procedury powoduje wpisanie adresu początku
następnej instrukcji na wierzch stosu i zwiększenie jego rejestru o dwa.
Analogicznie operacja powrotu korzysta z dwóch oktetów poniżej
wartości rejestru stosu jako adres skoku. Następnie zmniejsza wartość
rejestru stosu o dwa.
Operacja zatrzymania maszyny powoduje całkowite zatrzymanie
przebiegu przetwarzania instrukcji.
Zapis wartości rozpościerających się na szereg adresów następuje
zgodnie ze wzrostem adresów. Oktety uszeregowane są przeciwnie do
adresacji pod względem wyższości. W notacji pomocniczej
dwuoktetowych wartości liczbowych lewy oktet zawiera bardziej
znaczącą część, w tym cyfrę znaku pod najbardziej lewą cyfrą.
Operacja połowiczna na wartości rejestru wpływa tylko na prawy oktet.
Operacja połowiczna na pamięci traktuje wartość pod adresem jako
jednooktetową.
Po uruchomieniu Wisła 64 rozpoczyna wykonywanie instrukcji począwszy od adresu zerowego.
Ostatnie 32 oktety pamięci są służą do programowego monitorowania oraz kontroli podstawowego funkcjonowania maszyny.
Maszyna zlicza swój czas działania i udostępnia go w trzech licznikach
kodujących nieujemne wartości całkowite
#hff80 - dwuoktetowy licznik mikrosekund, który przekręca się co 10
tys. mikrosekund
#hff82 - dwuoktetowy licznik setnych sekundy, który przekręca się co
600 sekund
#hff84 - jednooktetowy licznik jednej szóstej godzin, który przekręca
się co 42 godziny
APPENDIX C
WYBRANE FRAGMENTY DOKUMENTACJI DRZWI
Drzwi to program nadzorujący dedykowany na maszyny kalkulujące
Wisła 64 oraz podobnej mocy obliczeniowej.
To również ekosystem w którym programy mogą być wykonywane
współbieżnie. Dostarcza on szeregu funkcjonalności ogólnego
zastosowania, dzięki czemu programy nie muszą powielać
powszechnych procedur.
Programy wykonywane pod nadzorem Drzwi mają przydzielane
segmenty pamięci. Pierwszy program uruchomiony pod nadzorem
znajduje się w segmencie zaraz za segmentem programu nadzorowania.
Na końcu puli pamięci znajdują się oktety, które program nadzorujący
przydziela na żądanie. Taka pamięć może być współdzielona między
programami.
Segment programu wykonywanego składa się z następujących części.
- tabela adresów procedur
- instrukcje główne
- adresy pomocnicze
- stos wykonania programu
Dla wszystkich procedur znajdujących się w obrazie programu należy
utworzyć tabelę adresów początkowych.
Do wywołania procedury należy użyć adresu rekordu w tabeli adresów
początkowych procedur. Dzięki temu program nadzorujący Drzwi
może przeliczyć wartości adresów po umieszczeniu obrazu w pamięci
operacyjnej.
Wykonanie programu wymaga wskazania jego obrazu. Obraz programu wykonywalnego pod programem nadzorującym Drzwi musi zawierać nagłówek danych.
- wartość adresu pierwszej instrukcji programu - 2 oktety
- adres tabeli adresów procedur adekwatny do adresu pierwszej instrukcji - 2 oktety
- liczba procedur w tabeli - 1 oktet
- liczba oktetów na adresy pomocnicze - 1 oktet
Schemat notacji pomocniczej Wisła 64 z której wygeneruje się obraz programu.
#h0100
#@tabelaAdresowProcedur
#02
#0a
[...]
@instrukcje
[...]
stop
@tabelaAdresowProcedur
@adresProcedury1
#@procedura1
@adresProcedury2
#@procedura2
@procedury
@procedura1
wst R #0
pwr
Operandy adresowe większe niż 84(h) są rekalkulowane względem adresu pierwszej instrukcji obrazu po jego umieszczeniu w segmencie pamięci.
Program oraz jego procedury wykonywane pod nadzorem Drzwi
powinny dokonywać transferu wartości w następujący sposób.
Parametry programu muszą mieć określoną kolejność. Ich wartości
należy odłożyć na stos w tej właśnie kolejności przed wykonaniem
procedury.
Wartość zwrotna programu musi zostać umieszczona w rejestrze
roboczym przed powrotem z procedury.
Ekosystem Drzwi dostarcza sposobu kodowania oraz procedur
przetwarzania liczb przecinkowych.
Jest to zmiennoprzecinkowy format o podstawie dwójkowej z
rozróżnieniem dodatnie/ujemne, 9-cyfrową mantysą i 6-cyfrową
eksponentą.
Pierwsza cyfra od lewej koduje kierunek względem zera. Wartość 0
oznacza liczby dodatnie, a 1 ujemne.
Cyfry od drugiej do dziesiątej kodują mantysę. Każda cyfra to składnik
kolejnej ujemnej potęgi dwa począwszy od dwa do minus pierwszej.
Cyfry od jedenastej do szesnastej kodują wykładnik w formacie
uzupełnień do dwóch z najmniej znaczącą najbardziej prawą cyfrą.
Program nadzorujący Drzwi dostarcza procedury wszechstronnego
użytku.
Pozycje poszczególnych procedur bazowych w tabeli adresów są stałe.
Rozszerzenie do programu kodującego nadaje im aliasy o stałych
wartościach.
Aliasy procedur w notacji pomocniczej:
Drzwi-Zmiennoprzecinkowe-dodaj
Drzwi-Zmiennoprzecinkowe-odejmij
Drzwi-Zmiennoprzecinkowe-mnoz
Drzwi-Zmiennoprzecinkowe-dziel
Drzwi-Pamiec-rezerwuj
Drzwi-Pamiec-zapisz
Drzwi-Pamiec-czytaj
Drzwi-Pamiec-zwolnij
Drzwi-DrzewoBinarne-rezerwuj
Drzwi-DrzewoBinarne-wstaw
Drzwi-DrzewoBinarne-znajdz
Drzwi-DrzewoBinarne-zwolnij
procedura Drzwi-DrzewoBinarne-rezerwuj
parametr 1
rodzaj wartości przeszukiwania oraz rodzaj wartości w liściach - 1 oktet
pierwsza połowa oktetu koduje rodzaj przeszukiwania, a druga rodzaj
wartości w liściach
rodzaje danych:
1 - liczba całkowita
2 - liczba zmiennoprzecinkowa
3 - łańcuch znaków
wartość zwracana
adres pod którym znajdują się dane drzewa
procedura Drzwi-DrzewoBinarne-wstaw
parametr 1
wartość wyszukiwania - 2 oktety
parametr 2
wartość liścia - 2 oktety
wartość zwracana
brak
procedura Drzwi-DrzewoBinarne-znajdz
parametr 1
wartość przeszukiwania - 2 oktety
wartość zwracana
znaleziona wartość lub zera w przypadku nieistniejącej wartości
wyszukiwania