Schnelle Textausgabe

Sicherlich ist es Ihnen auch schon aufgefallen, daß die Textausgabe bei den meisten Anwendungen sehr langsam ist. Daß es auch schneller geht, kann man unter anderem bei Tempus sehen. Mit dieser Routine kann nun jeder Programmierer in seinen eigenen Programmen für eine schnelle Textausgabe sorgen.

Das Prinzip, mit dem der Text auf den Bildschirm gebracht wird, ist eigentlich sehr einfach. Ein einzelnes Zeichen aus dem Standard-Zeichensatz besteht aus 16 Bytes, die untereinander im Bildschirmspeicher stehen. Soll nun ein Zeichen auf den Bildschirm gebracht werden, so muß man nur die betreffenden 16 Bytes in den Bildschirmspeicher kopieren. Dazu ist es natürlich notwendig zu wissen, wo sich diese 16 Bytes für das auszugebende Zeichen befinden. Beim Aufruf der Routine wird unter anderem auch die Startadresse des Zeichensatzes mit übergeben. Die Adresse, ab der die 16 Bytes für ein einzelnes Zeichen stehen, berechnet sich folgendermaßen: Startadresse des Zeichensatzes + 16 * ASCII -Wert des Zeichens.

Der Aufruf der Routine müßte von jeder Programmiersprache aus möglich sein, die Maschinenroutinenaufrufe zuläßt. Es sind folgende Parameter zu übergeben: zuerst die Adresse des Strings, also die Adresse des ersten auszugebenden Zeichens. Dann wird die Länge des Strings übergeben. Das überrascht vielleicht einige, war aber nötig, um einerseits eine hohe Ausgabegeschwindigkeit zu erreichen, und anderseits den Aufruf von jeder Programmiersprache aus zu ermöglichen. Hiernach kommen die Cursorkoordinaten. Für die Cursor-Home-Position gilt: Zeile=1; Spalte=1. Jetzt wird die Zeichensatzadresse übergeben. Zuletzt kommt noch die Bildschirmadresse. Auch dies geschieht wieder aus Geschwindigkeitsgründen. Die Übergabe einer Variablen ist schneller als das Ermitteln der Bildschirmadresse innerhalb der Routine.

Der Zeichensatz ist 4096 Bytes (256 Zeichen * 16 Bytes) lang. Das erste Zeichen belegt die ersten 16 Bytes, das zweite die darauf folgenden usw... Möglicherweise ist es dem einen oder anderen hier schon aufgefallen, daß STAD- bzw. TEMPUS-Zeichensätze genauso lang sind. Sie sind nicht nur gleich lang, sondern sie haben auch noch das gleiche Format. Was natürlich sehr praktisch ist, weil sich diese Zeichensätze ebenfalls verwenden lassen.

Das Assembler-Listing

Zuerst werden die übergebenen Werte vom Stack geholt. Wer sich sicher ist, daß seine Strings niemals über den rechten Rand hinausgehen, der kann die Zeilen 19-23 ersatzlos streichen. Wer das im Voraus jedoch nicht so genau weiß, der muß diese Zeilen stehen lassen. Zu der Begrenzung auf maximal 80 Zeichen bzw. dem Abschneiden am rechten Rand haben wir uns entschlossen, da es eigentlich keine sinnvolle Anwendung für ein Hinausschreiben über den rechten Rand gibt. Durch diese Vereinfachung läuft die Routine natürlich auch etwas schneller.

Im folgenden werden Bildschirm- und Zeichensatzadresse des auszugebenden Zeichens berechnet und die 16 Bytes in den Bildschirmspeicher kopiert. Um ein Maximum an Geschwindigkeit zu erreichen, haben wir bei dem Kopiervorgang auf eine Schleife verzichtet.

Außer der END-Anweisung werden in dem Listing keine weiteren assemblerspezifischen Befehle verwendet. Den Text sollte also jeder Assembler compilieren können.

Die GFA-Basic-Listings

Als höhere Programmiersprache haben wir GfA-Basic wegen seiner großen Verbreitung gewählt. Listing Nummer 2 erzeugt den Zeichensatz und speichert ihn auf Diskette ab. Durch den DEFTEXT-Befehl lassen sich unterschiedliche Zeichensätze erstellen.

Das Listing 3 verdeutlicht zum einen den Aufruf der Routine (Die Art und Weise wie Langworte bzw. Worte von GfA-Basic übergeben werden, ist in der ST-Computer 1/88 schon genaustens beschrieben worden.), und zeigt den Geschwindigkeitsunterschied recht deutlich. Mit Hilfe der linken Maustaste kann man zwischen der normalen und der neuen Ausgaberoutine hin- und herschalten. Das 4. Listing speichert die Assembler-Routine auf Diskette ab, wodurch auch diejenigen, die über keinen Assembler verfügen, diese Routine nutzen können.

;
; Routine zur schnellen Ausgabe von Strings
;
;   1987 TK-Soft
; Thomas Moltzen 
; (K.E.Neugebauer)
; WasmannstraPe 9 
; 2000 Hamburg 60

    move.1  4(SP),A2 ;Adresse des Strings
    move.w 8(SP),D1 ;Länge des Strings 
    move.w 10(SP),D2 ;Cursor-Spalte 
    move.w 12(SP),D3 ;Cursor-Zeile 
    move.1 14(SP),D4    ;Adresse des Zeichensatzes
    move.1 18(SP),A1 ;aktuelle Bildschirmadresse 
    subq    #1,D2   ;Anpassung an
    subq    #1,D3   ;' Print At '
    subq #1, D1 ;Zähler anpassen 
    move.w #80,D7 ;begrenzt String 
    sub. w  D2, D7  ;auf
    cmp D7, D1  ; eine
    ble.s OK    ; Zeilenlänge
    move.w D7,D1 ; (hier gleich 80 Zeichen)
OK: mulu #1280,D3 ;Umrechnung der Cursor-
    adda.w D2,A1    ; Koordinaten in Bildschirm
    adda.w D3,A1    ; adresse für Stringausgabe
    clr D6  ; Zähler für Stringlänge=0

Schreiben: clr  D5  ;wegen Byte-Verarbeitung (ungerade Adressen) 
    move.b  (A2)+,D5    ;akt. Zeichen i.String
    lsl #4,D5   ;Multiplikation mit 16
    move.1  D4,A0   ;Anfangsadresse des Zeichensatzes 
    adda.w D5,A0    ; plus
Text_ausgabe: move.b (A0)+, (A1) ;Diese Routine schreibt die Daten
    move.b (A0)+,80(A1) ;aus dem selbst-erstellten Zeichen-
    move.b (A0)+,160 (A1) ;satz auf den Bildschirm, 
    move.b (A0)+,240(A1)    ;Der Zeichensatz ist so abgelegt, 
    move.b (A0)+,320(A1)    ;daß die 16 Graphikbytes für 
    move.b (A0)+,400(A1)    ;je ein ASCII-Zeichen hintereinander 
    move.b (A0)+,480(A1)    ;stehen,
    move.b (A0)+,560(A1)    ;
    move.b (A0)+,640(A1)    ;
    move.b (A0)+,720(A1)    ;
    move.b (A0)+,800(A1)    ;
    move.b (A0)+,880(A1)    ;
    move.b (A0)+,960(A1)    ;
    move.b (A0)+,040(A1)    ;
    move.b (A0)+,120(A1)    ;
    move.b (A0),1200(A1)    ;
    addq.w #1,A1    ;Adresse für Stringausgabe erhöhen 
    dbra    D1,Schreiben
    rts ;Rücksprung

    end

Listing 1

'
' Dieses File erzeugt die Zeichensatzdatei 'Z_SATZ.DAT', 
' auf die die Assembler-Routine zugreift.
'
Screen%=Xbios(2)    !Startadresse des Bildschirms.
Zeichen_satz$=Space$(4096) IReserviert Speicher. 
Z_satz_adresse%=Varptr(Zeichen_satz$) ! Ermittelt Speicher-Adresse. 
For I%=0 To 255 !0-255 ==>Zeichenanzahl.
    Deftext 1,0,0,13    !Legt den Zeichensatz fest.
    Text 1,13,Chr$(I%)  !Ausgabe des Zeichens.
    For Z%=0 To 15  !Auslesen der Bytewerte des
        Poke Z_satz_adresse%+Zz%,Peek(Screen%+Z%*80) ! dargestellten Zeichens und 
        Inc Zz% ! Ablage im reservierten Speicher
    Next Z%
Next I% !Nächstes Zeichen.
Bsave "Z_SATZ . DAT", Z_satz_adresse%,4096 ! Speichern des Zeichensatzes.

Listing 2

@Init
'
Do
    Repeat
        @Text_normal(Zz%)   !Textausgabe normal.
        @Zz !Erhöht Buchstaben-Zähler
    Until Mousek=l  !Bis Mousk=1
    @Pause 
    Repeat
        @Text_fast(Zz%) !Textausgabe schnell.
        @Zz !Erhöht Buchstaben-Zähler.
    Until Mousek=1  !Bis Mousek=1
    @Pause 
Loop
'
Procedure Text_normal(Zz%)
    For Z%=2 To 24 
        Print At(2,Z%);Text$(Zz%) !Ausgabe von Zeile2-24 
    Next Z%
Return
'
Procedure Text_fast(Zz%)
    Local Maschinen_routine%
    Maschinen_routine%=Varptr(Maschinen_routine$) !Ermittelt Adresse.
    For Z%=2 To 24 
        ' Adresse der Routine,Adresse des Strings,
        ' Länge des Strings,X-Pos,Y-Pos,Zeichensatzesadresse, 
        ' Bildschirmadresse 
        Void C:Maschinen_routine%(L:Varptr(Text$(Zz%)),W:Len(Text$(Zz%)),W:2,W:Z%,L:Varptr(Zeichen_satz$),L:Screen%)
    Next Z%
Return
'
Procedure Zz 
    Inc Zz%
    If Zz%>26 !Alle Buchstaben wurden gezeigt,
        Zz%=1   !also wieder von vorne beginnen.
    Endif
Return
'
Procedure Pause
    Repeat  !Wartet auf Mousek=0
    Until Mousek=0 
Return
'
Procedure Init
    Hidem   !Maus ausschalten.
    Dim Text$(26)   !Array für Demo-Alphabet.
    For Z%=1 To 26 !Die Buchstaben werden dem
        Let Text$(Z%)=String$(78,64+Z%) ! Array zugewiesen.
    Next Z%
    Screen%=Xbios (2) ! aktueller Bildschirm. 
    Zeichen_satz$=Space$ (4096) !Reserviert Speicher. 
    Bload "Z_SATZ.DAT",Varptr(Zeichen_satz$) !Lädt Zeichensatz.
    Maschinen_routine$=Space$(140) !Reserviert Speicher. 
    Bload "STRING.B",Varptr(Maschinen_routine$) !Lädt Maschinen-Routine.
Return

Listing 3

'
' Dieses File erzeugt die Maschinendatei 'STRING.B',
' die auch vom Assembler erzeugt werden kann.
'
string$=SPACE$(140)
RESTORE string 
FOR z%=0 TO 139 
    READ wert%
    POKE VARPTR(string$)+z%,wert%
NEXT z%
BSAVE "STRING.B",VARPTR(string$),140 
string:
DATA 036,111,000,004,050,047,000,008,052,047,000, 010,054,047,000,012,040,047
DATA 000,014,034,111,000,018,083,066,083,067,083,065, 062,060,000,080,158,066
DATA 178,071,111,002,050,007,198,252,005, 000,210,194, 210,195,066,070,066,069
DATA 026,026,233,077,032,068,208,197,018,152,019,088, 000, 080,019,088,000,160
DATA 019,088,000,240,019,088,001,064,019, 088, 001,144, 019,088,001,224,019,088
DATA 002,048,019,088,002,128,019,088,002,208,019,088, 003,032,019,088,003,112
DATA 019,088,003,192,019,088,004,016,019,088,004,096, 019,080,004,176,082,073
DATA 081,201,255,180,078,117,000, 000, 000, 000, 000, 000,000,000

Listing 4
Thomas Moltzen, K.E.Neugebauer



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]