cc65 Graphics 8


cc65 Graphics 8

von atarixle » So 21. Aug 2016, 15:24
Wie schalte ich in cc65 den Grafik-8-Modus ein?

Code: Alles auswählen
#include <stdio.h>
#include <atari.h>
#include <peekpoke.h>
#include <6502.h>

int
main(void)
{
   int address, i, fill;
   fill=170;

   _graphics(8);

   address=PEEKW(88);
   POKE(709,0x00);
   POKE(710,0x0f);

   for(i=0; i<7680; i++)
   {
      POKE(address++, fill);
   }

   do{}while(1);
   return 0;
}

funktioniert schonmal _nicht_ ...

(kompiliert mit
Code: Alles auswählen
cl65 -t atarixl desktop.c -o DESKTOP.XEX
)

Re: cc65 Graphics 8

von Irgendwer » So 21. Aug 2016, 18:33
Na, gestern ein wenig Inspiration bekommen? :wink:

Also, eines der wichtigsten Features von cc65 sind 'Speicherkonfigurationen'. Ohne jetzt zu sehr in die Tiefe gehen zu wollen, passt die Default-Konfiguration nicht zu Graphics 8. Siehe auch

http://www.cc65.org/doc/atari-5.html

Auch würde ich für den Anfang die Finger von der atarixl-Konfiguration lassen. Das OS-Banking verkompliziert den Einstieg unnötig.

Deine Lösung besteht in der Verwendung einer Konfiguration die zu Gr.8 passt, z.B. die hier:

Code: Alles auswählen
FEATURES {
    STARTADDRESS: default = $2000;
}
SYMBOLS {
    __EXEHDR__:          type = import;
    __SYSTEM_CHECK__:    type = import;  # force inclusion of "system check" load chunk
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $0800; # 2k stack
    __STARTADDRESS__:    type = export, value = %S;
    __RESERVED_MEMORY__: type = weak, value = $2000;
}
MEMORY {
    ZP:         file = "", define = yes, start = $0082, size = $007E;

# file header, just $FFFF
    HEADER:     file = %O,               start = $0000, size = $0002;

# "system check" load chunk
    SYSCHKHDR:  file = %O,               start = $0000, size = $0004;
    SYSCHKCHNK: file = %O,               start = $2E00, size = $0300;
    SYSCHKTRL:  file = %O,               start = $0000, size = $0006;

# "main program" load chunk
    MAINHDR:    file = %O,               start = $0000, size = $0004;
    MAIN:       file = %O, define = yes, start = %S,    size = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__ - %S;
    TRAILER:    file = %O,               start = $0000, size = $0006;
}
SEGMENTS {
    ZEROPAGE:  load = ZP,         type = zp;
    EXTZP:     load = ZP,         type = zp,                optional = yes;
    EXEHDR:    load = HEADER,     type = ro;
    SYSCHKHDR: load = SYSCHKHDR,  type = ro,                optional = yes;
    SYSCHK:    load = SYSCHKCHNK, type = rw,  define = yes, optional = yes;
    SYSCHKTRL: load = SYSCHKTRL,  type = ro,                optional = yes;
    MAINHDR:   load = MAINHDR,    type = ro;
    STARTUP:   load = MAIN,       type = ro,  define = yes;
    LOWCODE:   load = MAIN,       type = ro,  define = yes, optional = yes;
    ONCE:      load = MAIN,       type = ro,                optional = yes;
    CODE:      load = MAIN,       type = ro,  define = yes;
    RODATA:    load = MAIN,       type = ro;
    DATA:      load = MAIN,       type = rw;
    INIT:      load = MAIN,       type = rw,                optional = yes;
    BSS:       load = MAIN,       type = bss, define = yes;
    AUTOSTRT:  load = TRAILER,    type = ro;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = ONCE;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}


Das z.B. als mem.cfg speichern und beim Übersetzen mit -C angeben:

cl65 -C mem.cfg -t atari desktop.c -o DESKTOP.XEX

Noch drei Hinweise:
* Mehr Speed beim Füllen gibt's mit angeschalteter Optimierung: cl65 -O2 ... (oder gleich memset() aus der Bibliothek verwenden... (ist sogar von mir 8) ))
* Die Default-Konfiguration lässt den Speicher bei $2400 beginnen (für ein DOS mit mehr Buffern, Laufwerken etc.). Wie oben ersichtlich habe ich die Startaddresse auf $2000 gelegt, das reicht i.d.R. aus - ggf. anpassen.
* Da cc65 nicht super schlau ist, ist ++var schneller als var++: cc65 erkennt nicht ob die Variable vor dem Inkrementieren noch zugewiesen wird

Wenn größeres Interesse besteht könnte ich mal (wie damals beim RMT) 'ne Tagesschulung anbieten...

Grüße
I.

Re: cc65 Graphics 8

von atarixle » So 21. Aug 2016, 20:24
Ja, das gestern hat mich absolut inspiriert!

Das mit dem address++ ist Absicht, Optimierungen gebe ich später hinzu.

Wenn ich deine mem.cfg verwende, kriege ich tausende Fehlermeldungen :/

Aber das Problem mit dem Speicher scheint der Grund zu sein, ich hab's mal mit Graphics 7 probiert (und der Standard-Config atarixl.cfg) und siehe da, es geht ...

Re: cc65 Graphics 8

von Irgendwer » So 21. Aug 2016, 23:53
atarixle hat geschrieben:Wenn ich deine mem.cfg verwende, kriege ich tausende Fehlermeldungen :/


Das ist sehr seltsam, wenn ich (wie oben angegeben)
Code: Alles auswählen
cl65 -C mem.cfg -t atari desktop.c -o DESKTOP.XEX

zum Übersetzten angebe (cl65 V2.15), sagt der Compiler keinen Mucks und spuckt die funktionierende 'xex'-aus.

Nicht zufällig doch -t atarixl genommen?

(Auch bei GR.7 müsste der freie 'Top-Speicher' zu gering sein, da derzeit aber nichts an Programm dort liegt kann das zufällig funktionieren. (So lange bis Du seltsame Grafikfragmente siehst...))

Re: cc65 Graphics 8

von atarixle » Mo 22. Aug 2016, 01:34
Genau das kann es gewesen sein! Ich habe -t atarixl genommen. Mal sehen, wie es mit -t atari aussieht.

Re: cc65 Graphics 8

von atarixle » Mo 22. Aug 2016, 09:40
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atari.h>
#include <peekpoke.h>
#include <6502.h>

int
main(void)
{
   int address, fill;
   fill=170;

   _graphics(8);

   address=PEEKW(88);
   POKE(708,0x00);
   POKE(709,0x24);
   POKE(710,0x0f);
   POKE(712,0x26);

   printf("Hallo, Welt\n");

   /* do
   {
      POKE(address, fill);
   }
   while (fin_address>++address); */

   memset((unsigned int*)address, 170, 7680);

   do; while(1);

   return 0;
}


Code: Alles auswählen
cl65 -C mem.cfg -O2 -t atari desktop.c -o DESKTOP.XEX


läuft! Danke für die Hilfe!

Re: cc65 Graphics 8

von atarixle » Mo 22. Aug 2016, 21:38
jetzt gibt es nur noch eine Hürde zu meistern: Wie kriege ich das Programm unter MyDOS zum Laufen?

In Altirra ohne DOS rennt es, aber nicht in MyDOS auf dem echten Atari (irgendwas mit MEMLO). Da weisst du sicher auch schon die Lösung, oder?

Re: cc65 Graphics 8

von Irgendwer » Mo 22. Aug 2016, 22:38
atarixle hat geschrieben:jetzt gibt es nur noch eine Hürde zu meistern: Wie kriege ich das Programm unter MyDOS zum Laufen?

In Altirra ohne DOS rennt es, aber nicht in MyDOS auf dem echten Atari (irgendwas mit MEMLO). Da weisst du sicher auch schon die Lösung, oder?


Da ich mich weder mit MyDOS auskenne noch die Anzahl der bei Dir konfigurierten Buffer etc. weiß, ist es das Einfachste Du bootest mit Deinem DOS ins Basic (nicht Turbo-Basic!) und gibst ein:

Code: Alles auswählen
? PEEK(743)+PEEK(744)*256


Den angezeigten Wert kannst Du dann in die Speicherkonfiguration (so wie er ist oder "Hex"-umgewandelt mit '$'-Zeichen) hinter

Code: Alles auswählen
STARTADDRESS: default =


angeben. Wenn ich richtig liege, sollte er größer als $2000 sein, was die Probleme erklärt...

Re: cc65 Graphics 8

von atarixle » Mo 22. Aug 2016, 23:03
Der Wert liegt bei 7.912 = $1EE8 ... :/

Geb ich spaßeshalber $4000 in die mem.cfg, klappt es ... aber das ist sicher nicht die feine englische Art.

Re: cc65 Graphics 8

von Mathy » Di 23. Aug 2016, 00:45
Hallo Leute

Bei MyDOS reichen in den meisten Fällen drei Puffer völlig aus. Laut Anleitung.

Tschüß

Mathy

Re: cc65 Graphics 8

von cpg » Di 23. Aug 2016, 14:42
Man muß nicht unbedingt das linker config file ändern, um die Startadresse und __RESERVED_MEMORY__ zu setzen.

Es geht auch so:

Code: Alles auswählen
cl65 -t atari -Wl "-S 0x2000" -Wl "-D_RESERVED_MEMORY=0x2000" -o file.com file.c

Re: cc65 Graphics 8

von Irgendwer » Di 23. Aug 2016, 20:50
atarixle hat geschrieben:Der Wert liegt bei 7.912 = $1EE8 ... :/

Geb ich spaßeshalber $4000 in die mem.cfg, klappt es ... aber das ist sicher nicht die feine englische Art.


Das ist wirklich seltsam. Nur zur "Sicherheit": Du hast mit gedrückter "Option"-Taste gebootet?

Re: cc65 Graphics 8

von atarixle » Di 23. Aug 2016, 21:21
hehe, die meisten Programme blenden Atari-BASIC software-mäßig aus (u.a. Turbo-BASIC).
Deshalb hab ich an die Möglichkeit, mit Option zu booten, gar nicht mehr gedacht.

Mit Option zu booten reicht, um es mit $200 zu starten. Danke, da hattest du erneut den richtigen Riecher!

Macht schon echt Spaß, ein selbst geschriebenes, irre schnelles "Maschinenprogramm" zu laden, wenn man ein Assembler-Muffel ist.

Re: cc65 Graphics 8

von Irgendwer » Di 23. Aug 2016, 21:56
Freut mich, dass es nun klappt.

atarixle hat geschrieben:Macht schon echt Spaß, ein selbst geschriebenes, irre schnelles "Maschinenprogramm" zu laden, wenn man ein Assembler-Muffel ist.


Das und trotzdem die Möglichkeit jederzeit Assembler einfügen zu können falls die Performance mal nicht reicht, macht auch für mich den Reiz aus (...und sich dabei keine Gedanken machen zu müssen ob die Page 6 schon belegt ist).

Re: cc65 Graphics 8

von atarixle » Do 25. Aug 2016, 15:34
Wie sieht es hier mit Strukturen aus?

Scheinbar lassen sich Strukturen nur außerhalb von Funktionen deklarieren:

Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atari.h>
#include <peekpoke.h>
#include <6502.h>

struct Windows {
   int xw, yw, xs, ys;
};

int
atascii(int chr) {
   return
      (chr>95 ? chr :
         chr<32 ? chr+64 : chr-32
      );
}

void
text(struct Windows* window, int x, int y, char* text) {
   int p, yy, address;
   int len=strlen(text);
   int fnt=PEEK(756)*0x100;
   int pst=PEEKW(88);
   int xx=pst+x+window->xw;
   
   while(len-->0) {
      address=(atascii(text[len])<<3)+fnt;
      p=0;
      yy=xx+len+((window->yw+y)<<8)+((window->yw+y)<<6);
      do {
         POKE(yy,PEEK(address++));
         yy+=40;
      } while (++p!=8);
   }
}

void
drawWindow(struct Windows* window) {
   int pst=PEEKW(88);
   int i;
   int address=pst+(window->yw<<8)+(window->yw<<6)+window->xw;
   int lr=address-81;
   int rr=lr+window->xs+1;

   POKE(lr, PEEK(lr)&252);   
   POKE(rr, (PEEK(rr)&127)|64);   
   memset((unsigned int*)(address-80), 0, window->xs);
   
   POKE(lr+=40, (PEEK(lr)&253)|1);   
   POKE(rr+=40, PEEK(rr)|192);   
   memset((unsigned int*)(address-40), 255, window->xs);

   for(i=0; i<window->ys<<3; i++) {
      POKE(lr+=40, (PEEK(lr)&253)|1);   
      POKE(rr+=40, PEEK(rr)|192);   
      memset((unsigned int*)(address), 0, window->xs);
      address+=40;
   }
   for(i=0; i<2; i++) {
      POKE(lr+=40, (PEEK(lr)&253)|1);   
      POKE(rr+=40, PEEK(rr)|192);   
      memset((unsigned int*)(address), 255, window->xs);
      address+=40;
   }
}

struct Windows window;

int
main(void)
{
   int address, fill, i;
   fill=170;
      
   window.xw=2;
   window.yw=2;
   window.xs=36;
   window.ys=20;

   _graphics(24);

   address=PEEKW(88);
   POKE(708,0x00);
   POKE(709,0x24);
   POKE(710,0x0f);
   POKE(712,0x26);

   do {
      POKE(77, 0);
      memset((unsigned int*)address, 170, 40);
      memset((unsigned int*)(address+40), 85, 40);
      memcpy((void*)(address+80), (void*)address, 7600);

      drawWindow(&window);
      
      for(i=0; i<20; i++) text(&window, i, i, "Das ist ein Test!");
   } while(1);

   return 0;
}

funktioniert, aber
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atari.h>
#include <peekpoke.h>
#include <6502.h>

struct Windows {
   int xw, yw, xs, ys;
};

int
atascii(int chr) {
   return
      (chr>95 ? chr :
         chr<32 ? chr+64 : chr-32
      );
}

void
text(struct Windows* window, int x, int y, char* text) {
   int p, yy, address;
   int len=strlen(text);
   int fnt=PEEK(756)*0x100;
   int pst=PEEKW(88);
   int xx=pst+x+window->xw;
   
   while(len-->0) {
      address=(atascii(text[len])<<3)+fnt;
      p=0;
      yy=xx+len+((window->yw+y)<<8)+((window->yw+y)<<6);
      do {
         POKE(yy,PEEK(address++));
         yy+=40;
      } while (++p!=8);
   }
}

void
drawWindow(struct Windows* window) {
   int pst=PEEKW(88);
   int i;
   int address=pst+(window->yw<<8)+(window->yw<<6)+window->xw;
   int lr=address-81;
   int rr=lr+window->xs+1;

   POKE(lr, PEEK(lr)&252);   
   POKE(rr, (PEEK(rr)&127)|64);   
   memset((unsigned int*)(address-80), 0, window->xs);
   
   POKE(lr+=40, (PEEK(lr)&253)|1);   
   POKE(rr+=40, PEEK(rr)|192);   
   memset((unsigned int*)(address-40), 255, window->xs);

   for(i=0; i<window->ys<<3; i++) {
      POKE(lr+=40, (PEEK(lr)&253)|1);   
      POKE(rr+=40, PEEK(rr)|192);   
      memset((unsigned int*)(address), 0, window->xs);
      address+=40;
   }
   for(i=0; i<2; i++) {
      POKE(lr+=40, (PEEK(lr)&253)|1);   
      POKE(rr+=40, PEEK(rr)|192);   
      memset((unsigned int*)(address), 255, window->xs);
      address+=40;
   }
}


int
main(void)
{
   int address, fill, i;
   fill=170;
      
   struct Windows window;
   window.xw=2;
   window.yw=2;
   window.xs=36;
   window.ys=20;

   _graphics(24);

   address=PEEKW(88);
   POKE(708,0x00);
   POKE(709,0x24);
   POKE(710,0x0f);
   POKE(712,0x26);

   do {
      POKE(77, 0);
      memset((unsigned int*)address, 170, 40);
      memset((unsigned int*)(address+40), 85, 40);
      memcpy((void*)(address+80), (void*)address, 7600);

      drawWindow(&window);
      
      for(i=0; i<20; i++) text(&window, i, i, "Das ist ein Test!");
   } while(1);

   return 0;
}
geht nicht

Re: cc65 Graphics 8

von Irgendwer » Do 25. Aug 2016, 16:23
atarixle hat geschrieben:
Code: Alles auswählen
{
   int address, fill, i;
   fill=170;
      
   struct Windows window;
...
}

geht nicht


Da sich cc65 an den Standard hält.. :wink:

Bei (ANSI)-C dürfen Variablendeklarationen nur zu Beginn des Scopes erfolgen. Das wurde bei C++ und C99 aufgeweicht.
Gültig sind folglich:

Code: Alles auswählen
{
   int address, fill, i;
   struct Windows window;

   fill=170;
...
}


oder auch:

Code: Alles auswählen
{
   int address, fill, i;
        {
           struct Windows window;

           fill=170;
                ...
        }
...
}

Re: cc65 Graphics 8

von atarixle » Do 25. Aug 2016, 16:35
aaah, alles klar ... etwas, was ich an anderer Stelle schon bedacht hatte, aber nicht hier ... danke, jetzt klappt es.

Re: cc65 Graphics 8

von Irgendwer » Do 25. Aug 2016, 16:55
Noch eine Anmerkung: Wenn du schnelle Grafik in Gr.8 haben möchtest, könntest Du das "Tiny Graphics Interface" (TGI) probieren. Linien, Kästen und Text etc. sind da in schnellen Implementationen schon vorhanden. Es werden sogar Borlands Vektor-Fonts unterstützt.

Re: cc65 Graphics 8

von Bernd » So 28. Aug 2016, 22:57
atarixle hat geschrieben:jetzt gibt es nur noch eine Hürde zu meistern: Wie kriege ich das Programm unter MyDOS zum Laufen?

In Altirra ohne DOS rennt es, aber nicht in MyDOS auf dem echten Atari (irgendwas mit MEMLO). Da weisst du sicher auch schon die Lösung, oder?


Wenn du das DUP.SYS von MyDos überschreibst, sollte das Programm über RUNAD $2E0,$2E1 gestartet werden. Das Dos mag keine Binärdateien im Speicherbereich von DUP.SYS ohne RUNAD. Zudem sollten keine Packprogramme verwendet werden, sonst kommt es zu weiteren Problemen.

Viele Grüße,
Bernd