]> git.sur5r.net Git - cc65/blobdiff - src/sim65/config.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / sim65 / config.c
index b620a765f35528dddb439846f82eb349c4c0922c..f595361fc8dfb59246385f8b85924e727bb373c9 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                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                                    */
 /*****************************************************************************/
 
 
@@ -88,7 +69,7 @@ static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
  */
 {
     if (*Flags & Mask) {
-       CfgError ("%s is already defined", Name);
+        CfgError ("%s is already defined", Name);
     }
     *Flags |= Mask;
 }
@@ -99,98 +80,252 @@ static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
 /* 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);
     }
 }
 
@@ -200,34 +335,39 @@ static void ParseConfig (void)
 /* 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);
 }