/* ** Extended memory overlay demo program. ** ** Shows how to combine multiple cc65 features ** incl. overlays and extended memory drivers. ** ** 2012-17-07, Oliver Schmidt (ol.sc@web.de) ** */ #include #include #include #include #include #include #ifndef __CBM__ #include #include #else #include #include #endif /* 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__[]; 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__}}; /* 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 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); unsigned char loademdriver (void) { DIR *dir; struct dirent *ent; char *emd = NULL; unsigned char max = 0; unsigned char num; 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: Memorizing file %s\n", ent->d_name); emd = realloc (emd, FILENAME_MAX * (max + 1)); strcpy (emd + FILENAME_MAX * max++, ent->d_name); } closedir (dir); for (num = 0; num < max; ++num) { char *drv; drv = emd + FILENAME_MAX * num; printf ("Dbg: Trying emdriver %s\n", drv); if (em_load_driver (drv) == EM_ERR_OK) { printf ("Dbg: Loaded emdriver %s\n", drv); free (emd); return 1; } printf ("Dbg: Emdriver %s failed\n", drv); } free (emd); return 0; } unsigned char loadoverlay (unsigned char num) { if (overlay[num - 1].page < 0) { #ifndef __CBM__ 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); #else if (cbm_load (overlay[num - 1].name, getcurrentdevice (), NULL) == 0) { log ("Loading overlay file failed"); return 0; } #endif 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 copyoverlays (void) { unsigned page = 0; unsigned char num; for (num = 0; num < sizeof (overlay) / sizeof (overlay[0]); ++num) { struct em_copy copyinfo; unsigned size = (overlay[num].size + EM_PAGE_SIZE - 1) / EM_PAGE_SIZE; if (size > em_pagecount () - page) { printf ("Dbg: Not enough memory for overlay %u\n", num + 1); continue; } if (loadoverlay (num + 1) == 0) continue; copyinfo.offs = 0; copyinfo.page = page; copyinfo.buf = overlay[num].addr; copyinfo.count = overlay[num].size; em_copyto (©info); overlay[num].page = page; page += size; printf ("Dbg: Stored overlay %u in pages %u-%u\n", num + 1, overlay[num].page, page - 1); } } void main (void) { 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..."); getchar (); 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 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 (); } if (doesclrscrafterexit ()) { log ("Press any key..."); getchar (); } }