HC-FIX: Multitasking-Hardcopy-Routine

Obwohl beim ATARI ST die hardware-mäßigen Voraussetzungen für eine Druckausgabe parallel zu laufenden Programmen gegeben sind, wurde bei den Betriebssystemroutinen auf diese Möglichkeit verzichtet. Die Folgen sind Ihnen bekannt: Für die Dauer des Ausdruckens einer Hardcopy wird die Arbeit am Computer vollständig blockiert.

Mit der in Assembler geschriebenen Hardcopy-Routine HC-FIX für 24-Nadeldrucker sind diese Zeiten endgültig vorbei. Neben Ausnutzung der maximal möglichen Druckgeschwindigkeit - in Abhängigkeit vom angeschlossenen Drucker - ist die Routine multitaskingfähig, d.h. die Datenausgabe findet im Hintergrund statt.

Wie alles begann

Wegen der Unzulänglichkeiten der von ATARI vorgegebenen Betriebssystemroutine für die parallele Druckerschnittstelle entstanden die sogenannten Spooler. Unter einem Spooler versteht man ein Programm, das die Zeichenausgabe zum Drucker zunächst in einen eigenen Puffer (Speicherbereich) umlenkt. Danach zieht es sich in den Hintergrund zurück und füttert den Drucker, während ein anderes Programm gestartet werden bzw. weiterlaufen kann. Mit Hilfe dieses Verfahrens braucht der Anwender nicht zu warten, bis alle Daten an den Drucker übergeben worden sind. Er kann gleich nach der Umlenkung Weiterarbeiten, was bei mittellangen Texten eine beachtliche Zeitersparnis bedeutet. Allerdings ergeben sich bei der Anwendung dieser Methode auf Hardcopies zwei Probleme:

Einerseits fallen bei Grafiken große Datenmengen an. Um nämlich bei 24-Nadeldruckern auf eine Bildgröße von 18 * 11 cm zu kommen, muß man 128 kB Daten an den Drucker senden. Soll die Hardcopy eine DIN A4-Seite füllen, sind es sogar fast 300 kB (80% des Speicherplatzes eines 520 ST). Ein entsprechend großer Spooler-Puffer läßt schnell keinen Platz mehr für eine andere Applikation - es sei denn. Sie sind Besitzer eines Mega-ATARIs und haben genug Speicher.

Andererseits wird die Geschwindigkeit der Zeichenumlenkung in den Puffer von den BIOS-Routinen bestimmt; sie liegt bei ca. 4000 Baud. Selbst ein guter Spooler benötigt für 300 kB Daten mindestens 6 Minuten zur Übernahme.

Während dieser Zeit ist der Rechner blockiert, so daß kein Vorteil gegenüber der normalen Hardcopy entsteht.

Datenübertragung

Ein Lösungsansatz des Problems findet sich im Kommunikationsprinzip zwischen Rechner und Drucker.

Bei der Datenübermittlung werden außer den acht Datenleitungen ,die den Binärcode des Zeichens übertragen, noch zwei Steuerleitungen, Strobe und Busy, benutzt. Diese Leitungen regeln das Übertragungsprotokoll zwischen Rechner und Peripherie im sogenannten Handshake-Modus. Damit der Drucker nicht wahllos Zeichen einliest, generiert der Computer das Strobe-Signal, das die Gültigkeit der Daten auf den Leitungen anzeigt. Umgekehrt teilt das Ausgabegerät dem Rechner über die Busy-Leitung seine Empfangsbereitschaft mit.

Beim Senden eines Daten-Bytes legt der Computer die Strobe-Leitung kurzzeitig auf Low - das Signal zur Übernahme. Während der Drucker das Zeichen entgegennimmt, setzt er die Busy-Leitung auf High und zeigt damit dem Rechner, daß er beschäftigt ist. Erst mit einem Low-Pegel auf der Leitung kann die Ausgaberoutine das nächste Byte abschicken. Zur Überprüfung des Druckerzustandes gibt es zwei Möglichkeiten:

Das Konzept

Die Grundidee für das neue Hardcopy-Programm war denn auch, es als Interrupt-Routine laufen zu lassen. Natürlich darf dabei nicht die komplette Hardcopy ausgegeben werden, da sonst die Applikation nicht mehr zum Zuge kommt. Also wird HC-FIX portionsweise ausgeführt -genauer: bei jedem Busy-Interrupt wird nur ein Byte an den Drucker ausgegeben und die Routine danach terminiert. Damit HC-FIX beim nächsten Aufruf die folgende Position im Hardcopy-Puffer bearbeiten kann, müssen die dafür notwendigen Informationen abgespeichert werden. Das ist der Hauptunterschied zu normalen Interrupt-Routinen, die in sich abgeschlossene Programmstücke bilden und bei jedem Aufruf unabhängig vom vorherigen Aufruf arbeiten. Für interessierte Leser folgt eine detaillierte Beschreibung des interruptgesteuerten Multitaskings der Hardcopy-Routine.

Im Detail

HC-FIX benutzt diverse Register zur Verwaltung von Programmschleifen (Zeilen-/Spaltenzähler, siehe dokumentierte Registerbelegung im Listing) - sie entsprechen den Schleifenvariablen höherer Programmiersprachen. Zu ihrer Speicherung wird ein programminterner Stack benutzt.

Nach der Installation von HC-FIX kann ein beliebiges Programm gestartet werden (im folgenden auch Hauptprogramm genannt), das im ‘Vordergrund’ läuft. Löst man jetzt die Hardcopy aus, wird das Hauptprogramm unterbrochen und die neue Hardcopy-Routine ausgeführt. Sie lenkt zunächst den Busy-Interrupt-Vektor auf die Routine um und speichert die Register ab, die während der Hardcopy verändert werden. Nachdem sie ein Zeichen an den Drucker gesendet hat, kommt die Routine an eine Unterbrechungsstelle. Da der Drucker mit der Datenübernahme beschäftigt ist, kann sinnvollerweise das Hauptprogramm weiterlaufen. Also werden alle relevanten Registerinhalte auf dem eigenen Stack abgelegt, damit die Routine bei einem späteren Aufruf an dieser Stelle fortgesetzt werden kann. Außerdem wird die Registerbelegung des Hauptprogramms wiederhergestellt.

Das Hauptprogramm wird nun solange ausgeführt, bis der Drucker zur Aufnahme des nächsten Zeichens bereit ist und den Busy-Interrupt auslöst. Dieser führt bei der CPU zu einer Exception (Ausnahmebehandlung): Das Hauptprogramm wird unterbrochen und die Interrupt-Routine von HC-FIX ausgeführt. Sie rettet zunächst die Register des Hauptprogramms, lädt dann die Registerbelegung für die Hardcopy und stellt so den alten Zustand her. Dann wird erneut ein Daten-Byte berechnet und abgeschickt, und der Kreislauf kann von neuem beginnen.

Im Unterschied zum normalen Multitasking ist die Zeitspanne, in der der Hardcopy-Vorgang bedient wird, durch die festgelegte Unterbrechungsstelle immer gleich lang. Das erweist sich als optimal, denn durch die Interrupt-Technik werden einerseits die Daten entsprechend der Aufnahmegeschwindigkeit des Druckers weitergegeben. Auf der anderen Seite läuft das Hauptprogramm weiter, während der Drucker beschäftigt ist.

Klar, daß das Programm im Vordergrund durch die Interrupts langsamer wird - und zwar proportional zur Druckgeschwindigkeit. Deshalb war es wichtig, die Interrupt-Routine zu minimieren. Also wurden möglichst wenige Register benutzt, da ein erheblicher Teil der Rechenzeit zum Retten und Restaurieren ihrer Inhalte verbraucht wird. Beim NEC P6 verlangsamt sich die Ausführung durchschnittlich um den Faktor 1,3. Die Daten für einige andere Drucker sind in Tabelle 1 festgehalten.

Probleme treten bei sehr schnellen Druckern mit großem Zeichenpuffer auf, wie beim NEC P6 plus. Solche Geräte bremsen Vordergrundprogramme bis auf 10% der Ursprungsgeschwindigkeit ab! Bei einer Anfertigungszeit von 20 Sekunden für eine Hardcopy lohnt sich der Einsatz von HC-FIX in diesen Fällen aber ohnehin nicht. In Verbindung mit dem NEC P6 liefert HC-FIX das kleine Format in durchschnittlich 1 Minute 45 Sekunden. Die DIN A4-Hardcopy ist nach ca. 4 Minuten 20 Sekunden fertig.

Im Gegensatz zum Spooler genügen 32000 Bytes für die Kopie des Bildschirmspeichers. Dieser Puffer ist notwendig, damit Änderungen des Bildschirminhalts während der Programmausführung keine Auswirkungen auf den Ausdruck haben. Insgesamt belegt HC-FIX nur ca. 34 kB des Systemspeichers, so daß für die Hauptanwendung ausreichend Raum übrig bleibt.

Datenaufbereitung

Die Aufbereitung der Druckerdaten aus den Informationen des Puffers geschieht innerhalb der Interrupt-Routine, d.h. das auszugebende Byte wird erst nach Auslösen des Interrupts berechnet. Würde man die Daten 1:1 an den Drucker weitergeben, entstünde bei einer Einstellung von 180 Punkt/Zoll (dreifache Dichte) eine Mini-Hardcopy von 9 * 5,5 cm. Deshalb verdoppelt bzw. verdreifacht die Routine jeden Punkt in vertikaler und horizontaler Richtung. So erreicht die Hardcopy die zwei möglichen Bildgrößen von 11,3 x 18 cm und 17 x 26,5 cm. Allerdings erhöht sich damit auch die Datenmenge auf das Vier- bzw. Neunfache, was beim Spooler-Betrieb zu den oben aufgeführten Problemen führt.

Drucker mittlere maximale
NEC P6 1,30 1,35
NEC P2200 1,27 1,43
Seikosha SL-80 IP 1,13 1,20
Star LC 24-10 1,28 2,02

Tabelle: Verzögerung der Vordergrundprogramme

Druckqualität

Hardcopies vom Desktop oder von Punktmustern sind oft dunkler als erwartet. Das liegt am Durchmesser der Nadeln, der etwas größer als der darzustellende Punkt ist. Folglich sind die (gedruckten) schwarzen Punkte etwas größer als die weißen. Betrachten wir zur Veranschaulichung ein Schachbrettmuster, bei dem der Effekt am gravierendsten auftritt (siehe Bild auf der nächsten Seite).

Links sehen Sie die Punktdarstellung auf dem Monitor und die übliche Umsetzung für den Drucker. Der weiße Punkt in der Mitte ist beim normalen Ausdruck zu klein geraten. HC-FIX verwendet deshalb einen speziellen Algorithmus, um die Qualität zu verbessern (Abbildung rechts):

Normalerweise wird ein schwarzer Bildschirmpunkt mit vier quadratisch angeordneten Druckernadeln aufs Papier gebracht. Folgt auf einen schwarzen Punkt ein weißer (in vertikaler Richtung), werden bei HC-FIX von den vier Nadeln nur die beiden oberen benutzt. Der gedruckte Punkt ist zwar nicht mehr quadratisch - das fällt bei der Größe aber kaum auf - dafür erhält man Hardcopies mit einem größeren Graustufenumfang.

Auslösemechanismus

Die Hardcopy wird wie gewohnt durch Alternate-Help ausgelöst bzw. gestoppt. Durch gleichzeitiges Drücken der linken Shift-Taste erhalten Sie das größere Ganzseitenformat. Zur optischen Bestätigung des Vorgangs wird der Bildschirm kurz invertiert.

XBRA-Verfahren

Als residentes und vektorverbiegendes Programm ist HC-FIX selbstverständlich mit einer XBRA-Struktur ausgestattet. Sie befindet sich direkt vor der Stelle, auf die man den Vektor umgebogen hat - also der Einsprungadresse in das eigene Programm - und hat folgende Form:

xb_magic:   DC.B 'XBRA'
xb_id:      DC.B 'name'
;vier beliebige Zeichen zur individuellen Kennzeichnung des Programms

xb_oldvec:  DC.L 0
;Platz für ursprünglichen Vektor

prg_start:
;Hier fängt das eigene Programm an

Damit kann ein Programm leicht überprüfen, ob es schon installiert ist, bzw. ist es möglich, das Programm wieder zu entfernen. Das setzt allerdings voraus, daß alle nachfolgenden Programme, die den entsprechenden Vektor ebenfalls verbiegen, auch die XBRA-Struktur besitzen. Aus diesem Grund kann ich nur allen Programmierern empfehlen, die XBRA-Methode zu verwenden, wo immer es möglich ist.

Verträglichkeit mit anderen Programmen

Wegen der herkömmlichen Auslösemethode arbeitet die Routine nur mit Programmen zusammen, die keine Interrupts sperren. Programme die den Hardcopy-Vektor ($502) verbiegen, müssen nach Installation von HC-FIX gestartet werden (z.B Tempelmon). Besonderes Augenmerk wurde auf die Verträglichkeit mit Spoolern gelegt, die meistens auch Interrupts benutzen. Dazu wird bei Auslösung einer Hardcopy der Busy-Interrupt auf die eigenen Routine umgelenkt. Ein eventuell vorhandener Vektor eines Spoolers wird gerettet und nach Beendigung der Hardcopy wieder hergestellt. So können beide Routinen auf den Interrupt zugreifen.

Man sieht aber auch sofort, daß während einer Hardcopy kein Text durch den Spooler ausgegeben werden kann. Dieser würde die Interrupt-Routine der Hardcopy benutzen - eine Datenkollision wäre die Folge. Ebenso geht es im umgekehrten Fall. Hält man sich strikt an die zeitliche Trennung von Hardcopy und Textausgabe, kann eigentlich nichts passieren.


***************************************************
*                                                 *
*                    HC-FIX                       *
*                                                 *
*       multitaskingfähige Hardcopyroutine        *
*             für 24-Nadel-Drucker                *
*                                                 *
*             (c) MAXON Computer 1989             *
*                                                 *
*             written by MARCUS KRAFT,            *
*                                                 *
*             Niederramstädterstr. 187            *
*             61 Darmstadt                        *
*                                                 *
*             V 1.3  vom 18.08.89                 *
***************************************************

;-------------- Systemparameter -----------------

; Hardwareadressen

psg:        EQU $FFFF8800
mfp:        EQU $FFFFFA00
mfp_aer:    EQU mfp+$03
mfp_ierb:   EQU mfp+$09 
mfp_isrb:   EQU mfp+$11 
color_0:    EQU $FFFF8240

;Betriebssystemaufrufe

gemdos:     EQU 1
bios:       EQU 13
xbios:      EQU 14
physbase:   EQU $02 
super:      EQU $20
supexec:    EQU $26
ptermres:   EQU $31

; Systemvariablen

busy_vec:   EQU $0100 
_prt_cnt:   EQU $04EE 
savptr:     EQU $04A2
dump_vec:   EQU $0502

;Programmlänge ermitteln (mit Speicherplatz für den Spooler)

hc_install:
        movea.l 4(sp),a6        ;Basepage -> a6
        move.l  #$0100,d5       ;Länge der Basepage 
        add.l   12(a6),d5       ;+ Länge Textsegment 
        add.l   20(a6),d5       ;+ Länge Datensegment 
        add.l   28(a6),d5       ;+ Länge BSS-Segment

        pea     bieg(pc)
        move.w  #supexec,-(sp)  ;führt Routine bieg im Super aus
        trap    #xbios
        addq.l  #6,sp

        pea     meldung(pc)
        move.w  #9,-(sp)        ;Cconws: gibt Installations-meldung aus 
        trap    #gemdos
        addq.l  #6,sp

        moveq   #30,d1          ;Warteschleife

wa2:    moveq   #-1,d0
wa1:    dbra    d0,wa1
        dbra    d1,wa2

        move.l  d5,-(sp)        ;Programm resident machen 
        move.w  #ptermres,-(sp)
        trap    #gemdos

;Programm ist jetzt resident und wird an dieser Stelle verlassen

bieg:   move.l  dump_vec,xb_old     ;alten HC-Vektor nach XBRA-Konvention retten 
        move.l  #hcstart,dump_vec   ;Hardcopy Vektor auf neue Routine setzen

        rts

;Kennzeichnung nach XBRA-Konvention:

xb_magic: DC.B 'XBRA'           ;4 Bytes 'XBRA'
xb_id:    DC.B 'MKHC'           ;4 Bytes für Programmname
xb_old:   DC.L 0                ;4 Bytes für alten Vektor

hcstart:  cmpi.b    #-1,status  ;wird eine HC gedruckt ?
          beq.s     begin
break:    move.b    #2,status   ;ja, also HC stoppen
          rts

begin:    move      sr,-(sp)    ;macht aus dem Unterprogramm eine Exception 
          ori       #$0700,sr   ;alle Interrupts sperren 
          move.b    mfp_ierb,old_ierb ;altes IERB retten 
          move.l    busy_vec,mfp_vec0 ;alten Interruptvektor retten

          andi.b    #%11111110,mfp_aer   ;setze Active Edge auf fallende Flanke
          move.l    #busy_int,busy_vec   ;neuer Busy-Interrupt-Vektor

          subi.l    #46,savptr           ;damit Bios- und Xbios-Routinen vom 
          ;Interrupt aus aufgerufen werden können

          move.w    #0,-(sp)             ;aktiviere Busy-Interrupt: 
          move.w    #27,-(sp)            ;jenabint
          trap      #14
          addq.l    #4,sp

          move.w    #-1,_prt_cnt
          movea.l   #psg,a3              ;PSG-Adresse laden
          movem.l   d0-d6/a0-a3,-(sp)    ;Register retten
          move.l    sp,old sp            ;alten Stackpointer retten 
          lea       mystack(pc),sp       ;Stackpointer für HC-Routine 
          bsr       getadr               ;Bildschirmadresse->anfadr

shifttst:
          move.b    #0,mode
          move.w    #-1,-(sp)
          move.w    #11,-(sp) ;kbshift
          trap      #13
          addq.l    #4,sp

          addi.l    #46,savptr           ;Stackpointer für BIOS wiederherstellen 
          btst      #1,d0                ;wurde zusätzlich die Shifttaste gedrückt?
          beq.s     noshift
          move.b    #1,mode              ;ja: große HC
noshift:  bchg      #0,color_0           ;reverse video
          movea.l   anfadr,a0
          lea       puffer,a1
          move.w    #31999,d1
save_scr: move.b    (a0)+,(a1)+          ;kopiert normalen Bildschirm in Puffer 
          dbra      d1,save_scr
          bchg      #0,color_0 ;norm video
          btst      #0,color_0
          bne.s     pr_init
          lea       puffer(pc),a1
          move.w    #7999,d0
invert:   not.l     (a1)+                ;invertiere ggf.Pufferinhalt 
          dbra      d0,invert


pr_init:  move.b    #0,status            ;HC beginnt
          bsr       sender               ;Zeilenvorschub senden
          bsr       setlf                ;Linefeed für Grafikausdruck einstellen 
          lea       puffer(pc),a0
          tst.b     mode
          bne       vert_hc              ;mode=1 =>große

;--------------------------------------------------
;         Horizontale Hardcopy
;--------------------------------------------------

;--------------------------------------------------
;
; Registerbelegung der Routine bei horiz. Copy :
;
; d0- Zähler d.3 Druckerbytes f.1 Nadelreihe(24N)
; d1- Bitzähler für Puffer
; d2- Byte/Zeilenzähler für Puffer
; d3- 4malzähler f.1 Druckerbyte (jedes Bit 2mal)
; d4- zu druckendes Zeichen 
; d5- Anzahl Zeichen (für chrout)
; d6- Speicher für Portkommunikation 
; d7-
; a0- Pufferadresse
; a1- Kopie von a0, die aber verändert wird 
; a2- Adresse Zeichenstring (für chrout)
; a3- Adresse PSG
;
;--------------------------------------------------

          move.w    #33,d2               ;34 Zeilen (34*12=408) 
scr:      swap      d2
          move.w    #79,d2               ;eine Zeile drucken (80 B)
          bsr       grafon               ;Grafikzeile senden
row:      move.w    #7,d1                ;ein Byte bearbeiten
byte:     movea.l   a0,a1
          moveq     #2,d0                ;das ganze 3x
col:      moveq     #3,d3

four:     lsl.w     #2,d4                ;d4 ist das Druckerbyte
          btst      d1,0(a1)
          beq.s     offset               ;Punkt gesetzt?
          addq.w    #2,d4                ;ja, aber nur 1 Punkt für Drucker (statt 2) 
          btst      d1,80(a1)            ;teste den nachfolgenden Punkt 
          beq.s     offset
          addq.w    #1,d4                ;und setze ggf. den fehlenden Druckerpunkt 
offset:   adda.l    #80,a1
          dbra      d3,four
          move.w    d4,-(sp)             ;Druckerbyte retten
          bsr       chrout               ;und ausgeben
          dbra      d0,col               ;das ganze 3x
          move.w    4(sp),d4
          bsr       chrout               ;und die 3 Byte wg der horiz. 
          move.w    2(sp),d4             ;Verdopplung nochmal raus
          bsr       chrout
          move.w    (sp),d4
          bsr       chrout
          addq.l    #6,sp                ;Stack reinigen
          dbra      d1,byte              ;ganzes Byte abarbeiten
          addq.l    #1,a0                ;nächstes Byte
          dbra      d2,row               ;Zeile bearbeiten
          bsr       sender               ;Zeilenvorschub senden
          cmpi.b    #2,status            ;wurde alt-help gedrückt?
          beq.s     bye                  ;falls ja, Stop
          adda.l    #880,a0              ;Offset für die nächsten 12 Pixelzeilen 
          swap      d2
          dbra      d2,scr               ;ganzer Bildsch.
          bsr       sender
bye:      bsr       reslf
          move.b    #-1,status           ;HC beendet
          move.w    #-1,_prt_cnt
          move.b    old_ierb(pc),mfp_ierb;IERB restaurieren
          move.l    mfp_vec0(pc),busy_vec;wieder alten Interruptvektor benutzen
          bra       jobend

;--------------------------------------------------
;         Vertikale Hardcopy (groß)
;--------------------------------------------------

;--------------------------------------------------
;
; Registerbelegung bei vertikaler Hardcopy :
;
; d0 - Zähler f.d. 3fach-Ausgabe d.3 Druckerbytes 
; d1 - Bitzähler für Puffer 
; d2 - Bytezähler für Puffer 
; d3 - Zeilenzähler für Puffer 
; d4 - zu druckendes Zeichen 
; d5 - Anzahl Zeichen (für chrout)
; d6 - Speicher für Portkommunikation 
; d7 -
; a0 - Pufferadresse
; a1 - Kopie von a0, die aber verändert wird 
; a2 - Adresse Zeichenstring (für chrout)
; a3 - Adresse PSG
;
;--------------------------------------------------

vert_hc:    adda.l  #32000-80,a0        ;letzte Bildschirmzeile
            move.w  #79,d3
v_screen:   movea.l a0,a1
            bsr     v_grafon
            move.w  #399,d2
v_row:      move.w  #7,d1
v_byte:     lsl.l   #3,d4
            btst    d1,(a1)
            beq.s   noadd
            addq.l  #7,d4
noadd:      dbra    d1,v_byte
            move.w  d4,-(sp)            ;Byte 3
            lsr.l   #8,d4
            move.w  d4,-(sp)            ;Byte 2
            lsr.w   #8,d4
            move.w  d4,-(sp)            ;Byte 1
            move.w  #2,d0
dr_col:     move.w  (sp),d4             ;3 mal 3 Bytes ausgeben
            bsr.s   chrout
            move.w  2(sp),d4
            bsr.s   chrout
            move.w  4(sp),d4
            bsr.s   chrout
            dbra    d0,dr_col
            addq.l  #6,sp
            suba.l  #80,a1
            dbra    d2,v_row
            bsr     sendcr
            cmpi.b  #2,status
            beq     bye
            addq.l  #1,a0
            dbra    d3,v_screen
            bsr     sendcr
            bra     bye

;-------------------------------------------
;           Busy-Interrupt-Routine
;-------------------------------------------

busy_int:   cmpi.b  #-1,status          ;Hardcopy in process?
            bne.s   load
            bclr    #0,mfp_isrb         ;keine HC-Anforderung 
            rte

load:       movem.l d0-d6/a0-a3,-(sp)   ;Register und SP retten
            move.l  sp,old_sp
            movea.l new_sp(pc),sp       ;HC-SP u.-register laden
            movem.l (sp)+,d0-d5/a0-a3 
            bra.s   go_on               ;weitermachen,wo aufgehört wurde

;--------------------------------------------------
; Unterprogramm zur Zeichenausgabe auf Drucker 
;--------------------------------------------------
chrout:
            move.b  #7,(a3)
            move.b  (a3),d6
            or.b    #%10000000,d6       ;Port B als Ausgang 
            move.b  d6,2(a3)
            move.b  #15,(a3)            ;PSG Port B auswählen
            move.b  d4,2(a3)            ;d4 in Port B
            move.b  #14,(a3)            ;PSG Port A auswählen
            move.b  (a3),d6
            and.b   #%11011111,d6
            move.b  d6,2(a3)            ;Strobe senden (active low) 
            move.b  #14,(a3)
            move.b  (a3),d6
            or.b    #%100000,d6
            move.b  d6,2(a3)            ;Strobesignal abstellen

jobend:                                 ;Abbruch des Hintergrundjobs
            movem.l d0-d5/a0-a3,-(sp)
            move.l  sp,new_sp           ;Routinen-SP und-Register save
            movea.l old_sp(pc),sp
            movem.l (sp)+,d0-d6/a0-a3   ;alten SP und Register wiederherstellen
            bclr    #0,mfp_isrb
            rte                         ;und zurück zum unterbrochenen Hauptprogramm
go_on:      rts

;--------------------------------------------------
;           Diverse Unterprogramme
;--------------------------------------------------

getadr:     move.w  #physbase,-(sp)     ;Bildschirmadresse ermitteln 
            trap    #xbios
            addq.l  #2,sp
            move.l  d0,anfadr
            rts

grafon:     lea     grafdat(pc),a2      ;Grafikmodus f.horiz. HC einschalten 
            moveq   #8,d5
            bra.s   strout

v_grafon:   lea     v_grdat(pc),a2      ;Grafikmodus für vert. HC ein 
            moveq   #8,d5
            bra.s   strout

sendcr:     lea     feed(pc),a2         ;Zeilenvorschub
            moveq   #1,d5
            bra.s   strout

setlf:      lea     lfdat(pc),a2        ;Zeilenvorschub für Grafik ein 
            moveq   #2,d5
            bra.s   strout

reslf:      lea     oldlf(pc),a2        ;Normalen Zeilenvorschub hersteilen 
            moveq   #1,d5

strout:     move.b  (a2)+,d4            ;gibt durch a2 adr. String
            bsr     chrout              ;mit Lg.d5+1 aus
            dbra    d5,strout
endrout:    rts

            DATA

lfdat:      DC.B 27,'3',24
oldlf:      DC.B 27,'2'
grafdat:    DC.B 27,36,20,0,27,'*',39,0,5
v_grdat:    DC.B 27,36,30,0,27,'*',39,176,4
feed:       DC.B 13,10
status:     DC.B $FF
meldung:    DC.B 13,10,27,'K',13,10
            DC.B 9,27,'p','HC-FIX',27,'q',' V 1.3 installiert, (c) MAXON Computer 1989',27,'K' ,13,10 
            DC.B 9,'von Marcus Kraft, Niederramstädterstr. 187, 61 Darmstadt'
            DC.B 27,'K',13,10,27,'K',0 
            EVEN

            BSS

old_ierb:   DS.B 1 
mode:       DS.B 1
mfp_vec0:   DS.L 1 
old_sp:     DS.L 1
new_sp:     DS.L 1
anfadr:     DS.L 1
endstack:   DS.W 400 
mystack:    DS.W 1
puffer:     DS.B 32640  ;Puffer für Bildschirmsp.

            END

Marcus Kraft
Aus: ST-Computer 12 / 1989, Seite 88

Links

Copyright-Bestimmungen: siehe Über diese Seite