//----------------------------------------------------------------------------- // 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". // //----------------------------------------------------------------------------- // // Motorola MC68HC11 support Copyright (C) 1999 Cosmodog, Ltd. // //----------------------------------------------------------------------------- // 68HC11 ADDRESSING MODE FORMS // // inherent: op // immediate8: op #ii // immediate16: op #jjkk // direct: op dd // extended: op hhll // indexed_x: op ff,x // indexed_y: op ff,y // relative: op rr // bit_direct: op dd,mm // bit_indexed_x: op ff,x,mm // bit_indexed_y: op ff,y,mm // bit_direct_relative: op dd,mm,rr // bit_indexed_x_relative: op ff,x,mm,rr // bit_indexed_y_relative: op ff,y,mm,rr // // ii 8 bit immediate value // jjkk 16 bit immediate value (jj is upper 8 bits, kk is lower 8 bits) // dd 8 bit direct page address // hhll 16 bit address (hh is upper 8 bits, ll is lower 8 bits) // ff 8 bit unsigned offset // rr 8 bit signed offset // mm 8 bit mask // // ff is an implied 0 if it is not included in indexed addressing modes, i.e., // addd x // addd ,x // addd 0,x // are all the same instruction (and are all valid) // #include "include.h" static SYMTABLE *pseudoOpcodeSymbols, *opcodeSymbols; // enumerated addressing modes enum { OT_INHERENT = 0, // no operands OT_IMMEDIATE8, // one byte immediate operand OT_IMMEDIATE16, // two byte immediate operand OT_DIRECT, // one byte direct OT_EXTENDED, // two byte absolute OT_INDEXED_X, OT_INDEXED_Y, OT_RELATIVE, // one byte relative offset OT_BIT_DIRECT, // one byte direct, one bit mask OT_BIT_INDEXED_X, OT_BIT_INDEXED_Y, OT_BIT_DIRECT_RELATIVE, // one byte direct, one bit mask OT_BIT_INDEXED_X_RELATIVE, OT_BIT_INDEXED_Y_RELATIVE, OT_NUM // number of addressing modes }; // masks for the various addressing modes #define M_INHERENT (1< 0xff) put out both bytes { fail = !GenerateByte((opcode>>8)&0xff,listingRecord); } if(!fail) { fail = !GenerateByte(opcode&0xff,listingRecord); } return(!fail); } static bool HandleImmediate(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // an immediate addressing mode was located { bool fail=false; if(theOpcode->typeMask&M_IMMEDIATE8) // 8-bit immediate value { CheckByteRange(value,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_IMMEDIATE8],listingRecord); if(!fail) { fail=!GenerateByte(value,listingRecord); } } else if(theOpcode->typeMask&M_IMMEDIATE16) // 16-bit immediate value { CheckWordRange(value,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_IMMEDIATE16],listingRecord); if(!fail) { fail = !GenerateByte((value>>8)&0xff,listingRecord); if(!fail) { fail = !GenerateByte(value&0xff,listingRecord); } } } else { ReportBadOperands(); } 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 = !WriteOpcode(theOpcode->baseOpcode[OT_RELATIVE],listingRecord); if(!fail) { offset=0; if(!unresolved&¤tSegment) { offset=value-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; Check8RelativeRange(offset,true,true); } fail=!GenerateByte(offset,listingRecord); } return(!fail); } static bool HandleDirect(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // deal with direct mode output only { bool fail; fail=false; if(theOpcode->typeMask&M_DIRECT) { CheckUnsignedByteRange(value,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_DIRECT],listingRecord); if(!fail) { fail=!GenerateByte(value,listingRecord); } } 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); fail = !WriteOpcode(theOpcode->baseOpcode[OT_EXTENDED],listingRecord); if(!fail) { fail = !GenerateByte(value>>8,listingRecord); if(!fail) { fail=!GenerateByte(value&0xFF,listingRecord); } } } else { ReportBadOperands(); } return(!fail); } static bool HandleDirectOrExtended(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a direct or extended address has been parsed { bool fail; fail=false; if(theOpcode->typeMask&M_DIRECT) { if(((value>=0)&&(value<256))||!(theOpcode->typeMask&M_EXTENDED)) { fail=!HandleDirect(theOpcode,value,unresolved,listingRecord); } else { fail=!HandleExtended(theOpcode,value,unresolved,listingRecord); } } else { fail=!HandleExtended(theOpcode,value,unresolved,listingRecord); } return(!fail); } static bool HandleSingleAddress(OPCODE *theOpcode,int value,bool unresolved,LISTING_RECORD *listingRecord) // a lone address has been parsed // This means it is either a relative address (rr), direct (dd), or extended (hhll) { bool fail; fail=false; if(theOpcode->typeMask&M_RELATIVE) { fail=!HandleRelative(theOpcode,value,unresolved,listingRecord); } else if(theOpcode->typeMask&(M_DIRECT|M_EXTENDED)) { fail=!HandleDirectOrExtended(theOpcode,value,unresolved,listingRecord); } else { ReportBadOperands(); } return(!fail); } static bool HandleIndexedX(OPCODE *theOpcode,char *theLine,int *lineIndex,int value1,bool unresolved,LISTING_RECORD *listingRecord) // indexed x modes: // indexed_x: op ff,x // bit_indexed_x: op ff,x,mm // bit_indexed_x_relative: op ff,x,mm,rr { bool fail = false; int value2; int value3; int offset; bool unresolved2; bool unresolved3; int elementType; if(ParseCommaSeparator(theLine,lineIndex)) // look for a second separator { if(ParseOperandElement(theLine,lineIndex,&elementType,&value2,&unresolved2) && (elementType == POT_VALUE) ) { if(ParseCommaSeparator(theLine,lineIndex)) // look for a third separator { if(ParseOperandElement(theLine,lineIndex,&elementType,&value3,&unresolved3) && (elementType == POT_VALUE) && ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_INDEXED_X_RELATIVE ) { fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_INDEXED_X_RELATIVE],listingRecord); if(!fail) { CheckUnsignedByteRange(value1,true,true); // bit indexed x relative fail=!GenerateByte(value1,listingRecord); if(!fail) { CheckUnsignedByteRange(value2,true,true); fail=!GenerateByte(value2,listingRecord); } if(!fail) { offset=0; if(currentSegment) { offset=value3-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; Check8RelativeRange(offset,true,true); } fail=!GenerateByte(offset,listingRecord); } } } else { ReportBadOperands(); } } else if(ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_INDEXED_X) // bit indexed x { CheckUnsignedByteRange(value1,true,true); CheckUnsignedByteRange(value2,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_INDEXED_X],listingRecord); if(!fail) { fail=!GenerateByte(value1,listingRecord); if(!fail) { fail=!GenerateByte(value2,listingRecord); } } } else { ReportBadOperands(); } } else { ReportBadOperands(); } } else if(ParseComment(theLine,lineIndex)) { if(theOpcode->typeMask&M_INDEXED_X) { CheckUnsignedByteRange(value1,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_INDEXED_X],listingRecord); if(!fail) { fail=!GenerateByte(value1,listingRecord); } } else { ReportBadOperands(); } } else { ReportBadOperands(); } return(!fail); } static bool HandleIndexedY(OPCODE *theOpcode,char *theLine,int *lineIndex,int value1,bool unresolved,LISTING_RECORD *listingRecord) // indexed y modes: // indexed_y: op ff,y // bit_indexed_y: op ff,y,mm // bit_indexed_y_relative: op ff,y,mm,rr { bool fail = false; int value2; int value3; int offset; bool unresolved2; bool unresolved3; int elementType; if(ParseCommaSeparator(theLine,lineIndex)) // look for a second separator { if(ParseOperandElement(theLine,lineIndex,&elementType,&value2,&unresolved2) && (elementType == POT_VALUE) ) { if(ParseCommaSeparator(theLine,lineIndex)) // look for a third separator { if(ParseOperandElement(theLine,lineIndex,&elementType,&value3,&unresolved3) && (elementType == POT_VALUE) && ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_INDEXED_Y_RELATIVE ) { fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_INDEXED_Y_RELATIVE],listingRecord); if(!fail) { CheckUnsignedByteRange(value1,true,true); // bit indexed y relative fail=!GenerateByte(value1,listingRecord); if(!fail) { CheckUnsignedByteRange(value2,true,true); fail=!GenerateByte(value2,listingRecord); } if(!fail) { offset=0; if(currentSegment) { offset=value3-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; Check8RelativeRange(offset,true,true); } fail=!GenerateByte(offset,listingRecord); } } } else { ReportBadOperands(); } } else if(ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_INDEXED_Y) // bit indexed y { CheckUnsignedByteRange(value1,true,true); CheckUnsignedByteRange(value2,true,true); fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_INDEXED_Y],listingRecord); if(!fail) { fail=!GenerateByte(value1,listingRecord); if(!fail) { fail=!GenerateByte(value2,listingRecord); } } } else { ReportBadOperands(); } } else { ReportBadOperands(); } } else if(ParseComment(theLine,lineIndex)) { if(theOpcode->typeMask&M_INDEXED_Y) { fail = !WriteOpcode(theOpcode->baseOpcode[OT_INDEXED_Y],listingRecord); if(!fail) { CheckUnsignedByteRange(value1,true,true); fail=!GenerateByte(value1,listingRecord); } } else { ReportBadOperands(); } } else { ReportBadOperands(); } return(!fail); } static bool HandleBitDirect(OPCODE *theOpcode,char *theLine,int *lineIndex,int value1, int value2,LISTING_RECORD *listingRecord) { bool fail = false; int value3; bool unresolved3; int elementType; int offset; if(ParseCommaSeparator(theLine,lineIndex)) // separator indicates a third value { if(ParseOperandElement(theLine,lineIndex,&elementType,&value3,&unresolved3) && elementType==POT_VALUE) { if(ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_DIRECT_RELATIVE) { fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_DIRECT_RELATIVE],listingRecord); if(!fail) { CheckUnsignedByteRange(value1,true,true); fail=!GenerateByte(value1,listingRecord); if(!fail) { CheckUnsignedByteRange(value2,true,true); fail=!GenerateByte(value2,listingRecord); if(!fail) { offset=0; if(currentSegment) { offset=value3-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; Check8RelativeRange(offset,true,true); } fail=!GenerateByte(offset,listingRecord); } } } } else { ReportBadOperands(); } } else { ReportBadOperands(); } } else if(ParseComment(theLine,lineIndex) && theOpcode->typeMask&M_BIT_DIRECT) { fail = !WriteOpcode(theOpcode->baseOpcode[OT_BIT_DIRECT],listingRecord); if(!fail) { CheckUnsignedByteRange(value1,true,true); fail=!GenerateByte(value1,listingRecord); if(!fail) { CheckUnsignedByteRange(value2,true,true); fail=!GenerateByte(value2,listingRecord); } } } else { ReportBadOperands(); } return(!fail); } static bool HandleFirstValue(OPCODE *theOpcode,char *theLine,int *lineIndex,int value1,bool unresolved1,LISTING_RECORD *listingRecord) // a non-immediate value was parsed, so see what else we can find { bool fail; int elementType; int value2; bool unresolved2; fail=false; if(ParseCommaSeparator(theLine,lineIndex)) // make sure the next thing separates operands { if(ParseOperandElement(theLine,lineIndex,&elementType,&value2,&unresolved2)) { switch(elementType) { case POT_INDEX_X: // second operand was X return(HandleIndexedX(theOpcode,theLine,lineIndex,value1,unresolved1,listingRecord)); break; case POT_INDEX_Y: // second operand was Y return(HandleIndexedY(theOpcode,theLine,lineIndex,value1,unresolved1,listingRecord)); break; case POT_VALUE: return(HandleBitDirect(theOpcode,theLine,lineIndex,value1,value2,listingRecord)); break; default: ReportBadOperands(); break; } } else { ReportBadOperands(); } } 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; bool indexedMode; fail=false; actualOpcode=(OPCODE *)theOpcode; if(!ParseComment(theLine,lineIndex)) { indexedMode = ParseCommaSeparator(theLine,lineIndex); // if true mode must be indexed if(ParseOperandElement(theLine,lineIndex,&elementType,&value,&unresolved)) { switch(elementType) { case POT_IMMEDIATE: if(!indexedMode && ParseComment(theLine,lineIndex)) { return(HandleImmediate(actualOpcode,value,unresolved,listingRecord)); } else { ReportBadOperands(); } break; case POT_INDEX_X: value = 0; return(HandleIndexedX(actualOpcode,theLine,lineIndex,value,unresolved,listingRecord)); break; case POT_INDEX_Y: value = 0; return(HandleIndexedY(actualOpcode,theLine,lineIndex,value,unresolved,listingRecord)); break; case POT_VALUE: if(!indexedMode && ParseComment(theLine,lineIndex)) // if it's followed by comment/EOL, then its a single address { return(HandleSingleAddress(actualOpcode,value,unresolved,listingRecord)); } else { return(HandleFirstValue(actualOpcode,theLine,lineIndex,value,unresolved,listingRecord)); } break; } } else { ReportBadOperands(); } } else { if(actualOpcode->typeMask&M_INHERENT) { fail = !WriteOpcode(actualOpcode->baseOpcode[OT_INHERENT],listingRecord); } else { ReportBadOperands(); } } return(!fail); } static void *MatchOpcode(char *theOpcode) // match opcodes for this processor, return NULL if none matched { return(STFindDataForName(opcodeSymbols,theOpcode)); } 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 table { unsigned int i; bool fail; fail=false; if((pseudoOpcodeSymbols=STNewSymbolTable())) { for(i=0;!fail&&(i