// 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 Atmel AVR devices // ajp - 8 June 2000: // separated out processor-specific instructions // added incbin // // ajp - 10 June 2000: // reversed byte order for incbin and dc.b/db // corrected lpm instruction so extra modes are only supported on the mega161 // // ajp - 11 June 2000: // improved method of handling extra modes for ld and st on different parts // #include "include.h" static SYMTABLE *pseudoOpcodeSymbols, *opcodeSymbols, // symbols for the opcodes common to all *opcodeFullSymbols, // symbols for all remaining opcodes *opcode23xxSymbols, // symbols for the extra opcodes in the 23xx/44xx/85xx parts *opcodeMega103Symbols, // symbols for the extra opcodes in the mega103 part *opcodeMega8Mega161Symbols, // symbols for the extra opcodes in the mega8 and mega161 parts *opcodeTinySymbols, // symbols for the extra opcodes in the tiny parts except the ATtiny22 *opcodeTiny22Symbols; // symbols for the extra opcodes in the ATtiny22 static PROCESSOR *currentProcessor; typedef struct { int type; // type of operand located int value, // first immediate value, non immediate value, or register offset bit; // bit number if present bool unresolved, // if value was an expression, this tells if it was unresolved bitUnresolved; // if bit number was an expression, this tells if it was unresolved } OPERAND; // enumerated operand types (used when parsing) enum { OT_VALUE, // xxxx OT_REGISTER, // Rn OT_REG_X, // X OT_REG_XINC, // X+ OT_REG_DECX, // -X OT_REG_X_OFF, // X+xx <currentPC+currentSegment->codeGenOffset<(1<<22)) { if(!intermediatePass) // only do the real work if necessary { length=strlen(listingRecord->listObjectString); if(length+6listObjectString[length],"%04X ",wordValue); // create list file output } outputBytes[0]=wordValue&0xFF; // data is written as little endian words outputBytes[1]=wordValue>>8; fail=!AddBytesToSegment(currentSegment,currentSegment->currentPC*2,outputBytes,2); // each memory location is 16 bits wide } currentSegment->currentPC++; } else { AssemblyComplaint(NULL,true,"Attempt to write code outside address space\n"); } } else { AssemblyComplaint(NULL,true,"Code cannot occur outside of a segment\n"); } return(!fail); } static unsigned char heldByte; static int byteGenCounter; static void StartByteGeneration() // some opcodes generate bytes at a time which need to be packed into words // this makes that easier { byteGenCounter=0; } static bool GenerateAVRByte(unsigned char byteValue,LISTING_RECORD *listingRecord) // output the byteValue to the current segment { bool fail; fail=false; if(byteGenCounter&1) { fail=!GenerateAVRWord((byteValue<<8)|heldByte,listingRecord); } else { heldByte=byteValue; // just hold the byte until it is later flushed } byteGenCounter++; return(!fail); } static bool FlushByteGeneration(LISTING_RECORD *listingRecord) // flush out any odd byte { if(byteGenCounter&1) { return(GenerateAVRByte(0,listingRecord)); } return(true); } static bool ParseIndexRegister(char *theLine,int *lineIndex,int *index) // Parse out the name of one of the index registers (X,Y, or Z) // if one is located, return 0,1, or 2 to indicate which one // If none is located, return false // NOTE: this is brute force and inelegant. { if(theLine[*lineIndex]=='X'||theLine[*lineIndex]=='x') { (*lineIndex)++; *index=0; return(true); } if(theLine[*lineIndex]=='Y'||theLine[*lineIndex]=='y') { (*lineIndex)++; *index=1; return(true); } if(theLine[*lineIndex]=='Z'||theLine[*lineIndex]=='z') { (*lineIndex)++; *index=2; return(true); } return(false); } static bool ParseRegisterOperand(char *theLine,int *lineIndex,OPERAND *theOperand) // Try to parse out what looks like a register // This will match: // Rn (where n is 0-31) // X // X+ // -X // Y // Y+ // -Y // Y+xx // Z // Z+ // -Z // Z+xx // NOTE: if what was located does not look like a register return false { int inputIndex; int tempIndex; int regIndex; bool fail; fail=false; inputIndex=*lineIndex; if(theLine[inputIndex]=='r'||theLine[inputIndex]=='R') // register ? { theOperand->type=OT_REGISTER; inputIndex++; if(theLine[inputIndex]>='0'&&theLine[inputIndex]<='9') { theOperand->value=theLine[inputIndex]-'0'; inputIndex++; if(theLine[inputIndex]>='0'&&theLine[inputIndex]<='9') { theOperand->value=theOperand->value*10+(theLine[inputIndex]-'0'); inputIndex++; if(theOperand->value>=32) { fail=true; } } } else { fail=true; } } else // not a Rn register, try indexed { if(theLine[inputIndex]=='-') // predecrement? { inputIndex++; ParseWhiteSpace(theLine,&inputIndex); // move past any white space if(ParseIndexRegister(theLine,&inputIndex,®Index)) { switch(regIndex) { case 0: theOperand->type=OT_REG_DECX; break; case 1: theOperand->type=OT_REG_DECY; break; case 2: theOperand->type=OT_REG_DECZ; break; default: fail=true; // should not happen break; } } else { fail=true; } } else { if(ParseIndexRegister(theLine,&inputIndex,®Index)) // need to see an index register at this point { tempIndex=inputIndex; // might need to back up to here if '+' not located ParseWhiteSpace(theLine,&tempIndex); // move past any white space if(theLine[tempIndex]=='+') // post increment or offset? { tempIndex++; inputIndex=tempIndex; // ok so far, now see if there's something other than a separator or a comment if(!ParseComment(theLine,&tempIndex)&&!ParseCommaSeparator(theLine,&tempIndex)) // if not a comment, and not a separator, then assume expression used as an offset { if(ParseExpression(theLine,&tempIndex,&theOperand->value,&theOperand->unresolved)) // get the expression used for the offset { inputIndex=tempIndex; switch(regIndex) { case 0: theOperand->type=OT_REG_X_OFF; // we parse this, but the processor cannot handle it break; case 1: theOperand->type=OT_REG_Y_OFF; break; case 2: theOperand->type=OT_REG_Z_OFF; break; default: fail=true; // should not happen break; } } else { fail=true; // failed to parse an expression, but SOMETHING followed the +, so complain that nothing was found } } else // post increment { switch(regIndex) { case 0: theOperand->type=OT_REG_XINC; break; case 1: theOperand->type=OT_REG_YINC; break; case 2: theOperand->type=OT_REG_ZINC; break; default: fail=true; // should not happen break; } } } else // just an index register, no post increment or offset { switch(regIndex) { case 0: theOperand->type=OT_REG_X; break; case 1: theOperand->type=OT_REG_Y; break; case 2: theOperand->type=OT_REG_Z; break; default: fail=true; // should not happen break; } } } else { fail=true; } } } if(!fail) // something was located that looked like a register. Now make sure it does not run up against a label { if(!IsLabelChar(theLine[inputIndex])) // make sure the character following this does not look like part of a label { *lineIndex=inputIndex; return(true); } } return(false); } static bool ParseOperand(char *theLine,int *lineIndex,OPERAND *theOperand) // Parse an operand as the next thing on theLine // return it in theOperand // NOTE: if what was located does not look like an operand return false { int inputIndex; int value; bool unresolved; if(ParseRegisterOperand(theLine,lineIndex,theOperand)) { return(true); } else // not register form, so try immediate number, or value { inputIndex=*lineIndex; if(ParseExpression(theLine,&inputIndex,&value,&unresolved)) // whatever it is, must be an expression { theOperand->type=OT_VALUE; theOperand->value=value; theOperand->unresolved=unresolved; *lineIndex=inputIndex; return(true); } } return(false); } // opcode handling static bool CheckRegister3Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 3 bit register address // complain if not { if(theValue>=16&&theValue<24) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Register number (%d) out of range\n",theValue); } return(false); } static bool CheckRegister4Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 4 bit register address // complain if not { if(theValue>=16&&theValue<32) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Register number (%d) out of range\n",theValue); } return(false); } static bool CheckRegisterPair2Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 2 bit register pair address // complain if not { if(theValue==24||theValue==26||theValue==28||theValue==30) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Register number (%d) out of range\n",theValue); } return(false); } static bool CheckRegisterPair4Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 4 bit register pair address // complain if not { if((theValue&1)==0) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Register number (%d) out of range\n",theValue); } return(false); } static bool CheckImmediate6Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 6 bit immediate value // complain if not { if(theValue>=0&&theValue<64) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Immediate (0x%X) out of range\n",theValue); } return(false); } static bool CheckRelative7Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 7 bit relative value // complain if not { if(theValue>=-64&&theValue<64) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Relative offset (0x%X) out of range\n",theValue); } return(false); } static bool CheckRelative12Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 12 bit relative value // complain if not { if(theValue>=-2048&&theValue<2048) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Relative offset (0x%X) out of range\n",theValue); } return(false); } static bool CheckAddress5Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 5 bit address // complain if not { if(theValue>=0&&theValue<32) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Address (0x%X) out of range\n",theValue); } return(false); } static bool CheckAddress6Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 6 bit address // complain if not { if(theValue>=0&&theValue<64) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Address (0x%X) out of range\n",theValue); } return(false); } static bool CheckAddress16Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 16 bit address // complain if not { if(theValue>=0&&theValue<65536) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Address (0x%X) out of range\n",theValue); } return(false); } static bool CheckAddress22Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 16 bit address // complain if not { if(theValue>=0&&theValue<(1<<22)) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Address (0x%X) out of range\n",theValue); } return(false); } static bool CheckOffset6Range(int theValue,bool generateMessage,bool isError) // check value to see if it looks good as a 6 bit offset // complain if not { if(theValue>=0&&theValue<64) { return(true); } if(generateMessage) { AssemblyComplaint(NULL,isError,"Offset (0x%X) out of range\n",theValue); } return(false); } // pseudo op handling static bool HandleAVRDB(PSEUDO_OPCODE *opcode,char *theLine,int *lineIndex,bool haveLabel,bool isLocal,char *lineLabel,LISTING_RECORD *listingRecord) // declaring bytes of data, or packed strings { int value; bool unresolved; char outputString[MAXSTRING]; int stringLength; bool done, fail; int i; done=false; fail=!ProcessLineLocationLabel(haveLabel,isLocal,lineLabel); // deal with any label on the line StartByteGeneration(); while(!done&&!fail) { if(ParseQuotedString(theLine,lineIndex,'"','"',outputString,&stringLength)) { i=0; while(!fail&&i>8,listingRecord)) { fail=!GenerateAVRByte(value&0xFF,listingRecord); } else { fail=true; } } else { ReportBadOperands(); done=true; } if(!done&&!fail) // look for separator, or comment { if(ParseCommaSeparator(theLine,lineIndex)) { } else if(ParseComment(theLine,lineIndex)) { done=true; } else { ReportBadOperands(); done=true; } } } return(!fail); } static int ConvertRegister3(int theValue) // Make sure theValue is in range for a 3 bit register if not, complain and // force it into range // return the bitfield value needed to represent it { if(!CheckRegister3Range(theValue,true,true)) { theValue=16; } return(theValue-16); } static int ConvertRegister4(int theValue) // Make sure theValue is in range for a 4 bit register if not, complain and // force it into range // return the bitfield value needed to represent it { if(!CheckRegister4Range(theValue,true,true)) { theValue=16; } return(theValue-16); } static int ConvertRegister5(int theValue) // Make sure theValue is in range for a 5 bit register if not, complain and // force it into range // return the bitfield value needed to represent it { return(theValue); // this is guaranteed to be in range } static int ConvertRegisterPair2(int theValue) // Make sure theValue is in range for a 2 bit register pair if not, complain and // force it into range // return the bitfield value needed to represent it { if(!CheckRegisterPair2Range(theValue,true,true)) { theValue=24; } return((theValue-24)/2); } static int ConvertRegisterPair4(int theValue) // Make sure theValue is in range for a 4 bit register pair if not, complain and // force it into range // return the bitfield value needed to represent it { CheckRegisterPair4Range(theValue,true,true); theValue&=0xFE; return(theValue/2); } static int ConvertBit(int theValue) // Make sure theValue is in range for a bit index { Check8BitIndexRange(theValue,true,true); theValue&=0x07; return(theValue); } static int ConvertImmediate6(int theValue) // Make sure theValue is in range for a 6 bit immediate, complain and // force it into range { CheckImmediate6Range(theValue,true,true); theValue&=0x3F; return(theValue); } static int ConvertImmediate8(int theValue) // Make sure theValue is in range for a 8 bit immediate, complain and // force it into range { CheckByteRange(theValue,true,true); theValue&=0xFF; return(theValue); } static int ConvertRelative7(int theValue) // Make sure theValue is in range for a 7 bit relative address, complain and // force it into range { if(currentSegment) { theValue=theValue-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; CheckRelative7Range(theValue,true,true); theValue&=0x7F; } else { theValue=0; } return(theValue); } static int ConvertRelative12(int theValue) // Make sure theValue is in range for a 12 bit relative address, complain and // force it into range { if(currentSegment) { theValue=theValue-(currentSegment->currentPC+currentSegment->codeGenOffset)-1; CheckRelative12Range(theValue,true,true); theValue&=0xFFF; } else { theValue=0; } return(theValue); } static int ConvertAddress5(int theValue) // Make sure theValue is in range for a 5 bit address, complain and // force it into range { CheckAddress5Range(theValue,true,true); theValue&=0x1F; return(theValue); } static int ConvertAddress6(int theValue) // Make sure theValue is in range for a 6 bit address, complain and // force it into range { CheckAddress6Range(theValue,true,true); theValue&=0x3F; return(theValue); } static int ConvertAddress16(int theValue) // Make sure theValue is in range for a 16 bit address, complain and // force it into range { CheckAddress16Range(theValue,true,true); theValue&=0xFFFF; return(theValue); } static int ConvertAddress22(int theValue) // Make sure theValue is in range for a 22 bit address, complain and // force it into range { CheckAddress22Range(theValue,true,true); theValue&=0x3FFFFF; return(theValue); } static int ConvertOffset6(int theValue) // Make sure theValue is in range for a 6 bit offset, complain and // force it into range { CheckOffset6Range(theValue,true,true); theValue&=0x3F; return(theValue); } static bool HandleAddressingMode(ADDRESSING_MODE *theAddressingMode,int numOperands,OPERAND *operand1,OPERAND *operand2,LISTING_RECORD *listingRecord) // Given an addressing mode record, and a set of operands, generate code (or an error message if something is // out of range) // This will only return false on a 'hard' error { bool fail; int value1, value2; fail=false; switch(theAddressingMode->theMode) { case AM_IMPLIED: fail=!GenerateAVRWord(theAddressingMode->baseOpcode,listingRecord); break; case AM_REG3_REG3: value1=ConvertRegister3(operand1->value); value2=ConvertRegister3(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|value2,listingRecord); break; case AM_REG4: value1=ConvertRegister4(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG4_REG4: value1=ConvertRegister4(operand1->value); value2=ConvertRegister4(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|value2,listingRecord); break; case AM_REG4_IMMEDIATE8: value1=ConvertRegister4(operand1->value); value2=ConvertImmediate8(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0xF0)<<4)|(value2&0x0F),listingRecord); break; case AM_REG4_NOTIMMEDIATE8: value1=ConvertRegister4(operand1->value); value2=~ConvertImmediate8(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0xF0)<<4)|(value2&0x0F),listingRecord); break; case AM_REG5: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_REG5: value1=ConvertRegister5(operand1->value); value2=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0x10)<<5)|(value2&0x0F),listingRecord); break; case AM_REG5_DUP: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value1&0x10)<<5)|(value1&0x0F),listingRecord); break; case AM_REG5_BIT: value1=ConvertRegister5(operand1->value); value2=ConvertBit(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|value2,listingRecord); break; case AM_REG5_ADDR6: value1=ConvertRegister5(operand1->value); value2=ConvertAddress6(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0x30)<<5)|(value2&0x0F),listingRecord); break; case AM_REG5_ADDR16: value1=ConvertRegister5(operand1->value); value2=ConvertAddress16(operand2->value); if(GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord)) { fail=!GenerateAVRWord(value2,listingRecord); } else { fail=true; } break; case AM_REGPAIR2_IMMEDIATE6: value1=ConvertRegisterPair2(operand1->value); value2=ConvertImmediate6(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0x30)<<2)|(value2&0x0F),listingRecord); break; case AM_REGPAIR4_REGPAIR4: value1=ConvertRegisterPair4(operand1->value); value2=ConvertRegisterPair4(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|value2,listingRecord); break; case AM_SREG: value1=ConvertBit(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_SREG_RELATIVE7: value1=ConvertBit(operand1->value); value2=ConvertRelative7(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|value1|(value2<<3),listingRecord); break; case AM_RELATIVE7: value1=ConvertRelative7(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<3),listingRecord); break; case AM_RELATIVE12: value1=ConvertRelative12(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|value1,listingRecord); break; case AM_ADDR5_BIT: value1=ConvertAddress5(operand1->value); value2=ConvertBit(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<3)|value2,listingRecord); break; case AM_ADDR6_REG5: value1=ConvertAddress6(operand1->value); value2=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value2<<4)|((value1&0x30)<<5)|(value1&0x0F),listingRecord); break; case AM_ADDR16_REG5: value1=ConvertAddress16(operand1->value); value2=ConvertRegister5(operand2->value); if(GenerateAVRWord(theAddressingMode->baseOpcode|(value2<<4),listingRecord)) { fail=!GenerateAVRWord(value1,listingRecord); } else { fail=true; } break; case AM_ADDR22: value1=ConvertAddress22(operand1->value); if(GenerateAVRWord(theAddressingMode->baseOpcode|(value1>>16)&1|(((value1>>17)&0x1F)<<4),listingRecord)) { fail=!GenerateAVRWord(value1&0xFFFF,listingRecord); } else { fail=true; } break; case AM_REG5_OFFSETX: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETXINC: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETDECX: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETY: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETYINC: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETDECY: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETY6: value1=ConvertRegister5(operand1->value); value2=ConvertOffset6(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0x20)<<8)|((value2&0x18)<<7)|(value2&0x07),listingRecord); break; case AM_REG5_OFFSETZ: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETZINC: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETDECZ: value1=ConvertRegister5(operand1->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_REG5_OFFSETZ6: value1=ConvertRegister5(operand1->value); value2=ConvertOffset6(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4)|((value2&0x20)<<8)|((value2&0x18)<<7)|(value2&0x07),listingRecord); break; case AM_OFFSETX_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETXINC_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETDECX_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETY_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETYINC_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETDECY_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETY6_REG5: value1=ConvertOffset6(operand1->value); value2=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value2<<4)|((value1&0x20)<<8)|((value1&0x18)<<7)|(value1&0x07),listingRecord); break; case AM_OFFSETZ_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETZINC_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETDECZ_REG5: value1=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value1<<4),listingRecord); break; case AM_OFFSETZ6_REG5: value1=ConvertOffset6(operand1->value); value2=ConvertRegister5(operand2->value); fail=!GenerateAVRWord(theAddressingMode->baseOpcode|(value2<<4)|((value1&0x20)<<8)|((value1&0x18)<<7)|(value1&0x07),listingRecord); break; } return(!fail); } static bool OperandsMatchAddressingMode(ADDRESSING_MODE *theAddressingMode,int numOperands,OPERAND *operand1,OPERAND *operand2) // See if the given addressing mode matches the passed operands // return true for a match, false if no match { switch(theAddressingMode->theMode) { case AM_IMPLIED: return(numOperands==0); break; case AM_REG3_REG3: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REGISTER)); break; case AM_REG4: return((numOperands==1)&&(operand1->type==OT_REGISTER)); break; case AM_REG4_REG4: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REGISTER)); break; case AM_REG4_IMMEDIATE8: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REG4_NOTIMMEDIATE8: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REG5: return((numOperands==1)&&(operand1->type==OT_REGISTER)); break; case AM_REG5_REG5: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REGISTER)); break; case AM_REG5_DUP: return((numOperands==1)&&(operand1->type==OT_REGISTER)); break; case AM_REG5_BIT: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REG5_ADDR6: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REG5_ADDR16: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REGPAIR2_IMMEDIATE6: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_VALUE)); break; case AM_REGPAIR4_REGPAIR4: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REGISTER)); break; case AM_SREG: return((numOperands==1)&&(operand1->type==OT_VALUE)); break; case AM_SREG_RELATIVE7: return((numOperands==2)&&(operand1->type==OT_VALUE)&&(operand2->type==OT_VALUE)); break; case AM_RELATIVE7: return((numOperands==1)&&(operand1->type==OT_VALUE)); break; case AM_RELATIVE12: return((numOperands==1)&&(operand1->type==OT_VALUE)); break; case AM_ADDR5_BIT: return((numOperands==2)&&(operand1->type==OT_VALUE)&&(operand2->type==OT_VALUE)); break; case AM_ADDR6_REG5: return((numOperands==2)&&(operand1->type==OT_VALUE)&&(operand2->type==OT_REGISTER)); break; case AM_ADDR16_REG5: return((numOperands==2)&&(operand1->type==OT_VALUE)&&(operand2->type==OT_REGISTER)); break; case AM_ADDR22: return((numOperands==1)&&(operand1->type==OT_VALUE)); break; case AM_REG5_OFFSETX: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_X)); break; case AM_REG5_OFFSETXINC: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_XINC)); break; case AM_REG5_OFFSETDECX: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_DECX)); break; case AM_REG5_OFFSETY: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_Y)); break; case AM_REG5_OFFSETYINC: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_YINC)); break; case AM_REG5_OFFSETDECY: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_DECY)); break; case AM_REG5_OFFSETY6: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_Y_OFF)); break; case AM_REG5_OFFSETZ: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_Z)); break; case AM_REG5_OFFSETZINC: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_ZINC)); break; case AM_REG5_OFFSETDECZ: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_DECZ)); break; case AM_REG5_OFFSETZ6: return((numOperands==2)&&(operand1->type==OT_REGISTER)&&(operand2->type==OT_REG_Z_OFF)); break; case AM_OFFSETX_REG5: return((numOperands==2)&&(operand1->type==OT_REG_X)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETXINC_REG5: return((numOperands==2)&&(operand1->type==OT_REG_XINC)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETDECX_REG5: return((numOperands==2)&&(operand1->type==OT_REG_DECX)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETY_REG5: return((numOperands==2)&&(operand1->type==OT_REG_Y)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETYINC_REG5: return((numOperands==2)&&(operand1->type==OT_REG_YINC)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETDECY_REG5: return((numOperands==2)&&(operand1->type==OT_REG_DECY)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETY6_REG5: return((numOperands==2)&&(operand1->type==OT_REG_Y_OFF)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETZ_REG5: return((numOperands==2)&&(operand1->type==OT_REG_Z)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETZINC_REG5: return((numOperands==2)&&(operand1->type==OT_REG_ZINC)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETDECZ_REG5: return((numOperands==2)&&(operand1->type==OT_REG_DECZ)&&(operand2->type==OT_REGISTER)); break; case AM_OFFSETZ6_REG5: return((numOperands==2)&&(operand1->type==OT_REG_Z_OFF)&&(operand2->type==OT_REGISTER)); break; } return(false); } static bool ParseOperands(char *theLine,int *lineIndex,int *numOperands,OPERAND *operand1,OPERAND *operand2) // parse from 0 to 2 operands from the line // return the operands parsed // If something does not look right, return false { bool fail; fail=false; *numOperands=0; if(!ParseComment(theLine,lineIndex)) // make sure not at end of line { if(ParseOperand(theLine,lineIndex,operand1)) { *numOperands=1; if(!ParseComment(theLine,lineIndex)) // make sure not at end of line { if(ParseCommaSeparator(theLine,lineIndex)) { if(!ParseComment(theLine,lineIndex)) // make sure not at end of line { if(ParseOperand(theLine,lineIndex,operand2)) { *numOperands=2; if(!ParseComment(theLine,lineIndex)) // make sure were at end of line { fail=true; } } else { fail=true; } } else { fail=true; } } else { fail=true; } } } else { fail=true; } } 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; int numOperands; OPERAND operand1, operand2; int i; bool done; bool fail; fail=false; actualOpcode=(OPCODE *)theOpcode; if(ParseOperands(theLine,lineIndex,&numOperands,&operand1,&operand2)) // fetch operands for opcode { done=false; for(i=0;!done&&(inumModes);i++) { if(OperandsMatchAddressingMode(&(actualOpcode->addressingModes[i]),numOperands,&operand1,&operand2)) { fail=!HandleAddressingMode(&(actualOpcode->addressingModes[i]),numOperands,&operand1,&operand2,listingRecord); done=true; } } if(!done) { ReportBadOperands(); } } else { ReportBadOperands(); } return(!fail); } static void *MatchOpcode(char *theOpcode) // match opcodes for this processor, return NULL if none matched { void *result; result=NULL; if(currentProcessor->processorData) { result=STFindDataForName(*((SYMTABLE **)(currentProcessor->processorData)),theOpcode); // search enhanced opcodes first } if(!result) { result=STFindDataForName(opcodeSymbols,theOpcode); // fallback to here if nothing located } 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 { currentProcessor=theProcessor; if(currentSegment) { currentSegment->currentPC=(currentSegment->currentPC+1)/2; currentSegment->codeGenOffset=(currentSegment->codeGenOffset+1)/2; } return(true); } static void DeselectProcessor(PROCESSOR *theProcessor) // A processor in this family is being deselected { if(currentSegment) { currentSegment->currentPC*=2; currentSegment->codeGenOffset*=2; } } static void UnInitFamily() // undo what InitFamily did { STDisposeSymbolTable(opcodeTiny22Symbols); STDisposeSymbolTable(opcodeTinySymbols); STDisposeSymbolTable(opcodeMega8Mega161Symbols); STDisposeSymbolTable(opcodeMega103Symbols); STDisposeSymbolTable(opcode23xxSymbols); STDisposeSymbolTable(opcodeFullSymbols); STDisposeSymbolTable(opcodeSymbols); STDisposeSymbolTable(pseudoOpcodeSymbols); } static bool AddSymbols(SYMTABLE **symbols,OPCODE *theOpcodes,unsigned int numOpCodes) // Create a new symbol table, and add numOpCodes of theOpcodes to the table // if there is a problem, return false { unsigned int i; bool fail; fail=!(*symbols=STNewSymbolTable()); if(!fail) { for(i=0;!fail&&(i