]> git.sur5r.net Git - cc65/blob - src/sim65/chip.c
Working
[cc65] / src / sim65 / chip.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                    chip.c                                 */
4 /*                                                                           */
5 /*                        Interface for the chip plugins                     */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <dlfcn.h>
38
39 /* common */
40 #include "coll.h"
41 #include "fname.h"
42 #include "print.h"
43 #include "xmalloc.h"
44
45 /* sim65 */
46 #include "cfgdata.h"
47 #include "chipdata.h"
48 #include "cpucore.h"
49 #include "error.h"
50 #include "chip.h"
51
52
53
54 /*****************************************************************************/
55 /*                                 Forwards                                  */
56 /*****************************************************************************/
57
58
59
60 static int GetCfgId (void* CfgInfo, const char* Name, char** Id);
61 /* Search CfgInfo for an attribute with the given name and type "id". If
62  * found, remove it from the configuration, pass a pointer to a dynamically
63  * allocated string containing the value to Id, and return true. If not
64  * found, return false. The memory passed in Id must be free by a call to
65  * Free();
66  */
67
68 static int GetCfgStr (void* CfgInfo, const char* Name, char** S);
69 /* Search CfgInfo for an attribute with the given name and type "id". If
70  * found, remove it from the configuration, pass a pointer to a dynamically
71  * allocated string containing the value to Id, and return true. If not
72  * found, return false. The memory passed in S must be free by a call to
73  * Free();
74  */
75
76 static int GetCfgNum (void* CfgInfo, const char* Name, long* Val);
77 /* Search CfgInfo for an attribute with the given name and type "number".
78  * If found, remove it from the configuration, copy it into Val and return
79  * true. If not found, return false.
80  */
81
82
83
84 /*****************************************************************************/
85 /*                                     Data                                  */
86 /*****************************************************************************/
87
88
89
90 /* Sorted list of all chip data structures */
91 static Collection Chips = STATIC_COLLECTION_INITIALIZER;
92
93 /* A collection containing all libraries */
94 static Collection ChipLibraries = STATIC_COLLECTION_INITIALIZER;
95
96 /* SimData instance */
97 static const SimData Sim65Data = {
98     1,                  /* MajorVersion */
99     1,                  /* MinorVersion */
100     xmalloc,
101     xfree,
102     Warning,
103     Error,
104     Internal,
105     Break,
106     GetCfgId,
107     GetCfgStr,
108     GetCfgNum
109 };
110
111
112
113 /*****************************************************************************/
114 /*                               Helper functions                            */
115 /*****************************************************************************/
116
117
118
119 static int GetCfgId (void* CfgInfo, const char* Name, char** Id)
120 /* Search CfgInfo for an attribute with the given name and type "id". If
121  * found, remove it from the configuration, pass a pointer to a dynamically
122  * allocated string containing the value to Id, and return true. If not
123  * found, return false. The memory passed in Id must be free by a call to
124  * Free();
125  */
126 {
127     return CfgDataGetId (CfgInfo, Name, Id);
128 }
129
130
131
132 static int GetCfgStr (void* CfgInfo, const char* Name, char** S)
133 /* Search CfgInfo for an attribute with the given name and type "id". If
134  * found, remove it from the configuration, pass a pointer to a dynamically
135  * allocated string containing the value to Id, and return true. If not
136  * found, return false. The memory passed in S must be free by a call to
137  * Free();
138  */
139 {
140     return CfgDataGetStr (CfgInfo, Name, S);
141 }
142
143
144
145 static int GetCfgNum (void* CfgInfo, const char* Name, long* Val)
146 /* Search CfgInfo for an attribute with the given name and type "number".
147  * If found, remove it from the configuration, copy it into Val and return
148  * true. If not found, return false.
149  */
150 {
151     return CfgDataGetNum (CfgInfo, Name, Val);
152 }
153
154
155
156 static int CmpChips (void* Data attribute ((unused)),
157                      const void* lhs, const void* rhs)
158 /* Compare function for CollSort */
159 {
160     /* Cast the object pointers */
161     const Chip* Left  = (const Chip*) rhs;
162     const Chip* Right = (const Chip*) lhs;
163
164     /* Do the compare */
165     return strcmp (Left->Data->ChipName, Right->Data->ChipName);
166 }
167
168
169
170 static Chip* FindChip (const char* Name)
171 /* Find a chip by name. Returns the Chip data structure or NULL if the chip
172  * could not be found.
173  */
174 {
175     unsigned I;
176
177     /* ## We do a linear search for now */
178     for (I = 0; I < CollCount (&Chips); ++I) {
179
180         /* Get the chip at this position */
181         Chip* C = CollAt (&Chips, I);
182
183         /* Compare the name */
184         if (strcmp (Name, C->Data->ChipName) == 0) {
185             /* Found */
186             return C;
187         }
188     }
189
190     /* Not found */
191     return 0;
192 }
193
194
195
196 /*****************************************************************************/
197 /*                                   Code                                    */
198 /*****************************************************************************/
199
200
201
202 static ChipLibrary* NewChipLibrary (const char* PathName)
203 /* Create, initialize and return a new ChipLibrary structure */
204 {
205     /* Allocate memory */
206     ChipLibrary* L = xmalloc (sizeof (ChipLibrary));
207
208     /* Initialize the fields */
209     L->LibName   = xstrdup (FindName (PathName));
210     L->PathName  = xstrdup (PathName);
211     L->Handle    = 0;
212     L->Chips     = EmptyCollection;
213
214     /* Return the allocated structure */
215     return L;
216 }
217
218
219
220 static void FreeChipLibrary (ChipLibrary* L)
221 /* Free a ChipLibrary structure */
222 {
223     /* Free the names */
224     xfree (L->LibName);
225     xfree (L->PathName);
226
227     /* If the library is open, close it. Discard any errors. */
228     if (L->Handle) {
229         dlclose (L->Handle);
230         (void) dlerror ();
231     }
232
233     /* We may have to handle the Chip pointers, but currently the function
234      * is never called with a non empty Chips collection, so we don't care
235      * for now.
236      */
237     xfree (L);
238 }
239
240
241
242 static Chip* NewChip (ChipLibrary* Library, const ChipData* Data)
243 /* Allocate a new chip structure, initialize and return it */
244 {
245     /* Allocate memory */
246     Chip* C = xmalloc (sizeof (Chip));
247
248     /* Initialize the fields */
249     C->Library   = Library;
250     C->Data      = Data;
251     C->Instances = EmptyCollection;
252
253     /* Insert the new chip into the collection of all chips */
254     CollAppend (&Chips, C);
255
256     /* Return the structure */
257     return C;
258 }
259
260
261
262 ChipInstance* NewChipInstance (const char* ChipName, unsigned Addr,
263                                unsigned Size, Collection* Attributes)
264 {
265     ChipInstance* CI;
266
267     /* Find the chip with the given name */
268     Chip* C = FindChip (ChipName);
269     if (C == 0) {
270         Error ("No chip `%s' found for address $%06X", ChipName, Addr);
271     }
272
273     /* Allocate a new ChipInstance structure */
274     CI = xmalloc (sizeof (*CI));
275
276     /* Initialize the fields */
277     CI->C    = C;
278     CI->Addr = Addr;
279     CI->Size = Size;
280     CI->Data = C->Data->InitInstance (Addr, Size, Attributes);
281
282     /* Assign the chip instance to the chip */
283     CollAppend (&C->Instances, CI);
284
285     /* Return the new instance struct */
286     return CI;
287 }
288
289
290
291 ChipInstance* MirrorChipInstance (const ChipInstance* Orig, unsigned Addr)
292 /* Generate a chip instance mirror and return it. */
293 {
294     /* Allocate a new ChipInstance structure */
295     ChipInstance* CI = xmalloc (sizeof (*CI));
296
297     /* Initialize the fields */
298     CI->C    = Orig->C;
299     CI->Addr = Addr;
300     CI->Size = Orig->Size;
301     CI->Data = Orig->Data;
302
303     /* Assign the chip instance to the chip */
304     CollAppend (&CI->C->Instances, CI);
305
306     /* Return the new instance struct */
307     return CI;
308 }
309
310
311
312 void SortChips (void)
313 /* Sort all chips by name. Called after loading */
314 {
315     /* Last act: Sort the chips by name */
316     CollSort (&Chips, CmpChips, 0);
317 }
318
319
320
321 void LoadChipLibrary (const char* LibName)
322 /* Load a chip library. This includes loading the shared libary, allocating
323  * and initializing the data structure, and loading all chip data from the
324  * library.
325  */
326 {
327     const char* Msg;
328     int (*GetChipData) (const struct ChipData**, unsigned*);
329     int ErrorCode;
330     const ChipData* Data;       /* Pointer to chip data */
331     unsigned ChipCount;         /* Number of chips in this library */
332     unsigned I;
333
334
335     /* Allocate a new ChipLibrary structure */
336     ChipLibrary* L = NewChipLibrary (LibName);
337
338     /* Open the library */
339     L->Handle = dlopen (L->PathName, RTLD_GLOBAL | RTLD_LAZY);
340
341     /* Check for errors */
342     Msg = dlerror ();
343     if (Msg) {
344         Error ("Cannot open `%s': %s", L->PathName, Msg);
345         FreeChipLibrary (L);
346         return;
347     }
348
349     /* Locate the GetChipData function */
350     GetChipData = dlsym (L->Handle, "GetChipData");
351
352     /* Check the error message */
353     Msg = dlerror ();
354     if (Msg) {
355         /* We had an error */
356         Error ("Cannot find export `GetChipData' in `%s': %s", L->LibName, Msg);
357         FreeChipLibrary (L);
358         return;
359     }
360
361     /* Call the function to read the chip data */
362     ErrorCode = GetChipData (&Data, &ChipCount);
363     if (ErrorCode != 0) {
364         Error ("Function `GetChipData' in `%s' returned error %d", L->LibName, ErrorCode);
365         FreeChipLibrary (L);
366         return;
367     }
368
369     /* Remember the library */
370     CollAppend (&ChipLibraries, L);
371
372     /* Print some information */
373     Print (stderr, 1, "Opened chip library `%s'\n", L->PathName);
374
375     /* Create the chips */
376     for (I = 0; I < ChipCount; ++I) {
377
378         Chip* C;
379
380         /* Get a pointer to the chip data */
381         const ChipData* D = Data + I;
382
383         /* Check if the chip data has the correct version */
384         if (D->MajorVersion != CHIPDATA_VER_MAJOR) {
385             Warning ("Version mismatch for `%s' (%s), expected %u, got %u",
386                      D->ChipName, L->LibName,
387                      CHIPDATA_VER_MAJOR, D->MajorVersion);
388             /* Ignore this chip */
389             continue;
390         }
391
392         /* Initialize the chip passing the simulator data */
393         D->InitChip (&Sim65Data);
394
395         /* Generate a new chip */
396         C = NewChip (L, D);
397
398         /* Insert a reference to the chip into the library exporting it */
399         CollAppend (&L->Chips, C);
400
401         /* Output chip name and version to keep the user happy */
402         Print (stdout, 1,
403                "  Found %s `%s', version %u.%u in library `%s'\n",
404                (D->Type == CHIPDATA_TYPE_CHIP)? "chip" : "cpu",
405                D->ChipName,
406                D->MajorVersion,
407                D->MinorVersion,
408                L->LibName);
409     }
410 }
411
412
413