// Copyright (C) 1999-2003 Core Technologies. // // This file is part of tpasm. // // tpasm is free software; you can redistribute it and/or modify // it under the terms of the tpasm LICENSE AGREEMENT. // // tpasm is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // tpasm LICENSE AGREEMENT for more details. // // You should have received a copy of the tpasm LICENSE AGREEMENT // along with tpasm; see the file "LICENSE.TXT". // Handle interface to all supported processors // NOTE: this uses a little more of C++ than the rest of the code because // it is very handy to be able to build the list of processors at run time // based on which processor modules have been linked to the executable. // Doing this keeps ALL code for a new processor local to the source file // which supports it. #include "include.h" static PROCESSOR_FAMILY *topProcessorFamily=NULL; // list of processor families (created at run time) static PROCESSOR *currentProcessor; static SYMTABLE *processorSymbols; // symbol table of names of all supported processors PSEUDO_OPCODE *MatchProcessorPseudoOpcode(char *theOpcodeString) // match pseudo opcodes for the current processor, return NULL if none matched { if(currentProcessor) { return(currentProcessor->family->matchPseudoFunction(theOpcodeString)); } return(NULL); } bool HandleProcessorPseudoOpcode(PSEUDO_OPCODE *theOpcode,char *theLine,int *lineIndex,bool haveLabel,bool isLocal,char *lineLabel,LISTING_RECORD *listingRecord) // handle pseudo opcodes for the current processor { if(currentProcessor) { return(currentProcessor->family->handlePseudoFunction(theOpcode,theLine,lineIndex,haveLabel,isLocal,lineLabel,listingRecord)); } return(false); } void *MatchProcessorOpcode(char *theOpcodeString) // match opcodes for the current processor, return NULL if none matched { if(currentProcessor) { return(currentProcessor->family->matchFunction(theOpcodeString)); } return(NULL); } bool HandleProcessorOpcode(void *theOpcode,char *theLine,int *lineIndex,LISTING_RECORD *listingRecord) // handle opcodes for the current processor { if(currentProcessor) { return(currentProcessor->family->handleFunction(theOpcode,theLine,lineIndex,listingRecord)); } return(false); } static void CreateProcessorLabelName(PROCESSOR *theProcessor,char *labelName) // create the name of the label used for the given processor { char *theName; sprintf(labelName,"__%s",theProcessor->name); theName=labelName; while(*theName) { *theName=toupper(*theName); theName++; } } static void UnAssignProcessorLabel(PROCESSOR *theProcessor) // get rid of a label for the passed processor { char labelName[MAXSTRING]; CreateProcessorLabelName(theProcessor,labelName); UnAssignSetConstant(labelName); } static bool AssignProcessorLabel(PROCESSOR *theProcessor) // Create a label for the passed processor { char labelName[MAXSTRING]; CreateProcessorLabelName(theProcessor,labelName); return(AssignSetConstant(labelName,1,true)); } bool SelectProcessor(char *processorName,bool *found) // select the processor based on the passed name // NOTE: if processorName is passed in as a zero length string, // the current processor will be set to NULL // NOTE: this creates an assembler set label of the processor name (in all uppercase) // preceded by two underscores. // NOTE: this only returns false on "hard" errors { int i; char convertedName[MAXSTRING]; void *resultValue; bool fail; fail=false; *found=false; if(currentProcessor) { UnAssignProcessorLabel(currentProcessor); currentProcessor->family->deselectProcessorFunction(currentProcessor); // let this processor know it is being deselected currentProcessor=NULL; } if(!fail) { i=0; while(processorName[i]) // make name lower case { convertedName[i]=tolower(processorName[i]); i++; } convertedName[i]='\0'; if(i) { if((resultValue=STFindDataForName(processorSymbols,convertedName))) { currentProcessor=(PROCESSOR *)resultValue; *found=true; if(AssignProcessorLabel(currentProcessor)) { currentProcessor->family->selectProcessorFunction(currentProcessor); // let this processor know it has been selected } else { fail=true; } } } else { *found=true; // empty name can always be found } } return(!fail); } static void UnInitProcessorFamily(PROCESSOR_FAMILY *theFamily) // Uninitialize a processor family { PROCESSOR *theProcessor; theProcessor=theFamily->lastProcessor; while(theProcessor) { STRemoveEntry(processorSymbols,theProcessor->theSymbol); theProcessor=theProcessor->previousProcessor; } theFamily->uninitFamilyFunction(); } static bool InitProcessorFamily(PROCESSOR_FAMILY *theFamily) // Call the processor family's init function, and add each // processor in the family's symbols to the table { bool fail; PROCESSOR *theProcessor; fail=false; if(theFamily->initFamilyFunction()) { theProcessor=theFamily->firstProcessor; while(theProcessor&&!fail) { if((theProcessor->theSymbol=STAddEntryAtEnd(processorSymbols,theProcessor->name,theProcessor))) { theProcessor=theProcessor->nextProcessor; } else { fail=true; } } if(!fail) { return(true); } theProcessor=theProcessor->previousProcessor; while(theProcessor) { STRemoveEntry(processorSymbols,theProcessor->theSymbol); theProcessor=theProcessor->previousProcessor; } theFamily->uninitFamilyFunction(); } return(false); } void UnInitProcessors() // undo what InitProcessors did { PROCESSOR_FAMILY *theFamily; theFamily=topProcessorFamily; while(theFamily&&theFamily->nextFamily) // race to the bottom so we can un-init in reverse order { theFamily=theFamily->nextFamily; } while(theFamily) { UnInitProcessorFamily(theFamily); theFamily=theFamily->previousFamily; } STDisposeSymbolTable(processorSymbols); } bool InitProcessors() // initialize symbol table for processor selection, and initialize all the processor family handler functions { bool fail; PROCESSOR_FAMILY *theFamily; currentProcessor=NULL; // no processor chosen as current fail=false; if((processorSymbols=STNewSymbolTable())) { theFamily=topProcessorFamily; while(theFamily&&!fail) { if(InitProcessorFamily(theFamily)) { theFamily=theFamily->nextFamily; } else { ReportComplaint(true,"Failed to initialize processor family: %s\n",theFamily->name); fail=true; } } if(!fail) { return(true); } theFamily=theFamily->previousFamily; while(theFamily) { UnInitProcessorFamily(theFamily); theFamily=theFamily->previousFamily; } STDisposeSymbolTable(processorSymbols); } else { ReportComplaint(true,"Failed to create symbol table for processors\n"); } return(false); } static void DumpProcessorFamilyMembers(FILE *theFile,PROCESSOR_FAMILY *theFamily) // dump out the members of the given processor family { int longestMember; PROCESSOR *theProcessor; int length, sumLength; // first run through and find the longest name longestMember=0; theProcessor=theFamily->firstProcessor; while(theProcessor) { length=strlen(theProcessor->name); if(length>longestMember) { longestMember=length; } theProcessor=theProcessor->nextProcessor; } // now print out the names theProcessor=theFamily->firstProcessor; while(theProcessor) { length=strlen(theProcessor->name); fprintf(theFile," %s",theProcessor->name); // print the first item on the row, spaced in sumLength=(2+longestMember+1)+(longestMember+1); // account for item just printed, and item about to be printed theProcessor=theProcessor->nextProcessor; while(theProcessor&&(sumLength<80)) { fprintf(theFile,"%*s%s",(longestMember-length)+1,"",theProcessor->name); // space over, and print the next entry sumLength+=longestMember+1; length=strlen(theProcessor->name); // get length of this one for next time theProcessor=theProcessor->nextProcessor; } fprintf(theFile,"\n"); } } void DumpProcessorInformation(FILE *theFile) // tell what processors and families are supported by the assembler { PROCESSOR_FAMILY *theFamily; theFamily=topProcessorFamily; while(theFamily) { fprintf(theFile,"%s\n",theFamily->name); DumpProcessorFamilyMembers(theFile,theFamily); theFamily=theFamily->nextFamily; } } // Constructors used to link processor functions to global list at run-time PROCESSOR_FAMILY::PROCESSOR_FAMILY(const char *theName,InitFamilyFunction *theInitFunction,UnInitFamilyFunction *theUnInitFunction,SelectProcessorFunction *theSelectFunction,DeselectProcessorFunction *theDeselectFunction,MatchPseudoOpcodeFunction *theMatchPseudoFunction,HandlePseudoOpcodeFunction *theHandlePseudoFunction,MatchOpcodeFunction *theMatchFunction,HandleOpcodeFunction *theHandleFunction) // Use this to add a given processor family // to the global list { name=theName; initFamilyFunction=theInitFunction; uninitFamilyFunction=theUnInitFunction; selectProcessorFunction=theSelectFunction; deselectProcessorFunction=theDeselectFunction; matchPseudoFunction=theMatchPseudoFunction; handlePseudoFunction=theHandlePseudoFunction; matchFunction=theMatchFunction; handleFunction=theHandleFunction; firstProcessor=NULL; lastProcessor=NULL; if((nextFamily=topProcessorFamily)) // link to next one { topProcessorFamily->previousFamily=this; // link next one to this one } previousFamily=NULL; // none previous to this topProcessorFamily=this; // point at this one } PROCESSOR_FAMILY::~PROCESSOR_FAMILY() // When a processor family goes out of scope, get rid of it here // NOTE: all processors in this family must have already been destroyed { if(nextFamily) { nextFamily->previousFamily=previousFamily; // point next's previous to our previous } if(previousFamily) { previousFamily->nextFamily=nextFamily; // point previous' next to our next } else { topProcessorFamily=nextFamily; // if no previous, then we were the top, so set top to our next } } PROCESSOR::PROCESSOR(PROCESSOR_FAMILY *theFamily,const char *theName,const void *theData) // Use this to construct a processor which will be added to the // list or processors supported by the assembler { family=theFamily; theSymbol=NULL; name=theName; processorData=theData; // link to end of processors in the family nextProcessor=NULL; if((previousProcessor=theFamily->lastProcessor)) { previousProcessor->nextProcessor=this; } else { theFamily->firstProcessor=this; // first in the family } theFamily->lastProcessor=this; } PROCESSOR::~PROCESSOR() // When a processor goes out of scope, get rid of it here { if(nextProcessor) { nextProcessor->previousProcessor=previousProcessor; // point next's previous to our previous } else { family->lastProcessor=previousProcessor; } if(previousProcessor) { previousProcessor->nextProcessor=nextProcessor; // point previous' next to our next } else { family->firstProcessor=nextProcessor; // if no previous, then we were the top, so set top to our next } }