// 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". // Generate code for Sunplus SPCxxxx (crippled 6502 core) #include "include.h" static SYMTABLE *pseudoOpcodeSymbols, *opcodeSymbols; // enumerated addressing modes #define OT_IMPLIED 0 // no operands #define OT_IMMEDIATE 1 // #xx #define OT_ZEROPAGE 2 // xx #define OT_ZEROPAGE_OFF_X 3 // xx,X #define OT_EXTENDED 4 // xxxx #define OT_EXTENDED_OFF_X 5 // xxxx,X #define OT_INDIRECT_OFF_X 6 // (xx,X) #define OT_INDIRECT_WORD 7 // (xxxx) #define OT_RELATIVE 8 // one byte relative offset #define OT_NUM OT_RELATIVE+1 // number of addressing modes // masks for the various addressing modes #define M_IMPLIED (1<typeMask&M_IMMEDIATE) { CheckByteRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_IMMEDIATE],listingRecord)) { fail=!GenerateByte(value,listingRecord); } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleZeroPage(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // deal with zero page mode output only { bool fail; fail=false; if(theOpcode->typeMask&M_ZEROPAGE) { CheckUnsignedByteRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_ZEROPAGE],listingRecord)) { fail=!GenerateByte(value,listingRecord); } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleExtended(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // deal with extended mode output only { bool fail; fail=false; if(theOpcode->typeMask&M_EXTENDED) { CheckUnsignedWordRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_EXTENDED],listingRecord)) { if(GenerateByte(value&0xFF,listingRecord)) { fail=!GenerateByte(value>>8,listingRecord); } else { fail=true; } } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleZeroPageOrExtended(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a zero page or extended address has been parsed { bool fail; fail=false; if(theOpcode->typeMask&M_ZEROPAGE) { if(((value>=0)&&(value<256))||!(theOpcode->typeMask&M_EXTENDED)) { fail=!HandleZeroPage(theOpcode,value,unresolved,listingRecord); } else { fail=!HandleExtended(theOpcode,value,unresolved,listingRecord); } } else { fail=!HandleExtended(theOpcode,value,unresolved,listingRecord); } return(!fail); } static bool HandleRelative(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a relative operand has been parsed { bool fail; int offset; fail=false; if(GenerateByte(theOpcode->baseOpcode[OT_RELATIVE],listingRecord)) { offset=0; if(!unresolved&¤tSegment) { offset=value-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; Check8RelativeRange(offset,true,true); } fail=!GenerateByte(offset,listingRecord); } else { fail=true; } return(!fail); } static bool HandleValue(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a value has been parsed, it might be relative, zero page, or extended { bool fail; fail=false; if(theOpcode->typeMask&M_RELATIVE) { fail=!HandleRelative(theOpcode,value,unresolved,listingRecord); } else { fail=!HandleZeroPageOrExtended(theOpcode,value,unresolved,listingRecord); } return(!fail); } static bool HandleZeroPageOffX(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // deal with zero page offset by X { bool fail; fail=false; if(theOpcode->typeMask&M_ZEROPAGE_OFF_X) { CheckUnsignedByteRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_ZEROPAGE_OFF_X],listingRecord)) { fail=!GenerateByte(value,listingRecord); } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleExtendedOffX(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // deal with extended mode offset by X { bool fail; fail=false; if(theOpcode->typeMask&M_EXTENDED_OFF_X) { CheckUnsignedWordRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_EXTENDED_OFF_X],listingRecord)) { if(GenerateByte(value&0xFF,listingRecord)) { fail=!GenerateByte(value>>8,listingRecord); } else { fail=true; } } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleValueOffX(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // possible extended or zeropage value offset by X { bool fail; fail=false; if(theOpcode->typeMask&M_ZEROPAGE_OFF_X) { if(((value>=0)&&(value<256))||!(theOpcode->typeMask&M_EXTENDED_OFF_X)) { fail=!HandleZeroPageOffX(theOpcode,value,unresolved,listingRecord); } else { fail=!HandleExtendedOffX(theOpcode,value,unresolved,listingRecord); } } else { fail=!HandleExtendedOffX(theOpcode,value,unresolved,listingRecord); } return(!fail); } static bool HandleIndirect(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a indirect value has been parsed, it must be indirect word { bool fail; fail=false; if(theOpcode->typeMask&M_INDIRECT_WORD) { CheckUnsignedWordRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_INDIRECT_WORD],listingRecord)) { if(GenerateByte(value&0xFF,listingRecord)) { fail=!GenerateByte(value>>8,listingRecord); } else { fail=true; } } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleIndirectOffX(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a indirect value offset by X has been parsed, it must be zero page { bool fail; fail=false; if(theOpcode->typeMask&M_INDIRECT_OFF_X) { CheckUnsignedByteRange(value,true,true); if(GenerateByte(theOpcode->baseOpcode[OT_INDIRECT_OFF_X],listingRecord)) { fail=!GenerateByte(value,listingRecord); } else { fail=true; } } else { ReportBadOperands(); } return(!fail); } static bool HandleOpcode(void *theOpcode,char *theLine,int *lineIndex,LISTING_RECORD *listingRecord) // look at the type of opcode available, parse operands as allowed // return false only if there was a 'hard' error { OPCODE *actualOpcode; bool fail; int elementType; int value; bool unresolved; fail=false; actualOpcode=(OPCODE *)theOpcode; if(!ParseComment(theLine,lineIndex)) { if(ParseOperand(theLine,lineIndex,&elementType,&value,&unresolved)) { switch(elementType) { case POT_IMMEDIATE: return(HandleImmediate(actualOpcode,value,unresolved,listingRecord)); break; case POT_VALUE: return(HandleValue(actualOpcode,value,unresolved,listingRecord)); break; case POT_VALUE_OFF_X: return(HandleValueOffX(actualOpcode,value,unresolved,listingRecord)); break; case POT_INDIRECT: return(HandleIndirect(actualOpcode,value,unresolved,listingRecord)); break; case POT_INDIRECT_OFF_X: return(HandleIndirectOffX(actualOpcode,value,unresolved,listingRecord)); break; } } else { ReportBadOperands(); } } else { if(actualOpcode->typeMask&M_IMPLIED) { fail=!GenerateByte(actualOpcode->baseOpcode[OT_IMPLIED],listingRecord); } else { ReportBadOperands(); } } return(!fail); } static void *MatchOpcode(char *theOpcode) // match opcodes for this processor, return NULL if none matched { void *result; result=STFindDataForName(opcodeSymbols,theOpcode); return(result); } static bool HandlePseudoOpcode(PSEUDO_OPCODE *theOpcode,char *theLine,int *lineIndex,bool haveLabel,bool isLocal,char *lineLabel,LISTING_RECORD *listingRecord) // look at the type of opcode available, parse operands as allowed // return false only if there was a 'hard' error { return(theOpcode->theFunction(theOpcode,theLine,lineIndex,haveLabel,isLocal,lineLabel,listingRecord)); } static PSEUDO_OPCODE *MatchPseudoOpcode(char *theOpcode) // match pseudo opcodes for this processor, return NULL if none matched { return((PSEUDO_OPCODE *)STFindDataForName(pseudoOpcodeSymbols,theOpcode)); } static bool SelectProcessor(PROCESSOR *theProcessor) // A processor in this family is being selected to assemble with { return(true); } static void DeselectProcessor(PROCESSOR *theProcessor) // A processor in this family is being deselected { } static void UnInitFamily() // undo what InitFamily did { STDisposeSymbolTable(opcodeSymbols); STDisposeSymbolTable(pseudoOpcodeSymbols); } static bool InitFamily() // initialize symbol tables { unsigned int i; bool fail; fail=false; if((pseudoOpcodeSymbols=STNewSymbolTable())) { for(i=0;!fail&&(i