/* Disassembles an assembled instruction, including its operands. */ int disassembleInstruction(disassembledInstruction *dInstruction, const assembledInstruction *aInstruction, int instructionSetIndex) { int instructionIndex, i; if (dInstruction == NULL) return ERROR_INVALID_ARGUMENTS; if (instructionSetIndex != PIC_BASELINE && instructionSetIndex != PIC_MIDRANGE && instructionSetIndex != PIC_MIDRANGE_ENHANCED) return ERROR_INVALID_ARGUMENTS; /* Look up the instruction */ instructionIndex = lookupInstruction(aInstruction->opcode, 0, instructionSetIndex); /* Copy over the address, and reference to the instruction, set * the equivilant-encoded but different instruction to NULL for now. */ dInstruction->address = aInstruction->address; dInstruction->instruction = &(allInstructionSets[instructionSetIndex].instructionSet[instructionIndex]); dInstruction->alternateInstruction = NULL; /* Copy out each operand, extracting the operand data from the original * opcode using the operand mask. */ for (i = 0; i < allInstructionSets[instructionSetIndex].instructionSet[instructionIndex].numOperands; i++) dInstruction->operands[i] = extractDataFromMask(aInstruction->opcode, dInstruction->instruction->operandMasks[i]); /* Disassemble operands */ if (disassembleOperands(dInstruction) < 0) return ERROR_INVALID_ARGUMENTS; /* Only possible error for disassembleOperands() */ return 0; }
/* Look up an instruction by it's opcode in the instructionSet, * starting from index offset. Always returns a valid instruction * index because the last instruction in the instruction set database * is set to be a generic data word (.DW). */ static int lookupInstruction(uint16_t opcode, int offset) { uint16_t opcodeSearch, operandTemp; int insidx, ghostRegisterConfirmed, i, j; for (insidx = offset; insidx < AVR_TOTAL_INSTRUCTIONS; insidx++) { opcodeSearch = opcode; /* If we have a ghost register operand (OPERAND_REGISTER_GHOST), * we need to confirm that all of the other register operands are the same */ ghostRegisterConfirmed = 1; /* We want to mask out all of the operands. We don't count up to * instructionSet[insidx].numOperands because some instructions, * such as clr R16, are actually encoded with two operands (so as eor R16,R16), * and we want to screen out both operands to get the most simplest form of * the instruction. */ for (i = 0; i < AVR_MAX_NUM_OPERANDS; i++) { if (instructionSet[insidx].operandTypes[i] == OPERAND_REGISTER_GHOST) { /* Grab the first operand */ operandTemp = extractDataFromMask(opcode, instructionSet[insidx].operandMasks[0]); /* Compare the remaining operands to the first */ for (j = 1; j < AVR_MAX_NUM_OPERANDS; j++) { if (extractDataFromMask(opcode, instructionSet[insidx].operandMasks[i]) != operandTemp) ghostRegisterConfirmed = 0; } } opcodeSearch &= ~(instructionSet[insidx].operandMasks[i]); } /* If we encountered a ghost register and were unable confirm that * all register operands were equal (in this case ghostRegisterConfirmed * would have changed), then move the match-search onto the next instruction. */ if (ghostRegisterConfirmed == 0) continue; if (opcodeSearch == instructionSet[insidx].opcodeMask) break; } /* It's impossible not to find an instruction, because the last instruction ".DW", * specifies a word of data at the addresses, instead of an instruction. * Its operand 2 mask, 0x0000, will set opcode search to 0x0000, and this will always * match with the opcodeMask of 0x0000. */ return insidx; }
/* Disassembles an assembled instruction, including its operands. */ int disassembleInstruction(disassembledInstruction *dInstruction, const assembledInstruction aInstruction) { int insidx, i; if (dInstruction == NULL) return ERROR_INVALID_ARGUMENTS; /* Look up the instruction */ insidx = lookupInstruction(aInstruction.opcode, 0); if (insidx == AVR_TOTAL_INSTRUCTIONS) { // invalid instruction return 0; } /*** AVR SPECIFIC */ /* If a long instruction was found in the last instruction disassembly, * extract the rest of the address, and indicate that it is to be printed */ if (AVR_Long_Instruction == AVR_LONG_INSTRUCTION_FOUND) { AVR_Long_Instruction = AVR_LONG_INSTRUCTION_PRINT; AVR_Long_Address |= aInstruction.opcode; /* We must multiply by two, because every instruction is 2 bytes, * so in order to jump/call to the right address (which increments by * two for every instruction), we must multiply this distance by two. */ //printf ("ii=%d\n", insidx); if (insidx==86) AVR_Long_Address *= 2; *dInstruction = longInstruction; return 0; /* If a long instruction was printed in the last instruction disassembly, * reset the AVR_Call_Instruction variable back to zero. */ } else if (AVR_Long_Instruction == AVR_LONG_INSTRUCTION_PRINT) { AVR_Long_Instruction = 0; } /* Copy over the address, and reference to the instruction, set * the equivilant-encoded but different instruction to NULL for now. */ dInstruction->address = aInstruction.address; dInstruction->instruction = &instructionSet[insidx]; dInstruction->alternateInstruction = NULL; /* Copy out each operand, extracting the operand data from the original * opcode using the operand mask. */ for (i = 0; i < instructionSet[insidx].numOperands; i++) { dInstruction->operands[i] = extractDataFromMask(aInstruction.opcode, dInstruction->instruction->operandMasks[i]); /*** AVR SPECIFIC */ /* If this is an instruction with a long absolute operand, indicate that a long instruction has been found, * and extract the first part of the long address. */ if (dInstruction->instruction->operandTypes[i] == OPERAND_LONG_ABSOLUTE_ADDRESS) { AVR_Long_Instruction = AVR_LONG_INSTRUCTION_FOUND; AVR_Long_Address = dInstruction->operands[i] << 16; longInstruction = *dInstruction; } } /* Disassemble operands */ if (disassembleOperands(dInstruction) < 0) return ERROR_INVALID_ARGUMENTS; /* Only possible error for disassembleOperands() */ if (AVR_Long_Instruction == AVR_LONG_INSTRUCTION_FOUND) { /* If we found a long instruction (32-bit one), * Copy this instruction over to our special longInstruction variable, that * will exist even after we move onto the next 16-bits */ longInstruction = *dInstruction; } return 0; }