ndr-nkc.de ndr-nbc.de
  
Startseite
News
 
NDR-NKC
Geräte Z80
Geräte 68000
Geräte 8088
 
NKC Emulator
 
Z80 Section
Baugruppen
ROM's
Software
68000 Section
Baugruppen
ROM's
PASCAL/S
Software
CP/M 68K
8088 Section
Baugruppen
Downloads
 
Bussysteme
Stromversorgung
Input / Output
Grafikkarten
Speicherkarten
Massenspeicher
Weitere Baugruppen
 
Projekte
 
Dokumentation
Datenblätter
Glossar
Portraits
Links

Impressum

 

Nutzen von Unterprogrammen aus dem Grundprogramm

Das Grundprogramm beinhaltet viele Unterprogramme, die auch in C-Programmen genutzt werden können. Die Routinen können allerdings nicht direkt wie andere C-Funktionen genutzt werden. Stattdessen erfolgt der Aufruf durch einen Escape-Code beim der Bildschirmausgabe mittels der printf() Funktion von C.

In den Ausgaben 4 und 5 der Zeitschrift LOOP sind diese Möglichkeiten ausgiebig beschrieben worden und sollen hier nicht weiter behandelt werden. Statt dessen wird hier auf eine in Assembler umgesetzte Bibliothek zur direkten Nutzung der Funktionen beschrieben.

Zurück zum Inhaltsverzeichnis der Beiträge

Die Bibliothek GP.S

Die Bibliothek kann nach den eigenen Bedürfnissen erweitert werden, wenn andere Funktionen des Grundprogramms verwendet werden sollen. Hier werden nur Funktionen umgesetzt, die eine Nutzung der Grafik unter C ermöglichen.

Vorteile der Bibliothek GP.S

Obwohl eine zusätzliche Objekt-Datei in das Programm gelinkt wird, ist das ausführbare Programm kleiner als bei der Verwendung der Escape-Codes. Der C-Quellcode ist deutlich einfacher zu lesen, da die Grafik-Funktionen wie normale C-Funktionen aufgerufen werden. Gegenüber einer Umsetzung mit Escape-Codes ist die Ausführung um ein vielfaches schneller. Das erste Beispiel-Programm läuft mit der Bibliothek etwa 15-mal schneller ab.

Funktionen in GP.S

Die Bibliothek stellt folgende Funktionen zur Verfügung. Die exakte Funktion kann in der Dokumentation des Grundprogramms nachgelesen werden.

  • moveto(x,y) - Setzen des Grafik-Cursors
  • drawto(x,y) - Zeichnen einer Linie von der letzten Position des Grafik-Cursors
  • plot(x,y) - Setzen eines Pixels an der angegebenen Position
  • clrscreen() - Löscht die sichtbare Bildschirmseite
  • clrpage(p) - Löscht eine nicht sichtbare Bildschirmseite
  • curon() - Schaltet den Text-Cursor ein
  • curoff() - Schaltet den Text-Cursor aus
  • setpen() - Grafikausgaben werden sichtbar gezeichnet
  • erapen() - Grafikausgaben löschen darunter liegende Pixel
  • setxor() - Aktiviert den XOR-Modus zum invertierenden Zeichnen
  • setflip() - Bestimmt die Umschaltrate von Bildschirmseiten
  • page(w,r) - Setzen der Schreib- und Leseseite des Bildschirms
  • waitkey() - Warten auf Tastendruck
  • Funktionsweise von GP.S

    Beim ersten Aufruf einer dieser Funktionen wird die Adresse des Grundprogramms ermittelt und gespeichert. Dazu dient die Init-Routine, die entweder sofort die schon ermittelte Adresse des Grundprogramm in A1 liefert oder vorher mithilfe der BIOS-Funktion 23 die Adresse ermittelt und im Datenbereich sichert.

    Alle anderen Funktionen sichern das für CP/M essentielle Register A6 aus dem Stack, rufen Init auf, um die Adresse des Grundprogramms zu erhalten, speichern die Funktion-Parameter in den passenden Registern und rufen dann die Funktion im Grundprogramm-ROM auf.

    *******************************************
    * Grafik-Bibliothek zur Nutzung des GP in C
    *******************************************
    * Zu beachten
    *   - Das Register A6 muss gesichert werden 
    *******************************************
    
    __init:
        tst.l gpadr       ; Schon initialisiert?
        beq.s __ini2      ; nein, GP Adresse holen
        movea.l gpadr,a1  ; ja, GP Adresse nach A1
        rts
    __ini2:
        move #23,d0       ; BIOS Funktion 23
        trap #3           ; GP Adreese nach A4
        move.l a4,gpadr   ; dort sichern
        move.l a4,a1      ; und nach A1 kopieren
        rts
    
    * Zeichenposition auf X,Y setzen
    
    .globl _moveto
    
    _moveto:
        link a6,#0
        movem.l a6,-(a7)  ; A6 sichern
        bsr __init        ; GP-Adresse holen
        move  8(A6),d1    ; X-Koordinate nach D1
        move 10(A6),d2    ; Y-Koordinate nach D2
        move #8,d7        ; Funktionsnummer GP
        jsr $420(a1)      ; Funktion aufrufen
        movem.l (a7)+,a6  ; A6 wiederherstellen
        unlk a6
        rts
    
    * Linie Zeichnen von letzter Position nach X,Y
    
    .globl _drawto
        
    _drawto:
        link a6,#0
        movem.l a6,-(a7)  ; A6 sichern
        bsr __init        ; GP-Adresse holen
        move  8(A6),d1    ; X-Koordinate nach D1
        move 10(A6),d2    ; Y-Koordinate nach D2
        move #9,d7        ; Funktionsnummer GP
        jsr $420(a1)      ; Funktion aufrufen
        movem.l (a7)+,a6  ; A6 wiederherstellen
        unlk a6
        rts
    
    * Zeichnen eines Punktes an X,Y
    
    .globl _plot
    
    _plot:
        link a6,#0
        movem.l a6,-(a7)  ; A6 sichern
        bsr __init        ; GP-Adresse holen
        move  8(A6),d1    ; X-Koordinate nach D1
        move 10(A6),d2    ; Y-Koordinate nach D2
        move #8,d7        ; Funktion moveto
        jsr $420(a1)      ; Aufruf GP
        move #9,d7        ; Funktion drawto
        jsr $420(a1)      ; Funktion aufrufen
        movem.l (a7)+,a6  ; A6 wiederherstellen
        unlk a6
        rts
    
    * Loeschen der sichtbaren Bildschirmseite
    
    .globl _clrscreen 
    
    _clrscreen:
        movem.l a6,-(a7)
        bsr __init
        move #20,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Loeschen einer unsichtbaren Bildschirmseite
    
    .globl _clrpage
    
    _clrpage:
        movem.l a6,-(a7)
        bsr __init
        move #17,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Cursor einschalten
    
    .globl _curon
    
    _curon:
        movem.l a6,-(a7)
        bsr __init
        move #81,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Cursor ausschalten
    
    .globl _curoff
    
    _curoff:
        movem.l a6,-(a7)
        bsr __init
        move #82,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Schreibmodus fuer drawto setzen
    
    .globl _setpen
    
    _setpen:
        movem.l a6,-(a7)
        bsr __init
        move #37,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Loeschmodus fuer drawto setzen
    
    .globl _erapen
    
    _erapen:
        movem.l a6,-(a7)
        bsr __init
        move #38,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * XOR Modus fuer drawto setzen
    
    .globl _setxor
    
    _setxor:
        movem.l a6,-(a7)
        bsr __init
        move #77,d7
        jsr $420(a1)
        movem.l (a7)+,a6
        rts
    
    * Bildschirmumschaltrate in Millisekunden setzen
    
    .globl _setflip
    
    _setflip:
        link a6,#0
        movem.l a6,-(a7)  ; A6 sichern
        bsr __init        ; GP-Adresse holen
        move  8(A6),d0    ; Rate nach D0
        move #34,d7       ; Funktion setflip
        jsr $420(a1)      ; Funktion aufrufen
        movem.l (a7)+,a6  ; A6 wiederherstellen
        unlk a6
        rts
    
    * Lese und Schreibseite setzen
    
    .globl _page
    
    _page:
        link a6,#0
        movem.l a6,-(a7)  ; A6 sichern
        bsr __init        ; GP-Adresse holen
        move  8(A6),d0    ; Schreibseite nach D0
        move 10(A6),d1    ; Leseseite nach D1
        move #27,d7       ; Funktionsnummer GP
        jsr $420(a1)      ; Funktion aufrufen
        movem.l (a7)+,a6  ; A6 wiederherstellen
        unlk a6
        res
    
    * Warten auf Tastendruck
    
    .globl _waitkey
    
    _waitkey:
        movem.l a6,-(a7)
        bsr __init
    __wait1
        move #17,d7
        jsr $420(a1)
        beq.s __wait1
        movem.l (a7)+,a6
        rts
    
    
    * Ablage der Grundprogramm-Adresse
    
    .data
    
    gpadr: dc.l 0
    

    Beispielprogramm SINCOS.C

    In diesem Beispiel wird ein Koordinatensystem mit den Funktionswerten der Sinis- und Cosinus-Funktion gezeichnet. Das Programm ist selbsterklärend.

    #include "stdio.h"
     
    EXTERN FLOAT sin(),cos();
    
    main() {
      FLOAT winkel;
      int x,y;
    
      clrscreen();
      setflip(0);
      curoff();
     
      // X-Achse zeichnen
      moveto(0,128); drawto(511,128);
      for (x=0; x<512; x+=25) {
        moveto(x,124); drawto(x,132);
      }
    
      // Y-Achse zeichnen
      moveto(0,0); drawto(0,255);
      for (y=0; y<256; y+=16) {
        moveto(0,y); drawto(5,y);
      }
    
      // Sinus- und Cosinus-Kurve plotten
      for (winkel=0,x=0; x<511; x++,winkel=winkel+3.1416/100) {
        y = (sin(winkel)*120+128);
        plot(x,y);
        y = (cos(winkel)*120+128);
        plot(x,y);
      }  
    
      waitkey();
      clrscreen();
      exit(0);  
    }
    

    Wegen der Nutzung von Fließkomma-Arithmaetik muss zum Übersetzen die Submit-Datei CF.SUB oder CE.SUB verwendet werden. Er ergibt sich eine Programmgröße von "nur" 12 bzw. 14 kByte je nach gewählter Fließkomma-Bibliothek. Es ist jedoch zu beachten, dass jede neue Funktion auch die Bibliothek und die erzeugte Programm-Datei vergrößern. LO68 bindet nur komplette Objekt-Dateien ein und analysiert nicht, welche Funktionen tatsächlich genutzt werden.

    cf sincos gp
    ce sincos gp
    

    Screenshot

    Nach dem Aufruf des generierten Programms SINCOS.68K zeigt der NKC folgendes Bild.




    Beispielprogramm RANDOM.C

    Dieses Programm verzichtet auf Fließkomma-Arithmetik und zeichnet zufällige Linien auf dem Bildschirm. Die C-Funktion rand() erzeugt pseudo-zufällige Integer Zahlen von 0 bis 32767, die durch die Division durch 64 bzw. 128 auf die Auflösung des Bildschirms skaliert werden.

    #include "stdio.h"
    
    main() {
      int x,y;
      long I;
      clrscreen(); curoff();
      for(i=0;i<300;i++) {     
        moveto(rand()/64, rand()/128); 
        drawto(rand()/64, rand()/128);
      }
      waitkey(); clrscreen();
      exit(0);  
    }
    

    Zum Übersetzen des Quelltextes wird jetzt die Submit-Datei C.SUB verwendet, da wir keine Fließkomma-Arithmetik verwenden.

    c random gp
    

    Screenshot

    Nach dem Aufruf des generierten Programms RANDOM.68K zeigt der NKC folgendes Bild.



    Zurück zum Inhaltsverzeichnis der Beiträge