/* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdhdr.h" #include "libgputils.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) gp_boolean gp_decode_mnemonics = false; gp_boolean gp_decode_extended = false; int gp_disassemble(MemBlock *m, int org, enum proc_class class, char *buffer, size_t sizeof_buffer) { int i; int value; long int opcode; struct insn *instruction = NULL; int num_words = 1; opcode = i_memory_get(m, org) & 0xffff; switch (class) { case PROC_CLASS_EEPROM8: case PROC_CLASS_GENERIC: snprintf(buffer, sizeof_buffer, "unsupported processor class"); return 0; case PROC_CLASS_PIC12: for(i = 0; i < num_op_12c5xx; i++) { if((op_12c5xx[i].mask & 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].mask & opcode) == op_sx[i].opcode) { instruction = &op_sx[i]; break; } } break; case PROC_CLASS_PIC14: for(i = 0; i < num_op_16cxx; i++) { if((op_16cxx[i].mask & opcode) == op_16cxx[i].opcode) { instruction = &op_16cxx[i]; break; } } break; case PROC_CLASS_PIC16: for(i = 0; i < num_op_17cxx; i++) { if((op_17cxx[i].mask & opcode) == op_17cxx[i].opcode) { instruction = &op_17cxx[i]; break; } } break; case PROC_CLASS_PIC16E: if (gp_decode_mnemonics) { for(i = 0; i < num_op_18cxx_sp; i++) { if((op_18cxx_sp[i].mask & 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].mask & 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].mask & 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->class) { 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 = (i_memory_get(m, org + 1) & 0xfff) << 8; dest |= opcode & 0xff; DECODE_ARG1(dest * 2); } break; case INSN_CLASS_CALL20: { long int dest; num_words = 2; dest = (i_memory_get(m, org + 1) & 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 = i_memory_get(m, org + 1) & 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 = i_memory_get(m, org + 1) & 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 = i_memory_get(m, org + 1) & 0xfff; DECODE_ARG2(offset, file); } break; case INSN_CLASS_SS: { long int offset1; long int offset2; num_words = 2; offset1 = opcode & 0x7f; offset2 = i_memory_get(m, org + 1) & 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 operator[5]; switch(opcode & 0x3) { case 0: strncpy(operator, "*", sizeof(operator)); break; case 1: strncpy(operator, "*+", sizeof(operator)); break; case 2: strncpy(operator, "*-", sizeof(operator)); break; case 3: strncpy(operator, "+*", sizeof(operator)); break; default: assert(0); } snprintf(buffer, sizeof_buffer, "%s\t%s", instruction->name, operator); } 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; }