1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-11 20:29:36 +00:00

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
This commit is contained in:
ol.sc 2012-08-08 21:23:18 +00:00
parent 942c0b6b2f
commit 2d97630d03
2 changed files with 257 additions and 0 deletions

View File

@ -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

253
samples/multidemo.c Normal file
View File

@ -0,0 +1,253 @@
/*
* Minimalistic overlay demo program.
*
* 2012-17-07, Oliver Schmidt (ol.sc@web.de)
*
*/
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <em.h>
#include <conio.h>
/* 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 (&copyinfo);
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 ();
}