Laseransteuerung - Direkt gepunktet

Fast jeder Programmierer wird früher oder später sein Prunkstück von Programm mit Druckertreibern ausstatten. Wenn dabei Ataris Laserdrucker »SLM 804« oder SLM 605 angesteuert werden sollen, gibt es für die Grafikausgabe nur den »legalen« Weg über GDOS oder über einen der mitgelieferten Druckeremulatoren. Wer sich nicht auf die Erzeugnisse der Atari-Software-Klempnerei verlassen will oder kann, dem bleibt nur der direkte Sprung ins heiße Herz der feinen Laserstrahler Unser kommentiertes Assemblerlisting hilft Ihnen und dem Atari-Laser auf die Sprünge und zeigt außerdem, wie Sie die größere Auflösung 600 x 300 dpi des Marvin-Laserkit nutzen können.

Wie man mit wenig Hirn und großer Masse erfolgreich durchs Leben kommt, haben die urzeitlichen Dinosaurier bewiesen. Zumindest über eine lange Zeit, denn irgendwann sind sie ja bekanntlich aus noch nicht völlig geklärten Gründen in der Versenkung der Erdgeschichte verschwunden.

Wie man ohne Hirn und mit viel Power einen erfolgreichen Laserdrucker auf dem Markt etabliert, hat die vereinigte »Brainpower« von Ataris Entwicklungs- und Marketingabteilung bewiesen. Das Konzept des hirnlosen Laserpixlers mit schlummernder Dinosaurierkraft in puncto Druckgeschwindigkeit und Pixelauflösung hat sich im Bereich der Atari-Computer durchgesetzt.

Die beiden Laserdrucker-Dinosaurier SLM804 und SLM605 aus dem Hause Atari arbeiten ohne eigenen Mikroprozessor und verlassen sich bekanntlich voll und ganz auf die Macht des sie steuernden Computerhirns ST und TT. Zur vollendeten Umsetzung der Idee ist allerdings einiges an »Gehirnschmalz« notwendig, das von den Programmieren in die Verbindung einzubringen ist.

Zum Lieferumfang der Atari-Laserdrucker gehören zwei Druckeremulatoren (bezeichnenderweise trägt ein Emulator den Namen »Laserbrain«) und der GDOS-Treiber. Diese »Zwischenhirne« schaffen eine Verständigungsbrücke zwischen Programm und Laserdrucker, indem sie per Software die Steuersignale bestimmter Druckerstandards an die Bedürfnisse des unintelligenten Laserdruckwerks anpassen. Wer sich als Programmierer mit den Leistungen dieser Emulatoren nicht zufriedengeben will, muß sein Programm mit einem eigenen Assemblerhirn für den Laserdrucker ausstatten.

Leider existiert nur wenig Literatur über die Laserdruckeransteuerung, und häufig hagelt es auch Bomben, wenn man beispielsweise die GDOS-Version wechselt. Möchte man zu allem Überfluß die auf 600 x 300 dpi erhöhte Auflösung des 600-dpi-Kit der »Marvin AG« nutzen (Bezug über »Richter Distributor« in Gevelsberg), lohnt es, sich mit der direkten Programmierung des SLM804 auseinanderzusetzen.

Der Atari-Laserdrucker ist über den DMA-Bus mit dem »ST« oder »TT« verbunden. Mit diesem Bus betreibt man bekanntlich bis zu acht Geräte gleichzeitig. Jeder »Teilnehmer« wird über seine »Telefon«-Nummer angewählt.

Der Atari-Laserdrucker wird meist mit der Gerätenummer 5 oder 7 ausgeliefert. Hat man dann endlich herausgefunden, ob und unter welcher Nummer der Laser zu erreichen ist, beginnt man einen informativen Dialog, fragt nach seinem Befinden (Blattgröße ... ) und teilt ihm unsere sehnlichsten Wünsche mit (300 oder 600 dpi, ...). Worauf der Laser es kaum noch erwarten kann, unsere Bitmap in sich »hineinzuschlürfen«.

Bis dahin ist es jedoch ein weiter Assembler-Weg:

Die Adressen für die Hardware-Register sind hoffentlich selbsterklärend:

DMADATA EQU $FFFF8604
DMAMODE EQU $FFFF8606
DMAHIGH EQU $FFFF8609
DMAMID EQU $FFFF860B
DMALOW EQU $FFFF860D
SOUND EQU $FFFF8800
GPIP EQU SFFFFFAO1
ACIACTRL EQU $FFFFFC02

; Systemvariablen

Hz200 EQU $04BA
flock EQU S043E

; Befehle an den Laser-Controller

PRINT EQU $OA
INQUIRY EQU $12
M_SELECT EQU $15
M_SENSE EQU $1A

Die folgende Programmzeile dient lediglich Testzwecken. Sie verzweigt in ein kleines Assembler-Programm am Ende des Listings, das unser Hausprogrammierer Michael Bernards für uns entworfen hat. Das Assembler-Programm erzeugt eine Bitmap (senkrechte Streifen) und gibt sie wahlweise mit 300 dpi oder 600 x 300 dpi auf dem SLM804 aus:

 jmp slm_test

Zunächst jedoch weiter in den Ansteuerungsroutinen. Zu Beginn müssen wir einige grundlegende Routinen bereitstellen, die auch für Festplattenstationen verwendet werden können. Eine genaue Dokumentation kann man z.B. im »Atari ST Profibuch« oder dem »Scheibenkleister« nachlesen.

Da wäre zunächst einmal eine Routine, die ein Byte über den ACSI-Bus jagt. In D0 stehen sowohl das Byte selbst (Highword) als auch der Status für das Mode-Select-Register (Lowword). Nach dem Abschicken wird auf die Quittung vom Device gewartet. Hat in unserem Fall der Laser das Byte erhalten, liefert er den Wert 0 zurück, andernfalls -1:

wcbyte:move.l D0, DMADATA.w ; Schreibe in CAC und DMA-Mode
       move.w #$64, D1
wwait: dbra D1, wwait    ; Moment warten
       move.l #$0A,D1    ; Zähler für Timeout setzen
       add.l HZ200.w, D1 ; Timeout nach 10 * 5 = 50 msec
       moveq #0, D0      ; default return = TRUE
ww_1:  btst #5, GPIP.w   ; INT aufgetreten?
       beq.b wend        ; Ja -> alles in Ordnung
       cmp.l HZ200.w, D1 ; Timeout?
       bpl.b ww_1
       moveq #-1, D0     ; return Timeout
wend:  rts

rsbyte ist das Gegenstück zu wcbyte! Diese Routine wartet auf ein Byte vom Laser. Bei Timeout wird -1 zurückgeliefert. Ein positiver Rückgabewert repräsentiert das gelesene Byte:

rsbyte:
 move.w #$64, D0 ; Moment warten
rbyte:
 dbra D0, rbyte
 move.l #$0A, D0 ; Timeout
 add.l HZ200.w, D0
rwbyte:
 btst #5, GPIP.w ; Interrupt?
 beq.b lrbyte
 cmp.l HZ200.w, D0 ; Timeout?
 bpl.b rwbyte ; weiter warten
 moveq #-1, D0 ; return FALSE
 rts
lrbyte:
 moveq #0, D0 ; Byte einlesen
 move.w DMADATA.w, D0
 andi #$FF, D0 ; und Byte maskieren
 rts

Gehen wir das erste Problem an: Woher weiß ich, welche Geräteadresse das winzige »Mäuseklavier« in dem grauen Kistchen zwischen Rechner und Laser für unseren Drucker festlegt? Zu diesem Zweck können wir natürlich das Interface aufschrauben, die Schalterstellung ablesen (sofern unser eigenes digitallogisches Verständnis zur krausen Atari-Logik dieser DIP-Schalter kompatibel ist) und die Steuerroutinen auf eine feste ACSII-Adresse abstimmen.

Fähige Programmierer lösen die Aufgabe jedoch intelligenter. Dazu muß man wissen, daß alle ACSII-Geräte zur Auskunft über ihre Geräteadresse verpflichtet sind. Das Zauberwort, das solche Geräte verstehen müssen, heißt INQUIRE. Nach diesem Befehl muß das Gerät mindestens 5 Byte zurückliefern, in denen der Typ (Platte, Drucker usw.) verschlüsselt ist. Anschließend kann es seinen tatsächlichen Namen als ASCII-Text kundtun. Wir schicken nun sinvollerweise von Device 7 abwärts allen Geräten ein Inquire und fragen ihre Druckfähigkeit ab:

find_dev:
 move SR, D0 ; Altes Statusregister merken
 ori #$0700, SR ; Keine Störung bitte -> IRQ aus!
 move.b #$0E, SOUND.w ; Floppy selekt
 move.b SOUND.w, D1
 move D0, SR ; Interupt wieder ein
 andi.w #6, D1
 cmp.w #6, D1 ; Laufwerk A noch selektiert?
 bne.b find_dev ; wenn ja, warten
 move.l #$14, D1
 add.l Hz200.w, D1
find1:
 cmp.l Hz200.w, D1 ; Warten
 bpl.b find1
 move.w #$2710, D0 ; Warten
find2:
 dbra D0, find2
 moveq #8, D7 ; D7 = aktuelles Device
nextdev:
 subq.w #1, D7 ; Wir fangen mit Device 7 an
 bmi.b fail ; Bei 0 hören wir auf
 move.l D7, D0 ; In D0 basteln wir das Kommando
 lsl.b #5, D0 ; Device in Bit 5..7
 ori.b #INQUIRY, D0
 swap D0
 move.l #$8A, D2 ; DMA-Mode
 moveq #4, D3 ; 4+1 = 5 Byte senden
 move.w #$88, DMAMODE.w
devnextb:
 move.w D2, D0
 bsr wcbyte ; Byte schreiben
 dbmi D3, devnextb
 bmi.b nextdev ; Bei Timeout, mit nächstem Device
 move.l #$80008A, DMADATA.w ; Das letzte Byte muß $80 sein
 lea id_list, A0
 moveq #5, D2 ; 1 Status + 5 ID-Byte lesen
idnextb:
 bsr rsbyte
 bmi.b nextdev ; Bei Fehler natürlich abbrechen
 move.b D0,(A0)+ ; Byte in Liste schreiben
 dbra D2, idnextb ; nächstes Byte
 move.w D0, D2 ; Letztes Byte gibt Länge des
 subq.w #1, D2 ; ID-Strings an:
strnextb:
 bsr rsbyte ; Lesen wir auch dieses ein
 bmi.b nextdev
 move.b D0, (A0)+
 dbra D2, strnextb
 clr.b (A0) ; String terminieren
 cmpi.b #2, slm_id ; 1.Byte in Liste ist Status!!!
 bne.b nextdev ; Kein Drucker, Pech gehabt
 move.w D7, device ; Sonst ist er unser Laser, toll!
 moveq #0, D0 ; Eine positive Antwort
 rts
fail:
 moveq #-1, D0 ; ... sonst eine traurige Nachricht
 rts
DATA
EVEN
device:
 dc.w 7
 dc.b 0
idlist:
 dc.b 0
slm-id:
 dc.l 0,0,0,0,0.0,0.0,0,0,0,0,0,0,0,0,0
TEXT

Nachdem wir nun wissen, daß ein Laserdrucker vorhanden ist, fragen wir nach der Größe der Bitmap. Der Laserdrucker kann verschiedene Papierformate ausdrucken:

Brief 216 x 279 mm oder 2400x3180 Pixel
Standard 216 x 356 mm oder 2400x4080 Pixel
DIN A4 210 x 297 mm oder 2336x3386 Pixel
DIN B5 182 x 257 mm oder 2016x2914 Pixel
Die Einzelpapierzufuhr erfolgt immer im Briefformat.

Da man das Papierformat durch verschiedene Papierkassetten einfach wechseln kann, muß man unbedingt vor dem Drucken die aktuelle Einstellung auslesen und seine Bitmap entsprechend anpassen. Dazu liest man eine Parameterliste mittels REQUEST SENSE vom Laser ein, die folgendermaßen aufgebaut ist:

Byte 0: Länge der Liste
Byte l+2: Blockhöhe
Byte 3+4: Blockbreite
Byte 5+6: Oberer Rand
Byte 7+8: Linker Rand
Byte 9: Bit 0: Einzelblatt
Byte 10+11: Vertikale Auflösung
Byte 12+13: Horizontale Auflösung
Byte 14: Timeout
Byte 15+16: Scantime
Byte 17+18: Anzahl gedruckter Seiten
Byte 19+20: Eingangskapazität
Byte 21+22: Ausgangskapazität

Wir haben die Liste bis zum bitteren Ende aufgeführt, um Sie ein wenig zu erschrecken. Wollen Sie nämlich später auf Einzelblatt (600 dpi beim Laserkit) schalten, müssen Sie dem Laser die komplette Liste schicken, was ganz schön lästig ist. Wir werden später jedoch trickreich mit REQUEST SENSE eine solche Liste anfordern, die entsprechende Stelle ändern und den Laser mit einer korrekten Parameterliste überraschen.

Man kann diesem Parameterblock entnehmen, wie breit (Byte 3 + 4) und wie hoch (Byte 1 + 2) die zu sendende Bitmap sein soll. Der Rest ist zu diesem Zeitpunkt noch uninteressant. Später kann man - schaltet man auf 600 dpi (Einzelblatt gesetzt) - noch den oberen Rand vergrößern, um (Achtung aufs Briefformat) die zu druckende Bitmap auf dem Blatt zu zentrieren.

Da Atari nicht an 600 dpi gedacht hat, liefert der Controller »fälschlicherweise« auch bei 600 dpi eine 300er Breite. Wir müssen also per Hand die Breite verdoppeln:

mode_sense:
 move.w #$2710, D0 ; warten
mode_s1:
 dbra D0, mode_s1
 clr.l D0 ; Kommando basteln
 move.w device, D0
 lsl.b #5, D0 ; Device an Bit 5..7
 ori.b #M_SENSE, D0 ; Befehl
 swap D0
 move.l #$8A, D2 ; DMA-Mode
 moveq #5, D3 ; 6-Byte
 move.w #$88, DMAMODE.w
mnextb:
 move.w D2, D0
 bsr wcbyte ; Byte schreiben
 dbmi D3, mnextb
 bmi return
 lea prstat, A0 ; Liste bei prstat ablegen
 moveq #1, D2 ; 1 Status + 1 Parm-Länge
mplen:
 bsr rsbyte
 bmi return
 move.b D0, (A0)+ ; an prstat schreiben
 dbra D2, mplen
 move.w D0, D2 ; Länge der Liste in d0
 subq.w #1, D2 ; eins abziehen wegen dbf
mparm:
 bsr rsbyte ; Parameterliste einlesen
 bmi return
 move.b D0, (A0)+ ; und an prstat schreiben
 dbra D2, mparm
 moveq #0' D0 ; D0 löschen
 move.b prstat, D0 ; prstat[0] gibt Status zurück
 rts
DATA
EVEN
prstat:
 dc.b 0 ; Status-Byte
parmIst:
 dc.b 0 ; Länge der Parameterliste
pr_height:
 dc.w 0 ; Bitmap Höhe
pr_width:
 dc.w 0 ; Bitmap Breite
top_mar:
 dc.w 0
left_mar:
 dc.w 0
parm9:
 dc.b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 dc.b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 dc.b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 dc.b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
TEXT

Ist die fertige Parameterliste erst einmal via mode_sense eingelesen, kann man daran Änderungen vornehmen (z. B. auf 600 dpi schalten = Einzelblatt-Bit setzen) und das Ganze mit mode-select dem Laser mitteilen.

Hier noch eine Warnung: Es wäre töricht, mit Mode-Sense eine Auflösung von z. B. DIN A4 zu lesen und dann zu versuchen, auf Einzelblatt DIN A4 auszudrucken. Der Atari-Laserdrucker SLM 804 druckt nun einmal Einzelblätter grundsätzlich (weil hardwarefixiert) im amerikanischen Briefformat! Wenn man sich nicht sicher ist, sollte man das Einzelblatt-Bit setzen und erneut mit mode_sense die Auflösung erfragen. Dann sorgt der Drucker für die richtige Ausgabegröße: Der Laser wird das Bildformat entsprechend klippen.

mode_select:
 move.w #$2710, D0
mode_s2:
 dbra D0, mode_s2 ; warten
 clr.l d0 ; Kommando basteln
 move.w device, d0
 lsl.b #5, d0 ; Device Bit 5..7
 ori.b #M_SELECT, d0
 swap d0
 move.l #$8A, d2 ; DMA-Mode
 move.w D2, d0
 move.q #4, d3 ; 5 Byte
 mowe.w #$88, DMAMODE.w
mode_s3:
 bsr wcbyte ; Byte schreiben
 move.l d2, d0
 dbmi d3, mode_s3
 bmi.b return
 tst.w def_reset ; Reset aller Parameter?
 beq.b no_reset ; normale Funktion
 move.l #$80008A, d0
 bra.b pa_reset
no_reset:
 move.l #$8A, d0
pa_reset:
 bsr wcbyte ; letztes Byte des Kommandoblocks
 bmi.b return
 tst.w def_reset
 bne.b nolist ; bei Reset keine Liste
 lea parmlst, a0 ; Parameterliste von mode_sense
 moveq #0, d3
 move.b (a0), d3 ; 1. Byte gibt Länge an
mode_s4:
 move.b (a0)+, d0 ; Byte aus Liste nehmen
 swap d0
 move.w d2, d0
 bsr wcbyte ; ... und senden
 bmi.b return
 dbra d3, mode_s4
no_list:
 bsr rsbyte ; Status zurücklesen
return:
 rts
DATA
EVEN
def_reset:
 dc.w 0 ; gibt an, ob Reset oder Set
TEXT

Die Ausgabe der Bitmap ist nach dieser Vorarbeit nur noch eine Kleinigkeit. Schnell auf DMA-Turbo super schalten und warten, bis alles vorbei ist. Der Laser holt sich nämlich die Daten selbst aus dem Speicher: So gefällt es uns!

Leider sieht die Sache insofern knifflig aus, als die Blocklänge nicht beliebig lang programmiert werden kann. Der ST »schaufelt« maximal 256 Blöcke zu 512 Byte, also 128 KByte am Stück. Man muß also zwischendurch (wenn keine Daten abgeholt werden) den Sektorzähler neu setzen. Damit sich der DMA-Chip nicht verzählt, wollen wir die Angelegenheit diskret zwischen den Zeilen erledigen. Den rechten Zeitpunkt finden Sie, indem das Programm auf das Lowbyte des DMA-BaseRegisters schaut. Ändert sich dieses einige Zeit nicht, haben Sie die Austastlücke erwischt. Die Adresse im Speicher steht übrigens im Register A0.

dma_out:
 move.w #$01D0, DMAMODE.w ; DMA-FIFO löschen und
 move.w #$D0, DMAMODE.w ; auf Schreiben stellen
 move.w #$01D0, DMAMODE.w
 move.l (a0), -(sp) ; Basisadresse setzen
 move.b 3(sp), DMALOW.w
 move.b 2(sp), DMAMID.w
 move.b 1(sp), DMAHIGH.w
 addq.w #4, sp
 move.w #$2710, d0
out1:
 dbra d0, out1 ; warten
 move.w #$88, DMAMODE.w
 move.w #$0188, DMAMODE.w
 move.w #$88, DMAMODE.w
 moveq #0' d0
 move.w device, d0
 lsl.b #5, D0
 ori.b #PRINT, D0 ; Start Print (Na endlich!)
 swap D0
 move.l #$8A, D2 ; DMA-Mode
 moveq #4, D3 ; 5 Byte
out2:
 move.w D2, D0
 bsr wcbyte ; Byte schicken
 bmi.b return
 dbra D3, out2
 move.l #$0116, DMADATA.w ; DMA starten
 move.w #$3F, DMADATA.w ; Sector Count auf 63
 move SR, D7
 ori #$0700, SR ; IRQ aus
 move.w #$0116, DMAMODE.w
 move.b DMALOW.w, D2 ; momentanen Zählerstand
merken
 bra.b wr_loop
set_count:
 move.w #$3F, DMADATA.w ; Sector Count auf 63
wr_loop:
 move.b D2, D3 ; alten Zählerstand in d3 kopieren
 move.b DMALOW.w, D2 ; neuen Stand in D2
 cmp.b D3, D2 ; alten Stand mit neuem vergleichen
 bne.b set_count ; gleich geblieben -> Austast-
 btst #5, GPIP.w ; ende erreicht?
 bne.b wr_loop ; sonst warten
 move.w #$01CA, DMAMODE.w ; DMA-Transfer ausschalten
 moveq #0, D0
 move.w DMADATA.w, D1 ; Status abholen
 move.b D1, D0
 move D7, SR ; IRQ's wieder zulassen
 addi.l #1200, HZ200.w
out3:
 moveq #5, D1
 add.l HZ200.w, D1
out4:
 cmp.l HZ200.w, D1 ; warten
 bpl.b out4
 btst #5, GPIP.w ; Auf INT testen
 beq.b out3 ; weiter warten
 move.l #$14, D1
 add.l HZ200.w, D1
out5:
 cmp.l HZ200.w, D1 ; warten
 bpl.b out5
 btst #5, GPIP.w ; Auf INT testen
 beq.b out3 ; weiter warten
 neg.l D0
 rts

Bei den vorangegangenen Routinen können einige Fehler zurückgemeldet werden. Die meisten kommen direkt vom Controller des Lasers:

Rückmeldung / Fehlermeldungen:
-------------------------
 -1: TIMEOUT
 0: Alles OK
 1: DRUCKER IST NICHT EINGESCHALTET ODER NICHT
VORHANDEN!
 2: ALLGEMEINER HARDWARE-FEHLER!
 3: DER TONER IST LEER!
 4: NOCH NICHT FERTIG AUFGEHEIZT!
 5: DER PAPIERVORRAT IST LEER!
 6: DIE WALZE MUSS AUSGETAUSCHT WERDEN!
 7: PAPIERSTAU IN DER ZUFÜHRUNG!
 8: PAPIERSTAU IM INNEREN!
 9: PAPIERSTAU IN DER ABLAGE!
 10: BITTE GEHÄUSE SCHLIESSEN!
 11: FEHLER IN DER FIXIER-EINHEIT!
 12: FEHLER IN DER BELICHTUNGSEINHEITI
 13: MOTORFEHLFUNKTION!
 14: VIDEO-FEHLFUNKTION1
 16: SYSTEM TIMEOUT
 18: FALSCHER OP-CODE
 19: FALSCHES DEVICE
 20: FALSCHE PARAMETERLIST

Zum guten Schluß schreiben wir die Rahmenroutinen. Angenommen, wir hätten einen Aufruf zur Abfrage der Auflösung in C:

int cdeel slm_init (int mode, int &breite, int &hoehe);

mode soll für 600 dpi oder Einzelblatt 1, ansonsten 0 sein. Für Breite und Höhe der Bitmap übergeben wir Zeiger auf unsere Variablen, damit die Routine die aktuellen Werte hineinschreiben kann. Als Rückgabewert werden die oben aufgeführten Fehlermeldungen geliefert:

slm_init:
 link A6, #0
 movem.l D1-D7/A1-A5, -(A7) ; Register sichern
 clr.l -(A7)
 move #$20, -(A7) ; GEMDOS: SUPER
 trap #1
 addq.l #6, A7
 move.l D0, savesp ; Gut merken!
 st flock.w ; VBL fernhalten
 move.b #$13, ACIACTRL.w ; Tastatur aus
 bsr.b init
 movea.l 10(A6), A0 ; Pointer auf Breite
 move.w pr_width, D1
 tst.w 8(A6) ; 600 dpi?
 beq.b dpi300
 lsl.w #1, D1 ; Bei 600 dpi Breite mal 2
dp1300:
 move.w D1, (A0)
 movea.l 14(A6), A0 ; Pointer auf Höhe
 move.w pr_height, (A0)
pr_exit:
 sf flock.w ; ich bin fertig mit DMA
 move.b #$11, ACIACTRL.w ; Tastatur ein
 move.l savesp, -(A7)
 move.l D0, savesp ; D0 vor GEMDOS sichern
 move.w #$20, -(A7) ; GEMDOS: SUPER
 trap #1
 addq.l #6, A7
 move.l savesp, D0 ; D0 ist Rückgabewert
 movem.l (A7)-, D1-D7/A1-A5
 unlk a6
 rts
_init:
 bsr find_dev ; Device des Lasers suchen
 bmi return ; nicht gefunden ?
 bsr mode_sense ; Parameterblock laden
 cmp.w #-1, D0 ; Kein Parameterblock ?
 beq return ; Tut uns leid -> Ende
 st def_reset
 move.b #1, parm9
 bsr mode_select ; Parameterliste auf Default
 sf def_reset
 bsr mode_sense ; und neu einlesen
 move.w 8(A6), D0 ; 300 oder 600 dpi?
 move.b DO, parm9
 bsr mode_select ; Auswählen
 bsr mode_sense ; und Parameter lesen
 rts
BSS
EVEN
savesp:
 ds.l 1 ; von GEMDOS Super
TEXT

Drucken wollen wir wie folgt:

int cdecl slm_print (int mode,char *bild);

Mode sollte den gleichen Wert wie beim zugehörenden slm_init haben, »bild« ist ein Zeiger auf die zu druckende Bitmap. Als Rückgabewert erwarten wir die üblichen Fehlercodes:

slm_print:
 link a6, #0
 movem.l D1-D7/A1-A5, -(A7) ; Register sichern
 clr.l -(A7)
 move.w #$20, -(A7) ; GEMDOS: Super
 trap #1
 addq.l #6, A7
 move.l D0, savesp
 st flock.w ; VBL fernhalten
 move.b #$13, ACIACTRL.w ; Tastatur aus
 bsr.b _init ; INIT: Sicher ist sicher
 bne pr_exit
 movea.l 10(A6), A0 ; Pointer auf Bitmap
 bsr dma_out ; Bild drucken
 bmi pr_exit
 bsr mode_sense ; Status holen. Stellt sicher,
 bra pr_exit ; daß der Druckvorgang beendet ist

Damit Sie die Routinensammlung ohne weitere Klimmzüge testen können, hat Programmierer Bernards ein simples Testprogramm in Assembler entworfen, das eine Bitmap mit senkrechtem Streifenmuster erzeugt und über slm_init und slm_print auf dem SLM804 ausgibt. Die im Programm enthaltene Abfrage nach der Druckerauflösung hat natürlich nur dann einen Sinn, wenn Ihr Laserdrucker mit dem 600-dpiLaserkit aufgerüstet ist:

; nicht benötigten Speicher freigeben
slm_test:
 move.l 4(a7), a5
 move.l 12(a5), d0
 add.l 20(a5), d0
 add.l 28(a5), d0
 add.l #256, d0
 move.l d0, -(a7)
 move.l a5, -(a7)
 move.w #0, -(a7)
 move.w #74, -(a7)
 trap #1
 lea 10(a7), a7
; Meldung ausgeben
 pea msg
 move.w #9, -(a7)
 trap #1
 addq.l #6, a7
; Eingabe
 move.w #7, -(a7)
 trap #1
 addq.l #2, a7
; Eingabe auswerten
 andi.w #1, d0
 move.w d0, modus
; Drucker-Initialisierung
 pea hoehe
 pea breite
 move.w modus, -(a7)
 jsr slm_init
 lea 10(a7), a7
; Druckseiten-Aufbereitung
 move.w breite, d0
 lsl.w #3, d0
 mulu hoehe, d0
 move.l d0, size
 move.l d0, -(a7)
 move.w #72, -(a7)
 trap #1
 addq.l #6, a7
 move.l d0' buffer
 bmi error
 beq error
 move.l d0, a0
 move.l size, d0
 lsr.l #2, d0
 subq.l #1, d0
 move.l #$c0000003, d1
loopx:
 move.l d1, (a0)+
 subq.l #1, d0
 bpl.s loopx
; Seite drucken
 move.l buffer, -(a7)
 move.w modus, -(a7)
 jsr slm_print
 addq.l #6, a7

; Programm beenden
error:  clr.w -(a7)
        trap #1
DATA
buffer: dc.l 0
size:   dc.l 0
hoehe:  dc.w 0
breite: dc.w 0
modus:  dc.w 0
msg:    dc.b 'Möchten Sie 300 dpi (0) oder 600 dpi (1)?',0
        even
        END

Hat Ihr Assembler alles richtig assembliert, steht der »Punkteproduktion« per Laser ohne Emulatorumwege nichts mehr entgegen. Weisen Sie Ihren Programmen künftig den direkten Weg zum Laser!

Markus Breuer/W. Fastenrath/uw)



Aus: ST-Magazin 02 / 1991, Seite 112

Links

Copyright-Bestimmungen: siehe Über diese Seite