*************************************************************************** *** *** *** D o k u m e n t a t i o n *** *** zum EUMEL-Debugger *** *** *** *** Autor: Michael Staubermann *** *** Stand der Dokumentation: 03.12.86 *** *** Stand des Debuggers: 01.12.86 *** *** *** *************************************************************************** 1. Anwendung des Debuggers 1.1 Code Disassembler (Decoder) 1.1.1 Datenrepräsentation 1.1.2 Datenadressen 1.1.3 Codeadressen 1.2 Ablaufverfolgung (Tracer) 2. Die EUMEL0-Instruktionen 2.1 Erläuterung der Instruktionen (Thematisch sortiert) 2.2 Alphabetische Liste der Instruktionen 3. Beschreibung der Pakete 3.1 PACKET address 3.2 PACKET table routines 3.3 PACKET eumel decoder 3.4 PACKET tracer #page# #ub#1. Anwendung des Debuggers#ue# Der EUMEL-Debugger ist für die Software-Entwickler und nicht für die Anwender dieser Software gedacht. Insbesondere bei der Entwicklung systemnaher Software, wie z.B. Compiler, ist der Debugger hilfreich. (ELAN-)Programme werden wie bisher compiliert (z.B. insertiert), ohne daß der Quelltext des Programmes vorher modifiziert werden müßte. Um den Sourcetext während der Ablaufverfolgung (Trace) beobachten zu können, müßen die Programme mit 'check on' übersetzt werden. Die sinnvolle Anwendung des Debuggers setzt allerdings Kenntnis der EUMEL0-Instruktionen voraus, die im Kapitel 2 erläutert werden (Der Debugger setzt die Codierung BIT-A für diese Instruktionen voraus, d.h. er läuft zumindest in der interpretativen EUMEL0-Version.). #ub#1.1 Code Disassembler (Decoder)#ue# Der Decoder konvertiert die vom Compiler erzeugte Bitcodierung (16 Bit) in Mnemonics (Textdarstellung der Instruktionen), die in eine FILE geschrieben, bzw. optional auf dem Bildschirm ausgegeben werden können. Die Bitcodierung kann zusätzlich ausgegeben werden. Der Decoder wird mit 'decode' aufgerufen. Während der Dekodierung stehen folgende Tastenfunktionen zur Verfügung: Taste Funktion ----------------------------------------------------------------------- ESC Abbruch der Dekodierung. e Echo. Schaltet die parallel Bildschirmausgabe ein/aus. l Zeilennummern statt Hexadezimaladressen mitprotokollieren. a Hexadezimaladressen statt Zeilennummern mitprotokollieren. f Zeigt den Namen und die aktuelle Zeilennummer der Protokollfile. d getcommand ; docommand s storage info m Zeigt die aktuelle Modulnummer an (sinnvoll falls kein Echo) Q,W Zeilennummern/Hexadressen mitprotokollieren (falls kein Echo) S Keine Zeilennummern/Hexadressen ausgeben (läuft auch im Hintergrund) #ub#1.1.1 Datenrepräsentation#ue# INT-Zahlen werden hexadezimal (xxxxH, xxH) oder dezimal dargestellt, TEXTe in Anführungszeichen ("..."), REALs im 20-Stellen scientific-Format, TASK-Objekte durch XX-YYYY/"name" mit XX als Taskindex und YYYY als Version, wenn die Stationsnummer nicht 0 ist, wird sie vor XX als SS- dargestellt. DATASPACE-Objekte werden durch XX-YY repräsentiert (XX ist der eigene Taskindex, YY ist die Datenraumnummer), BOOL-Objekte durch TRUE oder FALSE. Module werden durch ihre Modulnummer, optional auch durch ihre Startadresse, und falls möglich durch ihren Namen repräsentiert. Die Parameterliste wird in den Fällen, wo das Modul in der Permanenttabelle vermerkt ist auch angegeben. Nicht weiter dereferenzierbare Adressen werden durch ein vorgestelltes '@' gekennzeichnet (z.B. BOUND-Objekte). In den Fällen, wo es mehrere sinnvolle Darstellungen gibt, werden diese durch ein '|' getrennt. #ub#1.1.2 Datenadressen#ue# Zusätzlich zu den globalen Daten (statische Variablen und Denoter) kann auch deren Adresse ausgegeben werden. Die Daten werden in einer, ihrem Typ entsprechenden, Darstellung ausgegeben. Komplexe oder zusammengesetzte Datentypen werden auf Repräsentationen elementarer Datentypen (INT, REAL, BOOL, TEXT, DATASPACE, TASK) abgebildet. Prozeduren, Operatoren und Paketinitialisierungen von Main-Packets werden zusammenfassend als Module bezeichnet. Einem Modul gehört ein eigener Stackbereich für lokale Daten, Parameter und Rücksprungadresse etc. In diesem Bereich stehen entweder die Datenobjekte selbst (z.B. lokale Variablen) oder lokale Referenzadressen auf beliebige Objekte (lokale, globale Daten, Fremddatenräume und sogar Module). Da die effektiven lokalen Adressen erst während der Runtime bekannt sind, findet man im Decoder-Output nur die Adressoffsets relativ zum Stackanfang des Moduls. Datenadressen werden in spitzen Klammern angegeben, Branch-Codeaddressen ohne Klammern. Alle Adressen sind Wortaddressen. Der Adresstyp wird durch einen Buchstaben nach '<' angezeigt: 'G' kennzeichnet eine globale Adresse (Denoter oder statische Variable). Die Representation der Daten kann immer angegeben werden (also nicht nur zur Runtime). 'L' kennzeichnet einen Adressoffset für ein lokales Datenobjekt auf dem Stack. Da die lokale Basis, d.h. die Anfangsadresse der Daten des aktuellen Moduls, erst bei Runtime feststehen, kann hier weder die effektive Datenadresse, noch der Inhalt des Datenobjekts angegeben werden. 'LR' kennzeichnet eine lokale Referenzadresse, d.h. auf dem Stack steht eine Adresse (32 Bit), die ein Datenobjekt adressiert. Ähnlich wie bei 'L' kann auch bei 'LR' erst zur Runtime eine Representation des adressierten Datenobjekts angegeben werden. Der Wert nach 'LR' bezeichnet den Offset, der zur lokalen Basis addiert werden muß, um die Adresse der Referenzadresse zu erhalten. Die niederwertigsten 16 Bit (das erste der beiden Wörter) können 128KB adressieren. Im höherwertigsten Byte des zweiten Wortes steht die Nummer des Datenraumes der eigenen Task, der das adressierte Datenobjekt enthält (0 entspricht dem Standarddatenraum). Das niederwertigste Byte des zweiten Wortes enthält die Segmentnummer (128KB-Segmente) mit dem Wertebereich 0 bis 7 (maximal also 1MB/Datenraum). Im Standarddatenraum (Datenraumnummer 4) enthalten die Segmente folgene Tabellen: Segment Tabelle ------------------------------------------------- 0 Paketdaten (high 120KB) und Moduladresstabelle 1 Stack (low 64K), Heap (high 64K) 2 Codesegment 3 Codesegment (120KB) u.a. für eigene Module 4 Compilertabellen temporär 5 Compilertabellen permanent 6 nilsegment für Compiler (FF's) 7 Compiler: Intermediate String Repräsentationen von Datenobjekten, die in Fremddatenräumen residieren (BOUND-Objekte) können zur Zeit noch nicht ausgegeben werden, statt dessen wird die Datenraumnummer und die Wortadresse innerhalb dieses Datenraums ausgegeben. #ub#1.1.3 Codeadressen#ue# Module werden in der Regel (Ausnahme: Parameterprozeduren) über ihre Modulnummer angesprochen, aus der dann die Adresse des Moduls berechnet werden kann (mithilfe der Moduladresstabelle). Die Adressen der Parameterprozeduren sind vom Typ 'LR' (Local-Reference), kommen nur als Parameter auf dem Stack vor und beeinhalten Codesegment und Codeadresse. Sprungadressen (von Branch-Befehlen) adressieren immer nur das eigene Segment und davon auch nur eine Adresse innerhalb eines 8 KB großen Bereichs. #ub#1.2 Ablaufverfolgung (Tracer)#ue# Um den eigenen (!) Code im Einzelschrittbetrieb abzuarbeiten, wird der Tracer benutzt. Außer den Inhalten der globalen Daten kann man sich die Inhalte der Stackobjekte (lokale Variablen) und der aktuellen Parameter eines Prozeduraufrufs (auch von Parameterprozeduren) ansehen. Es können keine Daten verändert werden! Man hat die Möglichkeit - die Resultate der letzten ausgeführten Instruktion oder - die aktuellen Parameter für den nächsten Instruktionsaufruf zu beobachten. Der Inhalt des Stacks kann sequentiell durchgesehen werden, Error- und Disablestop-Zustand können gelöscht werden. Der Einzelschrittablauf kann protokolliert und die entsprechende Sourceline parallel zum ausgeführten Code beobachtet werden. Der Einzelschrittbetrieb kann, über Teile des Codes hinweg, ausgeschaltet werden, z.B. für häufig durchlaufene Schleifen. Für die Repräsentation der Daten und deren Adressen gilt das unter 1.1 gesagte. Der Tracer wird mit 'trace' aufgerufen. Während der Aktivität des Tracers stehen folgende Funktionen zur Verfügung (Nur der erste Buchstabe wird getippt): Abkürzung Funktion -------------------------------------------------------------------------- Auto Die Befehle werden im Einzelschrittbetrieb ausgeführt, ohne daß eine Taste gedrückt werden muß. Bpnt Der nächste Breakpoint wird an eine vom Benutzer festgelegte Codeadrese gesetzt. Damit können Teile des Codes abgearbeitet werden, ohne daß der Einzelschrittmodus aktiv ist. Nach der Eingabe der Adresse wird der Befehl an dieser Adresse angezeigt. Bestätigt wird die Richtigkeit mit oder 's'. Clrr Ein eventuell vorliegender Fehlerzustand wird gelöscht. Dstp 'disable stop' wird für das untersuchte Modul gesetzt. Estp 'enable stop' wird für das untersuchte Modul gesetzt. File Der Name der kompilierten Quelldatei wird eingestellt. Go Der Code wird bis zum Ende abgearbeitet, ohne daß der Tracer aktiviert wird. Prot Der Name der Protokollfile wird eingestellt. Die abgearbeiteten Instruktionen werden in dieser File protokolliert. Rslt Es wird umgeschaltet, ob die angezeigte Instruktion nach oder 's' abgearbeitet werden soll (Forward-Trace, 'F') oder ob das Ergebnis der letzten ausgeführten Instruktion angezeigt werden soll (Result-Trace, 'R'). Der aktuelle Zustand dieses Switches wird in der ersten Bildschirmzeile durch 'R' oder 'F' gekennzeichnet. Kurzzeitige Umschaltung, um das Ergebnis der letzten Operation anzusehen, ist auch möglich (zweimal 'r' tippen). Step/CR Mit oder 's' wird die nächste Instruktion ausgeführt. Dies ist bei Forward-Trace die angezeigte Instruktion. Term Bis zur nächst 'höheren' Prozedur der CALL-Sequence, die im 'disable stop'-Zustand arbeitet, werden die Module verlassen. In der Regel bedeutet dies ein Programmabbruch. Alle Breakpoints sind anschließend zurückgesetzt. - Der Stackpointer auf den sichtbaren Stack (in der ersten Bildschirmzeile) wird um zwei verringert. Er zeigt auf die nächst tiefere Referenzadresse. Der EUMEL-0-Stackpointer wird nicht verändert. + Der Stackpointer auf den sichtbaren Stack wird um zwei erhöht. < Bei der Befehlsausgabe werden die Parameteradressen zusätzlich ausgegeben (in spitzen Klammern). > Bei der Befehlsausgabe werden keine Parameteradressen ausgegeben, sondern nur die Darstellungen der Parameter (z.B. Variableninhalte) #page# #ub#2. EUMEL0-Instruktionen#ue# #ub#2.1 Erläuterung der Instruktionen (Thematisch sortiert)#ue# Nach der Häufigkeit ihres Vorkommens im Code unterscheidet man 3 Klassen von Instruktionen: 30 Primärbefehle, 6 Spezialbefehle und z.Zt. 127 Sekundärbefehle. Die Primärbefehle enthalten im ersten Wort den Opcode (5 Bit) und 11 Bit für die erste Parameteradresse d.h. den Wertebereich 0..2047. Liegt die Parameteradresse außerhalb dieses Bereichs, dann ersetzt ein Umschaltprefix (LONGAddress) die Opcodebits und im lowbyte des ersten Wortes wird der Opcode codiert. Die erste Parameteradresse befindet sich dann als 16 Bit-Wert im zweiten Wort. Spezialbefehle enthalten im ersten Wort außer dem Opcode (8 Bit) noch einen 8 Bit-Immediatewert (Bytekonstante). Sekundärebefehle enthalten im ersten Wort nur den Opcode (16 Bit), der aus einem Umschaltprefix (ESCape, wird im folgenden weggelassen) und im lowbyte dem 8 Bit Sekündaropcode besteht. Im folgenden werden Datenadressen mit 'd', Immediatewerte mit 'v' (Value), Codeadressen mit 'a' und Modulnummern mit 'm' bezeichnet. Die Anzahl dieser Buchstaben gibt die Länge der benötigten Opcodebits (DIV 4) an. Ausnahmsweise bezeichnet .nn:dd einen 5 Bit Opcode ('nn') und eine 11 Bit Adresse ('dd'). Der Adresstyp ist in den Bits 14 und 15 codiert: 15 14 Typ Effektive Adresse 0 0 global dddd + pbase (pbase wird mit PENTER eingestellt) 1 0 local (dddd AND 7FFF) DIV 2 + lbase (lbase wird beim CALL gesetzt) 1 1 local ref adr := ((dddd AND 7FFF) DIV 2 + lbase) ; (adr+1, adr) Der Wert eines Wortes an der ersten Parameteradresse wird mit bezeichnet. Ein Datentyp vor der spitzen Klammer gibt seinen Typ an. Für die anderen Parameter gilt entsprechendes (, , ...). #ub#2.1.1 Datentransportbefehle#ue# MOV .08:dd dddd 1 Wort (z.B. INT/BOOL) wird von der linken Adresse zur rechten Adresse transportiert. := FMOV .34:dd dddd 4 Wörter (z.B. REAL) von linker Adresse zur rechten Adresse tranportieren (kopiert). := TMOV .4C:dd dddd Kopiert einen Text von der linken Adresse zur rechten Adresse. TEXT := TEXT MOVi FC vv dddd Die Konstante vv (1 Byte) wird als positive 16 Bit-Zahl dem Wort an der Adresse dddd zugewiesen. := vv MOVii 7F 23 vvvv dddd Dem Wort an der Adresse dddd wird die 16-Bit Konstante vvvv zugewiesen. := vvvv MOVx 7D vv dddd dddd Von der linken Adresse zur rechten Adresse werden vv (max. 255) Wörter transportiert. := (vv Wörter) MOVxx 7F 21 vvvv dddd dddd Von der linken Adresse zur rechten Adresse werden vvvv (max. 65535) Wörter transportiert. := (vvvv Wörter) #ub#2.1.2 INT-Operationen#ue# ARITHS 7F 5B Schaltet um auf vorzeichenbehaftete INT-Arithmetik (Normalfall). ARITH := Signed ARITHU 7F 5C Schaltet um auf vorzeichenlose 16Bit-Arithmetik (Compiler). ARITH := Unsigned CLEAR .24:dd Dem Wort an der Adresse dd wird 0 zugewiesen. := 0 INC1 .0C:dd Der Inhalt des Wortes an der Adresse dddd wird um eins erhöht. := + 1 DEC1 .10:dd Der Inhalt des Wortes an der Adresse dddd wird um eins verringert. := - 1 INC .14:dd dddd Der Inhalt des Wortes an der ersten Adresse wird zum Inhalt des Wortes an der zweiten Adresse addiert. := + DEC .18:dd dddd Der Inhalt des Wortes an der ersten Adresse wird vom Inhalt des Wortes an der zweiten Adresse subtrahiert. := - ADD .1C:dd dddd dddd Der Inhalt der Worte der beiden ersten Adressen wird addiert und bei der dritten Adresse abgelegt. := + SUB .20:dd dddd dddd Der Inhalt des Wortes an der zweiten Adresse wird vom Inhalt des Wortes an der ersten Adresse subtrahiert und das Resultat im Wort an der dritten Adresse abgelegt. := - MUL 7F 29 dddd dddd dddd Der Wert der Wörter an den beiden ersten Adressen wird vorzeichenbehaftet multipliziert und im Wort an der dritten Adresse abgelegt. Ein Überlauf wird im Falle der vorzeichenlosen Arithmetik ignoriert ( MOD 65536). := * IMULT 7F 28 dddd dddd dddd Der Wert der Wörter an den beiden ersten Adressen wird vorzeichenlos multipliziert und im Wort an der dritten Adresse abgelegt. Falls das Resultat ein Wert größer 65535 wäre, wird := FFFFH, sonst := * DIV 7F 2A dddd dddd dddd Der Wert des Wortes an der ersten Adresse wird durch den Wert des Wortes an der zweiten Adresse dividiert und im Wort an der dritten Adresse abgelegt. Eine Division durch 0 führt zum Fehler. := DIV MOD 7F 2B dddd dddd dddd Der Rest der Division (wie bei DIV) wird im Wort an der dritten Adresse abgelegt. Falls = 0 ist, wird ein Fehler ausgelöst. := MOD NEG 7F 27 dddd Der Wert des Wortes an der Adresse dddd wird arithmetisch negiert (Vorzeichenwechsel). := - AND 7F 7C dddd dddd dddd Der Wert der beiden Wörter an den beiden ersten Adressen wird bitweise UND-verknüpft und das Resultat im Wort an der dritten Adresse abgelegt. := AND OR 7F 7D dddd dddd dddd Der Wert der beiden Wörter an den beiden ersten Adressen wird bitweise ODER-verknüpft und das Resultat im Wort an der dritten Adresse abgelegt. := OR XOR 7F 79 dddd dddd dddd Der Wert der beiden Wörter an den beiden ersten Adressen wird bitweise Exklusiv-ODER-verknüpft und das Resultat im Wort an der dritten Adresse abgelegt. := XOR ROTATE 7F 53 dddd dddd Der Wert an der ersten Adresse wird um soviele Bits links oder rechts rotiert, wie es der Wert des zweiten Parameters angibt (positiv = links). IF < 0 THEN := ROR ELSE := ROL FI #ub#2.1.3 REAL-Operationen#ue# FADD .38:dd dddd dddd Die beiden ersten REAL-Werte werden addiert und das Resultat an der dritten Adresse abgelegt. REAL := REAL + REAL FSUB .3C:dd dddd dddd Der zweite REAL-Wert wird vom ersten subtrahiert und das Resultat an der dritten Adresse abgelegt. REAL := REAL + REAL FMUL .40:dd dddd dddd Die beiden ersten REAL-Werte werden multipliziert und das Resultat an der dritten Adresse abgelegt. REAL := REAL * REAL FDIV .44:dd dddd dddd Der erste REAL-Wert wird durch den zweiten dividiert und das Resultat an der dritten Adresse abgelegt. REAL := REAL / REAL FNEG 7F 26 dddd Das Vorzeichen des REAL-Wertes an der Adresse dddd wird gewechselt. REAL := -REAL FSLD 7F 60 dddd dddd dddd Die Mantisse des REAL-Wertes an der zweiten Adresse wird um ein Digit (4 Bit BCD) nach links verschoben, Vorzeichen und Exponent bleiben unverändert. Das vorher höherwertigste Digit steht danach im Wort an der dritten Adresse. Das neue niederwertigste Digit wurde aus dem Wort der ersten Adresse entnommen. INT := digit1 ; REAL := REAL SLD 1 ; digit13 := INT< 1> GEXP 7F 61 dddd dddd Der Exponent des REAL-Wertes an der ersten Adresse wird in das Wort an der zweiten Adresse gebracht. INT := exp SEXP 7F 62 dddd dddd Der Wert des Wortes an der ersten Adresse wird in den Exponenten des REAL-Wertes an der zweiten Adresse gebracht. exp := INT FLOOR 7F 63 dddd dddd Der REAL-Wert an der ersten Adresse wird ohne Dezimalstellen an der zweiten Adresse abgelegt. := floor #ub#2.1.4 TEXT-Operationen#ue# ITSUB 7F 2D dddd dddd dddd Aus dem TEXT an der ersten Adresse wird das Wort, dessen Position durch das Wort an der zweiten Adresse beschrieben wird, im Wort an der dritten Adresse abgelegt. INT := TEXT[INT,2] (Notation: t[n,s] bezeichnet das n. Element mit einer Größe von s Bytes, der Bytekette t an der Byteposition n*s+1) ITRPL 7F 2E dddd dddd dddd In dem TEXT an der ersten Adresse wird das Wort, dessen Position durch das Wort an der zweiten Adresse beschrieben wird, durch das Wort an der dritten Adresse ersetzt. TEXT[INT,2] := INT DECOD 7F 2F dddd dddd Der dezimale ASCII-Wert des Zeichens im TEXT an der ersten Adresse wird im Wort an der zweiten Adresse abgelegt. INT := code (TEXT) ENCOD 7F 30 dddd dddd Dem der TEXT an der zweiten Adresse wird ein Zeichen zugewiesen, das dem ASCII-Wert im Wort an der ersten Adresse entspricht. TEXT := code (INT) SUBT1 7F 31 dddd dddd dddd Dem TEXT an der dritten Adresse wird das Zeichen des TEXTes an der ersten Adresse zugewiesen, dessen Position durch das Wort an der zweiten Adresse bestimmt ist. TEXT := TEXT[INT, 1] SUBTFT 7F 32 dddd dddd dddd dddd Dem TEXT an der vierten Adresse wird ein Teiltext des TEXTes an der ersten Adresse zugewiesen, dessen Startposition im Wort an der zweiten Adresse steht und dessen Endposition im Wort an der dritten Adresse steht. TEXT := subtext (TEXT, INT, INT) SUBTF 7F 33 dddd dddd dddd Dem TEXT an der dritten Adresse wird ein Teiltext des TEXTes an der ersten Adresse zugewiesen, der an der durch das Wort an der zweiten Adresse beschriebenen Position beginnt und bis zum Ende des Sourcetextes geht. TEXT := subtext (TEXT, INT, length (TEXT)) REPLAC 7F 34 dddd dddd dddd Der TEXT an der ersten Adresse wird ab der Position, die durch das Wort an der zweiten Position bestimmt wird, durch den TEXT an der dritten Adresse ersetzt. replace (TEXT, INT, TEXT) CAT 7F 35 dddd dddd Der TEXT an der zweiten Adresse wird an das Ende des TEXTes an der ersten Adresse angefügt. TEXT := TEXT + TEXT TLEN 7F 36 dddd dddd Die Länge des TEXTes an der ersten Adresse wird im Wort an der zweiten Adresse abgelegt. INT := length (TEXT) POS 7F 37 dddd dddd dddd Die Position des ersten Auftretens des TEXTes an der zweiten Adresse, innerhalb des TEXTes an der ersten Adresse, wird im Wort an der dritten Adresse abgelegt. INT := pos (TEXT, TEXT, 1, length (TEXT)) POSF 7F 38 dddd dddd dddd dddd Die Position des ersten Auftretens des TEXTes an der zweiten Adresse, innerhalb des TEXTes an der ersten Adresse, ab der Position die durch den Inhalt des Wortes an der dritten Adresse bestimmt ist, wird im Wort an der vierten Adresse abgelegt. INT := pos (TEXT, TEXT, INT, length (TEXT)) POSFT 7F 39 dddd dddd dddd dddd dddd Die Position des ersten Auftretens des TEXTes an der zweiten Adresse, innerhalb des TEXTes an der ersten Adresse, ab der Position die durch den Inhalt des Wortes an der dritten Adresse bestimmt ist, bis zur Position die durch den Inhalt des Wortes an der vierten Adresse bestimmt ist, wird im Wort an der fünften Adresse abgelegt. INT := pos (TEXT, TEXT, INT, INT) STRANL 7F 3A dddd dddd dddd dddd dddd dddd dddd (ROW 256 INT CONST, INT VAR, INT CONST, TEXT CONST, INT VAR, INT CONST, INT VAR): Vereinfachte funktionsweise: extension := FALSE ; FOR INT FROM INT UPTO min (INT, length (TEXT)) WHILE INT < INT REP IF extension THEN extension := FALSE ELSE INT:=ROW[TEXT[INT,1]]; IF INT < 0 THEN extension := TRUE ; INT INCR (INT-8000H) ELSE INT INCR INT FI FI PER POSIF 7F 3B dddd dddd dddd dddd dddd Die Position des ersten Auftretens des, durch die beiden Zeichen des TEXTes an der zweiten und dritten Adresse begrenzten ASCII-Bereichs (lowchar, highchar), Zeichens innerhalb des TEXTes an der ersten Adresse, wird ab der Position, die durch das Wort an der vierten Adresse beschrieben wird, im Wort an der fünften Adresse abgelegt. INT := pos (TEXT, TEXT, TEXT, INT). GARB 7F 5F Es wird eine Garbagecollection für den taskeigenen TEXT-Heap durchgeführt. HPSIZE 7F 5E dddd Die aktuelle Größe des TEXT-Heaps wird in dem Wort an der Adresse dddd abgelegt. := heapsize RTSUB 7F 64 dddd dddd dddd Aus dem TEXT an der ersten Adresse wird der REAL-Wert, dessen Position durch das Wort an der zweiten Adresse beschrieben wird, an der dritten Adresse abgelegt. REAL := TEXT[INT, 8] RTRPL 7F 65 dddd dddd dddd In dem TEXT an der ersten Adresse wird der REAL-Wert, dessen Position durch das Wort an der zweiten Adresse beschrieben wird, durch den REAL-Wert an der dritten Adresse ersetzt. TEXT[INT, 8] := REAL #ub#2.1.5 DATASPACE-Operationen#ue# DSACC .58:dd dddd Die dsid an der ersten Adresse wird auf Gültigkeit geprüft und an der zweiten Adresse eine Referenzaddresse abgelegt, die auf das 4. Wort des Datenraumes (den Anfang des Datenbereichs) zeigt. IF valid ds (DS) THEN REF := DATASPACE.ds base ELSE "falscher DATASPACE-Zugriff" FI ALIAS 7F 22 vvvv dddd dddd Dem BOUND-Objekt an der dritten Adresse wird der Datenraum an der zweiten Adresse zugewiesen (INT-Move). Zuvor wird geprüft, ob dies der erste Zugriff auf den Datenraum ist. Falls ja, wird der Datenraumtyp auf 0 gesetzt. Falls ein Heap aufgebaut werden muß und noch keiner angelegt wurde, wird die Anfangsadresse des Heaps auf den Wert vvvv+4 innerhalb des Datenraumes gesetzt. IF DATASPACE.typ < 0 THEN DATASPACE.typ := 0 FI ; IF DATASPACE.heapanfang < 0 THEN DATASPACE.heapanfang := vvvv+4 FI ; INT := INT NILDS 7F 45 dddd Dem Datenraum an der Adresse dddd wird der 'nilspace' zugewiesen. INT := 0 DSCOPY 7F 46 dddd dddd Dem Datenraum an der ersten Adresse wird eine Kopie des Datenraumes an der zweiten Adresse zugewiesen (neue dsid). Es wird ein neuer Eintrag in die Datenraumverwaltung aufgenommen. DATASPACE := DATASPACE DSFORG 7F 47 dddd Der Datenraum, dessen dsid an der Adresse dddd steht, wird aus der Datenraumverwaltung gelöscht. forget (DATASPACE) DSWTYP 7F 48 dddd dddd Der Typ des Datenraums, dessen dsid an der ersten Adresse steht, wird auf den Wert des Wortes an der zweiten Adresse gesetzt. DATASPACE.typ := INT ; IF DATASPACE.heapanfang < 0 THEN DATASPACE.heapanfang := vvvv+4 FI DSRTYP 7F 49 dddd dddd Der Typ des Datenraums, dessen dsid an der ersten Adresse steht, wird in dem Wort an der zweiten Adresse abgelegt. INT := DATASPACE.typ ; IF DATASPACE.heapanfang < 0 THEN DATASPACE.heapanfang := vvvv+4 FI DSHEAP 7F 4A dddd dddd Die Endaddresse Textheaps des Datenraums, dessen dsid an der ersten Adresse steht, in 1kB Einehiten, wird in dem Wort an der zweiten Adresse abgelegt. Falls dieser Wert = 1023 oder < 96 ist, ist kein Heap vorhanden, anderenfalls ist seine Größe (in KB): -96. INT := DATASPACE.heapende DIV 1024 NXTDSP 7F 4B dddd dddd dddd Für den Datenraum an der ersten Adresse wird die Nummer der Seite, die auf die Nummer der Seite folgt, die in dem Wort an der zweiten Adresse steht an der zweiten Adresse abgelegt. Falls keine Seite mehr folt, wird -1 geliefert. INT := nextdspage (DATASPACE, INT) DSPAGS 7F 4C dddd dddd dddd Für den Datenraum mit der Nummer, die im Wort an der ersten Adresse steht, und der Task deren Nummer im Wort an der zweiten Adresse steht, wird die Anzahl der belegten Seiten im Wort an der dritten Adresse abgelegt. INT := ds pages (INT, INT) SEND 7F 71 dddd dddd dddd dddd Der Datenraum an der dritten Adresse wird der Task, deren id an der ersten Adresse steht, mit dem Messagecode der an der zweiten Adresse steht, gesendet. Der Antwortcode wird im Wort an der vierten Adresse abgelegt. Vereinfachte Semantik: send (TASK, INT, DATASPACE, INT) WAIT 7F 72 dddd dddd dddd Die eigene Task geht in einen offenen Wartezustand, bei dem sie empfangsbereit ist für einen Datenraum einer anderen Task. Die id der sendenden Task wird an der ersten Adresse abgelegt, der Messagecode an der zweiten Adresse, der gesendete Datenraum an der dritten Adresse. Vereinfachte Semantik: wait (TASK, INT, DATASPACE) SWCALL 7F 73 dddd dddd dddd dddd Der Datenraum an der dritten Adresse wird der Task, deren id an der ersten Adresse steht, mit dem Messagecode der an der zweiten Adresse steht, gesendet bis die Task empfangsbereit ist. Dann wird auf einen zurückgesandten Datenraum dieser Task gewartet, der an der dritten Adresse abgelegt wird. Der zurückgesendete Messagecode wird an der vierten Adresse abgelegt. Vereinfachte Semantik: REP send (TASK, INT, DATASPACE,INT) UNTIL INT <> task busy PER ; wait (TASK, INT, DATASPACE) PPCALL 7F 7A dddd dddd dddd dddd Wirkt wie SWCALL, wartet aber nicht bis die Zieltask empfangsbereit ist, sondern liefert -2 an der vierten Adresse zurück, wenn die Task nicht empfangsbereit ist. Vereinfachte Semantik: send (TASK, INT, DATASPACE,INT); IF INT <> task busy THEN wait (TASK, INT, DATASPACE) FI SENDFT 7F 7F dddd dddd dddd dddd dddd Der Datenraum an der vierten Adresse wird der Task, deren id an der zweiten Adresse steht, mit dem Messagecode der an der dritten Adresse steht, gesendet als ob er von der Task käme, deren id an der ersten Adresse steht. Der Antwortcode wird im Wort an der vierten Adresse abgelegt. Dieser Befehl setzt eine Priviligierung >= 1 voraus und ist nur wirksam, wenn die from-Task einer anderen Station angehört. Vereinfachte Semantik: IF station (TASK) = station (myself) THEN send (TASK, INT, DATASPACE, INT) ELSE save myself := myself ; myself := TASK ; send (TASK, INT, DATASPACE, INT) ; myself := save myself FI #ub#2.1.6 TASK-Operationen#ue# TWCPU 7F 52 dddd dddd Die CPU-Zeit der Task, deren Nummer an der ersten Adresse steht, wird auf den REAL-Wert, der an der zweiten Adresse steht gesetzt. Dieser Befehl setzt eine Privilegierung > 1 voraus (Supervisor). pcb(INT).clock := REAL TPBEGIN 7F 5F dddd dddd dddd aaaaaa Als Sohn der Task, deren Nummer an der ersten Adresse steht, wird eine Task eingerichtet, deren Nummer an der zweiten Adresse steht. Die neue Task erhält die Privilegierung, deren Nummer in dem Wort an der dritten Adresse steht und wird mit der Prozedur gestartet, deren Code bei der durch den vierten Parameter übergebenen Refereznadresse beginnt. Dieser Befehl setzt eine Privilegierung > 1 voraus (Supervisor). TRPCB 7F 68 dddd dddd dddd Der Wert des Leitblockfeldes der Task deren Nummer an der ersten Adresse steht und der Nummer, die in dem Wort an der zweiten Adresse steht, wird an der dritten Adresse abgelegt. INT := pcb(INT, INT) TWPCB 7F 69 dddd dddd dddd Der Wert an der dritten Adresse wird in das Leitblockfeld mit der Nummer an der zweiten Adresse der Task übertragen, deren Nummer an der ersten Adresse steht. Privilegierung: 0: Nur linenumber-Feld (0), der eigenen Task 1: linenumber-Feld der eigenen Task und prio-Feld (5) jeder Task 2: Alle Felder Für den Fall, daß die Privilegierung ok ist gilt: pcb (INT, INT) := INT TCPU 7F 6A dddd dddd Die CPU-Zeit der Task, deren Nummer an der ersten Adresse steht, wird als REAL-Wert an der zweiten Adresse abgelegt. REAL := pcb (INT).clock TSTAT 7F 6B dddd dddd Der Status (busy, i/o, wait) der Task, deren Nummer an der ersten Adresse steht, wird im Wort an der zweiten Adresse abgelegt. INT := pcb (INT).status ACT 7F 6C dddd Die Task mit der Nummer, die an der Adresse dddd steht wird aktiviert (entblockt). Dieser Befehl setzt eine Privilegierung >= 1 voraus. activate (INT) DEACT 7F 6D dddd Die Task, deren Nummer an der Adresse dddd steht, wird deaktiviert (geblockt). Dieser Befehl setzt eine Privilegierung >= 1 voraus. deactivate (INT) THALT 7F 6E dddd In der Task, deren Nummer an der Adresse dddd steht, wird ein Fehler 'halt vom Terminal' induziert. Dieser Befehl setzt eine Privilegierung > 1 voraus (Supervisor). halt process (INT) TBEGIN 7F 6F dddd aaaaaa Eine neue Task wird eingerichtet, deren Nummer an der ersten Adresse steht. Die Adresse der Startprozedur wird als Referenzadresse im zweiten Parameter übergeben. Der Datenraum 4 wird von der aufrufenden Task geerbt. Als Privilegierung wird 0 eingetragen. Dieser Befehl setzt eine Privilegierung > 1 voraus (Supervisor). TEND 7F 70 dddd Die Task, deren Nummer an der Adresse dddd steht, wird gelöscht (alle Datenräume) und aus der Prozessverwaltung entfernt. Dieser Befehl setzt eine Privilegierung > 1 voraus (Supervisor). PNACT 7F 76 dddd Die Nummer der nächsten aktivierten Task wird aus der Aktivierungstabelle gelesen. Die Suche beginnt mit dem Wert+1 an der Adresse. Die Nummer nächsten aktivierten Task wird an dieser Adresse abgelegt. INT := next active (INT) DEFCOL 7F 80 dddd Die Task an der Adresse wird als Collectortask (für Datenaustausch zwischen Stationen) definiert. Dieser Befehl setzt eine Privilegierung >= 1 voraus. TASK collector := TASK #ub#2.1.7 Tests und Vergleiche#ue# Alle Tests und Vergleiche liefern ein BOOL-Resultat, welches den Opcode des nachfolgenden Branch-Befehls bestimmt (Aus LN wird BT aus BR wird BF). TEST .28:dd Liefert TRUE, wenn das Wort an der Adresse 0 ist (Auch für BOOL-Variablen gebraucht: TRUE=0, FALSE=1). FLAG := = 0 EQU .2C:dd dddd Liefert TRUE, wenn die Wörter der beiden Adressen gleich sind. FLAG := = LSEQ .30:dd dddd Liefert TRUE, wenn der Wert des Wortes an der ersten Adresse (vorzeichenbehaftet) kleiner oder gleich dem Wert des Wortes an der zweiten Adresse ist. FLAG := INT <= INT FLSEQ .48:dd dddd Liefert TRUE, wenn der REAL-Wert an der ersten Adresse kleiner oder gleich dem REAL-Wert an der zweiten Adresse ist. FLAG := REAL <= REAL FEQU 7F 24 dddd dddd Liefert TRUE, wenn der REAL-Wert an der ersten Adresse gleich dem REAL-Wert an der zweiten Adresse ist. FLAG := REAL = REAL TLSEQ 7F 25 dddd dddd Liefert TRUE, wenn der TEXT an der ersten Adresse kleiner oder gleich dem TEXT an der zweiten Adresse ist. FLAG := TEXT <= TEXT TEQU .50:dd dddd Liefert TRUE, wenn der TEXT an der ersten Adresse gleich dem TEXT an der zweiten Adresse ist. FLAG := TEXT = TEXT ULSEQ .54:dd dddd Liefert TRUE, wenn der Wert des Wortes an der ersten Adresse (vorzeichenlos) kleiner oder gleich dem Wert des Wortes an der zweiten Adresse ist. FLAG := INT "<=" INT EQUIM 7C vv dddd Liefert TRUE, wenn der Wert des Wortes an der Adresse dddd gleich der 8 Bit Konstanten vv ist. FLAG := INT = vv ISDIG 7F 12 dddd Liefert TRUE, wenn der ASCII-Code im Wort an der Adresse dddd einer Ziffer entspricht. FLAG := INT >= 48 AND INT <= 57 ISLD 7F 13 dddd Liefert TRUE, wenn der ASCII-Code im Wort an der Adresse dddd einer Ziffer oder einem Kleinbuchstaben entspricht. FLAG := INT >= 48 AND INT <= 57 OR INT >= 97 AND INT <= 122 ISLCAS 7F 14 dddd Liefert TRUE, wenn der ASCII-Code im Wort an der Adresse dddd einem Kleinbuchstaben entspricht. FLAG := INT >= 97 AND INT <= 122 ISUCAS 7F 15 dddd Liefert TRUE, wenn der ASCII-Code im Wort an der Adresse dddd einem Großbuchstaben entspricht. FLAG := INT >= 65 AND INT <= 90 ISSHA 7F 18 dddd Liefert TRUE, wenn der Wert des Wortes an der Adresse dddd im Bereich 0..2047 liegt, d.h. eine Kurzadresse ist, die noch zusammen mit dem Opcode im ersten Wort eines Primärbefehls untergebracht werden kann. FLAG := INT < 2048 ISERR 7F 4E Liefert TRUE, wenn ein Fehlerzustand vorliegt. FLAG := ERROR EXTASK 7F 7B dddd Liefert TRUE, wenn die Task, deren id an der Adresse dddd steht, existiert (nicht "dead" und korrekte Versionsnummer). FLAG := TASK.version = pcb (TASK.nr).version AND pcb (TASK.nr).status <> dead #ub#2.1.8 I/O-Operationen#ue# OUT 7F 3C dddd Der Text an der Adresse wird ausgegeben. out (TEXT) COUT 7F 3D dddd Falls der Kanal frei ist und die INT-Zahl an der Adresse dddd positiv ist, wird sie als Dezimalzahl ausgegeben. IF free (channel) THEN out (text (INT, 5) + 5 * ""8"") FI OUTF 7F 3E dddd dddd Der Text an der ersten Adresse wird ab der Position, die durch den Wert des Wortes an der zweiten Adresse bestimmt wird, bis zum Ende ausgegeben. out (subtext (TEXT, INT, length (TEXT))) OUTFT 7F 3F dddd dddd dddd Der Text an der ersten Adresse wird ab der Position, die durch den Wert an der zweiten Adresse bestimmt wird, bis zur Position die durch den Wert an der dritten Adresse bestimmt wird, ausgegeben. out (subtext (TEXT, INT, INT)) INCHAR 7F 40 dddd Es wird auf ein Eingabezeichen gewartet, welches dann im TEXT an der Adresse dddd abgelegt wird. IF zeichen da (channel) THEN TEXT := incharety ELSE offener wartezustand (inchar) ; TEXT := incharety FI INCETY 7F 41 dddd Falls kein Eingabezeichen vorhanden ist, wird im TEXT an der Adresse dddd niltext geliefert, sonst das Eingabezeichen. IF zeichen da (channel) THEN TEXT := incharety ELSE TEXT := "" FI PAUSE 7F 42 dddd Der Wert an der Adresse dddd bestimmt die Wartezeit in Zehntelsekunden, die gewartet werden soll. Die Pause kann durch eine Eingabe auf dem Kanal abgebrochen werden. IF NOT zeichen da (channel) THEN modi := INT ; offener wartezustand (pause) FI GCPOS 7F 43 dddd dddd Die Cursorposition wird erfragt. Die x-Position wird an der ersten Adresse abgelegt, die y-Position an der zweiten Adresse. getcursor (INT, INT) CATINP 7F 44 dddd dddd Aus dem Eingabepuffer werden alle Zeichen gelesen und an den TEXT an der ersten Adresse gehängt, bis entweder der Eingabepuffer leer ist oder ein Zeichen mit einem Code < 32 gefunden wurde. Im ersten Fall wird niltext an der zweiten Adresse abgelegt, im zweiten Fall das Trennzeichen. REP IF zeichen da (channel) THEN zeichen := incharety ; IF code (zeichen) < 32 THEN TEXT := zeichen ELSE TEXT CAT zeichen FI ELSE TEXT := "" ; LEAVE CATINP FI PER CONTRL 7F 54 dddd dddd dddd dddd Der IO-Controlfunktion mit der Nummer, die an der ersten Adresse steht, werden die beiden Parameter übergeben, die an der zweiten und dritten Adresse stehen. Die Rückmeldung wird an der vierten Adresse abgelegt. IF channel > 0 THEN iocontrol (INT, INT, INT, INT) FI BLKOUT 7F 55 dddd dddd dddd dddd dddd Die Seite des Datenraums, dessen dsid an der ersten Adresse steht, mit der Seitennummer, die an der zweiten Adresse steht, wird auf dem aktuellen Kanal ausgegeben. Als Parameter werden die Werte an der dritten und vierten Adresse übergeben. Der Returncode wird an der fünften Adresse abgelegt. IF channel > 0 THEN blockout (DATASPACE[INT, 512], INT, INT, INT) FI BLKIN 7F 56 dddd dddd dddd dddd dddd Die Seite des Datenraums, dessen dsid an der ersten Adresse steht, mit der Seitennummer, die an der zweiten Adresse steht, wird an dem aktuellen Kanal eingelesen. Als Parameter werden die Werte an der dritten und vierten Adresse übergeben. Der Returncode wird an der fünften Adresse abgelegt. IF channel > 0 THEN blockout (DATASPACE[INT, 512], INT, INT, INT) FI #ub#2.1.9 Ablaufsteuerung (Branch und Gosub)#ue# B .70:aa bzw. .74:aa Unbedingter Sprung an die Adresse. ICOUNT := aaaa (aaaa gilt nur für den Debugger/Tracer, da die Adressrechung intern komplizierter ist) BF .70:aa bzw. .74:aa Wenn der letzte Befehl FALSE lieferte, Sprung an die Adresse. IF NOT FLAG THEN ICOUNT := aaaa (aaaa s.o.) FI BT .00:aa bzw. .04:aa Wenn der letzte Befehl TRUE lieferte, Sprung an die Adresse (auch LN-Opcode). IF FLAG THEN ICOUNT := aaaa (aaaa s.o.) FI BRCOMP 7F 20 dddd vvvv Wenn das Wort an der Adresse dddd kleiner als 0 oder größer als die Konstante vvvv ist, wird mit dem auf den BRCOMP-Befehl folgenden Befehl (i.d.R. ein B-Befehl) fortgefahren. Sonst wird die Ausführung an der Adresse des BRCOMP-Befehls + 2 + (dddd) (auch ein B-Befehl) fortgesetzt. IF >= 0 AND <= vvvv THEN ICOUNT INCR ( + 1) FI GOSUB 7F 05 aaaa Die aktuelle Codeadresse wird auf den Stack gebracht und das Programm an der Adresse aaaa fortgesetzt. :=(LBASE, PBASE, ICOUNT, ENSTOP, ARITH) ; LBASE := TOP ; ICOUNT := aaaa ; CMOD := high (ICOUNT) + 16 GORET 7F 07 Das Programm wird an der oben auf dem Stack stehenden Returnadresse fortgesetzt. TOP := LBASE ; SP := TOP + 4 ; (LBASE, PBASE, ICOUNT, ENSTOP, ARITH) := #ub#2.1.10 Modul-Operationen#ue# PPV .68:dd Das Wort an der Adresse wird auf den Stack gebracht. Dieser Befehl wird vom Compiler nicht generiert. := INT ; SP INCR 2 PP .6C:dd Die Referenzadresse des Objektes wird auf den Stack gebracht (2 Worte). := REF d1 ; SP INCR 2 PPROC 7F 1E mmmm Die Adresse der Prozedur mit der Modulnummer mmmm wird als Referenzadresse (Codesegment, Codeadresse) auf den Stack gebracht. := mod addr (mmmm) ; SP INCR 2 HEAD vvvv (kein Opcode) Der Speicherplatz für lokale Variablen und Parameter in diesem Modul wird vermerkt, indem der Stacktop um vvvv erhoht wird. TOP INCR vvvv ; SP := TOP + 4 PENTER FE vv Die Paketbasis (Basis der globalen Adressen dieses Moduls) wird auf den Wert vv*256 gesetzt. PBASE := vv * 256 CALL .78:mm Das Modul mit der Nummer mm wird aufgerufen. :=(LBASE, PBASE, ICOUNT, ENSTOP, ARITH) ; LBASE := TOP ; ICOUNT := mod addr (mm) ; CMOD := high (ICOUNT) + 16 PCALL 7F 1F dddd Die (Parameter-)Prozedur, deren Startadresse als Referenzadresse auf dem Stack steht, wird aufgerufen. :=(LBASE, PBASE, ICOUNT, ENSTOP, ARITH) ; LBASE := TOP ; ICOUNT := d1 ; CMOD := high (ICOUNT) + 16 . EXEC 7F 1D dddd Das Modul dessen Nummer in dem Wort an der Adresse dddd steht, wird aufgerufen. :=(LBASE, PBASE, ICOUNT, ENSTOP, ARITH) ; LBASE := TOP ; ICOUNT := ; CMOD := high (ICOUNT) + 16 . RTN 7F 00 Das Modul wird verlassen, die Programmausführung setzt an der, auf dem Stack gesicherten, Adresse fort. TOP := LBASE ; SP := TOP + 4 ; (LBASE, PBASE, ICOUNT, ENSTOP, ARITH) := RTNT 7F 01 Das Modul wird verlassen und der BOOL-Wert TRUE geliefert (für den dem CALL/PCALL folgenden BT/BF-Befehl). Die Programmausführung setzt an der, auf dem Stack gesicherten, Adresse fort. TOP := LBASE ; SP := TOP + 4 ; (LBASE, PBASE, ICOUNT, ENSTOP, ARITH) := ; FLAG := TRUE RTNF 7F 02 Das Modul wird verlassen und der BOOL-Wert FALSE geliefert (für den dem CALL/PCALL folgenden BT/BF-Befehl). Die Programmausführung setzt an der, auf dem Stack gesicherten, Adresse fort. TOP := LBASE ; SP := TOP + 4 ; (LBASE, PBASE, ICOUNT, ENSTOP, ARITH) := ; FLAG := FALSE #ub#2.1.10 Datenadressrechnung#ue# REF .5C:dd dddd An der zweiten Adresse wird die Referenzadresse der ersten Adresse abgelegt (2 Wört-MOV). REF := d1 SUBS .60:vv vvvv dddd dddd dddd Wenn der Inhalt des Wortes an der dritten Adresse (ROW-Index) größer oder gleich der Konstanten vvvv (limit-1) ist, wird "Subscript Überlauf" gemeldet, falls der ROW-Index kleiner als eins ist wird "Subscript Ünterlauf" gemeldet. Andernfalls wird der um eins verringerte ROW-Index mit der Konstanten vv (Size eines ROW-Elements) multipliziert, zur Basisaddresse (vierter Parameter) addiert und als Referenzadresse an der fünften Adresse abgelegt. IF INT <= vvvv AND INT > 0 THEN REF := d2 + vv * (INT-1) ELSE "Fehler" s.o. FI SEL .64:dd vvvv dddd Die Konstante vvvv (Selektor-Offset einer STRUCT) wird zur Adresse dd addiert und als Referenzadresse auf dem Stack an der Adresse dddd abgelegt. REF := vv + d1 CTT 7F 0C dddd dddd Die Adresse des Strings(!) an der ersten Adresse wird an der zweiten Adresse als Referenzadresse (Segment 0, DS 4) abgelegt. CTT steht für Compiler-Table-Text. REF := REF (0004, INT) #ub#2.1.12 Compiler-Spezialbefehle#ue# PUTW FD v1v2 dddd dddd Das lowbyte des Opcode besteht aus den beiden Nibbles v1 (Segment) und v2 (Wordoffset). Das Wort an der zweiten dddd-Adresse wird an die Adresse im Datenraum 4, Segment v1 geschrieben, die durch den Wert des Wortes an der ersten dddd-Adresse + v2 bestimmt ist. + v2> := INT GETW 7E v1v2 dddd dddd Das lowbyte des Opcode besteht aus den beiden Nibble v1 (Segment) und v2 (Wordoffset). Das Wort im Datenraum 4, Segment v1 an der durch den Wert des Wortes an der ersten dddd-Adresse + v2 bestimmten Adresse wird an der zweiten dddd-Adresse abgelegt. INT := + v2) PW 7F 6F dddd dddd dddd Das Wort an der dritten Adresse wird im Datenraum 4 an die Adresse geschrieben, die durch das Segment (erste Adresse) und die Adresse in diesem Segment (zweite Adresse) bestimmt ist. * 64KW + INT> := INT GW 7F 70 dddd dddd dddd Das Wort im Datenraum 4, das durch das Segment (erste Adresse) und die Adresse in diesem Segment (zweite Adresse) bestimmt ist, wird an der dritte Adresse abgelegt. INT := * 64KW + INT> BCRD 7F 08 dddd dddd Bereitet das Lesen einzelner Zeichen aus dem Segment 4 des Datenraumes 4 vor (Nametable). Das Wort an der ersten Adresse enthält die Startadresse des Strings und zeigt auf das Längenbyte. Nach dem Ausführen des Befehls enthält das Wort an der zweiten Adresse das Längenbyte und der Pointer an der ersten Adresse zeigt auf das erste Zeichen des Textes. Das Bit 15 des Pointers ist gesetzt, wenn das highbyte adressiert wird. INT := length (STRING) ; INT INCR 1/2 CRD 7F 09 dddd dddd Liest ein Zeichen aus dem String, dessen Lesen mit BCRD vorbereitet wurde. Die erste Adresse enthält einen Stringpointer, der nach jedem Lesen erhöht wird, die zweite Adresse enthält nach dem Aufruf des Befehls den Code des gelesenen Zeichens. INT := code (STRING) ; INT INCR 1/2 CWR 7F 0B dddd dddd dddd Der Hashcode an der ersten Adresse wird mit dem zu schreibenden Zeichencode (dritte Adresse) verknüpft und in den Bereich 0..1023 gemapt. Das Zeichen wird an die Position des Pointers geschrieben (Bit 15 des Pointers unterscheidet lowbyte und highbyte). Anschließend wird der Pointer auf die Adresse des nächsten Zeichens gesetzt. Der Pointer steht an der zweiten Adresse. Vor dem Schreiben des ersten Zeichens muß der Hashcode auf 0 gesetzt werden. INT INCR INT ; IF INT > 1023 THEN INT DECR 1023 FI ; INT := (INT + INT) MOD 1024 ; STRING> := code (INT) ; INT INCR 1/2 ECWR 7F 0A dddd dddd dddd Das Schreiben eines Strings wird beendet. Dazu wird an der ersten Adresse der Stringpointer übergegeben, an der zweiten Adresse wird die endgültige Stringlänge geliefert. An der dritten Adresse wird die Adresse des nächsten freien Platzes nach diesem Stringende geliefert. GETC 7F 0D dddd dddd dddd Dieser Befehl liefert ein BOOL-Result und zwar TRUE, wenn das Wort an der zweiten Adresse größer als 0 und kleiner als die Länge des TEXTes an der ersten Adresse ist. In diesem Fall wird im Wort an der dritten Adresse der Code des n. Zeichens des TEXTes geliefert. Die Position des Zeichens wird durch das Wort an der zweiten Adresse bestimmt. FLAG := INT > 0 AND INT <= length (TEXT) ; INT := code (TEXT[INT, 1]) FNONBL 7F 0E dddd dddd dddd Dieser Befehl liefert ein BOOL-Result. zaehler := INT ; (* Stringpointer *) WHILE TEXT[zahler, 1] = " " REP zaehler INCR 1 PER ; IF zaehler > length (TEXT) THEN FLAG := FALSE ELSE INT := code (TEXT[zaehler, 1]); INT := zaehler + 1 FI DREM256 7F 0F dddd dddd Das lowbyte des Wortes an der ersten Adresse wird in das Wort an der zweiten Adresse geschrieben, das highbyte des Wortes an der ersten Adresse ersetzt das gesamte erste Wort. INT := INT MOD 256 ; INT := INT DIV 256 AMUL256 7F 10 dddd dddd Umkerung von DREM256. INT := INT * 256 + INT GADDR 7F 16 dddd dddd dddd "Adresswort" mit Adresstyp generieren (z.B. = pbase). IF INT >= 0 (* Global *) THEN INT := INT - INT ELIF bit (INT, 14) (* Local Ref *) THEN INT := (INT AND 3FFFH)*2 + 1 ELSE INT := (INT AND 3FFFH)*2 (* Local *) FI GCADDR 7F 17 dddd dddd dddd Diese Instruktion liefert ein BOOL-Result. Mit = 0 wird sie eingesetzt, um die Zeilennummer im LN-Befehl zu generieren, mit <> 0 wird sie eingesetzt, um die Adresse im Branchbefehl zu generieren. Beide Befehle gibt es mit zwei Opcodes (00/04 bzw. 70/74). byte := high(INT)-high(INT) ; IF byte < 0 THEN byte INCR 16 ; (* Bit für LN1 bzw. B1 Opcode *) rotate (byte, right) ; FI ; INT := byte * 256 + low (INT) ; FALSE, wenn irgendeins der Bits 11..14 = 1 ist GETTAB 7F 1A Kopiert den Inhalt der unteren 64KB des Segments 5 im DS 4 in das Segment 4. (permanentes Segment --> temporäres Segment) DS4: 50000..57FFF --> 40000..47FFF (Wortaddr) PUTTAB 7F 1B Kopiert den Inhalt der unteren 64KB des Segments 4 im DS 4 in das Segment 5. (Temporäre Daten werden permanent) DS4: 40000..47FFF --> 50000..57FFF (Wortaddr) ERTAB 7F 1C Kopiert den Inhalt des Segments 6 im DS 4 (besteht nur aus FF's) in die Segmente 4 und 7, d.h. das temporäre Segment (u.a. Symboltabelle) und das Segment mit Compiler-Intermediatestring werden gelöscht. DS4: 60000..6FDFF --> 40000..4FDFF ; DS4: 60000..6FDFF --> 70000..7FDFF CDBINT 7F 74 dddd dddd Das Wort mit der Nummer wird aus dem Segment 5 gelesen und in abgelegt. INT := <50000H + INT> CDBTXT 7F 74 dddd dddd Der String(!) an der Adresse im Segment 5 wird in dem TEXT abgelegt. TEXT := ctt (<50000H + INT>) #ub#2.1.13 Instruktionen zur Programmsteuerung#ue# STOP 7F 04 Alle (aufrufenden) Module werden verlassen, bis das erste im 'disablestop'-Zustand angetroffen wird (Ähnlich errorstop ("")) ; WHILE ENSTOP REP return PER . return: TOP := LBASE ; SP := TOP + 4 ; (LBASE, PBASE, ICOUNT, ENSTOP, ARITH) := ESTOP 7F 4B Der 'enable stop'-Zustand wird eingeschaltet. ENSTOP := TRUE DSTOP 7F 4C Der 'disable stop'-Zustand wird eingeschaltet. ENSTOP := FALSE SETERR 7F 4D dddd Es wird der Fehlerzustand eingeschaltet, das Wort an der Adresse dddd wird in das pcb-Feld 'error code' gebracht. Falls das Modul im 'enablestop'-Zustand ist, wird das Modul verlassen. IF NOT ERROR THEN ERROR := TRUE ; pcb.error line := pcb.line ; pcb.error code := INT ; WHILE ENSTOP REP return PER FI CLRERR 7F 4F Falls der Fehlerzustand vorliegt, wird der Fehler gelöscht. ERROR := FALSE LN .00:vv und .04:vv Die Konstante vv wird in das pcb-Feld 'line number' gebracht (Zur Fehlerbehandlung). pcb.line := vv RPCB 7F 50 dddd dddd Der Inhalt des pcb-Feldes der eigenen Task mit der Nummer, die im Wort an der ersten Adresse steht, wird in das Wort an der zweiten Adresse gebracht. INT := pcb (myself, INT[) CLOCK 7F 66 dddd dddd Die Systemuhr mit der Nummer, die durch den Wert des Wortes an der ersten Adresse spezifiziert wird, wird gelesen und deren REAL-Wert an der zweiten Adresse abgelegt. Wenn = 0 ist, wird die CPU-Zeit der eigenen Task geliefert, anderenfalls die Systemuhr mit der Nummer 1..7 : Nummer Funktion 1 REAL-Time 2 Paging Wait 3 Paging Busy 4 Foreground Tasks cpu-time 5 Background Tasks cpu-time 6 System cpu-time 7 Reserviert IF INT = 0 THEN REAL := pcb.clock ELSE REAL := clock (INT) FI #ub#2.1.14 Systemglobale Instruktionen#ue# KE 7F 06 Der EUMEL0-Debugger 'Info' wird aufgerufen, falls dies ein infofähiges System ist. SYSG 7F 19 Sysgen (Nur beim Sysgen-Urlader). INFOPW 7F 51 dddd dddd dddd Das bis zu 10 Zeichen lange Infopassword an der zweiten Adresse (TEXT) wird eingestellt, falls das alte Infopassword mit dem TEXT an der ersten Adresse übereinstimmt. In diesem Fall wird im Wort an der dritten Adresse eine 0 abgelegt, andernfalls eine 1. Dies ist kein privilegierter Befehl, er funktioniert allerdings nur, wenn das alte Infopasswort bekannt ist. IF info password = TEXT THEN info password := TEXT ; INT := 0 ELSE INT := 1 FI STORAGE 7F 5A dddd dddd Die Größe des vorhandene Hintergrundspeichers in KB wird im Wort an der ersten Adresse abgelegt, die Größe des benutzten Hintergrundspeichers an der zweiten Adresse. INT := size ; INT := used SYSOP 7F 5B dddd Es wird eine Systemoperation mit der Nummer, die an der Adresse dddd steht, aufgerufen (1=Garbage Collection, 11=Savesystem, 4=Shutup, 2=Fixpoint). Dieser Befehl setzt eine Privilegierung >= 1 voraus. SETNOW 7F 67 dddd Die Realtime-Clock (clock(1)) des Systems wird auf den REAL-Wert an der Adresse dddd gesetzt. Dieser Befehl setzt eine Privilegierung >= 1 voraus. clock (1) := REAL SESSION 7F 7E dddd Der aktuelle Wert des Systemlaufzählers wird an der Adresse dddd abgelegt. INT := systemlaufzaehler ID 7F 81 dddd dddd Der Wert des id-Feldes mit der Nummer, die an der ersten Adresse steht, wird in das Wort an der zweiten Adresse geschrieben. Für dei Nummern der id-Felder gilt: Feld Inhalt 0 Kleinste HG-Version für EUMEL0 1 CPU-Type (1=Z80,3=8086,4=68000,5=80286) 2 Urlader-Version 3 Reserviert 4 Lizenznummer des Shards 5 Installationsnummer 6 Frei für Shard 7 Frei für Shard IF INT < 4 THEN INT := eumel0 id (INT) ELSE INT := shard id (INT) FI #ub#2.1 Alphabetische Liste der Befehle#ue# ACT 7F 6C dddd ADD .1C:dd dddd dddd ALIAS 7F 22 vvvv dddd dddd AMUL256 7F 10 dddd dddd AND 7F 7C dddd dddd dddd ARITHS 7F 5B ARITHU 7F 5C B .70:aa bzw. .74:aa BCRD 7F 08 dddd dddd BF .70:aa bzw. .74:aa BLKIN 7F 56 dddd dddd dddd dddd dddd BLKOUT 7F 55 dddd dddd dddd dddd dddd BRCOMP 7F 20 dddd vvvv BT .00:aa bzw. .04:aa CALL .78:mm CAT 7F 35 dddd dddd CATINP 7F 44 dddd dddd CDBINT 7F 74 dddd dddd CDBTXT 7F 74 dddd dddd CLEAR .24:dd CLOCK 7F 66 dddd dddd CLRERR 7F 4F CONTRL 7F 54 dddd dddd dddd dddd COUT 7F 3D dddd CRD 7F 09 dddd dddd CTT 7F 0C dddd dddd CWR 7F 0B dddd dddd dddd DEACT 7F 6D dddd DEC .18:dd dddd DEC1 .10:dd DECOD 7F 2F dddd dddd DEFCOL 7F 80 dddd DIV 7F 2A dddd dddd dddd DREM256 7F 0F dddd dddd DSACC .58:dd dddd DSCOPY 7F 46 dddd dddd DSFORG 7F 47 dddd DSHEAP 7F 4A dddd dddd DSPAGS 7F 4C dddd dddd dddd DSRTYP 7F 49 dddd dddd DSTOP 7F 4C DSWTYP 7F 48 dddd dddd ECWR 7F 0A dddd dddd dddd ENCOD 7F 30 dddd dddd EQU .2C:dd dddd EQUIM 7C vv dddd ERTAB 7F 1C ESTOP 7F 4B EXEC 7F 1D dddd EXTASK 7F 7B dddd FADD .38:dd dddd dddd FDIV .44:dd dddd dddd FEQU 7F 24 dddd dddd FLOOR 7F 63 dddd dddd FLSEQ .48:dd dddd FMOV .34:dd dddd FMUL .40:dd dddd dddd FNEG 7F 26 dddd FNONBL 7F 0E dddd dddd dddd FSLD 7F 60 dddd dddd dddd FSUB .3C:dd dddd dddd GADDR 7F 16 dddd dddd dddd GARB 7F 5F GCADDR 7F 17 dddd dddd dddd GCPOS 7F 43 dddd dddd GETC 7F 0D dddd dddd dddd GETTAB 7F 1A GETW 7E v1v2 dddd dddd GEXP 7F 61 dddd dddd GORET 7F 07 GOSUB 7F 05 aaaa GW 7F 70 dddd dddd dddd HEAD vvvv (kein Opcode) HPSIZE 7F 5E dddd ID 7F 81 dddd dddd IMULT 7F 28 dddd dddd dddd INC .14:dd dddd INC1 .0C:dd INCETY 7F 41 dddd INCHAR 7F 40 dddd INFOPW 7F 51 dddd dddd dddd ISDIG 7F 11 dddd ISERR 7F 4E ISLCAS 7F 13 dddd ISLD 7F 12 dddd ISSHA 7F 18 dddd ISUCAS 7F 14 dddd ITRPL 7F 2E dddd dddd dddd ITSUB 7F 2D dddd dddd dddd KE 7F 06 LN .00:vv und .04:vv LSEQ .30:dd dddd MOD 7F 2B dddd dddd dddd MOV .08:dd dddd MOVi FC vv dddd MOVii 7F 23 vvvv dddd MOVx 7D vv dddd dddd MOVxx 7F 21 vvvv dddd dddd MUL 7F 29 dddd dddd dddd NEG 7F 27 dddd NILDS 7F 45 dddd NXTDSP 7F 4B dddd dddd dddd OR 7F 7D dddd dddd dddd OUT 7F 3C dddd OUTF 7F 3E dddd dddd OUTFT 7F 3F dddd dddd dddd PAUSE 7F 42 dddd PCALL 7F 1F dddd PENTER FE vv PNACT 7F 76 dddd POS 7F 37 dddd dddd dddd POSF 7F 38 dddd dddd dddd dddd POSFT 7F 39 dddd dddd dddd dddd dddd POSIF 7F 3B dddd dddd dddd dddd dddd PP .6C:dd PPCALL 7F 7A dddd dddd dddd dddd PPROC 7F 1E mmmm PPV .68:dd PUTTAB 7F 1B PUTW FD v1v2 dddd dddd PW 7F 6F dddd dddd dddd REF .5C:dd dddd REPLAC 7F 34 dddd dddd dddd ROTATE 7F 53 dddd dddd RPCB 7F 50 dddd dddd RTN 7F 00 RTNF 7F 02 RTNT 7F 01 RTRPL 7F 65 dddd dddd dddd RTSUB 7F 64 dddd dddd dddd SEL .64:dd vvvv dddd SEND 7F 71 dddd dddd dddd dddd SENDFT 7F 7F dddd dddd dddd dddd dddd SESSION 7F 7E dddd SETERR 7F 4D dddd SETNOW 7F 67 dddd SEXP 7F 62 dddd dddd STOP 7F 04 STORAGE 7F 5A dddd dddd STRANL 7F 3A dddd dddd dddd dddd dddd dddd dddd SUB .20:dd dddd dddd SUBS .60:vv vvvv dddd dddd dddd SUBT1 7F 31 dddd dddd dddd SUBTF 7F 33 dddd dddd dddd SUBTFT 7F 32 dddd dddd dddd dddd SWCALL 7F 73 dddd dddd dddd dddd SYSG 7F 19 SYSOP 7F 5B dddd TBEGIN 7F 6F dddd aaaaaa TCPU 7F 6A dddd dddd TEND 7F 70 dddd TEQU .50:dd dddd TEST .28:dd THALT 7F 6E dddd TLEN 7F 36 dddd dddd TLSEQ 7F 25 dddd dddd TMOV .4C:dd dddd TPBEGIN 7F 5F dddd dddd dddd aaaaaa TRPCB 7F 68 dddd dddd dddd TSTAT 7F 6B dddd dddd TWCPU 7F 52 dddd dddd TWPCB 7F 69 dddd dddd dddd ULSEQ .54:dd dddd WAIT 7F 72 dddd dddd dddd XOR 7F 79 dddd dddd dddd #page# #ub#3. Beschreibung der Pakete#ue# #ub#3.1 PACKET address#ue# Mit diesem Paket werden die Operationen für 16 Bit Adressrechnung zur Verfügung gestellt. TEXT PROC hex8 (INT CONST dez) : Der INT-Parameter (0..255) wird in eine 2-Zeichen Hexdarstellung konvertiert. TEXT PROC hex16 (INT CONST dez) : Der INT-Parameter (0..65535) wird in eine 4-Zeichen Hexdarstellung (ohne Vorzeichen) konvertiert. INT PROC integer (TEXT CONST hex) : Der TEXT-Parameter (1-4 Byte Hexdarstellung, 0..9, a..f/A..F) wird in eine Dezimalzahl konvertiert. INT PROC getword (INT CONST segment, address) : Das Wort an der Adresse 'address' (0..65535) im Segment 'segment' (0..7) wird gelesen. PROC putword (INT CONST segment, address, value) : Der Wert 'value' wird in das Wort an der Adresse 'address' (0..65535) im Segment 'segment' (0..7) geschrieben. INT PROC cdbint (INT CONST address) : Der Wert an der Adresse 'address' (0..32767 sinnvoll) im Segment 5 (permanente Compilertabellen) wird gelesen. TEXT PROC cdbtext (INT CONST address) : Der String, der an der Adresse 'address' im Segment 5 (permanente Compilertabellen) beginnt, wird als TEXT gelesen. PROC splitword (INT VAR word, lowbyte) : Das Wort 'word' wird in den höherwertigen und niederwertigen Teil zerlegt. Das highbyte steht nach dieser Operation in 'word', das lowbyte in 'lowbyte'. PROC makeword (INT VAR word, INT CONST lowbyte) : word := word * 256 + lowbyte BOOL PROC ulseq (INT CONST left, right) : '<=' für positive INT-Zahlen (0..65535). OP INC (INT VAR word) : 'word INCR 1' für positive INT-Zahlen (0..65535), ohne daß ein Überlauf auftritt. OP DEC (INT VAR word) : 'word DECR 1' für poistive INT-Zahlen (0..65535), ohne daß ein Unterlauf auftritt. INT OP ADD (INT CONST left, right) : 'left + right' für positive INT-Zahlen (0..65535), ohne daß ein Überlauf auftritt. INT OP SUB (INT CONST left, right) : 'left - right' für positive INT-Zahlen (0..65535), ohne daß ein Überlauf auftritt. INT OP MUL (INT CONST left, right) : 'left * right' für positive INT-Zahlen (0..65535), ohne daß ein Überlauf auftritt. #ub#3.2 PACKET table routines#ue# PROC init module table (TEXT CONST name) : Ein benannter Datenraum ('name') wird eingerichtet. Dieser enthält die aufbereitete Permanenttabelle für schnelle Zugriffe. Die Datenstruktur beschreibt drei Tabellen (PACKETTABLE, MODULETABLE, TYPETABLE), über die zu einer Modulnummer deren Name und deren Parameter, sowie der zugehörige Paketname gefunden werden kann, wenn sie in der Permanenttabelle steht. Die TYPETABLE enthält zu jedem TYPE, der in der Permanenttabelle steht, seine Größe in Words. PROC add modules : Module und Typen neu insertierter Pakete werden in die 'module table' aufgenommen. PROC dump tables (TEXT CONST name) : Der Inhalt der geladenen Modultabelle wird in der FILE 'name' ausgedumpt. TEXT PROC module name and specifications (INT CONST module number) : Der Name und die Parameter des Moduls mit der Nummer 'module number' (0..2047) wird als TEXT geliefert. Falls das Modul nicht in der Permanenttabelle steht, wird niltext geliefert. TEXT PROC packetname (INT CONST module number) : Der Name des Pakets, das das Modul mit der Nummer 'module number' definiert, wird als TEXT geliefert. Falls das Modul nicht in der Permanenttabelle steht, wird der Name des letzten vorher insertierten Pakets geliefert (In manchen Fällen also nicht der wahre Paketname). INT PROC storage (TEXT CONST typename) : Aus der Modultabelle wird Größe des TYPEs mit dem Namen 'typname' gelesen. Wenn der Typ nicht in der Permanenttabelle steht, wird 0 geliefert. PROC getmodulenumber (INT VAR module number) : Erfragt eine Modulnummer am Bildschirm. Der Benutzer kann entweder eine Zahl eingeben oder den Namen einer PROC/OP. Wenn mehrere Module mit diesem Namen existieren, wird eine Auswahlliste angeboten. In 'module number' wird die ausgewählte Modulnummer übergeben. INT PROC codeaddress (INT CONST module number) : Liefert die Anfangsadresse des Moduls mit der Nummer 'module number'. INT PROC codesegment (INT CONST module number) : Liefert die Nummer des Codesegments, in dem der Code des Moduls mit der Nummer 'module number' steht. INT PROC hash (TEXT CONST object name) : Berechnet den Hashcode des Objekts 'object name', um über die Hashtable, Nametable, Permanenttable die Parameter eines Objekts zu suchen. #ub#3.3 PACKET eumel decoder#ue# #ub#3.3.1 Zugriff auf globale Parameter#ue# PROC default no runtime : Bereitet den Decoder darauf vor, daß keine runtime vorliegt, d.h. Stackzugriffe nicht sinnvoll sind. Für Parameter mit lokalen Adressen werden deshalb keine Variableninhalte dargestellt. Bei fast allen Decoderaufrufen mit 'decode'/'decode module' bis auf die 'decode' mit mehr als zwei Parametern, wird 'default no runtime' automatisch aufgerufen. PROC set parameters (INT CONST lbase, pbase, line number, c8k) : PROC get parameters (INT VAR lbase, pbase, line number, c8k) : Einstell- und Informationsprozeduren (für den Tracer). 'lbase' ist die lokale Basis (Stackoffset für dies Modul), 'pbase' ist das highbyte der Paketbasis, 'line number' ist die letzte 'LN'-Zeilennummer, 'c8k' (cmod) wird von EUMEL0 beim Eintritt in ein Modul auf high (Modulstartaddresse + 16KB) gesetzt (für Branch-Befehle). PROC pbase (INT CONST pbase highbyte) : INT PROC pbase : Einstell- und Informationsprozeduren, nicht nur für den Tracer. Die Paketbasis (Globale Daten) wird gesetzt. Dazu wird nur das Highbyte (z.B. nach 'PENTER') übergeben. PROC lbase (INT CONST local base) : Einstellprozedur für den Tracer. Stellt während der runtime die aktuelle Basis ein. Wird der Decoder nicht während runtime betrieben, sollte lbase(-1) eingestellt werden. INT PROC line number : Liefert die letzte, mit 'LN' eingestellte, Zeilennummer. PROC list filename (TEXT CONST name) : Stellt den Namens-Prefix der Outputfiles ein. Voreingestellt ist "". An den Filename wird ".n" angehängt, wobei n mit '0' beginnt. PROC bool result (BOOL CONST status) : BOOL PROC bool result : Einstell- und Informationsprozeduren, die für den Tracer benötigt werden. Lieferte der letzte disassemblierte Befehl ein BOOL-Result ? PROC with object address (BOOL CONST status) : BOOL with object address : Einstell- und Informationsprozeduren, nicht nur für den Tracer. Sollen außer den Darstellungen der Speicherinhalte auch die Parameteradressen (in spitzen Klammern) ausgegeben werden ? PROC with code words (BOOL CONST status) : BOOL PROC with code words : Einstell- und Informationsprozeduren, nicht für den Tracer. Sollen ab der 80. Spalte in der Outputfile die Hexdarstellungen der dekodierten Codewörter ausgegeben werden ? #ub#3.3.2 Aufruf des Disassemblers#ue# PROC decode : Aufruf des Decoders. Die Modulnummer der ersten zu dekodierenden Prozedur wird erfragt. Die Modultabelle wird ggf. ergänzt, es wird 'default no runtime' eingestellt. PROC decode (INT CONST first module number) : Aufruf des Decoders. Die Modulnummer der ersten zu dekodierenden Prozedur wird übergeben. Die Modultabelle wird ggf. ergänzt, es wird 'default no runtime' eingestellt. PROC decode (INT CONST segment, address) : Aufruf des Decoders. Die Disassemblierung beginnt in dem Codesegment/Adresse, das/die als Parameter übergeben wird. Die Modultabelle wird ggf. ergänzt, es wird 'default no runtime' eingestellt. PROC decode (INT CONST segment, INT VAR address, INT CONST to addr, BOOL CONST only one module) : Dieser Decoderaufruf setzt kein 'default no runtime', erweitert aber ggf. die Modultabelle. Der bei 'address' beginnende und bei 'to addr' endende Adressbereich im Codesegment 'segment' wird dekodiert. Ist 'only one module' TRUE, wird nur bis zum Ende des aktuellen Moduls dekodiert. 'address' zeigt nach dem Prozeduraufruf auf die nächste Instruktion nach 'to addr'. PROC decode (INT CONST segment, INT VAR address, TEXT VAR words, instruction, INT PROC (INT CONST, INT VAR, TEXT VAR) next word)): Diese Prozedur ist das Herz des Decoders. Sie disassembliert eine Instruktion, die im Codesegment 'segment', Adresse 'address' beginnt und legt die mit 'nextword' gelesenen Wörter als Hexdarstellung in 'words' ab. Die dekodierte Instruktion steht dann in 'instruction'. Vor dem Aufruf dieser Prozedur sollte 'words' und 'instruction' niltext zugewiesen werden. Die passende Prozedur 'nextword' wird auch vom 'eumel decoder' herausgereicht. 'address' zeigt nach der Ausführung des Befehls auf die nächste Instruktion. PROC decodemodule : Wie 'decode', nur wird bis nur zum Ende des gewünschten Moduls disassembliert. PROC decodemodule (INT CONST module number) : Wie 'decode', nur wird bis nur zum Ende des gewünschten Moduls disassembliert. #ub#3.3.3 Weitere Prozeduren#ue# PROC nextmoduleheader (INT CONST segment, INT CONST address, INT VAR header address, module number) : Diese Prozedur findet ab der angegeben Adresse ('segment'/'address') den Anfang des nächsten Moduls. In 'header address' wird die Startadresse des gefundenen Moduls geliefert (bleibt im Segment 'segment'), in 'module number' die Nummer des gefundenen Moduls. INT PROC next word (INT CONST segment, INT VAR address, TEXT VAR words) : Diese Prozedur liefert das durch 'segment'/'address' angegeben Wort, hängt die Hexdarstellung dieses Wortes an 'words' an und erhöht 'address' um eins. TEXT PROC data representation (INT CONST data addr, segment, address, type): Diese Prozedur liefert die Darstellung des Parameters 'data addr' ggf. mit Adresse (--> with object address). 'segment'/'address' bezeichnet die Position, an der die Instruktion für diesen Parameter steht. 'type' ist ein (durch die Instruktion festgelegter) Typ des Parameters, mit dem die Art der Darstellung gewählt wird (TEXT, REAL, INT, ...). Im Gegensatz zu 'object representation' braucht bei dieser Prozedur keine Darstellung vorhanden sein. In diesem Falle wird nur z.B. der Stackoffset '' ausgegeben. TEXT PROC object representation (INT CONST data segment, data address, segment, address, type) : Diese Prozedur wird von 'data representation' aufgerufen und liefert die Darstellung des Parameters. In 'data segment'/'data address' wird die Anfangsadresse der darzustellenden Daten übergeben. Die anderen drei Parameter verhalten sich wie bei 'data representation'. TEXT PROC last actual parameter : Liefert den Wert (nach TEXT konvertiert) des letzten dekodierten aktuellen Parameters (am sinnvollsten während runtime). Diese prozedur wird vom Tracer benutzt. #ub#3.4 PACKET tracer#ue# #ub#3.4.1 Zugriff auf globale Parameter#ue# PROC prot file (TEXT CONST filename) : TEXT PROC prot file : Einstell- und Informationsprozeduren für den Namen der Protokollfile. Wird ein 'filename' ungleich niltext eingestellt, dann werden die dekodierten Instruktionen während der Ablaufverfolgung zusätzlich in diese File geschrieben. PROC source file (TEXT CONST filename) : TEXT PROC source file : Einstell- und Informationsprozeduren für den Namen der Quelltextdatei. Wird ein 'filename' ungleich niltext eingestellt, dann wird nach dem Ausführen eines 'LN'-Befehls (LineNumber) die Zeile mit dieser Nummer aus der Quelldatei gelesen und parallel zur dekodierten EUMEL0-Instruktion angezeigt. PROC tracer channel (INT CONST) : INT PROC tracerchannel : Einstell- und Informationsprozeduren für den Kanal, an dem das Programm ausgeführt werden soll. Die Ablaufverfolgung bleibt an dem Kanal, an dem die PROC/OP aufgerufen wurde. #ub#3.4.2 Aufruf des Tracers#ue# Eine PROC/OP, in der ein Breakpoint gesetzt wurde, kann zum Beispiel im Monitor aufgerufen werden. Ab der Adresse, an der der Breakpoint gesetzt wurde, kann die Abarbeitung des Codes verfolgt werden. Das Setzen der Breakpoints geschieht mit 'set breakpoint'. PROC trace : Diese Prozedur erfragt vom Benutzer die PROC/OP, bei der der die Ablaufverfogung beginnen soll. Anschließend muß der Aufruf der PROC/OP eingegeben werden. Der Benutzer wird außerdem nach dem Namen der compilierten Quelldatei, dem Namen der Protokollfile und dem Abarbeitungskanal gefragt. Nachdem alle Angaben gemacht worden sind, wird der PROC/OP-Aufruf mit 'do' ausgeführt. PROC set breakpoint : Die Modultabelle wird ggf. erweitert, der Benutzer wird nach dem Namen einer PROC/OP gefragt, deren Codeabarbeitung verfolgt werden soll. Der Code dieser PROC/OP muß im Codesegment 3 stehen (sonst erfolgt ein 'errorstop'). Der Protokoll- und Sourcefilename werden auf niltext gesetzt. PROC set breakpoint (INT CONST breakpointnr, address) : Setzt an der übergebenen Codeadresse im Segment 3 einen Breakpoint der beiden Breakpoints (1 oder 2 als 'breakpointnr'). Der Benuzter ist selbst dafür verantwortlich daß - dies nicht die Einsprungsadresse eines Moduls ist (HEAD-Instruktion), - die übergebene Adresse das erste (Opcode-) Wort einer Instruktion ist, - vor dem Aufruf des Moduls die Paketbasis korrekt gesetzt ist, falls vor der ersten Instruktion mit Parametern kein 'PENTER' ausgeführt wird. PROC reset breakpoints : Die Breakpoints werden zurückgesetzt und der (wegen des Breakpointhandler- CALLs) gesicherte Code wieder an seinen Originalplatz zurückgeschrieben. PROC reset breakpoint (INT CONST breakpointnr) : Es wird nur gezielt der eine Breakpoint mit der Nummer 'breakpointnr' zurückgesetzt. PROC list breakpoints : Der Status, die Adresse und der gesicherte Code (an dieser Adresse) werden für beide Breakpoints gelistet.