LineA für Turbo-C

Die meisten C-Compiler für den ATARI ST werden mit umfangreichen Bibliotheken ausgeliefert, welche die Programmentwicklung wesentlich erleichtern. Jedoch fehlt bei den meisten Bibliotheken die Möglichkeit, die LineA-Funktionen aufzurufen. Für den Programmierer heißt das, will er beispielsweise einen Punkt auf dem Bildschirm setzen, eine eigene Routine zu programmieren oder sich dem langsamen und umständlichen VDI (Applikation anmelden, Workstation öffnen, VDI-Aufruf, Workstation schließen, Applikation abmelden) anzuvertrauen.

Das hier vorliegende Programm soll da Abhilfe schaffen. Es ermöglicht den Aufruf der Line A-Funktionen von Turbo-C aus. Das Programm läßt sich mit geringem Aufwand auch an jeden anderen C-Compiler anpassen.

Installation der LineA-Bibliothek

Wie funktionierte?

Die Funktionsweise ist bei allen LineA-Aufrufen prinzipiell gleich und vollzieht sich in drei Schritten. Im ersten Schritt werden die Parameter in die LineA-Variablen eingetragen. Um eine höhere Geschwindigkeit zu erreichen, wird die Turbo-C Option der Registerübergabe ausgenutzt, d.h. die ersten drei Werte-Parameter werden in den Registern D0-D2, die ersten beiden Zeiger in A0-A1 übergeben. Die restlichen Parameter liegen ab 4(sp) auf dem Stack (siehe Kapitel 7 des Turbo-C-Handbuchs). Im zweiten Schritt werden die Register D3-D7 und A2-A6 gerettet (Turbo-C hätte sie gerne unbeschädigt zurückerhalten). Schritt zwei kann auch vor Schritt eins ausgeführt werden, wenn keine Parameter auf dem Stack übergeben werden, da ein ‘movem’-Befehl den Stackpointer verändert (siehe Listing). Im dritten Schritt wird schließlich die entsprechende LineA-Funktion mit ‘.dc.w $a00x’ aufgerufen, und daran anschließend werden die Register restauriert.

Die Anpassung an andere Compiler

Um das Programm mit anderen Compilern zu verwenden (nicht nur C-Compiler verwenden das DR-Format...), müssen Sie das Listing so ändern, daß alle Parameter vom Stack genommen werden. Wo auf dem Stack die Parameter liegen und welche Register gerettet werden müssen, entnehmen Sie bitte dem entsprechenden Handbuch. Beachten Sie bitte auch die Reihenfolge, in der die Parameter übergeben werden.

Die Benutzung in eigenen Programmen

Laden Sie in jedes Programm, das auf die LineA-Grafik zugreift, die Datei ‘linea.h' mit Hilfe der Preprozessor-Anweisung ‘#include <linea.h>' Die besondere Art der Funktionsdeklaration von Turbo-C (siehe Kapitel 5 des Turbo-C-Handbuchs) ermöglicht es, daß grobe Fehler bei der Parameterübergabe vom Compiler erkannt und angezeigt werden. Achtung: Der Compiler erkennt nur Fehler bei unkorrekter Parameteranzahl und falschen Typen!!!

Beachten Sie bitte, daß die Compiler-Option Registerübergabe eingeschaltet ist.

Gehen Sie sehr sorgfältig bei der Nutzung von LineA vor. Unkorrekte Parameter können zu unerwünschten Resultaten oder gar zum Abstürzen des Betriebssystems führen!

Die Bedeutung der LineA-Parameter zu erklären, würde an dieser Stelle wohl den Rahmen sprengen. Die Bezeichnungen der Parameter entsprechen denen in der Fachliteratur. Einschlägige Bücher wie Data Beckers “ATARI ST Intern” oder das Markt&Technik-Buch “ATARI ST Assemblerbuch” geben jedoch knappe Auskunft über die Bedeutung der Parameter. Am besten probiert man nach dem Studium dieser Bücher ein wenig herum. Vielleicht schreibt ja auch mal jemand einem LineA-Kurs in dieser Zeitschrift...

Fehlersuche mit dem Debugger

Wenn sich ein Fehler bei der Benutzung der LineA-Bibliothek partout nicht finden lassen will, verwenden Sie einen Debugger zur Fehlersuche. Befreien Sie das fehlerhafte Programm mit den Befehlen '/’ und '/' von unnötigem Ballast. Beim GFA-Debugger ist folgendes Vorgehen sinnvoll:

Laden Sie das Programm mit dem Befehl ‘e “programmname”' in den Debugger. Auf dem Bildschirm wird unter anderem die Startadresse des Text-Segments angegeben. Schalten Sie die Registerüberwachung mit ‘regon ein. Tracen Sie nun das Programm mit dem Befehl ‘ta Adresse_des_Textsegments’. Anhand des gerade abgearbeiteten Befehls (die LineA -Routinen werden übrigens mit ‘jsr $xxxxxx’ angesprungen) und der Registerinhalte sollten Sie nun den Fehler lokalisieren können. Um die LineA-Parameter zu überwachen, die auf dem Stack übergeben werden, erstellen Sie eine zweite LineA-Datei, bei der Sie hinter jeden ‘move.x x(sp),x(a0)’ - Befehl die Anweisung 'move.x x(sp),d0’ setzen. In D0 können Sie sich so den Stack ansehen. Vergessen Sie nicht, vorher D0 zu retten. Nennen Sie die daraus entstehende Objekt-Datei 'lineadbg.o’ und erstellen Sie eine entsprechende Projektdatei. Wie Sie vielleicht bemerkt haben, sind nicht alle LineA-Routinen implementiert. Wenn Sie Lust haben, vervollständigen Sie die LineA-Bibliothek.

/*

        ************************************************************
        *                                                          *
        * Definitionsdatei für die LineA-Aufrufe unter Turbo-C *
        *                                                          *
        ************************************************************

                geschrieben von Thomas Schlesinger 
                            im Oktober 1988 
                            mit Turbo-C 1.0

*/

void Init_LineA     (void);

void Put_Pixel      ( int x, int y, int c );

int Get_Pixel       ( int x, int y ) ;

void Line           ( int x1, int y1, int x2, int y2,
                      int fgbp0, int fgbp1, int fgbp2, int fgbp3, 
                      int lnmask, int wrtmod, int lstlin );

void H_Line         ( int x1, int y1, int x2, int fgbp0,
                      int fgbp1, int fgbp2, int fgbp3, 
                      int wrtmod, int pattern[], intpatmask);

void Fill_Rect      ( int x1, int y1, int x2, int y2,
                      int fgbp0, int fgbp1, int fgbp2, 
                      int fgbp3, int wrtmod, int pattern[], 
                      int patmask, int multfil, intclip,
                      int xminclp, int xmaxclp, intyminclp,
                      int ymaxclp);

void Fill_Poly      ( int ptsin[], int size, int y,
                      int fgbp0, int fgbp1, int fgbp2, 
                      int fgbp3, int wrtmod, int pattern[], 
                      int patmask, int multifil, intclip,
                      int xminclp, int xmaxclp, intyminclp,
                      int ymaxclp);

void Mouse_on       (void);

void Mouse_Off      (void);

void Mouse_Form     ( int mask[], int cursdt[] );

void Undraw_Sprite  ( int save[] );

void Draw_Sprite    ( int x, int y, int data[], int save[] );

/*  Hinweis:

    Die Bedeutung der Parameter kann in einschlägige n Büchern, 
    wie z.B. Data Becker's >Atari ST Intern< nachgelesen werden. 
    Die Namen entsprechen den üblicherweise verw Bezeichnungen. 
    Bei den Funktionen Fill_Poly($a006), Fill_Rect($ aD05) müssen 
    die Clipping-Parameter mit übergeben werden. Falls nicht 
    geclippt wird, übergibt man Scheinparameter(Dummies).

*/

Listing 1: Header-Datei zur LineA-Bibliothek

    ; DEFAULT.PRJ, angepasst an LineA-Bibliothek
    ; ------------------------------------------
*   ; Programmname vom obersten Fenster
=               ;
tcstart.o       ; Initialisierungs-Modul
*               ;
linea.o         ; LineA-Bibliothek
tcfltlib.lib    ; Fliesskomma-Bibliothek
tcstdlib.lib    ; Standard-Bibliothek
tcextlib.lib    ; Extended-Bibliothek
tctoslib.lib    ; TOS-Bibliothek
tcgemlib.lib    ; AES & VDI-Bibliothek
                ; unnötige Bibliotheken entfernen

Listing 2: Neue Projektdatei

;************************************************
;*                                              *
;*  Line-A Grafik-Bibliothek für Turbo-C 1.0    *
;*                                              *
;*                                              *
;*  geschrieben von Thomas Schlesinger          *
;*              am  13.10.1988                  *
;*              mit dem GFA-Assembler           *
;*                                              *
;************************************************

; ** Alle Funktionen dem Linker bekanntmachen **

            .GLOBL Init_LineA 
            .GLOBL Put_Pixel
            .GLOBL Get_Pixel
            .GLOBL Line
            .GLOBL H_Line
            .GLOBL Fill_Rect
            .GLOBL Fill_Poly
            .GLOBL Mouse_On 
            .GLOBL Mouse_Off 
            .GLOBL Mouse_Form 
            .GLOBL Undraw_Sprite
            .GLOBL Draw_Sprite


; *** LineA-Variablen definieren ***

contrl      equ 4 
intin       equ 8
ptsin       equ 12
fgbp0       equ 24
fgbp1       equ 26
fgbp2       equ 28
fgbp4       equ 30
lstlin      equ 32 
ln_mask     equ 34 
wrt_mode    equ 36 
x1          equ 38
y1          equ 40
x2          equ 42
y2          equ 44
pat_ptr     equ 46 
pat_msk     equ 50 
multifil    equ 52 
clip        equ 54
xmin_clp    equ 56 
ymin_clp    equ 58 
xmax_clp    equ 60 
ymax_clp    equ 62


; *** Jetzt geht's los! ***



.TEXT

; ***********************************************
; *                                             *
; *  Init_LineA initialisiert die LineA-Grafik  *
; *                                             *
; ***********************************************

Init_LineA:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    .DC.w       $a000               ; Line-A-Init aufrufen
    move.l      a0,vars             ; Adresse der LineA-Varliste 
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Ab nach Hause

; **********************************************
; *                                            * 
; *  Put_Pixel setzt einen Punkt x,y in der    * 
; *  Farbe c                                   *
; **********************************************

Put_Pixel:
    movem.l     d3-d7/a2-a6/-(sp)   ; Register retten
    movea.1     vars,a0             ; LineA-Varliste
    movea.l     intin(a0),a1        ; Intin-Array
    movea.l     ptsin(a0),a2        ; Ptsin-Array
    move.w      d0,(a2)             ; x-Koordinate
    move.w      d1,2(a2)            ; y-Koordinate
    move.w      d2,(a1)             ; Farbe
    .DC.w       $a001               ; LineA-Putpixel
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren
    rts                             ; See you later, alligator !

; **********************************************
; *                                            * 
; *  Get_Pixel ermittelt die Farbe des         *
; *  Punktes x,y                               *
; **********************************************


Get_Pixel:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    movea.l     vars,a0             ; LineA-Varliste
    movea.l     ptsin(a0),a1        ; Ptsin-Array
    move.w      d0,(a2)             ; x-Koordinate
    move.w      d1,2(a2)            ; y-Koordinate
    .DC.w $a002                     ; LineA-Getpixel (Ergebnis in d0) 
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Good bye, crocodile !

; **********************************************
; *                                            * 
; *  Line zieht eine Linie vom x1,y1 nach      *
; *  x2,y2                                     *
; **********************************************

Line:
    movea.l     vars,a0             ; LineA-Varliste
    move.w      d0,x1(a0)           ; x1
    move.w      d1,y1(a0)           ; y1
    move.w      d2,x2(a0)           ; x2
    move.w      4(sp),y2(a0)        ; y2 vom Stack
    move.w      6(sp),fgbp0(a0)     ; Plane 0 vom Stack
    move.w      8(sp),fgbp1(a0)     ; Plane 1 vom Stack
    move.w      10(sp),fgbp2(a0)    ; Plane 2 vom Stack
    move.w      12(sp),fgbp3(a0)    ; Plane 3 vom Stack
    move.w      14(sp),ln_mask(a0)  ; LineMask v.Stack
    move.w      16(sp),wrt_mode(a0) ; WriteModev.Stack
    move.w      18(sp),lstlin(a0)   ; LstLine v.Stack 
    movem.l     d3-d7/a2-a6,-(sp)   ; erst jetzt Register retten 
    .DC.w $a003                     ; LineA-DrawLine
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Adios!

; **********************************************
; *                                            * 
; *  H_Line zieht eine hor. Linie vom x1,y1    *
; *  nach x2,y1                                *
; **********************************************

H_Line:
    move.l      a0,pp               ; PatternPointer retten
    movea.l     vars,a0             ; LineA-Varliste
    move.w      d0,x1(a0)           ; x1
    move.w      d1,y1(a0)           ; y1
    move.w      d2,x2(a0)           ; x2
    move.w      4(sp),fgbp0(a0)     ; Plane 0 vom Stack
    move.w      6(sp),fgbp1(a0)     ; Plane 1 vom Stack
    move.w      8(sp),fgbp2(a0)     ; Plane 2 vom Stack
    move.w      10(sp),fgbp(a0)     ; Plane 3 vom Stack
    move.w      12(sp),wrt_mode(a0) ; WriteMode v. Stack
    move.l      pp,pat_ptr(a0)      ; PatternPointer vom Stack
    move.w      14(sp),pat_msk(a0)  ; PatternMask vom Stack
    movem.l     d3-d7/a2-a6,-(sp)   ; erst jetzt  Register retten 
    .DC.w $a004                     ; LineA-DrawLine
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Auf Wiedersehen!

; **********************************************
; *                                            * 
; *  Filled Rect zeichnet gefülltes Rechteck   *
; *  (was sonst?)                              *
; **********************************************

Fill_Rect:
    move.l      a0,pp               ; PatternPointer retten
    movea.l     vars,a0             ; LineA-Varliste
    move.w      d0,x1(a0)           ; x1
    move.w      d1,y1(a0)           ; y1
    move.w      d2,x2(a0)           ; x2
    move.w      4(sp),y2(a0)        ; y2
    move.w      6(sp),fgbp0(a0)     ; Plane 0 vom Stack
    move.w      8(sp),fgbp1(a0)     ; Plane 1 vom Stack
    move.w      10(sp),fgbp2(a0)    ; Plane 2 vom Stack
    move.w      12(sp),fgbp3(a0)    ; Plane 3 vom Stack
    move.w      14(sp),wrt_mode(a0) ; WriteMode v.Stack 
    move.l      pp,pat_ptr(a0)      ; PatternPointer vom Stack
    move.w      16(sp),pat_msk(a0)  ; PatternMask vom Stack
    move.w      18(sp),multifil(a0) ; Multifill
    move.w      20(sp),clip(a0)     ; clip vom Stack
    move.w      22(sp),xmin_clp(a0) ; xminclp vom Stack
    move.w      24(sp),ymin_clp(a0) ; yminclp vom Stack 
    move.w      26(sp),xmax_clp(a0) ; xmaxclp vom Stack 
    move.w      28(sp),ymax_clp(a0) ; ymaxclp vom Stack 
    movem.l     d3-d7/a2-a6,-(sp)   ; erst jetzt Register retten 
    .DC.w $a005                     ; LineA-FilledRect
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Go Home!

; **********************************************
; *                                            * 
; *  Filled Polygon zeichnet ein gefülltes     *
; *  Polygon                                   *
; **********************************************

Fill_Poly:
    move.l      a0,arrp             ; Koordinaten-Pointer retten 
    move.l      a1,pp               ; Pattern-Pointer retten
    movea.l     vars,a0             ; Linea-Varliste
    movea.l     contrl(a0),a1       ; contrl[0]
    addq.l      #2,a1               ; contrl[1]
    move.w      d0,(a1)             ; Anzahl der Punkte in contrl[1]
    addq.w      #1,d0               ; Punkte+1, da Rückkehr zu Punkt 0
    asl.w       #1,d0               ; mal 2, da 1 Punkt=2 Koordinaten 
    movea.l     arrp,a1             ; PointerKoord-Array
    move.l      a2,help             ; A2 retten
    movea.l     ptsin(a0),a2        ; Array-Pointer in ptsin
    movea.l     a2,a0               ; A2 retten
loop1: move.w   (a1)+,(a2)+         ; Kopie User->ptsin Array 
    dbra        d0,loop1            ; Schleifenende
    movea.l     help,a2             ; A2 restaurieren
    movea.l     vars,a0             ; A0 restaurieren
    move.w      d1,y1(a0)           ; y-Wert
    move.w      d2,fgbp0(a0)        ; fgbp0
    move.w      4(sp),fgbp1(a0)     ; fgbp1
    move.w      6(sp),fgbp2(a0)     ; fgbp2
    move.w      8(sp),fgbp3(a0)     ; fgbp3
    move.w      10(sp),wrt_mode(a0) ; writemode
    move.w      12(sp),pat_msk(a0)  ; PatternMask 
    move.w      14(sp),multifil(a0) ; Multifill
    move.w      16(sp),clip(a0) ; clip
    move.w      18(sp),xmin_clp(a0) ; xminclp
    move.w      20(sp),ymin_clp(a0) ; xmaxclp
    move.w      22(sp),xmax_clp(a0) ; yminclp
    move.w      24(sp),ymax_clp(a0) ; ymaxclp
    move.l      pp,pat_ptr(a0)      ; Pattern Pointer
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    .DC.w $a006                     ; LineA-Filled Polygon
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Let's go home!

; **********************************************
; *                                            * 
; *  Mouse_On schaltet die Maus ein            *
; *                                            * 
; **********************************************


Mouse_On:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    .DC.w $a009                     ; LineA-Mouse on
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Adios!

; **********************************************
; *                                            * 
; *  Mouse_Off schaltet die Maus aus           *
; *                                            * 
; **********************************************

Mouse_Off:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    .DC.w $a00a                     ; LineA-Mouse off
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; und ab!

; ************************************
; *                                  *
; *  Mouse_Form veraendert die Maus  *
; *                                  *
; ************************************

Mouse_Form:
    move.l      a0,arrp             ; Pointer Maske sichern
    move.l      a1,pp               ; Pointer Cursordaten sichern
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten 
    movea.l     vars,a0             ; LineA-Varlist
    movea.l     intin(a0),a1        ; intin-Array
    move.w      #0,6(a1)            ; intin[3]=0
    move.w      #1,8(a1)            ; intin[4]=1
    movea.l     arrp,a0             ; Masken-Pointer
    adda.l      #10,a1              ; intin[5]
    move.w      #15,d0              ; 16 Worte kopieren
loop2: move.w   (a0)+,(a1)+         ; Kopie Mask->intin[5..20] 
    dbra        d0,loop2            ; Schleifenende
    movea.l     pp,a0               ; Cursordaten-Pointer
    move.w      #15,d0              ; 16 Worte kopieren
loop3: move.w   (a0)+,(a1)+         ; Kopie Cursd->intin[21..36] 
    dbra        d0,loop3            ; Schleifenende
    .DC.w $a00b                     ; LineA-MouseForm
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren
    rts                             ; That's it!

; ************************************
; *                                  *
; * Undraw_Sprite löscht ein Sprite  *
; *                                  *
; ************************************

Undraw_Sprite:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    movea.l     a0,a2               ; Sicherungsbereich in A2
    DC.w $a00c                      ; LineA-UndrawSprite
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Zurück ins Hauptprogramm!

; *************************************
; *                                   *
; *  Draw Sprite zeichnet ein Sprite  *
; *                                   *
; *************************************

Draw_Sprite:
    movem.l     d3-d7/a2-a6,-(sp)   ; Register retten
    movea.l     a1,a2               ; Sicherungsbereiche in A2
    DC.w $a00d                      ; LineA-DrawSprite
    movem.l     (sp)+,d3-d7/a2-a6   ; Register restaurieren 
    rts                             ; Good Bye!

    ; *** Zwischenspeicher ***

            .DATA 
vars:       .DC.l 1
arrp:       .DC.l 1
pp:         .DC.l 1
help:       .DC.l 1

    ;*****   Jetzt ist aber Schluss!   *****
            .END

Listing 3: Assemblerlisting (GFA-Assembler)


Thomas Schlesinger
Aus: ST-Computer 01 / 1989, Seite 41

Links

Copyright-Bestimmungen: siehe Über diese Seite