diff --git a/src/sim65/chip.c b/src/sim65/chip.c index 6bae69444..9f3b26b78 100644 --- a/src/sim65/chip.c +++ b/src/sim65/chip.c @@ -41,6 +41,7 @@ #include "xmalloc.h" /* sim65 */ +#include "cfgdata.h" #include "chipdata.h" #include "chiplib.h" #include "error.h" @@ -88,50 +89,6 @@ static int CmpChips (void* Data attribute ((unused)), -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -Chip* NewChip (ChipLibrary* Library, const ChipData* Data) -/* Allocate a new chip structure, initialize and return it */ -{ - /* Allocate memory */ - Chip* C = xmalloc (sizeof (Chip)); - - /* Initialize the fields */ - C->Library = Library; - C->Data = Data; - C->Instances = EmptyCollection; - - /* Insert the new chip into the collection of all chips */ - CollAppend (&Chips, C); - - /* Return the structure */ - return C; -} - - - -ChipInstance* NewChipInstance (unsigned long Addr, unsigned Size) -/* Allocate a new chip instance for the chip. */ -{ - /* Allocate a new ChipInstance structure */ - ChipInstance* Instance = xmalloc (sizeof (*Instance)); - - /* Initialize the fields */ - Instance->C = 0; - Instance->Addr = Addr; - Instance->Size = Size; - Instance->InstanceData = 0; - - /* Return the new struct */ - return Instance; -} - - - static Chip* FindChip (const char* Name) /* Find a chip by name. Returns the Chip data structure or NULL if the chip * could not be found. @@ -158,24 +115,80 @@ static Chip* FindChip (const char* Name) -void InitChipInstance (ChipInstance* CI, const char* ChipName, - const struct CfgData** Data, unsigned Count) -/* Initialize the given chip instance. Assign it to the chip named ChipName, - * and call the init function of the chip passing the given config data. - */ +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +Chip* NewChip (ChipLibrary* Library, const ChipData* Data) +/* Allocate a new chip structure, initialize and return it */ { + /* Allocate memory */ + Chip* C = xmalloc (sizeof (Chip)); + + /* Initialize the fields */ + C->Library = Library; + C->Data = Data; + C->Instances = EmptyCollection; + + /* Insert the new chip into the collection of all chips */ + CollAppend (&Chips, C); + + /* Return the structure */ + return C; +} + + + +ChipInstance* NewChipInstance (const char* ChipName, unsigned Addr, + unsigned Size, const Collection* Attributes) +{ + ChipInstance* CI; + /* Find the chip with the given name */ Chip* C = FindChip (ChipName); if (C == 0) { - Error ("No chip `%s' found for address $%6lX", ChipName, CI->Addr); + Error ("No chip `%s' found for address $%06X", ChipName, Addr); } - /* Call the initialization function */ - CI->InstanceData = C->Data->InitInstance (CI->Addr, CI->Size, Data, Count); + /* Allocate a new ChipInstance structure */ + CI = xmalloc (sizeof (*CI)); + + /* Initialize the fields */ + CI->C = C; + CI->Addr = Addr; + CI->Size = Size; + CI->Data = C->Data->InitInstance (Addr, Size, + (const CfgData**) Attributes->Items, + CollCount (Attributes)); /* Assign the chip instance to the chip */ - CI->C = C; CollAppend (&C->Instances, CI); + + /* Return the new instance struct */ + return CI; +} + + + +ChipInstance* MirrorChipInstance (const ChipInstance* Orig, unsigned Addr) +/* Generate a chip instance mirror and return it. */ +{ + /* Allocate a new ChipInstance structure */ + ChipInstance* CI = xmalloc (sizeof (*CI)); + + /* Initialize the fields */ + CI->C = Orig->C; + CI->Addr = Addr; + CI->Size = Orig->Size; + CI->Data = Orig->Data; + + /* Assign the chip instance to the chip */ + CollAppend (&CI->C->Instances, CI); + + /* Return the new instance struct */ + return CI; } diff --git a/src/sim65/chip.h b/src/sim65/chip.h index dbdbcaf3b..cf3342dba 100644 --- a/src/sim65/chip.h +++ b/src/sim65/chip.h @@ -61,10 +61,10 @@ typedef struct ChipInstance ChipInstance; /* One instance of a chip */ struct ChipInstance { - Chip* C; /* Pointer to corresponding chip */ - unsigned long Addr; /* Start address of range */ - unsigned Size; /* Size of range */ - void* InstanceData; /* Chip instance data */ + Chip* C; /* Pointer to corresponding chip */ + unsigned Addr; /* Start address of range */ + unsigned Size; /* Size of range */ + void* Data; /* Chip instance data */ }; /* Chip structure */ @@ -85,14 +85,12 @@ struct Chip { Chip* NewChip (struct ChipLibrary* Library, const ChipData* Data); /* Allocate a new chip structure, initialize and return it */ -ChipInstance* NewChipInstance (unsigned long Addr, unsigned Size); +ChipInstance* NewChipInstance (const char* ChipName, unsigned Addr, + unsigned Size, const Collection* Attributes); /* Allocate a new chip instance for the chip. */ -void InitChipInstance (ChipInstance* CI, const char* ChipName, - const struct CfgData** Data, unsigned Count); -/* Initialize the given chip instance. Assign it to the chip named ChipName, - * and call the init function of the chip passing the given config data. - */ +ChipInstance* MirrorChipInstance (const ChipInstance* Orig, unsigned Addr); +/* Generate a chip instance mirror and return it. */ void SortChips (void); /* Sort all chips by name. Called after loading */ diff --git a/src/sim65/config.c b/src/sim65/config.c index e29366c9e..c95380dee 100644 --- a/src/sim65/config.c +++ b/src/sim65/config.c @@ -50,6 +50,7 @@ #include "chip.h" #include "error.h" #include "global.h" +#include "memory.h" #include "scanner.h" #include "config.h" @@ -67,11 +68,11 @@ static Collection Locations; /* One memory location */ typedef struct Location Location; struct Location { - unsigned long Start; /* Start of memory location */ - unsigned long End; /* End memory location */ - Collection Attributes; /* Attributes given */ - unsigned Line; /* Line in config file */ - unsigned Col; /* Column in config file */ + unsigned Start; /* Start of memory location */ + unsigned End; /* End memory location */ + Collection Attributes; /* Attributes given */ + unsigned Line; /* Line in config file */ + unsigned Col; /* Column in config file */ }; @@ -94,7 +95,7 @@ static CfgData* NewCfgData (void) CfgData* D = xmalloc (sizeof (CfgData) + AttrLen); /* Initialize the fields */ - D->Type = CfgDataInvalid; + D->Type = CfgDataInvalid; D->Line = CfgErrorLine; D->Col = CfgErrorCol; memcpy (D->Attr, CfgSVal, AttrLen+1); @@ -105,6 +106,30 @@ static CfgData* NewCfgData (void) +static void FreeCfgData (CfgData* D) +/* Free a config data structure */ +{ + if (D->Type == CfgDataString) { + /* Free the string value */ + xfree (D->V.SVal); + } + /* Free the structure */ + xfree (D); +} + + + +static void CfgDataCheckType (const CfgData* D, unsigned Type) +/* Check the config data type */ +{ + if (D->Type != Type) { + Error ("%s(%u): Attribute `%s' has invalid type", + CfgGetName (), D->Line, D->Attr); + } +} + + + /*****************************************************************************/ /* struct Location */ /*****************************************************************************/ @@ -150,9 +175,9 @@ static int CmpLocations (void* Data attribute ((unused)), -static const CfgData* LocationFindAttr (const Location* L, const char* AttrName) -/* Find the attribute with the given name and return it. Return NULL if the - * attribute was not found. +static int LocationFindAttr (const Location* L, const char* AttrName) +/* Find the attribute with the given name and return its index. Return -1 if + * the attribute was not found. */ { unsigned I; @@ -166,12 +191,26 @@ static const CfgData* LocationFindAttr (const Location* L, const char* AttrName) /* Compare the name */ if (StrCaseCmp (D->Attr, AttrName) == 0) { /* Found */ - return D; + return I; } } /* Not found */ - return 0; + return -1; +} + + + +static int LocationGetAttr (const Location* L, const char* AttrName) +/* Find the attribute with the given name and return it. Call Error() if the + * attribute was not found. + */ +{ + int I = LocationFindAttr (L, AttrName); + if (I < 0) { + Error ("%s(%u): Attribute `%s' missing", CfgGetName(), L->Line, AttrName); + } + return I; } @@ -180,40 +219,17 @@ static int LocationIsMirror (const Location* L) /* Return true if the given location is a mirror of another one. */ { /* Find the "mirror" attribute */ - return (LocationFindAttr (L, "mirror") != 0); + return (LocationFindAttr (L, "mirror") >= 0); } /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name) -/* Check if the item is already defined. Print an error if so. If not, set - * the marker that we have a definition now. - */ -{ - if (*Flags & Mask) { - CfgError ("%s is already defined", Name); - } - *Flags |= Mask; -} - - - -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); - } -} - - - static void ParseMemory (void) /* Parse a MEMORY section */ { @@ -312,19 +328,106 @@ static void ParseMemory (void) if (LocationIsMirror (L)) { const CfgData* D; if (CollCount (&L->Attributes) > 1) { - Error ("%s(%u): Location at address $%06lX is a mirror " + Error ("%s(%u): Location at address $%06X is a mirror " "but has attributes", CfgGetName(), L->Line, L->Start); } D = CollConstAt (&L->Attributes, 0); - if (D->Type != CfgDataNumber) { - Error ("%s(%u): Mirror attribute is not an integer", - CfgGetName (), L->Line); - } + CfgDataCheckType (D, CfgDataNumber); } /* Remember this entry */ Last = L; } + + /* 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; + CI = NewChipInstance (D->V.SVal, L->Start, Range, &L->Attributes); + + /* Delete the "name" attribute */ + FreeCfgData (D); + + /* Assign the chip instance to memory */ + MemAssignChip (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 = MemGetChip (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 memory */ + MemAssignChip (MCI, L->Start, Range); + } } diff --git a/src/sim65/main.c b/src/sim65/main.c index 7cfd0ed5c..b8d7bc7d9 100644 --- a/src/sim65/main.c +++ b/src/sim65/main.c @@ -292,10 +292,13 @@ int main (int argc, char* argv[]) Error ("Simulator configuration missing"); } + /* Initialize the simulated CPU memory */ + MemInit (); + /* Read the config file */ CfgRead (); - MemInit (); + /* Initialize the CPU */ CPUInit (); #if 0 CPURun (); diff --git a/src/sim65/memory.c b/src/sim65/memory.c index 6454c75d3..727ba1ca6 100644 --- a/src/sim65/memory.c +++ b/src/sim65/memory.c @@ -39,84 +39,25 @@ /* common */ #include "coll.h" +#include "xmalloc.h" /* sim65 */ +#include "chip.h" +#include "cputype.h" #include "error.h" #include "memory.h" -/*****************************************************************************/ -/* Forwards */ -/*****************************************************************************/ - - - -static void MemWrite (unsigned Addr, unsigned char Val); -/* Write one byte to the memory cell */ - -static unsigned char MemRead (unsigned Attr); -/* Read one memory cell */ - - - /*****************************************************************************/ /* Data */ /*****************************************************************************/ -/* RAM attributes */ -#define RA_READFUNC_MASK 0x000F /* Up to 16 read functions */ -#define RA_WRITEFUNC_MASK 0x00F0 /* Up to 16 write functions */ -#define RA_INITIALIZED 0x0100 /* Memory cell is initialized */ -#define RA_WPROT 0x0200 /* Memory cell is write protected */ - -/* Defines reader and writer functions */ -#define RA_READFUNC_SHIFT 0 -#define RA_WRITEFUNC_SHIFT 4 -#define RA_READFUNC_MAX 16 -#define RA_WRITEFUNC_MAX 16 - -/* Read/write function declarations */ -typedef unsigned char (*ReadFunc) (unsigned Addr); -typedef void (*WriteFunc) (unsigned Addr, unsigned char Val); -static Collection ReadFuncs = STATIC_COLLECTION_INITIALIZER; -static Collection WriteFuncs = STATIC_COLLECTION_INITIALIZER; - -/* Memory attributes and the memory */ -static unsigned short MemAttr[0x10000]; -static unsigned char Mem[0x10000]; - - - -/*****************************************************************************/ -/* Internal functions */ -/*****************************************************************************/ - - - -static void MemWrite (unsigned Addr, unsigned char Val) -/* Write one byte to the memory cell */ -{ - if (MemAttr[Addr] & RA_WPROT) { - Warning ("Writing to write protected memory at $%04X", Addr); - } - Mem[Addr] = Val; - MemAttr[Addr] |= RA_INITIALIZED; -} - - - -static unsigned char MemRead (unsigned Addr) -/* Read one memory cell */ -{ - if ((MemAttr[Addr] & RA_INITIALIZED) == 0) { - /* We're reading a memory cell that was never written */ - Warning ("Reading from uninitialized memory at $%04X", Addr); - } - return Mem[Addr]; -} +/* Pointer to our memory */ +static const ChipInstance** MemData = 0; +unsigned MemSize = 0; @@ -129,12 +70,15 @@ static unsigned char MemRead (unsigned Addr) void MemWriteByte (unsigned Addr, unsigned char Val) /* Write a byte to a memory location */ { - /* Get the writer function */ - unsigned WI = (MemAttr[Addr] & RA_WRITEFUNC_MASK) >> RA_WRITEFUNC_SHIFT; - WriteFunc WF = CollAt (&WriteFuncs, WI); + /* Get the instance of the chip at this address */ + const ChipInstance* CI = MemData[Addr]; - /* Call the writer function */ - WF (Addr, Val); + /* Check if the memory is mapped */ + if (CI == 0) { + Warning ("Writing to unassigned memory at $%06X", Addr); + } else { + CI->C->Data->Write (CI->Data, Addr - CI->Addr, Val); + } } @@ -142,12 +86,16 @@ void MemWriteByte (unsigned Addr, unsigned char Val) unsigned char MemReadByte (unsigned Addr) /* Read a byte from a memory location */ { - /* Get the reader function */ - unsigned RI = (MemAttr[Addr] & RA_READFUNC_MASK) >> RA_READFUNC_SHIFT; - ReadFunc RF = CollAt (&ReadFuncs, RI); + /* Get the instance of the chip at this address */ + const ChipInstance* CI = MemData[Addr]; - /* Call the reader function */ - return RF (Addr); + /* Check if the memory is mapped */ + if (CI == 0) { + Warning ("Reading from unassigned memory at $%06X", Addr); + return 0xFF; + } else { + return CI->C->Data->Read (CI->Data, Addr - CI->Addr); + } } @@ -163,9 +111,9 @@ unsigned MemReadWord (unsigned Addr) unsigned MemReadZPWord (unsigned char Addr) /* Read a word from the zero page. This function differs from ReadMemW in that -* the read will always be in the zero page, even in case of an address -* overflow. -*/ + * the read will always be in the zero page, even in case of an address + * overflow. + */ { unsigned W = MemReadByte (Addr++); return (W | (MemReadByte (Addr) << 8)); @@ -173,46 +121,29 @@ unsigned MemReadZPWord (unsigned char Addr) -void MemLoad (const char* Filename, unsigned Addr, unsigned Size) -/* Load the contents of the given file into the RAM at the given address. - * If Size is not zero, we will read exactly Size bytes from the file and - * consider it an error if this is not possible. The memory attributes - * for the range is set to initialized. - */ +void MemAssignChip (const ChipInstance* CI, unsigned Addr, unsigned Range) +/* Assign a chip instance to memory locations */ { - unsigned BytesToRead; - unsigned BytesRead; - unsigned I; + /* Make sure, the addresses are in a valid range */ + PRECONDITION (Addr + Range <= MemSize); - /* Open the file */ - FILE* F = fopen (Filename, "rb"); - if (F == 0) { - Error ("Cannot open `%s': %s", Filename, strerror (errno)); + /* Assign the chip instance */ + while (Range--) { + CHECK (MemData[Addr] == 0); + MemData[Addr++] = CI; } +} - /* Set the number of bytes to read */ - BytesToRead = 0x10000 - Addr; - if (Size > 0) { - CHECK (Size <= BytesToRead); /* Must not exceed RAM */ - BytesToRead = Size; - } - /* Read data from the file */ - BytesRead = fread (Mem + Addr, 1, BytesToRead, F); - if (ferror (F)) { - Error ("Error reading from `%s': %s", Filename, strerror (errno)); - } - if (Size > 0 && BytesRead != Size) { - Error ("Cannot read %u bytes from `%s'", Size, Filename); - } - /* Close the file. Ignore errors, we were just reading. */ - fclose (F); +const struct ChipInstance* MemGetChip (unsigned Addr) +/* Get the chip that is located at the given address (may return NULL). */ +{ + /* Make sure, the address is valid */ + PRECONDITION (Addr < MemSize); - /* Set the memory attribute for the range to initialized */ - for (I = 0; I < BytesRead; ++I) { - MemAttr[Addr+I] |= RA_INITIALIZED; - } + /* Return the chip instance */ + return MemData[Addr]; } @@ -222,23 +153,21 @@ void MemInit (void) { unsigned I; - /* Clear the memory and it's attributes. Writing zeroes to the - * attribute array will cause any special flags to be reset and - * the default read and write functions to be used. - */ - for (I = 0; I < sizeof (Mem) / sizeof (Mem[0]); ++I) { - Mem[I] = 0; + /* Allocate memory depending on the CPU type */ + switch (CPU) { + case CPU_6502: + case CPU_65C02: + MemSize = 0x10000; + break; + default: + Internal ("Unexpected CPU type: %d", CPU); } - for (I = 0; I < sizeof (MemAttr) / sizeof (MemAttr[0]); ++I) { - MemAttr[I] = 0; + MemData = xmalloc (MemSize); + + /* Clear the memory */ + for (I = 0; I < MemSize; ++I) { + MemData[I] = 0; } - - /* Add the default reader and writer functions to the collection */ - CollAppend (&ReadFuncs, MemRead); - CollAppend (&WriteFuncs, MemWrite); - - MemWriteByte (0xFFFC, 0x00); - MemWriteByte (0xFFFD, 0x02); } diff --git a/src/sim65/memory.h b/src/sim65/memory.h index 43ac5f9df..55e828607 100644 --- a/src/sim65/memory.h +++ b/src/sim65/memory.h @@ -39,13 +39,21 @@ /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ +/* Forwards */ +struct ChipInstance; + +/* Memory size of the CPU */ +extern unsigned MemSize; + + + /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -65,12 +73,11 @@ unsigned MemReadZPWord (unsigned char Addr); * overflow. */ -void MemLoad (const char* Filename, unsigned Addr, unsigned Size); -/* Load the contents of the given file into the RAM at the given address. - * If Size is not zero, we will read exactly Size bytes from the file and - * consider it an error if this is not possible. The memory attributes - * for the range is set to initialized. - */ +void MemAssignChip (const struct ChipInstance* CI, unsigned Addr, unsigned Range); +/* Assign a chip instance to memory locations */ + +const struct ChipInstance* MemGetChip (unsigned Addr); +/* Get the chip that is located at the given address (may return NULL). */ void MemInit (void); /* Initialize the memory subsystem */ @@ -83,3 +90,4 @@ void MemInit (void); +