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