Hardcopy leicht gemacht
Jetzt bekommt Ihr Drucker was zu tun! Wir zeigen Ihnen, wie Sie die Basic-Hardcopy-Routine aus der Ausgabe 9/85 in Maschinensprache umsetzen können. Ein gedrucktes »Foto« des Textbildschirms auf Tastendruck.
Eine Hardcopy vom Textbildschirm des C 64 wird häufig gebraucht. Die Dokumentation eines selbstgeschriebenen Programms oder ein Beispielausdruck für eine Programmanleitung sind nur zwei Beispiele.
In der letzten Folge war die Hardcopy-Routine auf Commodore-Drucker zugeschnitten. Diesmal sind alle 8-Nadel-Drucker an der Reihe. Das Programm ist auf die Epson-Drucker FX und RX zugeschnitten. Ein verwendetes Interface muß sich durch die Sekundäradresse 1 im OPEN-Befehl in den Linearmodus schalten lassen. Lassen Sie sich davon aber nicht abschrecken, falls Ihr Interface oder Drucker auf andere Weise angesteuert wird. Wenn Sie Grundkenntnisse in der Assembler-Programmierung haben, sind Sie in der Lage, das Programm auch an Ihren Drucker anzupassen. Voraussetzung für das Gelingen der Anpassung ist nur, daß Ihr Drucker über einen Bitmustermodus mit acht ansteuerbaren Nadeln verfügt.
Wenn Sie keine Änderungen am Programm vornehmen möchten, sollten Sie den MSE-Lader (Listing 1) abtippen. Wollen Sie aber Änderungen und Verbesserungen daran vornehmen, verwenden Sie besser das Quellisting (Listing 2) und einen Assembler. Aber das werden Sie dann sowieso machen. Da in jeder Zeile nur ein einziger Befehl vorkommt, sollte das Quellisting ohne weiteres auf jeden Assembler, beispielsweise dem Hypra-Ass, übertragen werden können. Es müssen ja prinzipiell nur die Assembler-Anweisungen in den Zeilen 1000, 1010, 1100, 1110, 4070 und 4080 geändert werden. Die Bedeutung dieser Zeilen:
1000 Programmdatei für Maschinen-Code öffnen
1010 Starten des Assemblers
1100 Maschinen-Code in offene Datei schreiben
1110 Startadresse des Programms
4070 Ende des Quell-Codes
4080 Initialisierung der Hardcopy-Routine (nur sinnvoll, wenn der Maschinen-Code in den Speicher geschrieben wird und nicht auf Diskette gespeichert wird).
Hardcopy des Text-Bildschirms
Aber nun Schluß mit den allgemeinen Hinweisen. Im folgenden wird das Source-Listing anhand der Zeilennummern erklärt. Ab Zeile 1150 im Sourcelisting (Quellisting), werden den benötigten Betriebssystem-Routinen und Speicherzellen Labels (Namen) zugeordnet. Was die einzelnen Routinen leisten, entnehmen Sie bitte den Kommentaren im Quellisting.
Eine Hardcopy-Funktion für Textbildschirme wird erst dann so richtig interessant, wenn sie durch einfachen Tastendruck gestartet werden kann. Unabhängig davon, was der Computer gerade macht. Denn nur so kann man sich Beispiele von Bildschirmmasken etc. drucken lassen. Aus diesem Grund wurde dieser Hardcopy-Routine eine Tastenabfrage vorgeschaltet. So wird erreicht, daß durch kurzes Drücken der F1-Taste das Hardcopy-Programm startet. Wie man eine solche Tastenabfrage realisieren kann, sehen Sie ab Zeile 1460 im Quellisting. Dort wird die Abfrage-Routine in den Systeminterrupt des C 64 eingebunden. Danach wird die Taste pro Sekunde etwa 60mal abgefragt. Ist sie nicht gedrückt, wird der normale Systeminterrupt fortgesetzt. Zum Einbinden einer Routine in den Systeminterrupt (IRQ) muß der Interruptvektor in den Speicherzellen $314 und $315 auf die Routine »umgeleitet« werden. Im Normalfall zeigt der IRQ-Vektor auf den Beginn der Systeminterrupt-Routine bei $EA31. In diesem Fall wird er so verändert, daß er auf die Tastenabfrage, also auf $C00D zeigt. Genaueres zu diesem Thema können Sie beispielsweise im 64’er Sonderheft 4/85 nachlesen.
Die Veränderung des IRQ-Vektors wird in den Zeilen 1470 bis 1550vorgenommen. Bevor aber der Vektor verändert werden kann, ist ein SEI(set-interrupt-disable-flag)-Befehl nötig. Dieser Befehl setzt das IRQ (interrupt-request)-Flag. Das bewirkt, daß der Prozessor keinen Interrupt mehr annimmt. Es ist ja eigentlich einleuchtend, daß kein Interrupt stattfinden darf, wenn man gerade die IRQ-Sprungadresse verändert. Das wäre so, als ob Sie auf einer Kreuzung ein Umleitungsschild aufstellen wollen, wenn dort gerade ein Lastzug fährt. Sie müssen vorher schon den Verkehr anhalten. Die Umstellung des IRQ* Vektors geschieht in diesem Programm durch SYS 49152. Dadurch wird die ganze Hardcopy-Routine initialisiert. Von nun an springt der Prozessor bei jedem Interrupt in die Tastenabfrage ab Zeile 1570. Dort wird der Inhalt der Speicherzelle $C5 geladen und mit »4« verglichen. »4« ist der Tastencode der F1-Taste. Fällt der Vergleich negativ aus, erfolgt sofort ein Sprung zur Adresse $EA31, der Systeminterrupt-Routine des C 64 (Zeile 1640). Fällt der Vergleich dagegen positiv aus (F1 gedrückt), verzweigt die Abfrage-Routine ins eigentliche Hardcopy-Programm ab Zeile 1700.
Start auf Tastendruck
Am Anfang der Hardcopy-Routine wird als erstes die gesamte Zeropage (Speicherzellen 0-255) zwischengespeichert. Dieses Verfahren ist zwar alles andere als elegant, erspart aber sehr viel Denkarbeit. Der Zeitbedarf dafür ist so gering, daß er bei einer Hardcopy-Routine vernachlässigt werden kann.
Nach dem »Retten« der Zeropage wird der Druckerkanal eröffnet und der Drucker normiert (Zeile 1670 bis 2000). Der Druckerkanal hat die Filenummer 126 und die Sekundäradresse 1. Die Geräteadresse ist 4. Die File-Nummer wurde so hoch gewählt, damit es keine Schwierigkeiten mit eventuell schon vorhandenen offenen Dateien gibt. Wer verwendet in Programmen schon die File-Nummer 126? Achtung: Eine File-Nummer größer als 127 sendet ein Linefeed (Zeilenvorschub) »CHR$(10)« nach jedem Carriage Return.
Ist der Druckerkanal offen, wird der Zeilenabstand des Druckers so eingestellt, daß alle Zeilen dicht aneinander liegen. Beim Epson RX/FX geschieht das mit der Steuersequenz CHR$(27)"3"CHR$(24). Mit der PRINT-Routine wird ein Zeichen an das, durch die CHKOUT-Routine festgelegte, Gerät geschickt. In diesem Fall eben an den Drucker.
Ab Zeile 2040 wird die Anfangsadresse des Bildschirms geholt und in VIRAM und VIRAM+1 übergeben. Das Programm mußja wissen, wo die zu druckenden Daten stehen. Nach dieser Vorarbeit steht der eigentlichen Hardcopy-Routine nichts mehr im Weg.
In Zeile 2140 wird das x-Register mit der Zeilenzahl (25) des Bildschirms geladen. Danach wird die STOP-Taste abgefragt, um die Hardcopy vorzeitig beenden zu können. Die Abfrage findet übrigens zu Beginn jeder neu zu druckenden Bildschirmzeile statt. Ist die STOP-Taste gedrückt, wird die Hardcopy-Routine beendet und die normale Interrupt-Routine abgearbeitet. Wie die Hardcopy-Routine beendet wird, soll später erklärt werden. Vorläufig wird erstmal gedruckt!
Damit der richtige Zeichensatz aufs Papier kommt, wird ab Zeile 2390 bei jeder neuen Zeile ein Prüfprogramm (ab Zeile 3820, CHRTEST) aufgerufen, das den momentanen Schriftmodus überprüft. Groß-/Klein oder Groß-/Grafik-Zeichensatz. Die Startadresse des Zeichensatzes im Character-ROM wird dann in ZROM, ZROM+1 abgelegt. DerGroß/Klein-Zeichensatz hat die Startadresse $D800, der Groß/Grafik-Zeichensatz steht ab Adresse $D000. Welcher Zeichensatz gewählt ist, steht in Speicherzelle $D018 des Videochips. Ergibt der Inhalt von $D018 AND 2 das Ergebnis 2, ist der Groß/Grafik-Modus eingeschaltet. In Zeile 3890 finden Sie den BIT-Befehl $2C. Dieser Befehl vergleicht normalerweise den Akkuinhalt mit der angegebenen 2-Byte-Adresse und verändert entsprechend das Z-Flag. Diese Funktion ist aber hier nur Mittel zum Zweck. In diesem Fall soll der Prozessor nur die auf $2C folgenden 2 Bytes ignorieren. Genauer: Wird der Akku mit dem High-Byte der Startadresse des Zeichensatzes 1 geladen (Zeile 3870), wird der 2-Byte-Ladebefehl LDA # >CHRGEN2 (StartadresseZeichensatz #2) einfach ignoriert. Man erspart sich dadurch eine zusätzliche Abfrage und einen Branch-Befehl.
Nachdem der aktuelle Zeichensatz bekannt ist, wird der Drucker in den Bitmustermodus (Grafikmodus) geschaltet. Dazu werden aus der Tabelle GRAFIK sieben Steuercodes geholt und zeichenweise an den Drucker geschickt. Die Steuersequenz ist 24, 13, 27, "*", 4, 64, 1. »1« und »64« ist das High- beziehungsweise das Low-Byte von 320, der Anzahl der Grafikpunkte des C 64 in einer Zeile. Der Code »13« bewirkt nur einen Wagenrücklauf (Carriage Return), damit der Druckkopf am Zeilenanfang steht. CHR$(24) löst einen Drucker-Reset aus.
In zwei Schleifen wird nun der ganze Bildschirm »abgetastet« und die einzelnen Zeichen am Bildschirm in Bitmusterdaten übersetzt. Den Anfang der übergeordneten »Zeilenschleife« lernten Sie bereits kennen: LDX #25, STOP-Taste abfragen, Druckerzeile initialisieren (in Grafikmodus schalten). Die untergeordnete »Spaltenschleife« (Zeilen 2530 bis 2650) holt nacheinander den Bildschirmcode der Zeichen einer Zeile. Der Zeichencode wird in der Speicherzelle ZEICHEN abgelegt. Als Zählvariable für diese untergeordnete Schleife, die von 0 bis 39 zählt, wird das y-Register hergenommen. Der Abschnitt von Zeile 2250 bis 2330 überprüft, ob in einer Zeile überhaupt etwas steht. Wenn nicht, wird ein Zeilenvorschub ausgelöst und die nächste Zeile »abgetastet«.
Ist ein Zeichen-Code ermittelt, wird mit JRS AUSWERT in Zeile 2620 ein Unterprogramm aufgerufen, das aus dem Zeichensatz-ROM die Punktmuster der Zeichen liest. Dazu werden nacheinander die acht senkrechten Punktspalten eines Zeichens aus den Daten des Zeichensatz-ROMs zusammengesetzt. Jede fertige Punktspalte wird an den Drucker geschickt. Aus acht dieser Spalten entsteht dann ein Zeichen auf dem Papier, aus 320 solcher Spalten eine ganze Druckzeile. Das Lesen des Zeichensatz-ROMs und der Zusammenbau der Punktspalten ist für den Anfänger in Maschinensprache nicht ganz einfach zu verstehen und soll deshalb kurz erklärt werden.
Das Unterprogramm AUSWERT beginnt ab Zeile 3060 mit drei PHA (push akku)- und zwei Transferbefehlen, die den Inhalt des Akkus und des x-,y-Registers auf den Prozessorstack legen. Das ist nötig, da im Unterprogramm der Akku und das x- und y-Register verändert werden. Danach wird in den Zeilen 3160 bis 3290 die Startadresse des momentanen Zeichens im Zeichensatz-ROM berechnet. Die Startadresse berechnet Anfangsadresse + Offset (Speicherstelle im ZeichensatzROM). Offset = Bildschirm-Code x 8.
Wie schon erwähnt, wird ab Zeile 2530 der »Spaltenschleife« der Bildschirmcode eines jeden Zeichens am Bildschirm geholt (LDA (VRAM,Y)) und in ZEICHEN gespeichert. Der Inhalt von ZEICHEN wird in Zeile 3170 in die Speicherzelle ADRESSE kopiert. Dann wird durch drei ASL-Befehle der Inhalt Speicherzelle ADRESSE und ADRESSE+1 (Grundwert immer »0«) mit 8 multipliziert. Ein ASL (arithmical shift left) verdoppelt den Inhalt einer Speicherzelle. Tritt dabei ein Übertrag auf (Ergebnis > 255) wird das Carry-Flag gesetzt. Das Carry-Flag wird in der Speicherzelle ADRESSE+1 berücksichtigt. Ein ROL-Befehl schiebt das Carry-Bit »von rechts in die Speicherzelle ADR+1«. Fand kein Übertrag statt, schiebt der ROL-Befehl einfach eine »0« nach. Der ROL-Befehl hat die gleiche Wirkung, wie eine Verdopplung eines Speicherzelleninhalts mit ASL, nur wird anschließend noch das Carry-Bit addiert. Nach der Multiplikation mit 8 steht in ADRESSE und ADRESSE+1 in Low-/High-Bytedarstellung der Offset. Um die absolute Adresse zu erhalten, wird ab Zeile 3110 der Offset zur Anfangsadresse des Zeichensatz-ROMs addiert. Es steht dann die absolute Zeichenadresse in ADRESSE (Low-Byte) undADRESSE+1 (High-Byte).
Der Clear-Carry (CLC)-Befehl ist grundsätzlich vorjeder Addition notwendig, um ein eventuell gesetztes Carry-Flag zu löschen. Nur so kann ein Übertrag sicher festgestellt werden.
Ist die Anfangsadresse eines Bildschirmzeichens im Zeichensatz-ROM bekannt, fängt aber die Arbeit erst richtig an.
Ein Bildschirmzeichen setzt sich aus einer 8x8-Punktmatrix zusammen. Die Punktmatrix wird beim C 64 aus acht 8-Bit-Zahlen zusammengesetzt:
| Adresse | Adresse |
| $D000 ........ | $D005 ........ |
| $D001 ........ | $D006 ........ |
| $D002 ........ | $D007 ........ |
| $D003 ........ | $D008 ........ |
| $D004 ........ | $D009 ........ |
Mit einer 8-Bit-Zahl pro Punktzeile. Dabei bestimmt die erste Zahl im ROM das Punktmuster der obersten Punktzeile eines Zeichens. Stellen Sie sich eine 8-Bit-Zahl einmal in Binärform vor. Eine »1« ist dann ein gesetzter Punkt und eine »0« kein Punkt. So könnte die Zahl 0000 1000 (dez. 8) einen i-Punkt wiedergeben. Wie Sie sehen, sind die Bildschirmzeichen aus Punktzeilen aufgebaut; im Gegensatz zu den Druckerzeichen, die aus Punktspalten zusammengesetzt werden. Die beiden Formate bringen ein Problem mit sich, denn die Bitmusterdaten des Bildschirms müssen in die des Druckers übersetzt werden. Diese Konvertierung wird in den Zeilen 3330 bis 3660 vorgenommen.
Doch bevor man die Bitmusterdaten konvertiert, muß erstmal eine Punktzeile aus dem Zeichensatz-ROM gelesen werden. Wie Sie vielleicht wissen, liegt das Zeichensatz-ROM im $D000-Bereich, dem kompliziertesten Speicherteil des C 64. Im Bereich von $D000 bis $DFFF arbeiten nämlich noch alle I/O-Bausteine. Man spricht in diesem Zusammenhang von Speicherebenen, diesich einen Speicherbereich teilen. Damit der Zeichensatz gelesen werden kann, muß also noch die richtige Speicherebene selektiert werden. Doch dazu später mehr. Zuerst soll die Konvertierung der Bitmusterdaten geklärt werden.
Zur Konvertierung der Zeilenwerte in Spaltenwerte liest man nacheinander acht mal die Zeilenwerte des Zeichensatz-ROMs und vergleicht die Werte mit einer »Bit-Maske«. Die acht Bit-Masken sind:
| Maske bin. | Wertigkeit |
| 1000 0000 | 128 |
| 0100 0000 | 64 |
| 0010 0000 | 32 |
| 0001 0000 | 16 |
| 0000 1000 | 8 |
| 0000 0100 | 4 |
| 0000 0010 | 2 |
| 0000 0001 | 1 |
Beim ersten Durchgang hat die Bitmaske die Wertigkeit 128 (Zeile 3360). Mit dieser Maske werden nun nacheinander alle acht Punktzeilen eines Bildschirmzeichens AND-verknüpft. Ist beispielsweise in der Zeilenzahl das achte Bit gesetzt (Zahl >127), ist das Ergebnis der Verknüpfung 128, also größer 0. Liefert die Verknüpfung »0«, wird der nächste der acht Zeilenwerte mit der Maske verglichen. Ist das Ergebnis einer Verknüpfung größer als 0, muß an dieser Stelle eine Druckernadel anschlagen.
Bei einem 8-Nadeldrucker haben die Nadeln die binären Werte 1,2,4,8,16,32,64,128. Die unterste Nadel hat die Wertigkeit 1, die oberste die Wertigkeit 128. Ausnahmen bestätigen aber auch hier die Regel (Seikosha 550A: Die untere Nadel hat die Wertigkeit 128). Damit der Drucker die richtige Nadel anschlägt, muß die Wertigkeit der Nadel, oder die Summe der Wertigkeiten, dem Drucker geschickt werden. Dazu ordnet man den acht Punktzeilen eines Bildschirmzeichens die binären Wertigkeiten 1 bis 128 zu; entsprechend der Nadelanordung des Druckers. Bei jedem positiv ausgefallenen Maskenvergleich, addiert man die entsprechenden Nadelwertigkeiten. Wurden alle acht Zeichenzeilen auf diese Weise »abgetastet«, wird die Summe an den Drucker geschickt, der daraufhin eine senkrechte Punktreihe druckt.
Um die nächste Punktspalte drucken zu können, dividiert man die Maske mit »2«. Am einfachsten mit einem LSR (logical shift right)-Befehl. Dieser Befehl verschiebt die »1« in der »Binärmaske« um eine Stelle nach links, was eben einer Division mit 2 gleichkommt. Nun vergleicht man wieder die acht Zeilenwerte mit der neuen Maske und addiert die Nadelwertigkeiten. Nach acht Vergleichen ist der Druckercode für die zweite Druckspalte addiert und kann zu Papier gebracht werden. Dieses Spielchen wiederholt man, bis alle acht Punktspalten eines Zeichens gedruckt sind. Für ein einziges Zeichen sind insgesamt 64 Vergleiche nötig.
Als Basic-Programm wäre die Konvertierung der Bitmusterdaten des C 64 in die eines Druckers viel zu langsam. Es sind schließlich 64x40x25=64000 Konvertierungen pro Bildschirm nötig. Ebenso ist die »Bit-Schieberei« mit LSR, OR und AND in Basic ein Problem für sich.
Die Speicherebenenumschaltung auf das ZeichensatzROM findet in Zeile 3450 statt, nachdem zuvor das Interrupt-Flag gesetzt wurde. Denn solange Speicherzelle 1 den Wert $33 enthält, dürfen keine I/O-Operationen des Prozessors, wie Tastenabfrage und Cursor-Blinken, erfolgen. Der Prozessor würde unweigerlich abstürzen, wenn er auf das
Zeichensatz-ROM zugreift, anstelle auf einer der beiden CIAs oder dem VIC-Chip.
In Zeile 3480 wird das Zeichensatz-ROM ausgelesen und in Zeile 5335 mit der aktuellen Maske verglichen. Danach wird der ursprüngliche Inhalt von Speicherzelle 1 zurückgelassen und ein Interrupt wieder erlaubt.
Die Addition der Nadelwertigkeiten der Punktzeilen findet in Zeile 3590 mit einem ADC-Befehl statt. Die Wertigkeiten der Nadeln stehen in der Tabelle NWERT am Schluß des Programms. Nachdem alle acht Werte im Akku summiert sind, positive Maskenvergleiche vorausgesetzt, wird der Akkuinhalt an den Drucker geschickt. Der Befehl JSR PRINT schickt das Punktmuster der Druckzeichenspalte an den Drucker. Sind die acht Punktreihen gedruckt, werden sämtliche Register wieder hergestellt und die Unterroutine AUSWERT wird beendet. Der RTS-Befehl führt dann wieder in die Spaltenschleife zu Zeile 2510.
Sind auf diese Weise 40 Zeichen gedruckt, wird in der Zeilenschleife das y-Register wieder auf »0« gesetzt, der Drucker auf eine neue Druckzeile mit Bitmusterdaten eingestellt und eine neue Druckzeile abgearbeitet.
Ist der ganze Bildschirm ausgedruckt (oder die STOP-Taste gedrückt), wird ab Zeile 2980 das Programm beendet. Im einzelnen heißt das, daß der Druckerkanal geschlossen, die Zeropage zurückgeschrieben und die normale Interruptroutine bearbeitet wird.
Danach läuft Ihr Programm weiter als wenn nichts geschehen wäre.
(hm)1000 open2,8,2,"hardcopy.obj,p,w" 1010 sys9*4096 1020 ;********************************* 1030 ;* lowscreenhardcopy * 1040 ;* incl. * 1050 ;* grafik- und reverszeichen * 1060 ;* epson/wiesemann & komp. * 1070 ;* version 1.2 * 1080 ;* harald meyer 21.05.1985 * 1090 ;********************************* 1100 .opt o2 ; code auf disk 1110 *= $c000 ; startadresse 1120 ; routinen des betriebssytems 1130 ;********************************** 1140 ; 1150 open = $ffc0 ; file oeffnen 1160 setnam = $ffbd ; filenamen setzen 1170 setfls = $ffba ; fileparameter 1180 print = $ffd2 ; zeichen ausgeben 1190 clrch = $ffcc ; bildsch.-ausgabe 1200 chkout = $ffc9 ; ausgabegeraet 1210 close = $ffc3 ; file schliessen 1220 stop = $ffe1 ; stopvektor 1230 irqend = $ea31 ; kernal-irq-rout. 1240 lovideo = $d018 ; videoram lo 1250 chrgen1 = $d000 ; 1.zeichensatz 1260 chrgen2 = $d800 ; 2.zeichensatz 1270 ; 1280 ; benoetigte speicherzellen 1290 ; ********************************* 1300 ; 1310 cursor = 204 ; cursor aus/an 1320 irqvek = $0314 ; ieq-vektor 1330 taste = $c5 ; letzte taste 1340 f1 = 4 ; f1-matrixnummer 1350 cr = 13 ; carriage return 1360 esc = 27 ; escape 1370 adresse = $f8 ; zeichenadresse 1380 zeichen = $d6 ; zeichencode 1390 viram = $15 ; zeichenadresse 1400 zrom = $f9 ; zeichengenerator 1410 maske = $9d ; bit-abfrage 1420 ; 1430 ; interrupt initialisieren 1440 ; ********************************* 1450 ; 1460 sei ; irq verhindern 1470 lda #<start ; irq vektor auf 1480 ldy #>start ; dieses programm 1490 sta irqvek 1500 sty irqvek+1 1510 cli ; irq freigeben 1520 rts ; init. ende 1530 ; 1540 ; 1550 ; f1 gedrueckt, dann start 1560 ; ********************************* 1570 ; 1580 start lda taste ; tastenabfrage 1590 cmp #f1 ; taste = f1 "?" 1600 bne l1 ; nein, dann ende 1610 lda #00 ; tastendruck 1620 sta taste ; loeschen 1630 jsr hdcopy ; programmbeginn 1640 l1 jmp irqend ; zum kernal-irq 1650 ; 1660 ; 1670 ; zeropage retten 1680 ; ********************************* 1690 ; 1700 hdcopy ldx #$ff ; byte 255-0 1710 l2 lda 0,x ; laden 1720 sta memory,x ; und speichern 1730 dex ; naechstes byte 1740 bne l2 ; x=0, dann ende 1750 lda #01 1760 sta cursor ;ausschalten 1770 ; 1780 ; 1790 ; druckerfile oeffen und 1800 ; zeilenabstand initialisieren 1810 ; ********************************* 1820 lda #126 ; filenummer 1830 ldx #4 ; geraeteadresse 1840 ldy #1 ; sekundaeradresse 1850 jsr setfls ; parameter setzen 1860 lda #0 ; kein filenamen 1870 jsr setnam ; namen setzen 1880 jsr open ; file oeffnen 1890 ldx #126 ; alle 1900 jsr chkout ; ausgaben auf #126 1910 ; 1920 ; drucker auf einzeiligen abstand 1930 lda #esc ; esc-sequenz-beginn 1940 jsr print ; chr$(27) an drucker 1950 lda #"3" ; "3"+chr$(24) 1960 jsr print 1970 lda #24 1980 jsr print ; an drucker 1990 ; 2000 ; zeiger auf videoram 2010 ; ******************************** 2020 ; 2030 videoram lda #$00 2040 ldy $288 ; videoramadressen 2050 sta viram ; uebergeben 2060 sty viram+1 2070 ; 2080 ; 2090 ; zeichen vom screen holen, 2100 ; charaktergenerator lesen und 2110 ; zeichenmatrix zusammensetzen 2120 ; ********************************* 2130 ; 2140 ldx #25 ; zeilenanzahl 2150 ; 2160 ; ausgabeschleife 2170 ; ********************************* 2180 ; 2190 ausg jsr stop; stoptaste abfragen 2200 beq hdende ; gedrueckt,dann ende 2210 ; 2220 ; ist zeile leer "?" 2230 ; ********************************* 2240 ; 2250 ldy #39 2260 l9 lda (viram),y 2270 cmp #32 2280 bne l10 2290 dey 2300 bpl l9 2310 lda #cr 2320 jsr print 2330 jmp l11 2340 ; 2350 ; chrgen-adresse holen 2360 ; gross/klein oder gross/grafic 2370 ; ********************************* 2380 ; 2390 l10 jsr chrtest ;schriftmodus-test 2400 ; 2410 ; druckzeile vorbereiten 2420 ; ********************************* 2430 ; 2440 ldy #7 ; 6 codes 2450 l3 lda grafik,y ; esc-sequenz 2460 jsr print ; senden 2470 dey ; naechster code 2480 bne l3 ; fertig "?" 2490 ; 2500 ; neue zeile beginnen 2510 ; ********************************* 2520 ; 2530 ldy #0 ; zeile von neuem 2540 ; 2550 ; zeile abarbeiten, 2. schleife 2560 ; zeichen holen und im up bearbei. 2570 ; ********************************* 2580 ; zeichen v. bildsch. holen 2590 l5 lda #0 ; zeichen von 2600 lda (viram),y; bildschirm holen 2610 sta zeichen ; merken 2620 jsr auswert ; bearbeiten 2630 iny ; spalte erhoehen 2640 cpy #40 ; zeilenende "?" 2650 bne l5 ; bildsch.-ende "?" 2660 ; 2670 ; neue zeile vorbereiten 2680 ; ********************************* 2690 ; 2700 l11 lda #40; 40 spalten 2710 clc ; zeiger auf naechste zeile 2720 adc viram ; neue zeile setzen 2730 sta viram 2740 bcc l12 2750 inc viram + 1 2760 l12 dex ; zeilen erniedrigen 2770 bne ausg ; screen zu ende "?" 2780 hdende lda #13; zum ende cr an 2790 jsr print ; drucker senden 2800 ; 2810 ; fertig, dann file schliessen 2820 ; ********************************* 2830 ; 2840 lda #126 ; filenummer 2850 jsr close; druckerdatei schliessen 2860 jsr clrch; cmd auf screen 2870 ; 2880 ; 2890 ; zeropage wiederherstellen 2900 ; ********************************* 2910 ; 2920 ldx #$ff ; zeropage 2930 l4 lda memory,x; wieder 2940 sta $00,x ; herstellen 2950 dex 2960 bne l4 2970 ; 2980 rts ; hardcopy ende 2990 ; 3000 ; 3010 ; 3020 ; 3030 ; charaktergenerator lesen 3040 ; ********************************* 3050 ; 3060 auswert pha; register retten 3070 txa 3080 pha 3090 tya 3100 pha 3110 ; 3120 ; adresse im charakterram berech. 3130 ; = zeichencode * 8 3140 ; ********************************* 3150 ; 3160 lda zeichen; zeichencode laden 3170 sta adresse; adresse im zeichen- 3180 lda #0 ; rom feststellen 3190 sta adresse+1 3200 asl adresse; zeichencode 3210 rol adresse+1 3220 asl adresse 3230 rol adresse+1 3240 asl adresse 3250 rol adresse+1 ; mal 8 3260 lda adresse+1 3270 clc ; und 3280 adc zrom+1 ; romadresse 3290 sta adresse+1 ; addieren 3300 ; 3310 ; charaktergen. lesen und zeichen- 3320 ; matrix fuer drucker aufbereiten 3330 ; ********************************* 3340 ; 3350 ldx $01 ; speicherselekt 3360 lda #%10000000 ; bit-maske 3370 sta maske ; speichern 3380 l14 lda #$00 ; code 3390 pha ; loeschen 3400 ldy #7 ; 8 bytes abfragen 3410 ; 3420 ; chr-ram einschalten & byte lesen 3430 ; ********************************* 3440 ; 3450 l15 sei ; irq sperren 3460 lda #01:and #251 ; zeichen-rom 3470 sta $01 ; selektieren 3480 lda (adresse),y ; code holen 3490 and maske ; maskenvergleich 3500 ; 3510 ; chr-rom wieder einschalten 3520 ; ********************************* 3530 ; 3540 stx $01 ; norm speicherkonf. 3550 cli ; wieder herstellen 3560 beq l6 3570 pla ; code laden und 3580 clc ; code laden und 3590 adc nwert,y ; bitwert zu code add. 3600 pha ; und merken 3610 l6 dey ; naechstes byte 3620 bpl l15 ; 8 bits gelesen "?" 3630 pla ; ja, dann 3640 jsr print ; an drucker 3650 lsr maske ; maske erhoehen 3660 bcc l14 ; naechste punktzeile 3670 ; 3680 ; register wieder holen 3690 ; ********************************* 3700 ; 3710 pla ; register wieder holen 3720 tay 3730 pla 3740 tax 3750 pla 3760 rts 3770 ; 3780 ; anfangsadresse des charakterrams 3790 ; feststellen und merken 3800 ; ********************************* 3810 ; 3820 chrtest lda #$00 3830 sta zrom ; zeichensatzadr. lo 3840 lda lovideo ; zeichensatz-page 3850 and #%00000010 3860 bne l16 3870 lda #>chrgen1 ;$d000 3880 sta zrom + 1 3890 .byt $2c 3900 l16 lda #>chrgen2 ;$d800 3910 sta zrom + 1 3920 rts ; zum hauptprogramm 3930 ; 3940 ; 3950 ; 3960 ;tabelle 320 bitmusterdaten 3970 grafik .byt 0,$01,$40 3980 ; 3990 ;epson auf einzelnadelansteuerung 4000 .byt 4,"*",esc,cr,24 4010 ; 4020 ;tabelle fuer bit-wertigkeiten 4030 nwert .byt 128,64,32,16,8,4,2,1 4040 ; 4050 ;zeichensatz startadressen 4060 memory .byt 0 4070 .end 4080 sys49152 ready.
PROGRAMM : HARDCOPY.OBJ C000 C12F ----------------------------------- C000 : 78 A9 0D A0 C0 8D 14 03 73 C008 : 8C 15 03 58 60 A5 C5 C9 C9 C010 : 04 D0 07 A9 00 85 C5 20 F7 C018 : 1D C0 4C 31 EA A2 FF B5 FE C020 : 00 9D 2E C1 CA D0 F8 A9 1D C028 : 01 85 CC A9 7E A2 04 A0 A2 C030 : 01 20 BA FF A9 00 20 BD 86 C038 : FF 20 C0 FF A2 7E 20 C9 AA C040 : FF A9 1B 20 D2 FF A9 33 19 C048 : 20 D2 FF A9 18 20 D2 FF D4 C050 : A9 00 AC 88 02 85 15 84 DF C058 : 16 A2 19 20 E1 FF F0 3F 6A C060 : A0 27 B1 15 C9 20 D0 0B 9A C068 : 88 10 F7 A9 0D 20 D2 FF 48 C070 : 4C 91 C0 20 09 C1 A0 07 E8 C078 : B9 1E C1 20 D2 FF 88 D0 A6 C080 : F7 A0 00 A9 00 B1 15 85 EA C088 : D6 20 B7 C0 C8 C0 28 D0 49 C090 : F2 A9 28 18 65 15 85 15 A3 C098 : 90 02 E6 16 CA D0 BC A9 1F C0A0 : 0D 20 D2 FF A9 7E 20 C3 08 C0A8 : FF 20 CC FF A2 FF BD 2E 68 C0B0 : C1 95 00 CA D0 F8 60 48 7C C0B8 : 8A 48 98 48 A5 D6 85 F8 AF C0C0 : A9 00 85 F9 06 F8 26 F9 BF C0C8 : 06 F8 26 F9 06 F8 26 F9 C8 C0D0 : A5 F9 18 65 FA 85 F9 A6 36 C0D8 : 01 A9 80 85 9D A9 00 48 36 C0E0 : A0 07 78 A9 01 29 FB 85 AB C0E8 : 01 B1 F8 25 9D 86 01 58 67 C0F0 : F0 06 68 18 79 26 C1 48 61 C0F8 : 88 10 E7 68 20 D2 FF 46 B4 C100 : 9D 90 DA 68 A8 68 AA 68 F2 C108 : 60 A9 00 85 F9 AD 18 D0 FD C110 : 29 02 D0 05 A9 D0 85 FA 3C C118 : 2C A9 D8 85 FA 60 00 01 B4 C120 : 40 04 2A 1B 0D 18 80 40 64 C128 : 20 10 08 04 02 01 00 7E