]> git.sur5r.net Git - cc65/blob - samples/multidemo.c
038b74d6416927cad8be04d6ba0e4aab91ca0f9d
[cc65] / samples / multidemo.c
1 /*
2 ** Extended memory overlay demo program.
3 **
4 ** Shows how to combine multiple cc65 features
5 ** incl. overlays and extended memory drivers.
6 **
7 ** 2012-17-07, Oliver Schmidt (ol.sc@web.de)
8 **
9 */
10
11
12
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <dirent.h>
17 #include <em.h>
18 #include <cc65.h>
19 #ifndef __CBM__
20 #include <fcntl.h>
21 #include <unistd.h>
22 #else
23 #include <device.h>
24 #endif
25
26
27 /* The symbols _OVERLAY?_LOAD__ and _OVERLAY?_SIZE__ were generated by the
28 ** linker. They contain the overlay area address and size specific to a
29 ** certain program.
30 */
31 extern void _OVERLAY1_LOAD__[], _OVERLAY1_SIZE__[];
32 extern void _OVERLAY2_LOAD__[], _OVERLAY2_SIZE__[];
33 extern void _OVERLAY3_LOAD__[], _OVERLAY3_SIZE__[];
34
35 struct {
36     char     *name;
37     int      page;
38     void     *addr;
39     unsigned size;
40 } overlay[] =
41     {{"multdemo.1", -1, _OVERLAY1_LOAD__, (unsigned)_OVERLAY1_SIZE__},
42      {"multdemo.2", -1, _OVERLAY2_LOAD__, (unsigned)_OVERLAY2_SIZE__},
43      {"multdemo.3", -1, _OVERLAY3_LOAD__, (unsigned)_OVERLAY3_SIZE__}};
44
45
46
47 /* Functions resident in an overlay can call back functions resident in the
48 ** main program at any time without any precautions. The function log() is
49 ** an example for such a function resident in the main program.
50 */
51 void log (char *msg)
52 {
53     /* Functions resident in an overlay can access all program variables and
54     ** constants at any time without any precautions because those are never
55     ** placed in overlays. The string constant below is an example for such
56     ** a constant resident in the main program.
57     */
58     printf ("Log: %s\n", msg);
59 }
60
61
62 /* In a real-world overlay program one would probably not use a #pragma but
63 ** rather place all the code of certain source files into the overlay by
64 ** compiling them with --code-name OVERLAY1.
65 */
66 #pragma code-name (push, "OVERLAY1");
67
68 void foo (void)
69 {
70     log ("Calling main from overlay 1");
71 }
72
73 #pragma code-name (pop);
74
75
76 #pragma code-name (push, "OVERLAY2");
77
78 void bar (void)
79 {
80     log ("Calling main from overlay 2");
81 }
82
83 #pragma code-name (pop);
84
85
86 #pragma code-name (push, "OVERLAY3");
87
88 void foobar (void)
89 {
90     log ("Calling main from overlay 3");
91 }
92
93 #pragma code-name(pop);
94
95
96 unsigned char loademdriver (void)
97 {
98     DIR *dir;
99     struct dirent *ent;
100     char *emd = NULL;
101     unsigned char max = 0;
102     unsigned char num;
103
104     printf ("Dbg: Searching for emdrivers\n");
105     dir = opendir (".");
106     if (!dir) {
107         log ("Opening directory failed");
108         return 0;
109     }
110
111     while (ent = readdir (dir)) {
112         char *ext;
113
114         if (!_DE_ISREG (ent->d_type)) {
115             continue;
116         }
117
118         ext = strrchr (ent->d_name, '.');
119         if (!ext || strcasecmp (ext, ".emd")) {
120             printf ("Dbg: Skipping file %s\n", ent->d_name);
121             continue;
122         }
123
124         printf ("Dbg: Memorizing file %s\n", ent->d_name);
125         emd = realloc (emd, FILENAME_MAX * (max + 1));
126         strcpy (emd + FILENAME_MAX * max++, ent->d_name);
127     }
128     closedir (dir);
129
130     for (num = 0; num < max; ++num) {
131         char *drv;
132
133         drv = emd + FILENAME_MAX * num;
134         printf ("Dbg: Trying emdriver %s\n", drv);
135         if (em_load_driver (drv) == EM_ERR_OK) {
136             printf ("Dbg: Loaded emdriver %s\n", drv);
137             free (emd);
138             return 1;
139         }
140
141         printf ("Dbg: Emdriver %s failed\n", drv);
142     }
143
144     free (emd);
145     return 0;
146 }
147
148
149 unsigned char loadoverlay (unsigned char num)
150 {
151     if (overlay[num - 1].page < 0) {
152 #ifndef __CBM__
153
154         int file;
155
156         printf ("Dbg: Loading overlay %u from file\n", num);
157         file = open (overlay[num - 1].name, O_RDONLY);
158         if (file == -1) {
159             log ("Opening overlay file failed");
160             return 0;
161         }
162         read (file, overlay[num - 1].addr,
163                     overlay[num - 1].size);
164         close (file);
165
166 #else
167
168         if (cbm_load (overlay[num - 1].name, getcurrentdevice (), NULL) == 0) {
169             log ("Loading overlay file failed");
170             return 0;
171         }
172
173 #endif
174         return 1;
175     } else {
176         struct em_copy copyinfo;
177
178         printf ("Dbg: Loading overlay %u from memory\n", num);
179         copyinfo.offs  = 0;
180         copyinfo.page  = overlay[num - 1].page;
181         copyinfo.buf   = overlay[num - 1].addr;
182         copyinfo.count = overlay[num - 1].size;
183         em_copyfrom (&copyinfo);
184         return 1;
185     }
186 }
187
188
189 void copyoverlays (void)
190 {
191     unsigned page = 0;
192     unsigned char num;
193
194     for (num = 0; num < sizeof (overlay) / sizeof (overlay[0]); ++num) {
195         struct em_copy copyinfo;
196         unsigned size = (overlay[num].size + EM_PAGE_SIZE - 1) / EM_PAGE_SIZE;
197
198         if (size > em_pagecount () - page) {
199             printf ("Dbg: Not enough memory for overlay %u\n", num + 1);
200             continue;
201         }
202
203         if (loadoverlay (num + 1) == 0)
204             continue;
205
206         copyinfo.offs  = 0;
207         copyinfo.page  = page;
208         copyinfo.buf   = overlay[num].addr;
209         copyinfo.count = overlay[num].size;
210         em_copyto (&copyinfo);
211
212         overlay[num].page = page;
213         page += size;
214
215         printf ("Dbg: Stored overlay %u in pages %u-%u\n",
216                 num + 1, overlay[num].page, page - 1);
217     }
218 }
219
220
221 void main (void)
222 {
223     log ("Loading extended memory driver");
224     if (loademdriver ()) {
225         log ("Copying overlays into ext. memory");
226         copyoverlays ();
227     } else {
228         log ("No extended memory driver found");
229     }
230
231     log ("Press any key...");
232     getchar ();
233
234     if (loadoverlay (1)) {
235         log ("Calling overlay 1 from main");
236
237         /* The linker makes sure that the call to foo() ends up at the right mem
238         ** addr. However it's up to user to make sure that the - right - overlay
239         ** is actually loaded before making the the call.
240         */
241         foo ();
242     }
243
244     /* Replacing one overlay with another one can only happen from the main
245     ** program. This implies that an overlay can never load another overlay.
246     */
247     if (loadoverlay (2)) {
248         log ("Calling overlay 2 from main");
249         bar ();
250     }
251
252     if (loadoverlay (3)) {
253         log ("Calling overlay 3 from main");
254         foobar ();
255     }
256
257     if (doesclrscrafterexit ()) {
258         log ("Press any key...");
259         getchar ();
260     }
261 }