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