/* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1