OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [gdb-5.0/] [opcodes/] [or32-dis.c] - Diff between revs 579 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 579 Rev 1765
/* Instruction printing code for the OpenRISC 1000
/* Instruction printing code for the OpenRISC 1000
   Copyright (C) 1990, 93, 94, 95, 1998 Free Software Foundation, Inc.
   Copyright (C) 1990, 93, 94, 95, 1998 Free Software Foundation, Inc.
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Modified from a29k port.
   Modified from a29k port.
 
 
This file is part of GDB.
This file is part of GDB.
 
 
This program is free software; you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 
#define DEBUG 0
#define DEBUG 0
 
 
#include "dis-asm.h"
#include "dis-asm.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
 
 
#include <ctype.h>
#include <ctype.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
 
 
CONST unsigned int num_opcodes = (((sizeof or32_opcodes) / (sizeof or32_opcodes[0])) - 1);
CONST unsigned int num_opcodes = (((sizeof or32_opcodes) / (sizeof or32_opcodes[0])) - 1);
 
 
#define EXTEND29(x) ((x) & 0x10000000 ? ((x) | 0xf0000000) : ((x)))
#define EXTEND29(x) ((x) & 0x10000000 ? ((x) | 0xf0000000) : ((x)))
 
 
/* Calculates instruction length in bytes. Either 2 or 4 for OR16
/* Calculates instruction length in bytes. Either 2 or 4 for OR16
   and always 4 for OR32. */
   and always 4 for OR32. */
int insn_len (char *insn)
int insn_len (char *insn)
{
{
  CONST struct or32_opcode *pinsn;
  CONST struct or32_opcode *pinsn;
  char *enc;
  char *enc;
  int len = 0;
  int len = 0;
 
 
  for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) {
  for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) {
    if (strcmp(pinsn->name, insn) == 0) {
    if (strcmp(pinsn->name, insn) == 0) {
      for (enc = pinsn->encoding; *enc != '\0'; enc++)
      for (enc = pinsn->encoding; *enc != '\0'; enc++)
        if ((*enc == '0') && (*(enc+1) == 'x')) {
        if ((*enc == '0') && (*(enc+1) == 'x')) {
          len += 4;
          len += 4;
          enc += 2;
          enc += 2;
        }
        }
        else if (!isspace(*enc))
        else if (!isspace(*enc))
          len++;
          len++;
      return len / 8;
      return len / 8;
    }
    }
  }
  }
  printf("insn_len(%s): Unknown instruction.\n", insn);
  printf("insn_len(%s): Unknown instruction.\n", insn);
  exit(1);
  exit(1);
}
}
 
 
/* Now find the four bytes of INSN_CH and put them in *INSN.  */
/* Now find the four bytes of INSN_CH and put them in *INSN.  */
static void
static void
find_bytes_big (insn_ch, insn)
find_bytes_big (insn_ch, insn)
     unsigned char *insn_ch;
     unsigned char *insn_ch;
     unsigned long *insn;
     unsigned long *insn;
{
{
  *insn = ((unsigned long)insn_ch[0] << 24) +
  *insn = ((unsigned long)insn_ch[0] << 24) +
      ((unsigned long)insn_ch[1] << 16) +
      ((unsigned long)insn_ch[1] << 16) +
      ((unsigned long)insn_ch[2] << 8) +
      ((unsigned long)insn_ch[2] << 8) +
      (unsigned long)insn_ch[3];
      (unsigned long)insn_ch[3];
#if DEBUG
#if DEBUG
      printf("find_bytes_big3: %x\n", *insn);
      printf("find_bytes_big3: %x\n", *insn);
#endif
#endif
}
}
 
 
/* Is individual insn's operand signed or unsigned? */
/* Is individual insn's operand signed or unsigned? */
int letter_signed(char l)
int letter_signed(char l)
{
{
        struct or32_letter *pletter;
        struct or32_letter *pletter;
 
 
        for(pletter = or32_letters; pletter->letter != '\0'; pletter++)
        for(pletter = or32_letters; pletter->letter != '\0'; pletter++)
                if (pletter->letter == l)
                if (pletter->letter == l)
                        return pletter->sign;
                        return pletter->sign;
 
 
        printf("letter_signed(%c): Unknown letter.\n", l);
        printf("letter_signed(%c): Unknown letter.\n", l);
        return 0;
        return 0;
}
}
 
 
/* Number of letters in the individual lettered operand. */
/* Number of letters in the individual lettered operand. */
int letter_range(char l)
int letter_range(char l)
{
{
  CONST struct or32_opcode *pinsn;
  CONST struct or32_opcode *pinsn;
  char *enc;
  char *enc;
  int range = 0;
  int range = 0;
 
 
  for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) {
  for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) {
    if (strchr(pinsn->encoding,l)) {
    if (strchr(pinsn->encoding,l)) {
      for (enc = pinsn->encoding; *enc != '\0'; enc++)
      for (enc = pinsn->encoding; *enc != '\0'; enc++)
        if ((*enc == '0') && (*(enc+1) == 'x')) {
        if ((*enc == '0') && (*(enc+1) == 'x')) {
          enc += 2;
          enc += 2;
        }
        }
        else if (*enc == l)
        else if (*enc == l)
          range++;
          range++;
      return range;
      return range;
    }
    }
  }
  }
  printf("\nABORT: letter_range(%c): Never used letter.\n", l);
  printf("\nABORT: letter_range(%c): Never used letter.\n", l);
  exit(1);
  exit(1);
}
}
 
 
static void
static void
find_bytes_little (insn_ch, insn)
find_bytes_little (insn_ch, insn)
     unsigned char *insn_ch;
     unsigned char *insn_ch;
     unsigned long *insn;
     unsigned long *insn;
{
{
  *insn = ((unsigned long)insn_ch[3] << 24) +
  *insn = ((unsigned long)insn_ch[3] << 24) +
      ((unsigned long)insn_ch[2] << 16) +
      ((unsigned long)insn_ch[2] << 16) +
      ((unsigned long)insn_ch[1] << 8) +
      ((unsigned long)insn_ch[1] << 8) +
      (unsigned long)insn_ch[0];
      (unsigned long)insn_ch[0];
}
}
 
 
 
 
typedef void (*find_byte_func_type)
typedef void (*find_byte_func_type)
     PARAMS ((unsigned char *, unsigned long *));
     PARAMS ((unsigned char *, unsigned long *));
 
 
static unsigned long
static unsigned long
or32_extract(param_ch, enc_initial, insn)
or32_extract(param_ch, enc_initial, insn)
     char param_ch;
     char param_ch;
     char *enc_initial;
     char *enc_initial;
     unsigned long insn;
     unsigned long insn;
{
{
  char *enc;
  char *enc;
  unsigned long ret = 0;
  unsigned long ret = 0;
  int opc_pos = 0;
  int opc_pos = 0;
  int param_pos = 0;
  int param_pos = 0;
 
 
  for (enc = enc_initial; *enc != '\0'; enc++)
  for (enc = enc_initial; *enc != '\0'; enc++)
    if (*enc == param_ch)
    if (*enc == param_ch)
      {
      {
        if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
        if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
          continue;
          continue;
        else
        else
          param_pos++;
          param_pos++;
      }
      }
 
 
#if DEBUG
#if DEBUG
  printf("or32_extract: %c %x ", param_ch, param_pos);
  printf("or32_extract: %c %x ", param_ch, param_pos);
#endif
#endif
        opc_pos = 32;
        opc_pos = 32;
        for (enc = enc_initial; *enc != '\0'; )
        for (enc = enc_initial; *enc != '\0'; )
                if ((*enc == '0') && (*(enc+1) == 'x')) {
                if ((*enc == '0') && (*(enc+1) == 'x')) {
                  opc_pos -= 4;
                  opc_pos -= 4;
                  if ((param_ch == '0') || (param_ch == '1')) {
                  if ((param_ch == '0') || (param_ch == '1')) {
                        unsigned long tmp = strtol(enc, NULL, 16);
                        unsigned long tmp = strtol(enc, NULL, 16);
#if DEBUG
#if DEBUG
                        printf(" enc=%s, tmp=%x ", enc, tmp);
                        printf(" enc=%s, tmp=%x ", enc, tmp);
#endif
#endif
                        if (param_ch == '0')
                        if (param_ch == '0')
                          tmp = 15 - tmp;
                          tmp = 15 - tmp;
                        ret |= tmp << opc_pos;
                        ret |= tmp << opc_pos;
                   }
                   }
                   enc += 3;
                   enc += 3;
                }
                }
                else if ((*enc == '0') || (*enc == '1')) {
                else if ((*enc == '0') || (*enc == '1')) {
                  opc_pos--;
                  opc_pos--;
                  if (param_ch == *enc)
                  if (param_ch == *enc)
                        ret |= 1 << opc_pos;
                        ret |= 1 << opc_pos;
                  enc++;
                  enc++;
                }
                }
                else if (*enc == param_ch) {
                else if (*enc == param_ch) {
                        opc_pos--;
                        opc_pos--;
                        param_pos--;
                        param_pos--;
#if DEBUG
#if DEBUG
                        printf("\n  ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
                        printf("\n  ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
#endif
#endif
                        ret += ((insn >> opc_pos) & 0x1) << param_pos;
                        ret += ((insn >> opc_pos) & 0x1) << param_pos;
                        if (!param_pos && letter_signed(param_ch) && ret >> (letter_range(param_ch) - 1)) {
                        if (!param_pos && letter_signed(param_ch) && ret >> (letter_range(param_ch) - 1)) {
#if DEBUG
#if DEBUG
                           printf("\n  ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
                           printf("\n  ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
#endif
#endif
                           ret |= 0xffffffff << letter_range(param_ch);
                           ret |= 0xffffffff << letter_range(param_ch);
#if DEBUG
#if DEBUG
                           printf("\n  after conversion to signed: ret=%x\n", ret);
                           printf("\n  after conversion to signed: ret=%x\n", ret);
#endif
#endif
                        }
                        }
                        enc++;
                        enc++;
                }
                }
                else if (isalpha(*enc)) {
                else if (isalpha(*enc)) {
                        opc_pos--;
                        opc_pos--;
                        enc++;
                        enc++;
                }
                }
                else if (*enc == '-') {
                else if (*enc == '-') {
                  opc_pos--;
                  opc_pos--;
                  enc++;
                  enc++;
                }
                }
                else
                else
                        enc++;
                        enc++;
 
 
#if DEBUG
#if DEBUG
  printf("ret=%x\n", ret);
  printf("ret=%x\n", ret);
#endif
#endif
  return ret;
  return ret;
}
}
 
 
int
int
or32_opcode_match (insn, encoding)
or32_opcode_match (insn, encoding)
     unsigned long insn;
     unsigned long insn;
     char *encoding;
     char *encoding;
{
{
  unsigned long ones, zeros;
  unsigned long ones, zeros;
 
 
#if DEBUG
#if DEBUG
  printf("or32_opcode_match: %.8lx\n", insn);
  printf("or32_opcode_match: %.8lx\n", insn);
#endif    
#endif    
  ones = or32_extract('1', encoding, insn);
  ones = or32_extract('1', encoding, insn);
  zeros = or32_extract('0', encoding, insn);
  zeros = or32_extract('0', encoding, insn);
 
 
#if DEBUG
#if DEBUG
  printf("ones: %x \n", ones);
  printf("ones: %x \n", ones);
  printf("zeros: %x \n", zeros);
  printf("zeros: %x \n", zeros);
#endif
#endif
  if ((insn & ones) != ones) {
  if ((insn & ones) != ones) {
#if DEBUG
#if DEBUG
    printf("ret1\n");
    printf("ret1\n");
#endif
#endif
    return 0;
    return 0;
  }
  }
 
 
  if ((~insn & zeros) != zeros) {
  if ((~insn & zeros) != zeros) {
#if DEBUG
#if DEBUG
    printf("ret2\n");
    printf("ret2\n");
#endif
#endif
    return 0;
    return 0;
  }
  }
 
 
#if DEBUG
#if DEBUG
  printf("ret3\n");
  printf("ret3\n");
#endif
#endif
  return 1;
  return 1;
}
}
 
 
 
 
/* Print register to INFO->STREAM. Used only by print_insn. */
/* Print register to INFO->STREAM. Used only by print_insn. */
 
 
static void
static void
or32_print_register (param_ch, encoding, insn, info)
or32_print_register (param_ch, encoding, insn, info)
     char param_ch;
     char param_ch;
     char *encoding;
     char *encoding;
     unsigned long insn;
     unsigned long insn;
     struct disassemble_info *info;
     struct disassemble_info *info;
{
{
  int regnum = or32_extract(param_ch, encoding, insn);
  int regnum = or32_extract(param_ch, encoding, insn);
 
 
#if DEBUG
#if DEBUG
  printf("or32_print_register: %c, %s, %x\n", param_ch, encoding, insn);
  printf("or32_print_register: %c, %s, %x\n", param_ch, encoding, insn);
#endif  
#endif  
  if (param_ch == 'A')
  if (param_ch == 'A')
    (*info->fprintf_func) (info->stream, "r%d", regnum);
    (*info->fprintf_func) (info->stream, "r%d", regnum);
  else if (param_ch == 'B')
  else if (param_ch == 'B')
                (*info->fprintf_func) (info->stream, "r%d", regnum);
                (*info->fprintf_func) (info->stream, "r%d", regnum);
  else if (param_ch == 'S')
  else if (param_ch == 'S')
                (*info->fprintf_func) (info->stream, "r%d", regnum);
                (*info->fprintf_func) (info->stream, "r%d", regnum);
        else if (regnum < 16)
        else if (regnum < 16)
                (*info->fprintf_func) (info->stream, "r%d", regnum);
                (*info->fprintf_func) (info->stream, "r%d", regnum);
        else if (regnum < 32)
        else if (regnum < 32)
                (*info->fprintf_func) (info->stream, "r%d", regnum-16);
                (*info->fprintf_func) (info->stream, "r%d", regnum-16);
  else
  else
                (*info->fprintf_func) (info->stream, "X%d", regnum);
                (*info->fprintf_func) (info->stream, "X%d", regnum);
}
}
 
 
/* Print immediate to INFO->STREAM. Used only by print_insn. */
/* Print immediate to INFO->STREAM. Used only by print_insn. */
 
 
static void
static void
or32_print_immediate (param_ch, encoding, insn, info)
or32_print_immediate (param_ch, encoding, insn, info)
     char param_ch;
     char param_ch;
     char *encoding;
     char *encoding;
     unsigned long insn;
     unsigned long insn;
     struct disassemble_info *info;
     struct disassemble_info *info;
{
{
  int imm = or32_extract(param_ch, encoding, insn);
  int imm = or32_extract(param_ch, encoding, insn);
 
 
  if (letter_signed(param_ch))
  if (letter_signed(param_ch))
    (*info->fprintf_func) (info->stream, "0x%x", imm);
    (*info->fprintf_func) (info->stream, "0x%x", imm);
/*    (*info->fprintf_func) (info->stream, "%d", imm); */
/*    (*info->fprintf_func) (info->stream, "%d", imm); */
  else
  else
    (*info->fprintf_func) (info->stream, "0x%x", imm);
    (*info->fprintf_func) (info->stream, "0x%x", imm);
}
}
 
 
/* Print one instruction from MEMADDR on INFO->STREAM.
/* Print one instruction from MEMADDR on INFO->STREAM.
   Return the size of the instruction (always 4 on or32).  */
   Return the size of the instruction (always 4 on or32).  */
 
 
static int
static int
print_insn (memaddr, info)
print_insn (memaddr, info)
     bfd_vma memaddr;
     bfd_vma memaddr;
     struct disassemble_info *info;
     struct disassemble_info *info;
{
{
  /* The raw instruction.  */
  /* The raw instruction.  */
  unsigned char insn_ch[4];
  unsigned char insn_ch[4];
 
 
  /* Address. Will be sign extened 27-bit */
  /* Address. Will be sign extened 27-bit */
  int addr;
  int addr;
 
 
  /* The four bytes of the instruction.  */
  /* The four bytes of the instruction.  */
  unsigned long insn;
  unsigned long insn;
 
 
  find_byte_func_type find_byte_func = (find_byte_func_type)info->private_data;
  find_byte_func_type find_byte_func = (find_byte_func_type)info->private_data;
 
 
  struct or32_opcode CONST * opcode;
  struct or32_opcode CONST * opcode;
 
 
  {
  {
    int status =
    int status =
      (*info->read_memory_func) (memaddr, (bfd_byte *) &insn_ch[0], 4, info);
      (*info->read_memory_func) (memaddr, (bfd_byte *) &insn_ch[0], 4, info);
    if (status != 0)
    if (status != 0)
      {
      {
        (*info->memory_error_func) (status, memaddr, info);
        (*info->memory_error_func) (status, memaddr, info);
        return -1;
        return -1;
      }
      }
  }
  }
 
 
  (*find_byte_func) (&insn_ch[0], &insn);
  (*find_byte_func) (&insn_ch[0], &insn);
 
 
  for (opcode = &or32_opcodes[0];
  for (opcode = &or32_opcodes[0];
       opcode < &or32_opcodes[num_opcodes];
       opcode < &or32_opcodes[num_opcodes];
       ++opcode)
       ++opcode)
    {
    {
      if (or32_opcode_match (insn, opcode->encoding))
      if (or32_opcode_match (insn, opcode->encoding))
        {
        {
          char *s;
          char *s;
 
 
          (*info->fprintf_func) (info->stream, "%s ", opcode->name);
          (*info->fprintf_func) (info->stream, "%s ", opcode->name);
          for (s = opcode->args; *s != '\0'; ++s)
          for (s = opcode->args; *s != '\0'; ++s)
            {
            {
              switch (*s)
              switch (*s)
                {
                {
                case '\0':
                case '\0':
                  return 4;
                  return 4;
 
 
                case 'r':
                case 'r':
                  or32_print_register(*++s, opcode->encoding, insn, info);
                  or32_print_register(*++s, opcode->encoding, insn, info);
                  break;
                  break;
 
 
                case 'X':
                case 'X':
                  addr = or32_extract ('X', opcode->encoding, insn) << 2;
                  addr = or32_extract ('X', opcode->encoding, insn) << 2;
 
 
                  /* Calulate the correct address.  XXX is this really correct ?? */
                  /* Calulate the correct address.  XXX is this really correct ?? */
                  addr = memaddr + EXTEND29(addr);
                  addr = memaddr + EXTEND29(addr);
 
 
                  (*info->print_address_func)
                  (*info->print_address_func)
                    (addr, info);
                    (addr, info);
                  break;
                  break;
 
 
                default:
                default:
                  if (strchr (opcode->encoding, *s))
                  if (strchr (opcode->encoding, *s))
                    or32_print_immediate (*s, opcode->encoding, insn, info);
                    or32_print_immediate (*s, opcode->encoding, insn, info);
                  else
                  else
                    (*info->fprintf_func) (info->stream, "%c", *s);
                    (*info->fprintf_func) (info->stream, "%c", *s);
                }
                }
            }
            }
 
 
          return 4;
          return 4;
        }
        }
    }
    }
 
 
  /* This used to be %8x for binutils.  */
  /* This used to be %8x for binutils.  */
  (*info->fprintf_func)
  (*info->fprintf_func)
    (info->stream, ".word 0x%08x", insn);
    (info->stream, ".word 0x%08x", insn);
  return 4;
  return 4;
}
}
 
 
/* Disassemble a big-endian or32 instruction.  */
/* Disassemble a big-endian or32 instruction.  */
int
int
print_insn_big_or32 (memaddr, info)
print_insn_big_or32 (memaddr, info)
     bfd_vma memaddr;
     bfd_vma memaddr;
     struct disassemble_info *info;
     struct disassemble_info *info;
{
{
  info->private_data = (PTR) find_bytes_big;
  info->private_data = (PTR) find_bytes_big;
  return print_insn (memaddr, info);
  return print_insn (memaddr, info);
}
}
 
 
/* Disassemble a little-endian or32 instruction.  */
/* Disassemble a little-endian or32 instruction.  */
int
int
print_insn_little_or32 (memaddr, info)
print_insn_little_or32 (memaddr, info)
     bfd_vma memaddr;
     bfd_vma memaddr;
     struct disassemble_info *info;
     struct disassemble_info *info;
{
{
  info->private_data = (PTR) find_bytes_little;
  info->private_data = (PTR) find_bytes_little;
  return print_insn (memaddr, info);
  return print_insn (memaddr, info);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.