bildschirmausgabe.asm

Aus C64-Wiki
Zur Navigation springenZur Suche springen

Quelltext[Bearbeiten | Quelltext bearbeiten]

 ;####################################################################
 ;# Programm:      Sammlung von Funktionen für die Bildschirmausgabe
 ;# Dateiname:     bildschirmausgabe.asm
 ;#
 ;# Assembler:     ACME
 ;# Assemblierung: acme -f cbm -o output.prg bildschirmausgabe.asm
 ;#
 ;# Laden mit:     LOAD"output.prg",8,1
 ;#
 ;# Aufruf mit:    Ab der Adresse $c000 ist eine Sprungtabelle, über
 ;#                die jede Funktion mit jsr aufgerufen werden kann
 ;#
 ;# Quelltext:     * Kleinschreibung (bis auf Kommentare)
 ;#                * nur Leerzeichen, keine Tabulatoren
 ;#                * Labels immer in eigener Zeile
 ;#                * Befehle zwei Zeichen eingerückt
 ;#                * Kommentare i.d.R. nach den Befehlen
 ;#
 ;# Beschreibung:  Eine Sammlung an Funktionen zur Bildschirmausgabe.
 ;#                Sie ermöglicht die Auswahl von fünf verschiedenen
 ;#                festgelegten Bereichen (Fenster), die für die
 ;#                Ausgabe, das Löschen und das Scrolling gelten.
 ;#
 ;#                Die fünf festgelegten Bereiche, die als Fenster
 ;#                ausgewählt werden können, sind der gesamte Bild-
 ;#                schirm, sowie die linke, rechte, obere und untere
 ;#                Hälfte des Bildschirms.
 ;#
 ;#                Im ausgewählten Fenster sind folgende Aktionen
 ;#                möglich:
 ;#                * Löschen des gesamten Fensters
 ;#                * Vert. Scrolling des gesamten Fensters nach oben
 ;#                * Horiz. Scrolling der aktuellen Zeile nach links
 ;#                * Ausgabe einzelner Zeichen (direkt als Bildschirm-
 ;#                  code und ASCII)
 ;#                * Zeilenumbruch (mit vertikalem Scrolling)
 ;#                * Ausgabe eines 8-Bit-Werts in hexadezimaler,
 ;#                  binärer und dezimaler Form
 ;#
 ;#                Die Zeilen bzw. Zeichen, die beim Scrolling aus dem
 ;#                Fenster verschwinden, werden nicht gespeichert.
 ;#                Außerdem unterstützt das Scrolling nicht die
 ;#                Anpassung des Farbspeichers, d.h. die Funktionen
 ;#                sind für eine monochrome Bildausgaben gedacht.
 ;#
 ;####################################################################
 
 
 ; -- Startadresse --
 
   *=$c000
 
 
 ;####################################################################
 ;#
 ;# Speicherstellen
 ;#
 ;####################################################################
 
   !addr param = $0334 ; Temporäre Speicherstelle für Parameter
                       ; (ungenutzte Adresse in der erweiterten
                       ; Zeropage)
 
 ; -- Zeiger für das aktuelle Fenster --
   
   !addr wtlp =  $cf00 ; Zeiger auf das aktuelle Fenster
                       ; (top/left pointer)
 
   !addr wlnp =  $cf02 ; Zeiger auf die aktuelle Zeile
                       ; (line pointer)
 
 ; -- Parameter für das aktuelle Fenster --
 
 ;    Die Anzahl der Spalten und Zeilen variiert je nach Fenstertyp:
 ;
 ;    - ein großes Fenster (40 Spalten, 25 Zeilen) 
 ;    - ein halbes Fenster links (20 Spalten, 25 Zeilen) 
 ;    - ein halbes Fenster rechts (20 Spalten, 25 Zeilen) 
 ;    - ein halbes Fenster oben (40 Spalten, 13 Zeilen) 
 ;    - ein halbes Fenster unten (40 Spalten, 12 Zeilen)
 ;
 ;    Die Werte werden um eins verringert, weil wx und wy bei null
 ;    beginnen.
 
   !addr wcols = $cf04 ; Anzahl Spalten (cols; 39 oder 19)
   !addr wrows = $cf05 ; Anzahl Zeilen (rows; 24 oder 12 oder 11)
   !addr wx =    $cf06 ; Aktuelle X-Position
                       ; (Start mit 0; bis max. wcols)
   !addr wy =    $cf07 ; Aktuelle Y-Position
                       ; (Start mit 0; bis max. wrows)
 
 
 ;####################################################################
 ;#
 ;# Makros
 ;#
 ;####################################################################
 
 ; -- add_line_wlnp --
 
 ;    Addiert #40 zum Zeiger auf die aktuelle Zeile (wlnp) hinzu;
 ;    wird von delwin und newline verwendet
 
   !macro add_line_wlnp {
       clc
       lda wlnp
       adc #40
       sta wlnp
       lda wlnp+1
       adc #$00
       sta wlnp+1
   }
 
 ; -- wsel --
 
 ;    Setzt für das aktuelle Fenster den Zeiger auf die
 ;    aktuelle Zeile, sowie x und y auf die Startwerte;
 ;    wird von wselall, wselleft, wselright, wseltop,
 ;    wselbottom und delwin verwendet
 
   !macro wsel {
       lda #0
       sta wx
       sta wy
       lda wtlp
       sta wlnp
       lda wtlp+1
       sta wlnp+1
   }
 
 
 ;####################################################################
 ;#
 ;# Sprungtabelle
 ;#
 ;####################################################################
 
   jmp init       ; $c000
   jmp wselall    ; $c003
   jmp wselleft   ; $c006
   jmp wselright  ; $c009
   jmp wseltop    ; $c00c
   jmp wselbottom ; $c00f
   jmp delline    ; $c012
   jmp delwin     ; $c015
   jmp hscroll    ; $c018
   jmp chrout     ; $c01b
   jmp vscroll    ; $c01e
   jmp newline    ; $c021
   jmp hexout     ; $c024
   jmp binout     ; $c027
   jmp decout     ; $c02a
   jmp asciiout   ; $c02d
 
 
 ;####################################################################
 ;#
 ;# Funktionen
 ;#
 ;####################################################################
 
 
 ; -- init --
 
 ;    Standardinitialisierung: ein großes Fenster, das gelöscht wird
 
 init
   jsr wselall
   jsr delwin
   rts
 
 
 ; -- wselall --
 
 ;    Ein großes Fenster auswählen;
 ;    Akku wird überschrieben
 
 wselall
   lda #$00   ; Zeiger auf Bildschirmspeicher: $0400
   sta wtlp
   lda #$04
   sta wtlp+1
   lda #39    ; 40 (-1) Spalten
   sta wcols
   lda #24    ; 25 (-1) Zeilen
   sta wrows
   +wsel
   rts
 
 
 ; -- wselleft --
 
 ;    Ein halbes Fenster links auswählen;
 ;    Akku wird überschrieben
 
 wselleft
   lda #$00   ; Zeiger auf Bildschirmspeicher: $0400
   sta wtlp
   lda #$04
   sta wtlp+1
   lda #19    ; 20 (-1) Spalten
   sta wcols
   lda #24    ; 25 (-1) Zeilen
   sta wrows
   +wsel
   rts
 
 
 ;-- wselright --
 
 ;   Ein halbes Fenster rechts auswählen;
 ;   Akku wird überschrieben
 
 wselright
   lda #$14   ; Zeiger auf Bildschirmspeicher: $0414 (1024 + 20)
   sta wtlp
   lda #$04
   sta wtlp+1
   lda #19    ; 20 (-1) Spalten
   sta wcols
   lda #24    ; 25 (-1) Zeilen
   sta wrows
   +wsel
   rts
 
 
 ; -- wseltop --
 
 ;    Ein halbes Fenster oben auswählen;
 ;    Akku wird überschrieben
 
 wseltop
   lda #$00   ; Zeiger auf Bildschirmspeicher: $0400
   sta wtlp
   lda #$04
   sta wtlp+1
   lda #39    ; 40 (-1) Spalten
   sta wcols
   lda #12    ; 13 (-1) Zeilen
   sta wrows
   +wsel
   rts
 
 
 ; -- wselbottom --
 
 ;    Ein halbes Fenster unten auswählen;
 ;    Akku wird überschrieben
 
 wselbottom
   lda #$08   ; Zeiger auf Bildschirmspeicher: $0608 (1024 + 13*40)
   sta wtlp
   lda #$06
   sta wtlp+1
   lda #39    ; 40 (-1) Spalten
   sta wcols
   lda #11    ; 12 (-1) Zeilen
   sta wrows
   +wsel
   rts
 
 
 ; -- delline --
 
 ;    Löscht die aktuelle Zeile mit Leerzeichen;
 ;    Akku und Y-Register werden überschrieben;
 ;    benutzt die Zeropage-Adressen $61 und $62;
 ;    wird von delwin aufgerufen
 
 delline
   lda wlnp
   sta $61
   lda wlnp+1
   sta $62                
   ldy wcols
   lda #$20
 -
   sta ($61),y
   dey
   bpl -      ; Schleifenabbruch erst bei Y < 0
   rts                
 
 
 ; -- delwin --
 
 ;    Löscht das aktuelle Fenster mit Leerzeichen
 ;    der wlnp, sowie wx und wy werden zurückgesetzt;
 ;    Akku und Y-Register werden überschrieben
 
 delwin
   +wsel      ; Zeilenzeiger, x, y zurücksetzen
 -
   jsr delline
   +add_line_wlnp ; Zeiger auf Zeile erhöhen
   ldy wy
   iny
   cpy wrows
   sty wy
   bcc -      ; Schleife wird bei wy <= wrows fortgesetzt
   beq -
   +wsel      ; Zeilenzeiger, x, y wieder zurücksetzen
   rts
 
 
 ; -- hscroll --
 
 ;    Zeile horizontal um ein Zeichen scrollen:
 ;    Akku und Y-Register werden überschrieben;
 ;    verwendet die Zeropage-Adressen $61 bis $64;
 ;    wird von chrout aufgerufen
 
 hscroll
   sec          ; Addition +1 wird über gesetztes Carry-Bit gemacht
   lda wlnp
   sta $61      ; $61/$62 zeigt auf das erste Zeichen der Zeile
   adc #0       ; eins hinzu addieren (über gesetztes Carry, s.o.)
   sta $63      ; $63/$64 zeigt auf das zweite Zeichen der Zeile
   lda wlnp+1
   sta $62
   adc #0       ; (16-Bit-Addition)
   sta $64
   ldy #$00     ; von links nach rechts die Zeile durchgehen
 -
   lda ($63),y  ; Zeichen nach links verschieben
   sta ($61),y
   iny
   cpy wcols
   bne -        ; Abbruchbedingung: Y = wcols
                ; d.h. Spaltenanzahl-1 Durchgänge
   lda #$20     ; ein Leerzeichen ans Ende der Zeile schreiben
   ldy wcols
   sta ($61),y
   rts
 
 
 ; -- chrout --
 
 ;    Gibt den Wert im Akku (Bildschirmcode) aus. Wenn das
 ;    Zeilenende erreicht ist, wird horizontal gescrollt.
 ;    Y-Register wird überschrieben;
 ;    verwendet die Zeropage-Adressen $61/$62
 ;    (beim Scrolling auch die Adressen $63/$64):
 ;    wird von hexout, binout, decout und asciiout aufgerufen
 
 chrout
   pha         ; Bildschirmcode sichern
   lda wlnp
   sta $61
   lda wlnp+1
   sta $62
   ldy wx
   pla         ; Bidlschirmcode wieder holen
   sta ($61),y
   cpy wcols   ; Wenn Ende der Zeile erreicht ist, Scrolling durchführen
   beq +
   iny         ; ansonsten wx um eins erhöhen
   sty wx
   rts
 +
   jsr hscroll
   ; wlx nicht erhöhen
   rts
 
 
 ; -- vscroll --
 
 ;    Fensterinhalt um eine Zeile nach oben verschieben;
 ;    Akku, X- und Y-Register werden überschrieben;
 ;    die letzte Zeile wird zur aktuellen Zeile;
 ;    verwendet die Zeropageadressen $61-$64;
 ;    wird von newline aufgerufen
 
 vscroll
     clc
     lda wtlp
     sta $61    ; 1. Zeiger zeigt auf die erste Zeile
     adc #40
     sta $63    ; 2. Zeiger auf die zweite Zeile
     lda wtlp+1
     sta $62
     adc #0
     sta $64
 
     ldx wrows
 scroll_loop    ; 1. Schleife: alle Zeilen um eins nach oben verschieben
 
     ldy wcols
 -              ; 2. Schleife: alle Zeichen der Zeile durchgehen
     lda ($63),y
     sta ($61),y
     dey
     bpl -      ; Abbruch 2. Schleife erst bei Y < 0
     dex
     beq +      ; Abbruchbedingung 1. Schleife: X = wrows
                ; d.h. Zeilenanzahl-1 Durchgänge
 
     lda $61    ; 1. Zeiger um eine Zeile erhöhen
     clc
     adc #40
     sta $61
     lda $62
     adc #0
     sta $62
 
     lda $63    ; 2. Zeiger um eine Zeile erhöhen
     clc
     adc #40
     sta $63
     lda $64
     adc #0
     sta $64
     jmp scroll_loop
 +
     lda $63    ; $63/$64 zeigt auf die letzte Zeile
     sta wlnp   ; diese wird zur aktuellen Zeile
     lda $64
     sta wlnp+1
     jsr delline ; und ihr Inhalt gelöscht
     rts
 
 
 ; -- newline --
 
 ;    Zeilenumbruch durchführen
 ;    Wenn die letzte Zeile des Fensters die aktuelle Zeile
 ;    ist, wird ein Scrolling durchgeführt.
 ;    Akku und Y-Register werden überschrieben, beim
 ;    Scrolling auch das X-Register
 
 newline
   lda #$00  ; wx auf 0 setzen
   sta wx
   ldy wy
   cpy wrows ; wenn Ende des Fenster erreicht ist, dann scrollen
   beq +
   iny       ; Zeile um eins erhöhen ...
   sty wy
   +add_line_wlnp ; Zeiger auf Zeile erhöhen
   rts
 +
   jsr vscroll
   rts
 
 
 ; -- hexout --
 
 ;    Gibt den Wert im Akku in hexadezimaler Form aus;
 ;    Akku, X- und Y-Register (von chrout) werden überschrieben
 
 hexout
   pha       ; Wert sichern
   lsr       ; die oberen 4 Bits nach unten holen
   lsr
   lsr
   lsr
   tax       ; passendes Zeichen laden und ausgeben
   lda hex_digits,x
   jsr chrout
   pla       ; Wert wieder holen
   and #$0f  ; die unten 4 Bits isolieren
   tax       ; passendes Zeichen laden und ausgeben
   lda hex_digits,x
   jsr chrout
   rts
 
 hex_digits
   ; Bildschirmcodes Ziffern 0-9
   !by $30, $31, $32, $33, $34, $35, $36, $37, $38, $39
   ; Bildschirmcodes Buchstaben A-F
   !by $01, $02, $03, $04, $05, $06
 
 
 ; -- binout --
 
 ;    Gibt den Wert im Akku in binärer Form aus;
 ;    Akku, X- und Y-Register (von chrout) werden überschrieben;
 ;    die Speicherstelle param wird verändert
 
 binout
   sta param ; Wert ablegen
   ldx #$07  ; Zähler von 7 bis 0
 bin_loop    ; Den Wert bitweise von links nach rechts durchgehen
   txa       ; Zähler sichern
   pha
   lda param ; Das höchste Bit in den Carry-Flag befördern
   asl
   sta param
   bcc +     ; Abhängig vom Ergebnis '0' oder '1' ausgeben
   lda #$31
   bne ++
 +
   lda #$30
 ++
   jsr chrout
   pla       ; Zähler wieder holen
   tax
   cpx #$04  ; nach 4 Bits ein Leerzeichen ausgeben
   bne +
   lda #$20
   jsr chrout
 +
   dex
   bpl bin_loop ; Abbruchbedingung X < 0
   rts
 
 
 ; -- decout --
 
 ;    Gibt den Wert im Akku in dezimaler Form mit  
 ;    führenden Nullen aus;  
 ;    Akku, X- und Y-Register werden überschrieben;  
 ;    die Speicherstelle param wird verwendet  
 
 decout
   sta param ; Wert sichern
 
 ;    100-Stellen
 
   ldx #$00  ; dargestellte Ziffer (Startwert '0')
   cmp #$64  ; ist der Wert < 100
   bcc +     ; '0' ausgeben (X ist noch null)
   sec
 -
   sbc #$64  ; 100 abziehen
   bcc +     ; Abbruchbedingung: Wert wird negativ
   sta param ; verringerten Wert speichern
   inx       ; dargestellte Ziffer um eins erhöhen
   jmp -
 +
   txa
   ora #$30  ; Bildschirmcode setzen
   jsr chrout
 
 ;    10er-Stellen
 
   ldx #$00  ; dargestellte Ziffer (Startwert '0')
   lda param
   cmp #$0a  ; ist der Wert < 10
   bcc +     ; '0' ausgeben (X ist noch null)
   sec
 -
   sbc #$0a  ; 10 abziehen
   bcc +     ; Abbruchbedingung: Wert wird negativ
   sta param ; verringerten Wert speichern
   inx       ; dargestellte Ziffer um eins erhöhen
   jmp -
 +
   txa
   ora #$30  ; Bildschirmcode setzen
   jsr chrout
 
 ;    1er-Stellen
 ;    Der Restwert aus der Speicherstelle param kann
 ;    direkt ausgegeben werden.
 
   lda param
   ora #$30  ; Bildschirmcode setzen
   jsr chrout
   rts
 
 
 ; -- asciout --
 
 ;    Gibt das den im Akku enthaltenen ASCII-Wert aus
 ;    Akku, X- und Y-Register werden überschrieben
 
 ;    Es werden folgende ASCII-Werte unterstützt:  
 ;
 ;    - $0a/#10, $0d/#13:  Zeilenumbruch  
 ;    - $20-$3f/#32-#63:   Satzzeichen und Ziffern  
 ;    - $40-$5f/#64-#95:   Groß- (Font 1) bzw. Kleinbuchstaben (Font 2)
 ;    - $90-$7f/#96-#127:  Grafikzeichen 1 (Font 1) bzw. Großbuchstaben
 ;                         (Font 2)  
 ;    - $a0-$bf/#160-#191: Grafikzeichen 2  
 ;    - $93/#147:          Aktuelles Fenster löschen  
 ;
 ;    Bei allen anderen ASCII-Werten wird ein Fragezeichen ausgegeben.
 
 ;    Umwandlungen von ASCII nach Bildschirmcode:  
 ;
 ;    - Satzzeichen und Ziffern (kene Umwandlung)  
 ;      %001 00000 ($20) bis %001 11111 ($3f)  
 ;    - Großbuchstaben (Bit 6 invertieren und dadurch löschen)   
 ;      %010 00000 ($40) bis %010 11111 ($5f)  
 ;      %000 00000 ($00) bis %000 11111 ($1f)  
 ;    - Grafikzeichen 1 (Bit 5 inverieren und dadurch löschen)  
 ;      %011 00000 ($60) bis %011 11111 ($7f)  
 ;      %010 00000 ($40) bis %010 11111 ($5f)  
 ;    - Grafikzeichen 2 (Bits 7 und 6 invertieren)  
 ;      %101 00000 ($a0) bis %101 11111 ($bf)  
 ;      %011 00000 ($60) bis %011 11111 ($7f)  
 
 asciiout
   cmp #$0a   ; Zeilenumbruch
   bne +
   jsr newline
   rts
 +
   cmp #$0d   ; Zeilenumbuch
   bne +
   jsr newline
   rts
 +
   cmp #$93   ; Fenster löschen
   bne +
   jsr delwin
   rts
 +
   pha        ; ASCII-Wert sichern
   lsr        ; die 3 oberen Bits nach unten holen
   lsr
   lsr
   lsr
   lsr
   tax        ; und zur Auswertung ins X-Register schieben
   pla        ; ASCII-Wert wieder holen
   cpx #$01   ; Satzzeichen und Ziffern
   bne +
   jsr chrout
   rts
 +
   cpx #$02   ; Großbuchstaben
   bne +
   eor #$40
   jsr chrout
   rts
 +
   cpx #$03   ; Grafikzeichen 1
   bne +
   eor #$20
   jsr chrout
   rts
 +
   cpx #$05   ; Grafikzeichen 2
   bne +
   eor #$c0
   jsr chrout
   rts
 +
   lda #$3f   ; ansonsten Fragezeichen ausgeben
   jsr chrout
   rts


Demo-Programm[Bearbeiten | Quelltext bearbeiten]

 ;####################################################################
 ;# Programm:      Demo-Programm für Bildschirmausgabe
 ;#                mit Basic-Starter
 ;# Dateiname:     bildschirmdemo.asm
 ;#
 ;# Assembler:     ACME
 ;# Assemblierung: acme -f cbm -o output.bas bildschirmdemo.asm
 ;#
 ;# Laden mit:     NEW
 ;#                LOAD"output.bas",8
 ;#
 ;# Start mit:     RUN
 ;#
 ;# Quelltext:     * Kleinschreibung (bis auf Kommentare)
 ;#                * nur Leerzeichen, keine Tabulatoren
 ;#                * Labels immer in eigener Zeile
 ;#                * Befehle zwei Zeichen eingerückt
 ;#                * Kommentare i.d.R. nach den Befehlen
 ;#
 ;# Beschreibung:  Das Programm gibt nacheinander folgendes aus:
 ;#                - im linken Fenster die Hexwerte 0-255
 ;#                - im rechten Fenster die Binärwerte 0-255
 ;#                - im oberen Fenster die Dezimalwere 0-255
 ;#                - im unteren Fenster die ASCII-Werte 32-127
 ;#
 ;####################################################################
 
 
 ;####################################################################
 ;#
 ;# Basic-Starter
 ;#
 ;####################################################################
 
   *=$0801
 
 ; -- Basic-Startzeile erzeugen: 10 SYS 2061 --
 
   !by $0b, $0a           ; Zeiger zur zweiten Zeile
   !by $0a, $00           ; Zeilennummer (10)
   !by $9e                ; Token für SYS
   !by $32, $30, $36, $31 ; 2061 in ASCII
   !by $00                ; Ende der Basic-Zeile
   !by $00, $00           ; Zweite Basic-Zeile und zugleich Ende des
                          ; Basic-Programms
 
 
 ;####################################################################
 ;#
 ;# Hauptprogramm (Start bei $080d/#2061)
 ;#
 ;####################################################################
 
 
 ; -- Speicherstellen --
 
   !addr cnt = $0335      ; Zähler (ungenutzte Speicherstelle in der
                          ; erweiterten Zeropage)
 
 
 ; -- Start --
 
   jsr $c000 ; init
 
 
 ; -- Im linken Fenster Hexadezimalwerte ausgeben --
 
   jsr $c006 ; wselleft
   jsr $c015 ; delwin
   ldx #0    ; Hexwerte 0-255
 -
   stx cnt
   lda #$24  ; '$'
   jsr $c01b ; chrout
   txa
   jsr $c024 ; hexout
   jsr $c021 ; newline
   ldx cnt
   inx
   bne -
 
 ; -- Im rechten Fenster Binärwerte ausgeben --
 
   jsr $c009 ; wselright
   jsr $c015 ; delwin
   ldx #0    ; Binärwerte 0-255
 -
   stx cnt
   lda #$25  ; '%'
   jsr $c01b ; chrout
   txa
   jsr $c027 ; binout
   jsr $c021 ; newline
   ldx cnt
   inx
   bne -
 
 ; -- Im oberen Fenster Dezimalwerte ausgeben --
 
   jsr $c00c ; wseltop
   jsr $c015 ; delwin
   ldx #0    ; Dezimalwerte 0-255
 -
   stx cnt
   txa
   jsr $c02a ; decout
   jsr $c021 ; newline
   ldx cnt
   inx
   bne -
   
 ; -- Im unteren Fenster ASCII-Werte ausgeben --
 
   jsr $c00f ; wselbottom
   lda #147  ; Bildschirmhälfte löschen
   jsr $c02d ; asciiout
   ldx #$20  ; ASCII-Zeichen 32-63
 -
   stx cnt
   txa
   jsr $c02d ; asciiout
   ldx cnt
   inx
   cpx #$40
   bne -
   lda #10   ; Zeilenumbruch
   jsr $c02d ; asciiout
 
   ldx #$40  ; ASCII-Zeichen 64-95
 -
   stx cnt
   txa
   jsr $c02d ; asciiout
   ldx cnt
   inx
   cpx #$60
   bne -
   lda #13   ; Zeilenumbruch
   jsr $c02d ; asciiout
 
   ldx #$20  ; ASCII-Zeichen 32-95 mit horiz. Scrolling
 -
   stx cnt
   txa
   jsr $c02d ; asciiout
   ldx cnt
   inx
   cpx #$60
   bne -
   lda #13   ; Zeilenumbruch
   jsr $c02d ; asciiout
 
   ldx #$60  ; ASCII-Zeichen 96-127
 -
   stx cnt
   txa
   jsr $c02d ; asciiout
   ldx cnt
   inx
   cpx #$80
   bne -
   rts