From 2d97630d030c905f97dfef8fb8dab41bd5c71993 Mon Sep 17 00:00:00 2001 From: "ol.sc" Date: Wed, 8 Aug 2012 21:23:18 +0000 Subject: [PATCH] Added somewhat more complex demo. It looks for emdrivers in the current directory and tries to load them until one loads successfully. In that case it "streams" its overlay files into extended memory. Finally it loads its overlays from extended memory (or disk) and calls into them. git-svn-id: svn://svn.cc65.org/cc65/trunk@5806 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- samples/Makefile | 4 + samples/multidemo.c | 253 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 samples/multidemo.c diff --git a/samples/Makefile b/samples/Makefile index 81372f802..4499586ce 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -78,6 +78,7 @@ EXELIST = ascii \ hello \ mandelbrot \ mousedemo \ + multdemo \ nachtm \ ovrldemo \ plasma \ @@ -121,6 +122,9 @@ else mousedemo: mousedemo.o endif +multdemo: multidemo.o + @$(LD) -t $(SYS) -m $(basename $@).map -C $(SYS)-overlay.cfg -o $@ $^ $(CLIB) + nachtm: nachtm.o ovrldemo: overlaydemo.o diff --git a/samples/multidemo.c b/samples/multidemo.c new file mode 100644 index 000000000..e780e07a2 --- /dev/null +++ b/samples/multidemo.c @@ -0,0 +1,253 @@ +/* + * Minimalistic overlay demo program. + * + * 2012-17-07, Oliver Schmidt (ol.sc@web.de) + * + */ + + + +#include +#include +#include +#include +#include +#include +#include + + +/* The symbols _OVERLAY?_LOAD__ and _OVERLAY?_SIZE__ were generated by the + * linker. They contain the overlay area address and size specific to a + * certain program. + */ +extern void _OVERLAY1_LOAD__, _OVERLAY1_SIZE__; +extern void _OVERLAY2_LOAD__, _OVERLAY2_SIZE__; +extern void _OVERLAY3_LOAD__, _OVERLAY3_SIZE__; +extern void _OVERLAY4_LOAD__, _OVERLAY4_SIZE__; + +struct { + char *name; + int page; + void *addr; + unsigned size; +} overlay[] = + {{"multdemo.1", -1, &_OVERLAY1_LOAD__, (unsigned)&_OVERLAY1_SIZE__}, + {"multdemo.2", -1, &_OVERLAY2_LOAD__, (unsigned)&_OVERLAY2_SIZE__}, + {"multdemo.3", -1, &_OVERLAY3_LOAD__, (unsigned)&_OVERLAY3_SIZE__}, + {"multdemo.4", -1, &_OVERLAY4_LOAD__, (unsigned)&_OVERLAY4_SIZE__}}; + +/* Copy overlays into extended memory up to overlay 3. Overlay 4 is known to + * to be loaded only once for onetime initialization purposes so there's no + * use in allocating extended memory for it. + */ +#define MAX_EM_OVERLAY 3 + + +/* Functions resident in an overlay can call back functions resident in the + * main program at any time without any precautions. The function log() is + * an example for such a function resident in the main program. + */ +void log (char *msg) +{ + /* Functions resident in an overlay can access all program variables and + * constants at any time without any precautions because those are never + * placed in overlays. The string constant below is an example for such + * a constant resident in the main program. + */ + printf ("Log: %s\n", msg); +} + + +/* In a real-world overlay program one would probably not use a #pragma but + * rather place the all the code of certain source files into the overlay by + * compiling them with --code-name OVERLAY1. + */ +#pragma code-name (push, "OVERLAY1"); + +void foo (void) +{ + log ("Calling main from overlay 1"); +} + +#pragma code-name (pop); + + +#pragma code-name (push, "OVERLAY2"); + +void bar (void) +{ + log ("Calling main from overlay 2"); +} + +#pragma code-name (pop); + + +#pragma code-name (push, "OVERLAY3"); + +void foobar (void) +{ + log ("Calling main from overlay 3"); +} + +#pragma code-name(pop); + + +#pragma code-name (push, "OVERLAY4"); + +unsigned char loademdriver (void) +{ + DIR* dir; + struct dirent* ent; + + printf ("Dbg: Searching for emdrivers\n"); + dir = opendir ("."); + if (!dir) { + log ("Opening directory failed"); + return 0; + } + + while (ent = readdir (dir)) { + char *ext; + + if (!_DE_ISREG (ent->d_type)) { + continue; + } + + ext = strrchr (ent->d_name, '.'); + if (!ext || strcasecmp (ext, ".emd")) { + printf ("Dbg: Skipping file %s\n", ent->d_name); + continue; + } + + printf ("Dbg: Trying emdriver %s\n", ent->d_name); + if (em_load_driver (ent->d_name) == EM_ERR_OK) { + printf ("Dbg: Loaded emdriver %s\n", ent->d_name); + break; + } + + printf ("Dbg: Emdriver %s failed\n", ent->d_name); + } + + closedir (dir); + return ent != NULL; +} + +void copyoverlays (void) +{ + unsigned page = 0; + unsigned char num; + + for (num = 0; num < MAX_EM_OVERLAY; ++num) { + int file; + int size; + + if ((overlay[num].size + EM_PAGE_SIZE - 1) / EM_PAGE_SIZE > + em_pagecount () - page) { + printf ("Dbg: Not enough memory for overlay %u\n", num + 1); + continue; + } + + printf ("Dbg: Reading overlay file %s\n", overlay[num].name); + file = open (overlay[num].name, O_RDONLY); + if (file == -1) { + log ("Opening overlay file failed"); + continue; + } + + overlay[num].page = page; + size = overlay[num].size; + while (size) { + void *buf; + + /* In general one could as well use em_copyto() to copy a fully + * loaded overlay into extended memory in one step. However the + * "streaming" of an overlay from disk to extended memory shown + * here has two advantages: + * - It can be done from another overlay (like done here). + * - It avoids unnecessary double buffering with emdrivers that + * provide a hardware memory window. + */ + buf = em_use (page++); + size -= read (file, buf, EM_PAGE_SIZE); + em_commit (); + } + + printf ("Dbg: Stored overlay %u in pages %u-%u\n", + num + 1, overlay[num].page, page - 1); + + close (file); + } +} + +#pragma code-name(pop); + + +unsigned char loadoverlay (unsigned char num) +{ + if (overlay[num - 1].page < 0) { + int file; + + printf ("Dbg: Loading overlay %u from file\n", num); + file = open (overlay[num - 1].name, O_RDONLY); + if (file == -1) { + log ("Opening overlay file failed"); + return 0; + } + read (file, overlay[num - 1].addr, + overlay[num - 1].size); + close (file); + return 1; + } else { + struct em_copy copyinfo; + + printf ("Dbg: Loading overlay %u from memory\n", num); + copyinfo.offs = 0; + copyinfo.page = overlay[num - 1].page; + copyinfo.buf = overlay[num - 1].addr; + copyinfo.count = overlay[num - 1].size; + em_copyfrom (©info); + return 1; + } +} + +void main (void) +{ + if (loadoverlay (4)) { + log ("Loading extended memory driver"); + if (loademdriver ()) { + log ("Copying overlays into ext. memory"); + copyoverlays (); + } else { + log ("No extended memory driver found"); + } + } + + log ("Press any key..."); + cgetc (); + + if (loadoverlay (1)) { + log ("Calling overlay 1 from main"); + + /* The linker makes sure that the call to foo() ends up at the right mem + * addr. However it's up to user to make sure that the - right - overlay + * is actually loaded before making the the call. + */ + foo (); + } + + /* Replacing one overlay with another one can only happen from the main + * program. This implies that an overlay can never load another overlay. + */ + if (loadoverlay (2)) { + log ("Calling overlay 2 from main"); + bar (); + } + + if (loadoverlay (3)) { + log ("Calling overlay 3 from main"); + foobar (); + } + + log ("Press any key..."); + cgetc (); +} -- 2.39.5