/* Disassemble memory Copyright (C) 2001, 2002, 2003, 2004, 2005 Craig Franklin This file is part of gputils. gputils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gputils 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gputils; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "devices/pic/base/pic.h" #include "coff_object.h" #include "gpopcode.h" #define DECODE_ARG0 snprintf(buffer, sizeof_buffer, "%s", instruction->name) #define DECODE_ARG1(ARG1) snprintf(buffer, sizeof_buffer, "%s\t%#lx", \ instruction->name,\ ARG1) #define DECODE_ARG1WF(ARG1, ARG2) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %s", \ instruction->name,\ ARG1, \ (ARG2 ? "f" : "w")) #define DECODE_ARG2(ARG1, ARG2) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx", \ instruction->name,\ ARG1, \ ARG2) #define DECODE_ARG3(ARG1, ARG2, ARG3) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx, %#lx", \ instruction->name,\ ARG1, \ ARG2, \ ARG3) bool gp_decode_mnemonics = false; bool gp_decode_extended = false; int Coff::disassemble(long int opcode, long int opcode2, int org, Pic::Architecture architecture, char *buffer, size_t sizeof_buffer) { int i; int value; struct insn *instruction = NULL; int num_words = 1; switch (architecture.type()) { case Pic::Architecture::P24F: case Pic::Architecture::P24H: case Pic::Architecture::P30F: case Pic::Architecture::P33F: snprintf(buffer, sizeof_buffer, "--"); return 0; case Pic::Architecture::P10X: for(i = 0; i < num_op_12c5xx; i++) { if((op_12c5xx[i].tqmask & opcode) == op_12c5xx[i].opcode) { instruction = &op_12c5xx[i]; break; } } break; /* case PROC_CLASS_SX: for(i = 0; i < num_op_sx; i++) { if((op_sx[i].tqmask & opcode) == op_sx[i].opcode) { instruction = &op_sx[i]; break; } } break; */ case Pic::Architecture::P16X: for(i = 0; i < num_op_16cxx; i++) { if((op_16cxx[i].tqmask & opcode) == op_16cxx[i].opcode) { instruction = &op_16cxx[i]; break; } } break; case Pic::Architecture::P17C: for(i = 0; i < num_op_17cxx; i++) { if((op_17cxx[i].tqmask & opcode) == op_17cxx[i].opcode) { instruction = &op_17cxx[i]; break; } } break; case Pic::Architecture::P18C: case Pic::Architecture::P18F: case Pic::Architecture::P18J: if (gp_decode_mnemonics) { for(i = 0; i < num_op_18cxx_sp; i++) { if((op_18cxx_sp[i].tqmask & opcode) == op_18cxx_sp[i].opcode) { instruction = &op_18cxx_sp[i]; break; } } } if (instruction == NULL) { for(i = 0; i < num_op_18cxx; i++) { if((op_18cxx[i].tqmask & opcode) == op_18cxx[i].opcode) { instruction = &op_18cxx[i]; break; } } } if ((instruction == NULL) && (gp_decode_extended)) { /* might be from the extended instruction set */ for(i = 0; i < num_op_18cxx_ext; i++) { if((op_18cxx_ext[i].tqmask & opcode) == op_18cxx_ext[i].opcode) { instruction = &op_18cxx_ext[i]; break; } } } break; default: assert(0); } if (instruction == NULL) { snprintf(buffer, sizeof_buffer, "dw\t%#lx ;unknown opcode", opcode); return num_words; } switch (instruction->classType) { case INSN_CLASS_LIT3_BANK: DECODE_ARG1((opcode & 0x7) << 5); break; case INSN_CLASS_LIT3_PAGE: DECODE_ARG1((opcode & 0x7) << 9); break; case INSN_CLASS_LIT1: DECODE_ARG1(opcode & 1); break; case INSN_CLASS_LIT4: DECODE_ARG1(opcode & 0xf); break; case INSN_CLASS_LIT4S: DECODE_ARG1((opcode & 0xf0) >> 4); break; case INSN_CLASS_LIT6: DECODE_ARG1(opcode & 0x3f); break; case INSN_CLASS_LIT8: case INSN_CLASS_LIT8C12: case INSN_CLASS_LIT8C16: DECODE_ARG1(opcode & 0xff); break; case INSN_CLASS_LIT9: DECODE_ARG1(opcode & 0x1ff); break; case INSN_CLASS_LIT11: DECODE_ARG1(opcode & 0x7ff); break; case INSN_CLASS_LIT13: DECODE_ARG1(opcode & 0x1fff); break; case INSN_CLASS_LITFSR: DECODE_ARG2(((opcode >> 6) & 0x3), (opcode & 0x3f)); break; case INSN_CLASS_RBRA8: value = opcode & 0xff; /* twos complement number */ if (value & 0x80) { value = -((value ^ 0xff) + 1); } DECODE_ARG1((unsigned long)(org + value + 1) * 2); break; case INSN_CLASS_RBRA11: value = opcode & 0x7ff; /* twos complement number */ if (value & 0x400) { value = -((value ^ 0x7ff) + 1); } DECODE_ARG1((unsigned long)(org + value + 1) * 2); break; case INSN_CLASS_LIT20: { long int dest; num_words = 2; dest = (opcode2 & 0xfff) << 8; dest |= opcode & 0xff; DECODE_ARG1(dest * 2); } break; case INSN_CLASS_CALL20: { long int dest; num_words = 2; dest = (opcode2 & 0xfff) << 8; dest |= opcode & 0xff; snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx", instruction->name, dest * 2, (opcode >> 8) & 1); } break; case INSN_CLASS_FLIT12: { long int k; long int file; num_words = 2; k = opcode2 & 0xff; k |= ((opcode & 0xf) << 8); file = (opcode >> 4) & 0x3; DECODE_ARG2(file, k); } break; case INSN_CLASS_FF: { long int file1; long int file2; num_words = 2; file1 = opcode & 0xfff; file2 = opcode2 & 0xfff; DECODE_ARG2(file1, file2); } break; case INSN_CLASS_FP: DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 0x1f)); break; case INSN_CLASS_PF: DECODE_ARG2(((opcode >> 8) & 0x1f), (opcode & 0xff)); break; case INSN_CLASS_SF: { long int offset; long int file; num_words = 2; offset = opcode & 0x7f; file = opcode2 & 0xfff; DECODE_ARG2(offset, file); } break; case INSN_CLASS_SS: { long int offset1; long int offset2; num_words = 2; offset1 = opcode & 0x7f; offset2 = opcode2 & 0x7f; DECODE_ARG2(offset1, offset2); } break; case INSN_CLASS_OPF5: DECODE_ARG1(opcode & 0x1f); break; case INSN_CLASS_OPWF5: DECODE_ARG1WF((opcode & 0x1f), ((opcode >> 5) & 1)); break; case INSN_CLASS_B5: DECODE_ARG2((opcode & 0x1f), ((opcode >> 5) & 7)); break; case INSN_CLASS_B8: DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 7)); break; case INSN_CLASS_OPF7: DECODE_ARG1(opcode & 0x7f); break; case INSN_CLASS_OPF8: DECODE_ARG1(opcode & 0xff); break; case INSN_CLASS_OPWF7: DECODE_ARG1WF((opcode & 0x7f), ((opcode >> 7) & 1)); break; case INSN_CLASS_OPWF8: DECODE_ARG1WF((opcode & 0xff), ((opcode >> 8) & 1)); break; case INSN_CLASS_B7: DECODE_ARG2((opcode & 0x7f), ((opcode >> 7) & 7)); break; case INSN_CLASS_OPFA8: DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 1)); break; case INSN_CLASS_BA8: DECODE_ARG3((opcode & 0xff), ((opcode >> 9) & 7), ((opcode >> 8) & 1)); break; case INSN_CLASS_OPWFA8: DECODE_ARG3((opcode & 0xff), ((opcode >> 9) & 1), ((opcode >> 8) & 1)); break; case INSN_CLASS_IMPLICIT: DECODE_ARG0; break; case INSN_CLASS_TBL: { char op[5]; switch(opcode & 0x3) { case 0: strncpy(op, "*", sizeof(op)); break; case 1: strncpy(op, "*+", sizeof(op)); break; case 2: strncpy(op, "*-", sizeof(op)); break; case 3: strncpy(op, "+*", sizeof(op)); break; default: assert(0); } snprintf(buffer, sizeof_buffer, "%s\t%s", instruction->name, op); } break; case INSN_CLASS_TBL2: DECODE_ARG2(((opcode >> 9) & 1), (opcode & 0xff)); break; case INSN_CLASS_TBL3: DECODE_ARG3(((opcode >> 9) & 1), ((opcode >> 8) & 1), (opcode & 0xff)); break; default: assert(0); } return num_words; }