← ST-Magazin 02 / 1991

Laseransteuerung - Direkt gepunktet

ST-Expertenforum

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)