/*****************************************************************************/
/* */
-/* config.c */
+/* config.c */
/* */
/* Configuration file parsing for the sim65 6502 simulator */
/* */
/* */
/* */
-/* (C) 1998-2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2012, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include "check.h"
#include "bitops.h"
#include "print.h"
+#include "strutil.h"
#include "xmalloc.h"
/* sim65 */
+#include "addrspace.h"
#include "cfgdata.h"
#include "chip.h"
#include "error.h"
#include "global.h"
+#include "location.h"
#include "scanner.h"
#include "config.h"
/*****************************************************************************/
-/* struct CfgData */
-/*****************************************************************************/
-
-
-
-static CfgData* NewCfgData (const char* Tok)
-/* Create and intialize a new CfgData struct, then return it */
-{
- /* Allocate memory */
- CfgData* D = xmalloc (sizeof (CfgData));
-
- /* Initialize the fields */
- D->Attr = xstrdup (Tok);
- D->Type = Invalid;
-
- /* Return the new struct */
- return D;
-}
-
-
-
-/*****************************************************************************/
-/* Data */
+/* Code */
/*****************************************************************************/
*/
{
if (*Flags & Mask) {
- CfgError ("%s is already defined", Name);
+ CfgError ("%s is already defined", Name);
}
*Flags |= Mask;
}
/* Check that a mandatory attribute was given */
{
if ((Attr & Mask) == 0) {
- CfgError ("%s attribute is missing", Name);
+ CfgError ("%s attribute is missing", Name);
}
}
-static void ParseChips (void)
-/* Parse a CHIPS section */
+static void ParseCPU (void)
+/* Parse a CPU section */
{
static const IdentTok Attributes [] = {
- { "ADDR", CFGTOK_ADDR },
- { "RANGE", CFGTOK_RANGE },
+ { "TYPE", CFGTOK_TYPE },
+ { "ADDRSPACE", CFGTOK_ADDRSPACE },
};
- /* Bits and stuff to remember which attributes we have read */
enum {
- CA_ADDR = 0x01,
- CA_RANGE = 0x02
+ atNone = 0x0000,
+ atType = 0x0001,
+ atAddrSpace = 0x0002
};
- unsigned Attr;
+ unsigned Attr = 0;
+ unsigned long Size = 0;
- /* Attribute values. Initialize to make gcc happy. */
- const Chip* C;
- unsigned Addr = 0;
- unsigned Range = 0;
while (CfgTok == CFGTOK_IDENT) {
- /* Search the chip with the given name */
- C = FindChip (CfgSVal);
- if (C == 0) {
- CfgError ("No such chip: `%s'", CfgSVal);
- }
+ cfgtok_t AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
- /* Skip the name plus the following colon */
- CfgNextTok ();
- CfgConsumeColon ();
+ /* Check which attribute was given */
+ switch (AttrTok) {
- /* Read the attributes */
- Attr = 0;
- while (CfgTok == CFGTOK_IDENT) {
+ case CFGTOK_TYPE:
+ FlagAttr (&Attr, atType, "TYPE");
+ CfgAssureIdent ();
+ /* ### */
+ break;
- /* Map the identifier to a token */
- cfgtok_t AttrTok;
- CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
- AttrTok = CfgTok;
+ case CFGTOK_ADDRSPACE:
+ FlagAttr (&Attr, atAddrSpace, "ADDRSPACE");
+ CfgAssureInt ();
+ CfgRangeCheck (0x1000, 0x1000000);
+ Size = CfgIVal;
+ break;
- /* An optional assignment follows */
- CfgNextTok ();
- CfgOptionalAssign ();
+ default:
+ FAIL ("Unexpected attribute token");
- /* Check which attribute was given */
- switch (AttrTok) {
+ }
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+
+ /* Must have some attributes */
+ AttrCheck (Attr, atType, "TYPE");
+ AttrCheck (Attr, atAddrSpace, "ADDRSPACE");
+
+ /* Create the system using the specified CPU */
+ System = NewSystem (NewCPU ("6502", Size));
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+}
+
+
+
+static void ParseAddrSpace (void)
+/* Parse a ADDRSPACE section */
+{
+ unsigned I;
+
+ /* CPU must be defined before the address space */
+ if (System == 0) {
+ CfgError ("CPU must be defined before address space definitions");
+ }
- case CFGTOK_ADDR:
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFFFF);
- FlagAttr (&Attr, CA_ADDR, "ADDR");
- Addr = (unsigned) CfgIVal;
- break;
+ /* Parse addresses */
+ while (CfgTok == CFGTOK_INTCON) {
- case CFGTOK_RANGE:
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFFFF);
- FlagAttr (&Attr, CA_RANGE, "RANGE");
- Range = (unsigned) CfgIVal;
- break;
+ Location* L;
- default:
- FAIL ("Unexpected attribute token");
+ /* Remember the start address and skip it */
+ unsigned long Start = CfgIVal;
+ CfgNextTok ();
- }
+ /* .. must follow */
+ CfgConsume (CFGTOK_DOTDOT, "`..' expected");
- /* Skip the attribute value and an optional comma */
- CfgNextTok ();
- CfgOptionalComma ();
- }
+ /* End address must follow and must be greater than start */
+ CfgAssureInt ();
+ if (CfgIVal < Start) {
+ CfgError ("Start address must be greater than end address");
+ }
- /* Skip the semicolon */
- CfgConsumeSemi ();
+ /* Create a new location and add it to the list */
+ L = NewLocation (Start, CfgIVal);
+ CollAppend (&Locations, L);
- /* Check for mandatory parameters */
- AttrCheck (Attr, CA_ADDR, "ADDR");
- AttrCheck (Attr, CA_RANGE, "RANGE");
+ /* Skip the end address and the following colon */
+ CfgNextTok ();
+ CfgConsumeColon ();
- /* Address + Range may not exceed 16 bits */
- if (((unsigned long) Range) > 0x10000UL - Addr) {
- CfgError ("Range error");
- }
+ /* Parse attributes terminated by a semicolon */
+ while (CfgTok == CFGTOK_IDENT) {
- /* Create the chip ## */
+ /* Generate a new attribute with the given name, then skip it */
+ CfgData* D = NewCfgData ();
+ CfgNextTok ();
+ /* An optional assignment follows */
+ CfgOptionalAssign ();
+
+ /* Check and assign the attribute value */
+ switch (CfgTok) {
+
+ case CFGTOK_INTCON:
+ D->Type = CfgDataNumber;
+ D->V.IVal = CfgIVal;
+ break;
+
+ case CFGTOK_STRCON:
+ D->Type = CfgDataString;
+ D->V.SVal = xstrdup (CfgSVal);
+ break;
+
+ case CFGTOK_IDENT:
+ D->Type = CfgDataId;
+ D->V.SVal = xstrdup (CfgSVal);
+ break;
+
+ default:
+ CfgError ("Invalid attribute type");
+ }
+
+ /* Add the attribute to the location */
+ CollAppend (&L->Attributes, D);
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+ }
+
+ /* Sort all memory locations */
+ LocationSort (&Locations);
+
+ /* Check the locations for overlaps and other problems */
+ LocationCheck (&Locations);
+
+ /* Now create the chip instances. Since we can only mirror existing chips,
+ * we will first create all real chips and the mirrors in a second run.
+ */
+ for (I = 0; I < CollCount (&Locations); ++I) {
+
+ int Index;
+ CfgData* D;
+ unsigned Range; /* Address range for this chip */
+ ChipInstance* CI;
+
+ /* Get this location */
+ Location* L = CollAtUnchecked (&Locations, I);
+
+ /* Skip mirrors */
+ if (LocationIsMirror (L)) {
+ continue;
+ }
+
+ /* The chip must have an attribute "name" of type string */
+ Index = LocationGetAttr (L, "name");
+ D = CollAt (&L->Attributes, Index);
+ CfgDataCheckType (D, CfgDataString);
+
+ /* Remove the "name" attribute from the attribute list */
+ CollDelete (&L->Attributes, Index);
+
+ /* Create the chip instance for the address range */
+ Range = L->End - L->Start + 1;
+ CI = NewChipInstance (D->V.SVal, L->Start, Range, &L->Attributes);
+
+ /* Delete the "name" attribute */
+ FreeCfgData (D);
+
+ /* Assign the chip instance to address space */
+ ASAssignChip (CPUInstance->AS, CI, L->Start, Range);
+ }
+
+ /* Create the mirrors */
+ for (I = 0; I < CollCount (&Locations); ++I) {
+
+ const CfgData* D;
+ unsigned MirrorAddr; /* Mirror address */
+ unsigned Range; /* Address range for this chip */
+ unsigned Offs; /* Offset of the mirror */
+ const ChipInstance* CI; /* Original chip instance */
+ ChipInstance* MCI; /* Mirrored chip instance */
+
+ /* Get this location */
+ const Location* L = CollAtUnchecked (&Locations, I);
+
+ /* Skip non mirrors */
+ if (!LocationIsMirror (L)) {
+ continue;
+ }
+
+ /* Calculate the address range */
+ Range = L->End - L->Start;
+
+ /* Get the mirror address */
+ D = CollConstAt (&L->Attributes, 0);
+ MirrorAddr = (unsigned) D->V.IVal;
+
+ /* For simplicity, get the chip instance we're mirroring from the
+ * memory, instead of searching for the range in the list.
+ */
+ CI = ASGetChip (MirrorAddr);
+ if (CI == 0) {
+ /* We are mirroring an unassigned address */
+ Error ("%s(%u): Mirroring an unassigned address",
+ CfgGetName (), L->Line);
+ }
+
+ /* Make sure we're mirroring the correct chip */
+ CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
+
+ /* Calculate the offset of the mirror */
+ Offs = MirrorAddr - CI->Addr;
+
+ /* Check if the mirror range is ok */
+ if (Offs + Range > CI->Size) {
+ Error ("%s(%u): Mirror range is too large", CfgGetName (), L->Line);
+ }
+
+ /* Clone the chip instance for the new location */
+ MCI = MirrorChipInstance (CI, L->Start - Offs);
+
+ /* Assign the chip instance to address space */
+ ASAssignChip (CPUInstance->AS, MCI, L->Start, Range);
}
}
/* Parse the config file */
{
static const IdentTok BlockNames [] = {
- { "CHIPS", CFGTOK_CHIPS },
+ { "ADDRSPACE", CFGTOK_ADDRSPACE },
+ { "CPU", CFGTOK_CPU },
};
cfgtok_t BlockTok;
do {
- /* Read the block ident */
- CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
- BlockTok = CfgTok;
- CfgNextTok ();
+ /* Read the block ident */
+ CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
+ BlockTok = CfgTok;
+ CfgNextTok ();
+
+ /* Expected a curly brace */
+ CfgConsume (CFGTOK_LCURLY, "`{' expected");
- /* Expected a curly brace */
- CfgConsume (CFGTOK_LCURLY, "`{' expected");
+ /* Read the block */
+ switch (BlockTok) {
- /* Read the block */
- switch (BlockTok) {
+ case CFGTOK_ADDRSPACE:
+ ParseAddrSpace ();
+ break;
- case CFGTOK_CHIPS:
- ParseChips ();
- break;
+ case CFGTOK_CPU:
+ ParseCPU ();
+ break;
- default:
- FAIL ("Unexpected block token");
+ default:
+ FAIL ("Unexpected block token");
- }
+ }
- /* Skip closing brace */
- CfgConsume (CFGTOK_RCURLY, "`}' expected");
+ /* Skip closing brace */
+ CfgConsumeRCurly ();
} while (CfgTok != CFGTOK_EOF);
}