mirror of
https://github.com/cc65/cc65.git
synced 2024-11-18 00:07:21 +00:00
5d9f4dc89d
<conio.h> includes target-specific headers; so, we didn't bother to include <cbm.h> where it is needed. But, '#include <conio.h>' was removed from some files; so now, we must include <cbm.h> explicitly.
263 lines
6.2 KiB
C
263 lines
6.2 KiB
C
/*
|
|
** 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 <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <em.h>
|
|
#include <cc65.h>
|
|
#ifndef __CBM__
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#else
|
|
#include <cbm.h>
|
|
#include <device.h>
|
|
#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 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 ();
|
|
}
|
|
}
|