1 /*****************************************************************************/
5 /* Configuration file parsing for the sim65 6502 simulator */
9 /* (C) 1998-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
49 #include "addrspace.h"
60 /*****************************************************************************/
62 /*****************************************************************************/
66 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
67 /* Check if the item is already defined. Print an error if so. If not, set
68 * the marker that we have a definition now.
72 CfgError ("%s is already defined", Name);
79 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
80 /* Check that a mandatory attribute was given */
82 if ((Attr & Mask) == 0) {
83 CfgError ("%s attribute is missing", Name);
89 static void ParseCPU (void)
90 /* Parse a CPU section */
92 static const IdentTok Attributes [] = {
93 { "TYPE", CFGTOK_TYPE },
94 { "ADDRSPACE", CFGTOK_ADDRSPACE },
103 unsigned long Size = 0;
106 while (CfgTok == CFGTOK_IDENT) {
109 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
112 /* An optional assignment follows */
114 CfgOptionalAssign ();
116 /* Check which attribute was given */
120 FlagAttr (&Attr, atType, "TYPE");
125 case CFGTOK_ADDRSPACE:
126 FlagAttr (&Attr, atAddrSpace, "ADDRSPACE");
128 CfgRangeCheck (0x1000, 0x1000000);
133 FAIL ("Unexpected attribute token");
137 /* Skip the attribute value and an optional comma */
142 /* Must have some attributes */
143 AttrCheck (Attr, atType, "TYPE");
144 AttrCheck (Attr, atAddrSpace, "ADDRSPACE");
147 CPUInstance = NewCPU ("6502", Size);
149 /* Skip the semicolon */
155 static void ParseAddrSpace (void)
156 /* Parse a ADDRSPACE section */
160 /* CPU must be defined before the address space */
161 if (CPUInstance == 0) {
162 CfgError ("CPU must be defined before address space definitions");
165 /* Parse addresses */
166 while (CfgTok == CFGTOK_INTCON) {
170 /* Remember the start address and skip it */
171 unsigned long Start = CfgIVal;
175 CfgConsume (CFGTOK_DOTDOT, "`..' expected");
177 /* End address must follow and must be greater than start */
179 if (CfgIVal < Start) {
180 CfgError ("Start address must be greater than end address");
183 /* Create a new location and add it to the list */
184 L = NewLocation (Start, CfgIVal);
185 CollAppend (&Locations, L);
187 /* Skip the end address and the following colon */
191 /* Parse attributes terminated by a semicolon */
192 while (CfgTok == CFGTOK_IDENT) {
194 /* Generate a new attribute with the given name, then skip it */
195 CfgData* D = NewCfgData ();
198 /* An optional assignment follows */
199 CfgOptionalAssign ();
201 /* Check and assign the attribute value */
205 D->Type = CfgDataNumber;
210 D->Type = CfgDataString;
211 D->V.SVal = xstrdup (CfgSVal);
216 D->V.SVal = xstrdup (CfgSVal);
220 CfgError ("Invalid attribute type");
223 /* Add the attribute to the location */
224 CollAppend (&L->Attributes, D);
226 /* Skip the attribute value and an optional comma */
231 /* Skip the semicolon */
235 /* Sort all memory locations */
236 LocationSort (&Locations);
238 /* Check the locations for overlaps and other problems */
239 LocationCheck (&Locations);
241 /* Now create the chip instances. Since we can only mirror existing chips,
242 * we will first create all real chips and the mirrors in a second run.
244 for (I = 0; I < CollCount (&Locations); ++I) {
248 unsigned Range; /* Address range for this chip */
251 /* Get this location */
252 Location* L = CollAtUnchecked (&Locations, I);
255 if (LocationIsMirror (L)) {
259 /* The chip must have an attribute "name" of type string */
260 Index = LocationGetAttr (L, "name");
261 D = CollAt (&L->Attributes, Index);
262 CfgDataCheckType (D, CfgDataString);
264 /* Remove the "name" attribute from the attribute list */
265 CollDelete (&L->Attributes, Index);
267 /* Create the chip instance for the address range */
268 Range = L->End - L->Start + 1;
269 CI = NewChipInstance (D->V.SVal, L->Start, Range, &L->Attributes);
271 /* Delete the "name" attribute */
274 /* Assign the chip instance to address space */
275 ASAssignChip (CPUInstance->AS, CI, L->Start, Range);
278 /* Create the mirrors */
279 for (I = 0; I < CollCount (&Locations); ++I) {
282 unsigned MirrorAddr; /* Mirror address */
283 unsigned Range; /* Address range for this chip */
284 unsigned Offs; /* Offset of the mirror */
285 const ChipInstance* CI; /* Original chip instance */
286 ChipInstance* MCI; /* Mirrored chip instance */
288 /* Get this location */
289 const Location* L = CollAtUnchecked (&Locations, I);
291 /* Skip non mirrors */
292 if (!LocationIsMirror (L)) {
296 /* Calculate the address range */
297 Range = L->End - L->Start;
299 /* Get the mirror address */
300 D = CollConstAt (&L->Attributes, 0);
301 MirrorAddr = (unsigned) D->V.IVal;
303 /* For simplicity, get the chip instance we're mirroring from the
304 * memory, instead of searching for the range in the list.
306 CI = ASGetChip (MirrorAddr);
308 /* We are mirroring an unassigned address */
309 Error ("%s(%u): Mirroring an unassigned address",
310 CfgGetName (), L->Line);
313 /* Make sure we're mirroring the correct chip */
314 CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
316 /* Calculate the offset of the mirror */
317 Offs = MirrorAddr - CI->Addr;
319 /* Check if the mirror range is ok */
320 if (Offs + Range > CI->Size) {
321 Error ("%s(%u): Mirror range is too large", CfgGetName (), L->Line);
324 /* Clone the chip instance for the new location */
325 MCI = MirrorChipInstance (CI, L->Start - Offs);
327 /* Assign the chip instance to address space */
328 ASAssignChip (CPUInstance->AS, MCI, L->Start, Range);
334 static void ParseConfig (void)
335 /* Parse the config file */
337 static const IdentTok BlockNames [] = {
338 { "ADDRSPACE", CFGTOK_ADDRSPACE },
339 { "CPU", CFGTOK_CPU },
345 /* Read the block ident */
346 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
350 /* Expected a curly brace */
351 CfgConsume (CFGTOK_LCURLY, "`{' expected");
356 case CFGTOK_ADDRSPACE:
365 FAIL ("Unexpected block token");
369 /* Skip closing brace */
372 } while (CfgTok != CFGTOK_EOF);
378 /* Read the configuration */
380 /* If we have a config name given, open the file, otherwise we will read
388 /* Close the input file */