Residente 3fach-Hardcopy für 9-Nadeldrucker

Angeregt von einer Veröffentlichung in der Programmierpraxis in GFA-BASIC (Michael Kraus, Hardcopy für 9-Nadler, 12/88, S.88 f.) und in Erinnerung an ein älteres, etwas langsames, in Pascal erstelltes Programm aus der ST-PD-Sammlung (HACOMINI.TOS), wollte ich endlich einmal die Aufgabe, Hardcopies in besonderen Formaten auszugeben, a.) in ‘Assembler’ lösen und b.) als jederzeit abrufbare residente Routine gestalten (Start des Programms aus dem AUTO-Ordner).

Zwar graute mir insgeheim vor Seiten voller endloser Move-Befehle, mit denen ich jede einzelne Nadel mit jedem einzelnen Pixel bestücken müßte, doch faßte ich mir schließlich ein Herz und griff zum Druckerhandbuch samt Bleistift und Papier. Und siehe da, bald stellte sich heraus, daß bei einigermaßen geschickter Organisation alles nicht einmal halb so schlimm war, wie befürchtet: Es fing sogar an, Spaß zu machen!

Da der Computer auf jeden Fall sehr viel schneller sein würde als der Drucker, wurde die Kompaktheit des zu erzeugenden Codes höher bewertet als die reine Ablaufgeschwindigkeit. Der Registersatz des MC68K wurde wie üblich weitgehend ausgenutzt. Für Mini- und Midicopy entspricht das Vorgehen im Programm der Beschreibung in dem zitierten Artikel von M. Kraus.

Das Problem, die in den waagerechten Zeilen liegenden Pixel (oder Bits in den Bytes des Bildschirmspeichers) in eine für die Beschickung der Druckernadeln notwendige ‘senkrechte' Anordnung zu bekommen, wurde mit dem LSL-Befehl gelöst (in der Kernroutine der Minicopy steht add.w d0,d0 statt lsl.w #1,d0, es bewirkt das gleiche, ist nur kürzer und schneller!). So ergaben sich für die Hauptroutine der Minicopy fünf ineinandergeschachtelte DBF-Schleifen. Das Programm läuft von oben gleich in die innerste Schleife, wobei die Werte für die Auflösung und die Register (Schleifenzähler) vorbesetzt werden. Hier werden nun die Pixel, der Anzahl der druckenden Nadeln (D2) entsprechend, in D1 akkumuliert, beginnend in der äußersten Ecke oben links, im 3-Zeilen-Versatz (‘innerer Bildschirmzeiger' A3), und an den Drucker geschickt. D3 ist der Bitzähler (im Byte), und wenn er heruntergezählt ist, muß das nächste Byte geholt werden, das Ganze 80mal (D4), dann ist die oberste Zeile abgegrast (und natürlich auch acht weitere im 3-Zeilen-Versatz). Jetzt wird ein Mikro-Papiervorschub gemacht, und das Ganze noch zweimal (D5) jeweils eine Zeile tiefer wiederholt. Nun kann nach einem größeren Papiervorschub der ‘äußere Bildschirmzeiger' (A4) entsprechend weiter positioniert werden: Es wird der nächste Block hereingeholt, Ablauf wie oben, das Ganze insgesamt 16,7mal (D6). Um eine Sonderroutine für das letzte Bruchstück zu sparen und dennoch nicht etwa außerhalb des Bildschirmspeichers befindliche Daten zu Papier kommen zu lassen, wird einfach in der innersten Schleife abgefragt, ob sich die entsprechende Adresse überhaupt noch innerhalb des Bildschirms befindet (Bildschirmendadresse A6). Das geht in ‘Assembler' so kurz und schnell (4 Byte & 16/18 Taktzyklen), daß man es unbeschwert machen kann. Der Druckkopf bewegt sich sowieso nur, wenn es auch etwas zu drucken gibt. Dann noch ein Glocken- oder Piepston, und wir wären fertig!

Die Hauptroutine der Midicopy ist ganz analog programmiert, nur daß hier das vorher noch freie Register D7 als Schalter benutzt wird, um zwischen den ungeraden und den geraden Nadeln umzuschalten und, falls notwendig, einen zusätzlichen Papiervorschub auszuführen. Die Einzelheiten sind hoffentlich recht klar dem im Motorola-Standard gehaltenen Quelltext zu entnehmen.

Das einzige noch nicht genutzte ‘sichere’ Register ist A5, und das könnte von AS68-Anwendern auf Null gesetzt und zur - für diesen verbreiteten Assembler zwecks Optimierung notwendigen - relativen Adressierung der Systemvariablen genutzt werden, so wie es auch im TOS üblich ist.

Mini- und Midicopy sind, wie übrigens auch die Desktop-Hardcopy, in der Höhe um etwa 11% gestreckt, das liegt an der unterschiedlichen horizontalen und vertikalen Schrittweite der 9-Nadler (1/ 240” oder 1/120” bzw. 1/216” oder 1/108 “). Kreise erscheinen also als senkrecht stehende Ellipsen etc.. Nun gibt es aber auch eine Dichte mit gleicher Schrittweite in beiden Richtungen: die (beim NL10) sogenannte Plotterdichte mit 72 dpi, das entspricht genau dem Abstand der Nadeln im Druckkopf! Da ich nun schon einmal dabei war, wurde die ‘Plotcopy’ auch noch gleich programmiert.

Die Plotcopy muß wegen ihrer Abmessungen (ca. 11% lineare Vergrößerung in Bezug auf den Bildschirm) längs aufs DIN A4- Blatt gedruckt werden. Wenn man dabei unten links anfängt, braucht man beim Programmieren auch nicht die Bits in den Bytes (diesmal um 180°) zu drehen, sondern kann sich so bedienen, wie es da so schön im Speicher liegt: 80 Reihen zu je 400 Bytes, das geht sogar glatt auf, und so wurde es die kürzeste der drei Routinen.

Von diesen drei Hardcopy-Routinen wurden die gemeinsamen Teile nun zusammengefaßt und optimiert, und das Ganze mit einem gemeinsamen Kopf versehen, der u.a. die folgenden Aufgaben zu erfüllen hat:

  1. Identifikations-ASCII-String vor dem Einstieg bereitstellen
  2. wenn kein monochromer Grafikmodus, Programm verlassen. (Falls der Grafikmodus ohne Reset gewechselt wurde! Wie sinnvoll so etwas ist, kann ich nicht beurteilen, aber es gibt ja inzwischen diese Umschalter.)
  3. savptr retten und Platz für BIOS-Stack zuweisen
  4. wenn Drucker nicht bereit, Programm verlassen
  5. Bildschirmadresse feststellen
  6. feststellen, welche der drei Routinen angewählt ist

Um die Routinen nun auf Tastendruck jederzeit abrufbar zur Verfügung zu haben, sollte ein VBI (Vertical Blank Interrupt)-Slot belegt werden. Routinen, die so eingebunden sind, werden normalerweise (d.h. wenn sie nicht gerade gesperrt sind) bei jedem Vertikalrücklauf einmal abgearbeitet. Der Prozessor befindet sich dabei im Supervisor-Status, und die Routine muß mit RTS beendet werden (für Einzelheiten siehe Jankowski/Reschke/Rabich. ATARI ST Profibuch II, S. 177f.).

Um das Programm also dort zu verankern, mußte folglich ein Lader erstellt werden, der die folgenden Voraussetzungen erfüllen sollte:

  1. wenn keine 640*400 Auflösung im monochromen Modus, nicht laden
  2. wenn keine Slots vorhanden, nicht laden. Es wurde darauf verzichtet, welche einzurichten: Da defaultmäßig 8 Slots vorhanden sein sollten, muß ein anderes Programm nvbls auf Null gesetzt haben
  3. Wenn keine freien Slots vorhanden, nicht laden. Es wurde darauf verzichtet, die Liste evtl. zu verschieben und neue Slots einzurichten oder sich (inkorrekt!) zusätzlich in ein Slot ‘einzuklinken': Wenn der Zug schon so überfüllt ist, wollen wir mal lieber verzichten
  4. falls Programm schon geladen, nicht nochmals laden, aber Meldung und Bedienungsanleitung ausgeben, sowie auf Taste warten
  5. falls Programm geladen wird, gleich noch die Gelegenheit beim Schopfe packen und die ALT-HELP Standard-Hardcopy auf Epson-Drucker setzen. Meldung mit Anleitung ausgeben, dabei nicht auf Taste warten: Das Programm ist zum Start aus dem AUTO-Ordner vorgesehen!
  6. er Lader selbst soll nicht resident gehalten, sondern nach Gebrauch weggeworfen werden
  7. für die Fälle 1. bis 3. Fehlermeldung ausgeben und auf Taste warten, sowie negativen ‘retcode' an aufrufendes Programm übergeben

Die hier geübte Art der Behandlung der VBI-Slots wurde übrigens dem VBI-Handler des Betriebssystems nachempfunden.

Punkt 1. im Pflichtenheft des Laders und Punkt 2. im eigentlichen Programmkopf sind notwendig, weil das Programm nur eine einfache ‘Bit-Ebene' von 640*400 Elementen zum Drucker schaufeln kann: Das würde bei einer anderen (mittlerer oder niedriger) Auflösung zur Ausgabe von ‘Datenschrott' führen.

Zur Ermittlung des Grafikmodus' kann man hier direkt die Variable sshiftmd ($44C, sollte 2 sein) auslesen, weil sich der Prozessor ohnehin im Supervisormodus befindet. Das geht schneller und ist kürzer als der Aufruf der XBIOS-Funktion #4 Getrez, die übrigens auch nichts anderes tut. Doch da stellt sich nun folgendes Problem:

Was die hohe Auflösung betrifft, so gibt es ja neuerdings auch andere als die in der ATARI-Originaldokumentation erwähnten 640400 Pixel, z.B. 1280960 Pixel beim Anschluß eines Matscreen / M110 Großbild-Monitors. In GEM-Programmen ist dies kein Problem, da man die entsprechenden Parameter der Screen-Workstation ja leicht abfragen kann. In TOS-Programmen kann man sich mit der Abfrage dreier sog. Line-A- oder VDI-ESC-Variablen behelfen (Jankowski et al., op. cit., S.224 ff.). Also in ‘Assembler' etwa so:

Abfrage auf Bildschirmgröße 640*400 Pixel, monochrom

dc.w $A000      ; Line-A Basisadresse holen 
cmpi.w #1,(a0)  ; Anz. der Bildschirmebenen = 1 ? 
bne out         ;nein ? -> raus

cmpi.w #640,-12(a0) ; horizontale Auflösung = 640 ? 
bne out         ;nein ? -> raus

cmpi.w #400,-4(a0) ; vertikale Auflösung = 400 ? 
bne out         ;nein ? -> raus

Diese Werte sind erfreulicherweise schon vor der Initialisierung des GEM-AES vorhanden! Also auch beim Start eines Programmes aus dem AUTO-Ordner, ebenfalls beim Start vom COMMAND.PRG aus, wenn dies durch Setzen von _cmdload ($482) aus dem Bootsektor oder aus dem AUTO-Ordner gestartet wurde. Bis ATARI hier selbst einen anderen Vorschlag macht oder eine Variable für OEM-Auflösung deklariert, sollte man diese Möglichkeit nutzen, um die korrekte, systemkonforme Programmierung zu unterstützen. Ob man auf die Benutzung der entsprechenden XBIOS-Funktion dann möglicherweise verzichten könnte, ist (auch) eine Frage der Interpretation ihrer Bedeutung: Bezieht sie sich auf die Auflösung in Pixeln (Bildschirmbreite mal -höhe) oder die Anzahl der Bitebenen (1, 2 oder 4 entsprechend monochrom, 4 oder 16 Farben), d.h. die Organisation des Bildschirmspeichers? Den mir bekannten Originaldokumenten ist das nicht explizit zu entnehmen: Damals dachte man wahrscheinlich weder an die Implementierung eines ‘offenen Systems’ (Mega-Bus) noch an die softwaremäßige Nutzung anderer als der drei Standardauflösungen. Hardwaremäßige Überlegungen jedoch, sowie die Analyse der entsprechenden Routinen des Betriebssystems lassen den Schluß zu, daß man ‘Getrez’ besser in ‘Getshiftmd’ umbenennen und dann auch in diesem Sinne verwenden sollte [Hierzu siehe auch: Jankowski et al., op. cit., S.664 ff., Julian Reschke, Der weiche Großbildschirm, ST Magazin (M&T) 11188, S.76f und Arnd Beissner, Höhere Auflösung -mehr Farben, dgl. 12/88, S. 158f.]

Bliebe noch das Problem des nicht wiedereintrittsfähigen BIOS/XBIOS- Traphandlers zu erklären: Falls man aus dem Interrupt BIOS/XBIOS-Funktionen aufrufen möchte, muß man zuvor den ‘BIOS save area’-Vektor savptr ($4A2) umsetzen und einen neuen BIOS-Stackbereich einrichten: Für einfache Tiefe genügen 46 Bytes - 10 Register, PC & SR - bei erwarteter tieferer Rekursion entsprechend mehr (siehe dazu auch Kramer et al.. Das TOS-Listing, S.22 ff. & S.84 und Alex Esser, Die System-Variablen des TOS, Teil 2, ST Computer 12/88, S.126 ff.). Nach Ablauf der Routine wird dann alles wieder in den alten Zustand zurückversetzt.

Was die Shift-Tastenkombinationen betrifft, die ich hier gewählt habe, um die verschiedenen Hardcopies auszulösen, so kann sich das ja ein jeder so zusammenstellen, daß es bei ihm nicht mit anderen Anwendungen kollidiert. Auch Kombinationen mit anderen ‘richtigen’ Tasten sind natürlich denkbar, dann wird die Programmierung der Abfrage allerdings etwas aufwendiger. Man könnte die Routinen natürlich auch auf ganz andere Weise laden, sie z.B. in den scr_dump ($502) einklinken, dort eine Abfrage mit Verzweigung und evtl. eine Möglichkeit zum Abbruch vorsehen etc. p.p....

In der Praxis erweist es sich als angenehm, daß das Programm sofort zurückkehrt, wenn der Drucker nicht aufnahmebereit ist. Es wird erst dann die übliche halbe Minute gewartet, wenn die Ausgabe bereits begonnen hat und man danach den Drucker ‘offline’ schaltet.

Wem das nicht gefällt, der kann die Funktion bcostat ja herausnehmen.

Was die Qualität des Ausdrucks betrifft, so ist Minicopy (4-fache Dichte) gut für Strichzeichnungen bzw. Text geeignet (ich habe z.B. zum Spaß den Quelltext des Programms damit ausgedruckt, das war recht scharf und gut lesbar!). Gerastertes Grau hingegen, wie z.B. der Desktop-Hintergrund, läuft ziemlich zu, es sei denn, man hielte ein gut ‘ausgelutschtes’ Farbband bereit, was zu diesem Zweck sowieso vorzuziehen ist. Damit könnte man sich dann z.B. einen netten Bilderkatalog drucken. Midicopy (2fache Dichte) eignet sich auch oder gerade mit etwas frischerem Farbband für gut abgestufte Rasterbilder und schöne Strichschwärze, während man bei Plotcopy (Plotterdichte) auch schon die dichtgepackten Punkte einzeln erkennen kann und deshalb hier nur ein gutes Farbband zu empfehlen ist. Hier hat man gegenüber der Standard-Hardcopy jedoch den Vorteil der Aspekttreue (d.h. gleiches Verhältnis Breite/Höhe), und daß wieder jedem Pixel ein Punkt auf dem Papier entspricht.

Absichtlich habe ich darauf verzichtet, die Routinen mit Kinkerlitzchen wie z.B. Einstellen des linken Randes, diversen Papiervorschüben, Formfeeds etc. auszustatten, das sollte sich jeder nach seinem Gusto einrichten. Es kam mir hier nur darauf an, die - bei Wahrung der Übersichtlichkeit - hochoptimierten Kernroutinen und beispielhaft die korrekte Einbindung einer VBI-Slot-Routine mit Betriebssystemaufrufen sowie die exakte Abfrage auf die aktuelle Bildschirmgröße in TOS-Programmen zu demonstrieren, der Rest ist mehr oder weniger beliebig.

* --------------------------------------------------
* SCRNCOPY.S VBI-Slot residente 3-fach Hardcopy-Routine für STAR-NL10
* & andere EPSON-FX80 kompatible Drucker © MAXON Computer GmbH br 15.2.89
* ----—---------------------------------------------
start:      bra     install     ; -> Installation
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ----—---------------------------------------------
* residente Routine
* --------------------------------------------------
            dc.l    'SCRN'      ;Programmidentifikation
            dc.l    'COPY'      ;desgleichen

begin:      cmpi.b  #2,$44C     ;sshiftmd=monochr?
            bne.s   out         ;nein ? -> raus

            move.l  $4A2,savptr ;BIOS save area retten
            move.l  #savptr,$4A2;neuen BIOS-Stack besorgen

            clr.w   -(sp)       ;PRT
            move.w  #8,-(sp)    ;Bcostat
            trap    #13         ;BIOS
            addq.l  #4,sp       ;SP restaurieren

            tst.w   d0          ;Drucker bereit?
            beq.s   getout      ;nein ? -> raus

            move.l  $44E,a4     ;_v_bas_ad= Screenadresse
            move.l  a4,a6
            lea     31999(a6),a6;letztes Byte des Bildschirms

status:     move.w  #-1,-(sp)   ;mode: Status abfragen 
            move.w  #$B,-(sp)   ;Kbshift
            trap    #$D ;BIOS
            addq.l  #4,sp       ;SP restaurieren

            andi.b  #$F,d0      ;obere 4 Bits ausmaskieren 
            cmpi.b  #5,d0       ;SHIFT R - CTRL?
            beq.s   minicop     ;-> Minicopy

            cmpi.b  #3,d0       ;SHIFT R-SHIFT L?
            beq     midicop     ;-> Midicopy

            cmpi.b  #9,d0       ;SHIFT R - ALT?
            beq     plotcop     ;-> Plotcopy

getout:     move.l  savptr(pc),$4A2 ;BIOS save area zurückschreiben
out:        rts
* -----------------------—-----------------------—--
* gemeinsame Variablen & Unterroutinen
* -----------------------—-----------------------—--
resolve:    dc.w    0           ;
n1bytes:    dc.w    0           ;in grafmod ben.
n2bytes:    dc.w    0           ;
* -----------------------—-----------------------—--
grafmod:    moveq   #27,d0      ;ESC
            bsr.s   bconout     ;zum Drucker
            moveq   #42,d0      ;'*' = Grafikmodus
            bsr.s   bconout     ;zum Drucker
            move.w  resolve(pc),d0 ;n0 = Grafik-Auflösung 
            bsr.s   bconout     ;zum Drucker
            move.w  n1bytes(pc),d0 ;n1: siehe n2 
            bsr.s   bconout     ;zum Drucker
            move.w  n2bytes(pc),d0 ;n2: n1+256*n2 = Anzahl Bytes 
            bra.s   bconout     ;zum Drucker

papfeed:    moveq   #27,d0      ;ESC
            bsr.s   bconout     ;zum Drucker
            moveq   #74,d0      ;'J'=n/216" feed
            bsr.s   bconout     ;zum Drucker
            move.w  d3,d0       ;n
            bsr.s   bconout     ;zum Drucker
            moveq   #13,d0      ;CR

bconout:    move.w  d0,-(sp)    ;char
            clr.w   -(sp)       ;dev = PRT
            move.w  #3,-(sp)    ;Bconout
            trap    #13         ;BIOS
            addq.l  #6,sp       ;SP restaurieren
            rts

* -----------------------—-----------------------—--
* + + + + + + + + + + + +   Hauptroutine Minicopy
* -----------------------—-----------------------—--
minicop:    move.w  #3,resolve  ;n0 = Auflösung = 240 dpi 
            move.w  #128,n1bytes;n1 = 128 
            move.w  #2,n2bytes  ;n1+n2*256=640 Bytes senden

            moveq   #16,d6      ;Anzahl Blöcke (17)
nex1bloc:   moveq   #2,d5       ;Anzahl Microfeed-Zeilen = 3
nex1row:    moveq   #79,d4      ;Anzahl Bytes in Zeile = 80 
            bsr     grafmod     ;Grafikmodus einschalten
nex1byte:   moveq   #7,d3       ;Anzahl Bits im Byte = 8
get1col:    moveq   #7,d2       ;Anzahl druckender Nadeln = 8 
            moveq   #0,d0       ;für das zu druckende Byte lösch, 
            move.l  a4,a3       ;Bildschirmzeiger setzen
get1pix:    add.w   d0,d0       ;1 Bit nach links schieben
            move.b  (a3),d1     ;Byte holen
            btst    d3,d1       ;Bitnummer im Byte
            beq.s   no1set      ;0 ? -> weiter

            cmpa.l  a6,a3       ;Ende des Bildsch.
            bgt.s   no1set      ;nicht im Bereich? -> weiter

            addq.w  #1,d0       ;letztes Bit setzen &
no1set:     lea     240(a3),a3  ;3 Zeilen vorrücken 
            dbf     d2,get1pix  ;8 mal für 8 Nadeln

            bsr     bconout     ;fertiges Byte in D0 zum Drucker 
            dbf     d3,get1col  ;8 mal für 8 Bits pro Byte

            addq.l  #1,a4       ;nächstes Byte in Bildschirmzeile 
            dbf     d4,nexlbyte ;80 mal für 80 Bytes pro Zeile

            moveq   #1,d3       ;1/216" Micro-
            bsr     papfeed     ;Papiervorschub
            dbf     d5,nex1row  ;nächste Zeile von 80 Bytes

            lea     1680(a4),a4 ;zum nächsten Block
            moveq   #21,d3      ;21/216"
            bsr     papfeed     ;großer Vorschub
            dbf     d6,nex1bloc ;17 mal das Ganze für Bildschirm

            moveq   #7,d0       ;BEL
            bsr     bconout     ;zum Drucker
            bra     getout      ;fertig

* -----------------------—-----------------------—--
* + + + + + + + + + + + +   Hauptroutine Midicopy
* -----------------------—-----------------------—--
midicop:    move.w  #1,resolve  ;n0 = Auflösung = 120 dpi
            move.w  #128,n1bytes;n1 = 128
            move.w  #2,n2bytes  ;+2*256=640 Bytes senden

            moveq   #0,d7       ;D7 als Schalter
            moveq   #33,d6      ;Anzahl Blöcke(34)
nex2bloc:   not.w   d7          ;D7 umschalten
            moveq   #2,d5       ;Anzahl Microfeed-Zeilen = 3
nex2row:    moveq   #79,d4      ;Anzahl Bytes in Zeile = 80 
            bsr     grafmod     ;Grafikmodus einschalten
nex2byte:   moveq   #7,d3       ;Anzahl Bits im Byte = 8
get2col:    moveq   #3,d2       ;Anzahl druckender Nadeln = 4 
            moveq   #0,d0       ;für das zu druckende Byte lösch.
            move.l  a4,a3       ;Bildschirmzeiger initialisieren
get2pix:    lsl.w   #2,d0       ;2 bit schieben Nadeln 6,4,2,0 
            move.b  (a3),d1     ;Byte holen
            btst    d3,d1       ;Bitnummer im Byte
            beq.s   no2set      ;0 ? -> nächstes Pixel

            cmpa.l  a6,a3       ;Ende des Bildschirms - 1 ? 
            bgt.s   no2set      ;nicht im Bereich? -> weiter

            addq.w  #1,d0       ;letztes Bit setzen &
no2set:     lea     240(a3),a3  ;3 Zeilen vor
            dbf     d2,get2pix  ;4 mal für 4 Nadeln

            tst.w   d7          ;gesetzt ?
            beq.s   output      ;nein ? -> Nadeln 6,4,2,0

            add.w   d0,d0       ;1 bit schieben Nadeln 7,5,3,1 
output:     bsr     bconout     ;fertiges Byte zum Drucker (D0) 
            dbf     d3,get2col  ;8 mal für 8 Bits im Byte

            addq.l  #1,a4       ;1 Byte vor
            dbf     d4,nex2byte ;80 mal für die Zeile

            moveq   #2,d3       ;2/216" Micro-
            bsr     papfeed     ;Papiervorschub
            dbf     d5,nex2row  ;nächste Zeile von 80 bytes

            lea     720(a4),a4  ;zum nächsten Blk.
            tst.w   d7          ;gesetzt ?
            bne.s   short       ;ja ? -> benutzte Nadeln 7,5,3,1

            moveq   #6,d3       ;6/216"
            bsr     papfeed     ;Zusatzvorschub beim Nadelwechsel 
short:      moveq   #15,d3      ;15/216" | gerade -> ungerade 
            bsr     papfeed     ;großer Papiervorschub
            dbf     d6,nex2bloc ;34 mal die ganze Geschichte

            moveq   #7,d0       ;BEL
            bsr     bconout     ;zum Drucker
            bra     getout      ;na endlich
* -----------------------—-----------------------—--
* + + + + + + + + + + + +   Hauptroutine Plotcopy
* -----------------------—-----------------------—--
plotcop:    move.w  #5,resolve  ;n0 = Auflösung 72 dots per inch 
            move.w  #144,n1bytes ;n1 = 144
            move.w  #1,n2bytes  ;n1+n2*256=400 Bytes senden

            movea.l a6,a3       ;letztes Byte des Bildschirms 
            addq.l  #1,a3       ;+1:gerade draußen
            moveq   #79,d5      ;Anzahl (senkr.) Bytereihen
getrow:     move.w  #399,d4     ;Anzahl Bytes in einer Reihe
            bsr     grafmod     ;Grafikmodus  einschalten
getbyte:    lea     -80(a3),a3  ;nächstes Byte
            move.b  (a3),d0     ;Beginn in linker unterer Ecke 
            bsr     bconout     ;zum Drucker
            dbf     d4,getbyte  ;400 mal=1(senkr.) Reihe waagerecht 
                                ;aufs Papier drucken
            lea     32001(a3),a3;nächste Reihe ansteuern
            moveq   #24,d3      ;24/216" = 8/72"
            bsr     papfeed     ;Papiervorschub
            dbf     d5,getrow   ;80 Reihen a 400 Bytes = Bildsch.

            moveq   #7,d0       ;BEL
            bsr     bconout     ;zum Drucker

            bra     getout      ;das war's

* -----------------------—-----------------------—--
filler:     dc.l 0,0,0,0,0,0,0,0,0,0,0,0    ;neuer BIOS-Stack Bereich (12 .L) 
savptr:     dc.l 0                          ;alte BIOS save area Adresse
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* -----------------------—-----------------------—--
*  Installlationsroutine
* -----------------------—-----------------------—--
install:    clr.l   -(sp)       ;stack->superstack
            move.w  #$20,-(sp)  ;Super
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren
            move.l  d0,-(sp)    ;alten SSP auf den Stack retten

            dc.w    $A000       ;Line-A Basisadresse holen 
            cmpi.w  #1,(a0)     ;Anzahl der Bildschirmebenen=1? 
            bne     out         ;nein ? -> raus

            cmpi.w  #640,-12(a0);horizontale Auflösung=640? 
            bne     out         ;nein ? -> raus

            cmpi.w  #400,-4(a0) ;vertikale Auflösung=400? 
            bne     out         ;nein ? -> raus

            move.w  $454,d6     ;nvbls
            beq     noslot      ;kein Slot da? -> raus
            subq.l  #2,d6       ;Zähler für dbf Schleife 
            movea.l $456,a0     ;_vblqueue
            addq.l  #4,a0       ;erstes Slot auslassen (VDI) 
getslot:    movea.l (a0)+,a1    ;Eintrag holen
            cmpa.l  #0,a1       ;steht was drin?
            beq.s   action      ;nichts da? -> installieren!

            cmpi.l  #$5343524E,-8(a1) ; 'SCRN' schon da ? 
            bne.s   again       ;nein -> weiter

            cmpi.l  #$434F5059,-4(a1) ;'COPY' ?
            beq.s   donot       ;schon da? -> laß es!

again:      dbf     d6,getslot  ;nächstes Slot
        
            bra.s   noslot      ;kein freies Slot mehr da !
* -----------------------—-----------------------—--
action:     lea     begin(pc),a1;Startadresse des residenten Teils 
            move.l  a1,-4(a0)   ;ins VBI-Slot eintragen
            move.w  #$20,-(sp)  ;Super->User (SSP auf dem Stack!) 
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            move.w  #4,-(sp)    ;Epson-Drucker
            move.w  #$21,-(sp)  ;Setprt
            trap    #14         ;XBIOS
            addq.l  #4,sp       ;SP restaurieren

            pea     string1(pc) ;Meldung und Anleitung zeigen 
            move    #9,-(sp)    ;Cconws
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            lea     start(pc),a0;halte Code von hier
            lea     install(pc),a1 ;bis zu dieser Marke
            suba.l  a0,a1       ;Rest wegwerfen
            lea     $100(a1),a1 ;für die Basepage

            clr.w   -(sp)       ;retcode=0
            move.l  a1,-(sp)    ;keep: Anzahl von Bytes v. p_lowtpa 
            move.w  #$31,-(sp)  ;Ptermres
            trap    #1          ;GEMDOS
* -----------------------—-----------------------—--
donot:      move.w  #$20,-(sp)  ;Super->User (SSP auf dem Stack!) 
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            pea     string1(pc) ;Meldung und Anleitung zeigen 
            move    #9,-(sp)    ;Cconws
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            move.w  #7,-(sp)    ;Crawcin: auf Taste warten 
            trap    #1          ;GEMDOS

            clr.w   -(sp)       ;Pterm0
            trap    #1          ;GEMDOS
* -----------------------—-----------------------—--
noslot:     move.w  #$20,-(sp)  ;Super->User (SSP auf dem Stack!) 
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            pea     string2(pc) ;Fehlermeldung
            move    #9,-(sp)    ;Cconws
            trap    #1          ;GEMDOS
            addq.l  #6,sp       ;SP restaurieren

            move.w  #7,-(sp)    ;Crawcin: auf Taste warten 
            trap    #1          ;GEMDOS
            addq.l  #2,sp       ;SP restaurieren

            move.w  #-1,-(sp)   ;retcode-1:Fehler!
            move.w  #$4C,-(sp)  ;Pterm()
            trap    #1          ;GEMDOS
* -----------------------—-----------------------—--
string1:    dc.b    27,'v',13,10
            dc.b    '3-fach Hardcopy (9N) pd by br 0 2/89 |'
            dc.b    ' RSHFT-CTRL -> Minicopy ~ 6,8 * 4,7 cm2',13 
            dc.b    'RSHFT-ALT-> Plotcopy ~ 22,6 * 14, 1 cm2|'
            dc.b    ' RSHFT-LSHFT -> Midicopy ~ 13,6 * 9,4 cm2',13,10,7,0

string2:    dc.b 13,10,'SCRNCOPY nicht installiert! [Taste] ',13,10,7,0 
* -----------------------—-----------------------—--

Bernd Rosenlecher
Aus: ST-Computer 09 / 1989, Seite 94

Links

Copyright-Bestimmungen: siehe Über diese Seite