Auf grösseren Systemen der Datenverarbeitung finden sich Teile des Betriebssystems, die über bestimmte Ereignisse eine Art Logbuch führen. Für derartige Programme wird üblicherweise der Begriff Logger verwendet, eine Standardanwendung ist z.B. das Führen einer Fehlerliste. Als Testhilfe kann das hier von mir vorgestellte Programm dienen, das die Betriebssystemaufrufe des ATARI ST über die Trap-Befehle des 68000-Prozessors protokollieren kann. Der Quellcode bietet für den Interessierten darüber hinaus einen gewissen Einblick in die Handhabung der Ausnahmebehandlungen Trace und Line-F bei diesem Prozessor.
Vor der Implementierung eines Loggers waren einige grundsätzliche Betrachtungen anzustellen, die ich vorab kurz darlegen möchte. Zunächst muß die Programmierung wegen der möglichst hohen Ausführungsgeschwindigkeit in Assembler erfolgen. Weil der Start einer solchen Anwendung meiner Meinung nach auch aus dem AUTO-Ordner heraus möglich sein sollte, entfällt - leider -eine Realisierung als Accessory. Darüber hinaus erscheint mir eine Beschränkung des Protokolls auf die drei Bereiche GEMDOS, AES und VDI als sinnvoll, da diese die mächtigsten Funktionen des Betriebssystems zur Verfügung stellen. Um die zu erzeugende Liste auch nach einem Systemabsturz mit sich anschließendem Kaltstart verfügbar zu haben, kann diese nicht im RAM, z.B. in einem Ringspeicher, geführt werden. Sie muß vielmehr dauerhaft abgelegt werden, deshalb entschied ich mich für die Ausgabe über einen am Centronics-Port anzuschließenden Drucker. Als Kennzeichnung eines Betriebssystemaufrufs genügt dafür ein Buchstabe (‘A’: AES, ‘G’: GEMDOS, ‘V’: VDI), kombiniert mit einer zweistelligen Zahl, die die Funktionsnummer hexadezimal beinhaltet. Eine auf diese Weise geführte Liste zieht allerdings, trotz der kryptischen Ausgabe, einen enormen Papierverbrauch nach sich und ist wohl auch in den wenigsten Fällen gewünscht. Deshalb mußte ich die Möglichkeit schaffen, den Ausdruck ein- bzw. auszuschalten. Zur Vereinfachung der Handhabung war zudem die Implementierung einer ebenfalls schaltbaren Zeitlupe notwendig. Auf die Steuerung dieser Funktionen über die Tastatur konnte ich verzichten, da die Möglichkeit besteht, die RS232-Schnittstelle als 2-Bit-PIO zu benutzen. Die Funktion des residenten Programms sollte außerdem durch weitere Aufrufe ausgesetzt bzw. wieder aktiviert werden können.
Die elementare Funktion des Loggers besteht darin, nach der Auslösung eines der beiden Traps die Kennung des entsprechenden Betriebssystemaufrufes auszudrucken. Diese Aufgabe kann dadurch gelöst werden, daß man die jeweils zugehörige Ausnahmebehandlung über eine entsprechende Routine umleitet. Geholt werden die relevanten Daten dann vom Stack (Trap 1) bzw. über ein Register (Trap 2). Wenn es doch nur so einfach wäre! Leider ist eine derartige Installation nicht von Dauer, das Betriebssystem des ST boykottiert ein Verbiegen des Traps 2 gelegentlich durch Überschreiben des Vektors mit einem Zeiger auf sich selbst, z.B. wenn man sich eine Textdatei über das Desktop anzeigen läßt. Vor den Erfolg setzten die Götter die Reise - durch den Speicher des ATARI ST. Nach Lösen mehrerer Fahrkarten bei verschiedenen Reiseveranstaltern bzw. Debuggern konnte ich die gesuchten Übeltäter finden. Verantwortlich für die Reinitialisierung des Vektors für Trap 2 sind Teile des GEM, die durch Auslösung der Line-F-Ausnahme aufgerufen werden. Diese Ausnahmebehandlung wird beim ATARI ST im allgemeinen Line-F-Emulator genannt. Sie wird vom Prozessor eingeleitet, sobald er erkennt, daß im nächsten auszuführenden Befehlswort - in diesem Zusammenhang mit Opcode bezeichnet - die vier höchsten Bits gesetzt sind. Von den Schöpfern des GEM wurde diese Eigenschaft des 68000 benutzt, um häufig verwendete Befehlsfolgen zu ersetzen, dazu gehören auch die Aufrufe der eben angesprochenen Routinen. Auf die Nachteile dieser Art von Programmierung wurde schon in mehreren Artikeln hingewiesen, für den Logger war sie aber durchaus nützlich. Die Arbeitsweise des Line-F-Emulators, beschränkt auf seinen für dieses Programm relevanten Teil (Listing 1), möchte ich kurz erläutern.
Der Line-F-Emulator führt zwei grundsätzlich verschiedene Funktionen aus. Ist das niedrigste Bit des Opcodes gesetzt, erfolgt die Freigabe eines Stack-Bereiches über Unlink (UNLK). Andernfalls werden die unteren drei Bytes des Opcodes - er muß glatt durch vier teilbar sein - als Offset in einer Tabelle von Startadressen diverser GEMRoutinen interpretiert. An der auf diese Weise festgelegten Stelle wird das Programm dann mit dem Ende der Ausnahmebehandlung fortgesetzt. Diese stellt vorher noch den Status des Prozessors wieder richtig. Außerdem legt sie die Wortadresse auf dem Stack ab, die dem Befehl folgt, der die Ausnahme einleitete. Bei entsprechender Programmierung kann eine Anwendung die in Frage kommenden Routinen mittels Trace feststellen und ihre unerwünschten Resultate umgehen. Bei einer Installation des so erweiterten Loggers aus dem AUTO-Ordner heraus verweigert das System jedoch beim Aufbau des Desktops unwiderruflich seine Mitarbeit. Bei genauerer Untersuchung stellte ich fest, daß nicht alle über den Line-F Emulator angesprungenen Unterprogramme im Trace-Modus durchlaufen werden können. Das Problem kann aber doch durch eine Kombination von Änderungen in den Routinen für Line-F, Trace und illegale Adresse gelöst werden. Dabei habe ich den Umstand genutzt, daß die hier interessierenden Unterprogramme mit einem Return-Befehl (RTS) abschließen. Die Ausnahmebehandlung für Line-F muß dann so erfolgen, daß bei Nutzung des Emulators als Sprungverteiler die erzeugte Rücksprungadresse illegal ist. Bei Beendigung einer auf diesem Wege angesprungenen Routine erkennt der Prozessor dann die illegale Adresse und kann den Vektor für Trap 2 gegebenenfalls wieder aufsetzen.
Genug der langen Einleitung, ich komme zur Sache (Listing 2). Der ausführbare Code beginnt wie üblich mit der Berechnung des Stackpointers und der Programmngröße, dann wird Trap 1 nachdem XBRA-Standard abgeklopft. Befindet sich das Programm schon resident im Rechner, wird sein Status geändert, und eine entsprechende Meldung erscheint auf dem Monitor. Andernfalls wird der Logger für GEMDOS eingerichtet, und das Programm bleibt nach Beendigung im Speicher. Der beim Rücksprung in das Betriebssystem ausgelöste Trap 1 führt sofort wieder in die Anwendung zum GEMDOS-Logger. Dieser besteht aus einem ersten Teil, der die Installation für Trap 2 besorgen soll, und einem zweiten, der die Protokollierung für Trap 1 erledigt. Sobald das entsprechende Bit in der Steuervariablen ein fertig installiertes Desktop anzeigt, wird der erste Teil übersprungen. Solange das aber, wie auch beim ersten Durchlauf, noch nicht zutrifft, testet das Programm, ob das Desktop läuft. Dabei wird davon ausgegangen, daß nach Ende der Boot-Phase unterschiedliche Ausnahmebehandlungen für Line-F und Trace existieren. Verläuft der Test negativ, wird bei den folgenden Aufrufen des GEMDOS geprüft, ob sowohl Line-F-Emulator als auch AES/VDI zwischenzeitlich eingebunden wurden. Sobald das Desktop dann läuft, wird der Merker gesetzt, und die Vektoren für illegale Adresse, Line-F-Emulator, Trace und Trap 2 werden geändert. Die Installation ist damit beendet, und die Aufrufe von AES und VDI werden ebenfalls über den Drucker aufgelistet.
Für die Ausgabe des Protokolls wird bei Trap 1 und auch Trap 2 dasselbe Unterprogramm benutzt. Es beinhaltet außerdem noch die Zeitlupe und läuft über das BIOS. Zur Steuerung habe ich die Eingangssignale CTS (clear to send) und CD (carrier detect) bzw. die Ausgangssignale RTS (request to send) und DTR (data terminal ready) der seriellen Schnittstelle (Tabelle 1) vorgesehen. An Elektrikteilen braucht man einen 25poligen Stecker, ein Stück 4poliges Kabel und zwei Schalter. Die Teile sind jetzt so zu verlöten, daß mit dem einen Schalter CTS und RTS, mit dem anderen CD und DTR verbunden bzw. getrennt werden können. Am Parallel-Port des MFP 68901 kann dann die Schalterstellung gelesen werden.
014A74 MOVE.W (A7)+,D2 ; hole Kopie des alten Status'
014A76 MOVE.L (A7)+,A0 ; und Opcode (FXXX), Rücksprung-
014A78 MOVE.W (A0)+,D1 ; adresse jetzt in A0,
014A7A BTST #0,D1 ; Opcode testen, gegebenenfalls
014A7E BNE $014A9A ; UNLK-Funktion (...) ausführen,
014A80 MOVE.W D2,SR ; sonst Status restaurieren,
014A82 MOVE.L A0,-(A7) ; Rücksprungadresse auf Stack,
014A84 ANDI.W #$0FFF,D1 ; Adresse der
014A88 MOVE.L #$00FEE56A,A0 ; gewünschten Routine aus
014A8E MOVE.L $00(A0,D1.W),A0 ; der Tabelle holen und
014A92 JMP (A0) ; anspringen
014A94 ... ; ab hier Unlink-Funktion
Listing 1: Line-F-Emulator
Pin | Bezeichnung |
---|---|
1 | Gnd (ground) |
2 | TxD (transmit data) |
3 | RxD (receive data) |
4 | RTS (request to send) |
5 | CTS (clear to send) |
7 | Gnd (signal ground) |
8 | CD (carrier detect) |
20 | DTR (data terminal ready) |
22 | Rl (ring indicator) |
Tabelle 1: Belegung der RS232-Schnittstelle
Was passiert nun, wenn das Betriebssystem den Line-F-Emulator aufruft? Die modifizierte Ausnahmebehandlung prüft zunächst das niedrigste Bit des Opcodes, denn wenn der Line-F-Emulators im Unlink-Modus benutzt werden soll, kann ja ab hier wie bisher verfahren werden. Ansonsten wird der dem aktuellen Opcode-Wert entsprechende, beim Start des Loggers mit $FF vorbesetzte Merker getestet. Beinhaltet der Merker den Wert $00, so kann eine Reinitialisierung des Vektors für Trap 2 durch die zuzuordnende Routine ausgeschlossen werden; ohne Manipulationen läuft die Ausnahmebehandlung dann weiter über den Line-F-Emulator des GEM. Andernfalls wird die analog zur Vorgehens weise des Vorbildes erzeugte Rücksprungadresse auf dem Supervisor-Stack abgelegt. Anschließend wird in der Kopie des auf dem Stack abgelegten System-Bytes das Tracebit gesetzt. Schließlich kann über den gespeicherten alten Vektor der Sprung zum Original erfolgen. Hier weicht der Lauf der Dinge nur dann vom bisher bekannten ab, wenn die Kopie des Statuswortes, wie beschrieben, geändert wurde. Sobald dieses vom Stack geholt wird, um den Prozessorstatus zu restaurieren, wird der Trace-Modus eingeschaltet. Das Trace-Programm prüft ab jetzt nach jedem vom Line-F-Emulator ausgeführten Befehl, ob der auf dem entsprechenden Stack befindliche Eintrag identisch ist mit dem vorher abgelegten Rücksprungziel. Sobald dieser Zustand erreicht ist, wird das niedrigste Bit der weiterhin maßgeblichen Adresse gesetzt, die jetzt überzählige auf dem Supervisor-Stack gelöscht. Dann erfolgt die Beendigung des Trace-Modus’, und der Aufruf der gewünschten Routine schließt sich an. Nach deren Abarbeitung liest der Prozessor dann einen ungeraden Wert als Rücksprungadresse, also eine illegale Adresse. In der hierdurch ausgelösten Ausnahmebehandlung wird zuerst überprüft, ob sie durch eine Aktion des Loggers ausgelöst wurde, wenn nicht, hagelt es Bomben wie üblich. Ansonsten berichtigt die Routine entweder den Vektor für Trap 2, oder der dem soeben beendeten GEM-Teil zugeordnete Merker wird gelöscht. Dann wird das Programm an der richtigen Adresse fortgesetzt.
Zum Schluß gebe ich noch einige Anregungen zur eventuell nötigen Anpassung des Loggers an eine andere als die vorgesehene Konfiguration. Ein serieller Drucker kann relativ einfach angeschlossen werden, indem man die Stellung der Schalter über den Centronics-Port einliest. Diese Abfrage kann natürlich auch mit Hilfe einer I/O-Karte erfolgen, aber die hat ja nun mal nicht jeder. Obwohl von mir nur mit RAM-TOS bzw. Blitter-TOS auf einem Mega 1 entwickelt und getestet, habe ich die Hoffnung, daß das Programm auch mit den anderen Versionen des Betriebssystems läuft. Der kritische Punkt ist sicherlich der Test des Desktops. Das gilt vor allem für den neuen 1040 STE. Auf ihm, wie auch anderen Derivaten und zukünftigen Versionen des Betriebssystems (TOS030, PAK-68K, ...), die ohne Line-F-Emulator auskommen, kann der Logger in dieser Form nicht zum Laufen gebracht werden. Das ist der Preis, den man für eine solche Programmierung zahlen muß ... Aber ich weiß jetzt, was die Kiste beim Booten macht!
Literatur:
[1] Service Manual Mega 1, ATARI Corp.
[2] Brückmann, Englisch, Gerits, ATARI ST Intern. Data Becker GmbH Düsseldorf
;************************************************
;* TRAP_LOG.S - Stephan Simson *
;* (c) MAXON Computer GmbH 1991 *
;* Versionen *
;* 0.0 31.10.89: GEMDOS-Logger *
;* 1.0 10.12.89: AES/VDI-Logger *
;* 1.1 23.01.90: GEMDOS-Logger nur *
;* mit A0, D0 *
;* 2.0 27.03.90: AUTO-Start, XBRA *
;************************************************
;************************************************
;* Zuweisungen *
;************************************************
;
; Base-Page-Offset-Werte
TxtSgSiz EQU $00C ; Text-Segment-Größe
DatSgSiz EQU $014 ; Daten-Segment-Größe
BssSgSiz EQU $01C ; BSS-Segment-Größe
BasPgSiz EQU $100 ; Base-Page-Größe
;
; Ascii-Zeichen
;
NUL EQU $00
LF EQU $0A
CR EQU $0D
BLANK EQU $20
;
; Hardware-Adressen
;
MFP_PIO EQU $FFFA01 ; MFP 68901: par. I/O
;
; GEMDOS-Funktionen
;
CRAWCIN EQU $07 ; rohe Zeicheneingabe
CCONWS EQU $09 ; Stringausgabe
PTERM0 EQU $00 ; Programmende
PTERMRES EQU $31 ; Programmende / res.
;
; BIOS-Funktionen
;
SetExec EQU $05 ; Exc.-Vektor setzen
Bconout EQU $03 ; Ausgabe Zeichen
Bcostat EQU $08 ; Test Status Ausgabe
;
; Vektor-Nummern
;
IllAdVNr EQU $03 ; illegale Adresse
TraceVNr EQU $09 ; Trace
FLineVNr EQU $0B ; Line-F
T01VktNr EQU $21 ; Trap-01 (GEMDOS)
T02VktNr EQU $22 ; Trap-02 (AES / VDI)
;
; Trap-Nummern
;
GEMDOS EQU $01 ;
BIOS EQU $0D ;
;
; Geräte
;
PRN EQU 0 ; Centronics-Port
;
; Bits
;
Unlink EQU 0 ; FLine:Unlink-Modus
Gesperrt EQU 0 ; Funktion gesperrt
Drucken EQU 1 ; carrier detect
Zeitlupe EQU 2 ; clear to send
Desktop EQU 3 ; Desktop installiert
BootTest EQU 4 ; Boot-Test gelaufen
SuperMod EQU 5 ; Supervisor-Modus
TraceMod EQU 7 ; Trace-Modus
;
; Trap-2 Funktionen
;
AES_Code EQU $C8 ; AES-Funktion
VDI_Code EQU $73 ; VDI-Funktion
;
; Sonstige
;
StckSize EQU $100 ; Stack-Größe: 256
Bereit EQU $FFFF ; Geräte-Status
;************************************************
;* Programm *
;************************************************
TEXT
ProgrBgn:
;
; Berechnung: RAM-Bedarf und Stack-Pointer
;
LEA.L ProgrBgn-BasPgSiz(PC),SP
; SP -> BP
MOVE.L DatSgSiz(SP),D7 ; Data-Seg.
ADD.L BssSgSiz(SP),D7 ; BSS-Seg.
ADD.L #BasPgSiz,D7 ; Base-Page
ADD.L TxtSgSiz(SP),D7 ; Text-Seg.
ADD.L #StckSize,D7 ; Stack-Gr.
OR.B #$01,D7 ; D7: RAM-
ADDQ #$01,D7 ; Bedarf
ADD.L D7,SP ; SP okay
;
; Test der existierenden Trap-01-Routinen
;
MOVE.L #-1,-(SP) ; hole
MOVE.W #T01VktNr,-(SP) ; alten
MOVE.W #SetExec,-(SP) ; Vektor
TRAP #BIOS ; nach D0
ADDQ.L #8,SP ;
AND.L #$ 00FFFFFF,D0 ;
MOVE.L D0,A4 ;
SuchXBRA: CMP.L #'XBRA',-12(A4) ; nach
BNE InstaLOG ; XBRA
CMP.L #'TLOG',-8(A4) ; Standard
BEQ StatAend ; vorgehen
MOVE.L -4(A4),A4 ;
BRA SuchXBRA ;
;
; Status ändern
;
StatAend: BCHG #Gesperrt,-14(A4) ; ge-
BEQ NichtAkt ; sperrt ?
LEA Meldung2(PC),A0 ; Freigabe-
BRA ZeigStat ; oder
NichtAkt: LEA Meldung3(PC),A0 ; Sperr-
ZeigStat: BSR ZeigMeld ; Meldung
MOVE.W #PTERM0,-(SP) ; Programm
TRAP #GEMDOS ; beenden
;
; Installation des Loggers für Trap-01
;
InstaLOG: PEA Trp01LOG ; Routine
MOVE.W #T01VktNr,-(SP) ; für
MOVE.W #SetExec,-(SP) ; Trap-01
TRAP #BIOS ; einbauen
MOVE.L D0,_Trp01OV ;
ADDQ.L #8,SP ;
LEA Meldung1(PC),A0 ; Install.
BSR ZeigMeld ; melden
MOVE.W #0,(SP) ; Programm
MOVE.L D7,-(SP) ; beenden &
MOVE.W #PTERMRES,-(SP) ; resident
TRAP #GEMDOS ; halten
;
; Meldung zeigen und Taste warten
;
; Aufruf
; <A0>: Zeiger auf Meldungstext
;
ZeigMeld: MOVE.L A0,-(SP)
MOVE.W #CCONWS,-(SP) ; Meldung
TRAP #GEMDOS ; ausgeben
ADD.L #6,SP ;
MOVE.W #CRAWCIN,-(SP) ; warte auf
TRAP #GEMDOS ; Taste
ADD.L #2,SP ;
RTS ;
;
; Trap 01 TRAP_LOG.TOS
;
; benutzte Register: A0, D0
;
StrngFlg: DC.W NUL ; Steuerung
Magic_01: DC.B 'XBRA' ; Magic
Ident_01: DC.B 'TLOG' ; Ident-Nr.
_Trp010V: DC.L 0 ; Original
Trp01LOG: BTST #Desktop,StrngFlg ; ggf.
BNE Tr01LOG1 ; Trap-02-
BSR TestBoot ; Logger
BTST #Desktop, StrngFlg ; auch noch
BEQ Tr01LOG1 ; instal—
BSR InstTr02 ; lieren
Tr01LOG1: MOVE.L SP,A0 ; A0 = SP
BTST #SuperMod,(SP) ; alter
BNE Tr01LOG2 ; Status
MOVE.L USP,SP ; bestimmt,
MOVE.L SP,D0 ; ob USP zu
BRA Tr01LOG3 ; benutzen
Tr01LOG2: MOVE.L SP,D0 ; ist oder
ADDQ.L #6,D0 ; SSP
Tr01LOG3: EXG D0,A0 ; rette den
MOVE.L D0,-(SP) ; alten SP
BTST #Gesperrt,StrngFlg ; ge-
BNE Tr01LOG4 ; sperrt ?
MOVE.L A0,-(SP)
MOVE.W #'G',D0 ; 'G' für
BSR AusgZchn ; GEMDOS,
MOVE.L (SP)+,A0 ; dann über
MOVE.W (A0),D0 ; A0 adres-
MOVE.B D0,-(SP) ; sierte
ASR.B #4,D0 ; Nummer
BSR AusgHlbB ; ausgeben
MOVE.B (SP)+,D0 ;
BSR AusgHlbB ;
BSR AusgLeer ;
Tr01LOG4: MOVE.L (SP),SP ; SP okay
Tr01LOG5: MOVE.L _Trp01OV,A0 ; weiter
JMP (A0) ; wie sonst
;
; Installation Trap-02-Logger
;
InstTr02: BSR RettOrgV ; erst die
LEA IllAdLOG(PC),A0 ; Original-
MOVE.L A0,4*IllAdVNr ; Vektoren
LEA TraceLOG(PC),A0 ; sichern,
MOVE.L A0,4*TraceVNr ; dann die
LEA FLineLOG(PC),A0 ; Logger-
MOVE.L A0,4*FLineVNr ; Routinen
LEA Trp02LOG(PC),A0 ; ein-
MOVE.L A0,4*T02VktNr ; binden
RTS ;
;
; Rettung der Original-Vektoren
;
RettOrgV: MOVE.L 4*IllAdVNr,_IllAdOV ;
MOVE.L 4*TraceVNr,_TraceOV ;
MOVE.L 4*FLineVNr,_FLineOV ;
MOVE.L 4*T02VktNr,_Trp02OV ;
RTS ;
;
; Test, ob das Boot schon schwimmt
;
TestBoot: BSET #BootTest,StrngFlg ; Merker f.
BNE TstBoot2 ; TestBoot
MOVE.L 4*FLineVNr,-(SP) ; wenn
OR.L #$FF000000,(SP) ; FLine- &
MOVE.L 4*TraceVNr,D0 ; Trace-
OR.L #$FF000000,D0 ; Vektor
CMP.L (SP)+,D0 ; ungleich,
BEQ TstBoot1 ; dann
BSET #Desktop,StrngFlg ; läuft
RTS ; Desktop
TstBoot1: BSR RettOrgV ; Vektoren
RTS ; retten
TstBoot2: MOVE.L 4*FLineVNr,D0 ; Desktop
CMP.L _FLineOV,D0 ; läuft,
BEQ TstBoot9 ; wenn
MOVE.L 4*T02VktNr,D0 ; Vektoren
CMP.L _Trp02OV,D0 ; für FLine
BEQ TstBoot9 ; & Trap-02
BSET #Desktop,StrngFlg ; geändert
TstBoot9: RTS ;
;
; Trap 02 TRAP_LOG.TOS
;
; geänderte Register: keine
;
Magic_02: DC.B 'XBRA' ; Magic
Ident_02: DC.B 'TLOG' ; Ident-Nr.
_Trp02OV: DC.L 0 ; Original
Trp02LOG: BTST #Gesperrt,StrngFlg ; ge-
BNE Tr02LOG6 ; sperrt ?
MOVEM.L D0-D2/A0-A2,-(SP) ; rette
MOVE.L D1,-(SP) ; Register
CMP.W #AES_Code,D0 ; AES-
BEQ Trp02AES ; Aufruf ?
CMP.W #VDI_Code,D0 ; VDI-
BEQ Trp02VDI ; Aufruf ?
ADDQ.L #4,SP ; wer kommt
BRA Tr02LOG5 ; hierhin ?
Trp02VDI: MOVE.W #'V',D0 ; 'V' / 'A'
BRA Tr02LOG4 ; für
Trp02AES: MOVE.W #'A',D0 ; VDI / AES
Tr02LOG4: BSR AusgZchn ; ausgeben
MOVE.L (SP)+,A0 ; zeigt auf
MOVE.L (A0),A0 ; Zeiger,
MOVE.W (A0),D0 ; der zeigt
BSR AusgByte ; auf Nr.
BSR AusgLeer ;
Tr02LOG5: MOVEM.L (SP)+,D0-D2/A0-A2 ; Reg. okay
Tr02LOG6: MOVE.L _Trp02OV,-(SP) ; weiter,
RTS ; wie sonst
;
; illegale Adresse
;
_IllAdOV: DC.L NUL ; Original
IllAdLOG: MOVE.L A0,-(SP) ; A0 und D0
MOVE.L D0,-(SP) ; retten
MOVE.L 10(SP),A0 ; ill. Adr.
CMP.B #$F0,-3(A0) ; selbst
BLT IllAdAlt ; erzeugt ?
MOVE.L 4*T02VktNr,D0 ; Logger
CMP.L _Trp02OV,D0 ; wieder
BNE IlAdLOG1 ; einbin-
LEA Trp02LOG(PC),A0 ; den, wenn
MOVE.L A0,4*T02VktNr ; Vektor
BRA IlAdLOG2 ; verändert
IlAdLOG1: MOVE.W -3(A0),D0 ; sonst
AND.L #$00000FFF,D0 ; Merker
ASR.W #2,D0 ; für zuge
EXG.L D0,A0 ; hörige
ADD.L #FLineTab,A0 ; Routine
CLR.B (A0) ; löschen
IlAdLOG2: MOVE.L (SP)+,D0 ; A0, D0
MOVE.L (SP)+,A0 ; Stack und
MOVE.L 2(SP),10 (SP) ; Rück-
AND.L #$FFFFFFFE,10(SP) ; sprung
ADD.L #8,SP ; adresse
RTE ; okay
IllAdAlt: MOVE.L (SP)+,D0 ; D0 & A0
MOVE.L (SP)+,A0 ; okay,
MOVE.L _IllAdOV,A0 ; weiter
JMP (A0) ; wie sonst
;
; FLine
;
_FLineOV: DC.L NUL ; Original
FLineLOG: MOVE.L A0,-(SP) ; A0 retten
MOVE.L 6(SP),A0 ; Opcode
ADD.L #1,A0 ; testen
BTST #Unlink,(A0) ;
BNE FLinLOG1 ;
MOVE L D0,-(SP) ; D0 retten
ADD.L #1,A0 ; Nummer d.
MOVE.W -2(A0),D0 ; FLine-
AND.L #$00000FFF,D0 ; Routine
ASR.H #2,D0 ; bestimmen
EXG.L D0,A0 ; und zuge-
ADD.L #FLineTab,A0 ; hörigen
TST.B (A0) ; Merker
BEQ FLinLOGO ; testen,
MOVE.L (SP),-(SP) ; ggf.
MOVE.L 8(SP),4(SP) ; Adresse
MOVE.W 12(SP),8(SP) ; merken &
MOVE.L 14(SP),10(SP) ; und Trace
MOVE.L D0,14(SP) ; ver-
BSET #TraceMod,8(SP) ; anlassen
FLinLOG0: MOVE.L (SP)+,D0 ; D0 und A0
FLinLOG1: MOVE.L (SP),A0 ; okay
MOVE.L _FLineOV,(SP) ; weiter
RTS ; wie sonst
;
; Trace
;
_TraceOV: DC.L NUL ; Original
TraceLOG: MOVE.L A0,-(SP) ; A0 & D0
MOVE.L D0,-(SP) ; retten
BTST #SuperMod,8(SP) ; alter
BEQ TracLOG1 ; Status
MOVE.L SP,A0 ; bestimmt,
ADD.L #18,A0 ; ob SSP
BRA TracLOG2 ; oder USP
TracLOG1: MOVE.L USP,A0 ; zu nutzen
TracLOG2: MOVE.L (A0),D0 ; wenn Adr.
CMP.L 14(SP),D0 ; ungleich,
BEQ TraceEnd ; D0 & A0
MOVE.L (SP)+,D0 ; vom Stack
MOVE.L (SP)+,A0 ; holen,
RTE ; tracen
TraceEnd: BSET #0,3(A0) ; Adresse,
MOVE.L (SP)+,D0 ; D0, A0
MOVE.L (SP)+,A0 ; und Stack
MOVE.L 2(SP),6(SP) ; berichti-
MOVE.W (SP),4(SP) ; gen,
BCLR #TraceMod,4(SP) ; Trace
ADD.L #4,SP ; beenden
RTE ;
;
; Ausgabe Byte
;
AusgByte: MOVE.W D0,-(SP) ;
ASR.B #4,D0 ; oberes
BSR AusgHlbB ; Halbbyte
MOVE.W (SP)+,D0 ; unteres
BSR AusgHlbB ; Halbbyte
RTS
;
; Ausgabe Halb-Byte (nibble)
;
AusgHlbB: AND.W #$000F,D0 ; unterstes
LEA HexAscTb(PC),A0 ; Halbbyte
MOVE.B (A0,D0),D0 ; zeigt auf
BRA AusgZchn ; Zeichen
;
; Neue Zeile
;
NeueZeil: MOVE.W #CR,D0 ; Zeilen-
BSR AusgZchn ; anfang
MOVE.W #LF,D0 ; nächste
BRA AusgZchn ; Zeile
;
; Ausgabe Leerzeichen
;
AusgLeer: MOVE.W #BLANK,D0 ; ' ' !
;
; Ausgabe Zeichen
;
; enthalten sind Start/Stop und Zeitlupe
;
; Aufruf
;
; <D0>: Zeichen
;
AusgZchn: MOVEM.L D1-D2/A1-A2,-(SP) ; Register
MOVE.W D0,-(SP) ; retten
BTST #Zeitlupe,MFP_PIO ; Tee
BEQ AusgZch1 ; trinken,
MOVE.L #150,D0 ; wenn ge-
BSR Wartzeit ; schlossen
AusgZch1: BSR TstDruck ; zurück,
BNE AusgZch3 ; wenn
ADD.L #2,SP ; geöffnet
BRA AusgZch4 ;
AusgZch3: MOVE.W #PRN,-(SP) ; Status
MOVE.W #Bcostat,-(SP) ; des
TRAP #BIOS ; Druckers
ADDQ.L #4,SP ; ermitteln
CMP.W #Bereit,D0 ; wenn
BNE AusgZch1 ; bereit,
MOVE.W #PRN,—(SP) ; dann
MOVE.W #Bconout,-(SP) ; Zeichen
TRAP #BIOS ; ausgeben
ADDQ.L #6,SP ;
AusgZch4: MOVEM.L (SP)+,D1-D2/A1-A2 ; Register
RTS ; holen
;
; Wartezeit
;
; Aufruf
; <D0>: Anzahl der Wartezyklen,
; leider ein Software-Timer
;
Wartzeit: MOVE.L #10,D1
Wartzeil: DBRA D1,Wartzeil
DBRA D0,Wartzeit
RTS ; genug
;
; Test Schalter 'Drucken'
;
; Rücksprung
; <Z>: 1 - Druck
; 0 - kein Druck
;
TstDruck: MOVE.L D1,-(SP) ; D1 retten
MOVE.B MFP_PIO,D1 ; Wenn
MOVE.B StrngFlg,D0 ; Schalter
EOR.B D1,D0 ; betätigt,
BTST #Drucken,D0 ; dann Flag
BEQ TstDrck2 ; ändern &
BCHG #Drucken,StrngFlg ; ggf.
BNE TstDrck1 ; Zeilen-
BSR NeueZeil ; vorschub
TstDrck1: MOVE.L #1000,D0 ; Ent-
BSR Wartzeit ; prellen
TstDrck2: MOVE.L (SP)+,D1 ; D1 okay
BTST #Drucken,StrngFlg ; Test
RTS
;
; Konstanten
;
HexAscTb: DC.B '0123456789ABCDEF' ; Hex-Ascii
;
; Variablen
;
FLineTab: ; Merker
REPT $1000/4 ; für
DC.B $FF ; Trace
ENDM
;
; Texte
;
Meldung1: DC.B 'TRAP_LOG.PRG installiert'
DC.B CR,LF,LF
DC.B ' Stephan Simson 27.03.90'
DC.B CR,LF,NUL
Meldung2: DC.B 'TRAP_LOG.PRG wieder aktiv'
DC.B CR,LF,NUL
Meldung3: DC.B 'TRAP_LOG.PRG deaktiviert'
DC.B CR,LF,NUL
END