[BACK]Return to microblaze-dis.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / gpl3 / binutils.old / dist / opcodes

Annotation of src/external/gpl3/binutils.old/dist/opcodes/microblaze-dis.c, Revision 1.1

1.1     ! christos    1: /* Disassemble Xilinx microblaze instructions.
        !             2:
        !             3:    Copyright 2009, 2012 Free Software Foundation, Inc.
        !             4:
        !             5:    This file is part of the GNU opcodes library.
        !             6:
        !             7:    This library is free software; you can redistribute it and/or modify
        !             8:    it under the terms of the GNU General Public License as published by
        !             9:    the Free Software Foundation; either version 3, or (at your option)
        !            10:    any later version.
        !            11:
        !            12:    It is distributed in the hope that it will be useful, but WITHOUT
        !            13:    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
        !            15:    License for more details.
        !            16:
        !            17:    You should have received a copy of the GNU General Public License
        !            18:    along with this file; see the file COPYING.  If not, write to the
        !            19:    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
        !            20:    MA 02110-1301, USA.  */
        !            21:
        !            22:
        !            23: #include "sysdep.h"
        !            24: #define STATIC_TABLE
        !            25: #define DEFINE_TABLE
        !            26:
        !            27: #include "dis-asm.h"
        !            28: #include <strings.h>
        !            29: #include "microblaze-opc.h"
        !            30: #include "microblaze-dis.h"
        !            31:
        !            32: #define get_field_rd(instr)        get_field (instr, RD_MASK, RD_LOW)
        !            33: #define get_field_r1(instr)        get_field (instr, RA_MASK, RA_LOW)
        !            34: #define get_field_r2(instr)        get_field (instr, RB_MASK, RB_LOW)
        !            35: #define get_int_field_imm(instr)   ((instr & IMM_MASK) >> IMM_LOW)
        !            36: #define get_int_field_r1(instr)    ((instr & RA_MASK) >> RA_LOW)
        !            37:
        !            38:
        !            39:
        !            40: static char *
        !            41: get_field (long instr, long mask, unsigned short low)
        !            42: {
        !            43:   char tmpstr[25];
        !            44:
        !            45:   sprintf (tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
        !            46:   return (strdup (tmpstr));
        !            47: }
        !            48:
        !            49: static char *
        !            50: get_field_imm (long instr)
        !            51: {
        !            52:   char tmpstr[25];
        !            53:
        !            54:   sprintf (tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
        !            55:   return (strdup (tmpstr));
        !            56: }
        !            57:
        !            58: static char *
        !            59: get_field_imm5 (long instr)
        !            60: {
        !            61:   char tmpstr[25];
        !            62:
        !            63:   sprintf (tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
        !            64:   return (strdup (tmpstr));
        !            65: }
        !            66:
        !            67: static char *
        !            68: get_field_rfsl (long instr)
        !            69: {
        !            70:   char tmpstr[25];
        !            71:
        !            72:   sprintf (tmpstr, "%s%d", fsl_register_prefix,
        !            73:           (short)((instr & RFSL_MASK) >> IMM_LOW));
        !            74:   return (strdup (tmpstr));
        !            75: }
        !            76:
        !            77: static char *
        !            78: get_field_imm15 (long instr)
        !            79: {
        !            80:   char tmpstr[25];
        !            81:
        !            82:   sprintf (tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
        !            83:   return (strdup (tmpstr));
        !            84: }
        !            85:
        !            86: static char *
        !            87: get_field_special (long instr, struct op_code_struct * op)
        !            88: {
        !            89:   char tmpstr[25];
        !            90:   char spr[6];
        !            91:
        !            92:   switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
        !            93:     {
        !            94:     case REG_MSR_MASK :
        !            95:       strcpy (spr, "msr");
        !            96:       break;
        !            97:     case REG_PC_MASK :
        !            98:       strcpy (spr, "pc");
        !            99:       break;
        !           100:     case REG_EAR_MASK :
        !           101:       strcpy (spr, "ear");
        !           102:       break;
        !           103:     case REG_ESR_MASK :
        !           104:       strcpy (spr, "esr");
        !           105:       break;
        !           106:     case REG_FSR_MASK :
        !           107:       strcpy (spr, "fsr");
        !           108:       break;
        !           109:     case REG_BTR_MASK :
        !           110:       strcpy (spr, "btr");
        !           111:       break;
        !           112:     case REG_EDR_MASK :
        !           113:       strcpy (spr, "edr");
        !           114:       break;
        !           115:     case REG_PID_MASK :
        !           116:       strcpy (spr, "pid");
        !           117:       break;
        !           118:     case REG_ZPR_MASK :
        !           119:       strcpy (spr, "zpr");
        !           120:       break;
        !           121:     case REG_TLBX_MASK :
        !           122:       strcpy (spr, "tlbx");
        !           123:       break;
        !           124:     case REG_TLBLO_MASK :
        !           125:       strcpy (spr, "tlblo");
        !           126:       break;
        !           127:     case REG_TLBHI_MASK :
        !           128:       strcpy (spr, "tlbhi");
        !           129:       break;
        !           130:     case REG_TLBSX_MASK :
        !           131:       strcpy (spr, "tlbsx");
        !           132:       break;
        !           133:     default :
        !           134:       if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
        !           135:           == REG_PVR_MASK)
        !           136:         {
        !           137:          sprintf (tmpstr, "%spvr%d", register_prefix,
        !           138:                   (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
        !           139:                                     ^ op->immval_mask) ^ REG_PVR_MASK);
        !           140:          return (strdup (tmpstr));
        !           141:         }
        !           142:       else
        !           143:         strcpy (spr, "pc");
        !           144:       break;
        !           145:     }
        !           146:
        !           147:    sprintf (tmpstr, "%s%s", register_prefix, spr);
        !           148:    return (strdup (tmpstr));
        !           149: }
        !           150:
        !           151: static unsigned long
        !           152: read_insn_microblaze (bfd_vma memaddr,
        !           153:                      struct disassemble_info *info,
        !           154:                      struct op_code_struct **opr)
        !           155: {
        !           156:   unsigned char       ibytes[4];
        !           157:   int                 status;
        !           158:   struct op_code_struct * op;
        !           159:   unsigned long inst;
        !           160:
        !           161:   status = info->read_memory_func (memaddr, ibytes, 4, info);
        !           162:
        !           163:   if (status != 0)
        !           164:     {
        !           165:       info->memory_error_func (status, memaddr, info);
        !           166:       return 0;
        !           167:     }
        !           168:
        !           169:   if (info->endian == BFD_ENDIAN_BIG)
        !           170:     inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
        !           171:   else if (info->endian == BFD_ENDIAN_LITTLE)
        !           172:     inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
        !           173:   else
        !           174:     abort ();
        !           175:
        !           176:   /* Just a linear search of the table.  */
        !           177:   for (op = opcodes; op->name != 0; op ++)
        !           178:     if (op->bit_sequence == (inst & op->opcode_mask))
        !           179:       break;
        !           180:
        !           181:   *opr = op;
        !           182:   return inst;
        !           183: }
        !           184:
        !           185:
        !           186: int
        !           187: print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
        !           188: {
        !           189:   fprintf_ftype       print_func = info->fprintf_func;
        !           190:   void *              stream = info->stream;
        !           191:   unsigned long       inst, prev_inst;
        !           192:   struct op_code_struct * op, *pop;
        !           193:   int                 immval = 0;
        !           194:   bfd_boolean         immfound = FALSE;
        !           195:   static bfd_vma      prev_insn_addr = -1; /* Init the prev insn addr.  */
        !           196:   static int          prev_insn_vma = -1;  /* Init the prev insn vma.  */
        !           197:   int                 curr_insn_vma = info->buffer_vma;
        !           198:
        !           199:   info->bytes_per_chunk = 4;
        !           200:
        !           201:   inst = read_insn_microblaze (memaddr, info, &op);
        !           202:   if (inst == 0)
        !           203:     return -1;
        !           204:
        !           205:   if (prev_insn_vma == curr_insn_vma)
        !           206:     {
        !           207:       if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
        !           208:         {
        !           209:           prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
        !           210:          if (prev_inst == 0)
        !           211:            return -1;
        !           212:          if (pop->instr == imm)
        !           213:            {
        !           214:              immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
        !           215:              immfound = TRUE;
        !           216:            }
        !           217:          else
        !           218:            {
        !           219:              immval = 0;
        !           220:              immfound = FALSE;
        !           221:            }
        !           222:        }
        !           223:     }
        !           224:
        !           225:   /* Make curr insn as prev insn.  */
        !           226:   prev_insn_addr = memaddr;
        !           227:   prev_insn_vma = curr_insn_vma;
        !           228:
        !           229:   if (op->name == NULL)
        !           230:     print_func (stream, ".short 0x%04x", (unsigned int) inst);
        !           231:   else
        !           232:     {
        !           233:       print_func (stream, "%s", op->name);
        !           234:
        !           235:       switch (op->inst_type)
        !           236:        {
        !           237:         case INST_TYPE_RD_R1_R2:
        !           238:           print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
        !           239:                   get_field_r1(inst), get_field_r2 (inst));
        !           240:           break;
        !           241:         case INST_TYPE_RD_R1_IMM:
        !           242:          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
        !           243:                   get_field_r1(inst), get_field_imm (inst));
        !           244:          if (info->print_address_func && get_int_field_r1 (inst) == 0
        !           245:              && info->symbol_at_address_func)
        !           246:            {
        !           247:              if (immfound)
        !           248:                immval |= (get_int_field_imm (inst) & 0x0000ffff);
        !           249:              else
        !           250:                {
        !           251:                  immval = get_int_field_imm (inst);
        !           252:                  if (immval & 0x8000)
        !           253:                    immval |= 0xFFFF0000;
        !           254:                }
        !           255:              if (immval > 0 && info->symbol_at_address_func (immval, info))
        !           256:                {
        !           257:                  print_func (stream, "\t// ");
        !           258:                  info->print_address_func (immval, info);
        !           259:                }
        !           260:            }
        !           261:          break;
        !           262:        case INST_TYPE_RD_R1_IMM5:
        !           263:          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
        !           264:                   get_field_r1(inst), get_field_imm5 (inst));
        !           265:          break;
        !           266:        case INST_TYPE_RD_RFSL:
        !           267:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_rfsl (inst));
        !           268:          break;
        !           269:        case INST_TYPE_R1_RFSL:
        !           270:          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_rfsl (inst));
        !           271:          break;
        !           272:        case INST_TYPE_RD_SPECIAL:
        !           273:          print_func (stream, "\t%s, %s", get_field_rd (inst),
        !           274:                   get_field_special (inst, op));
        !           275:          break;
        !           276:        case INST_TYPE_SPECIAL_R1:
        !           277:          print_func (stream, "\t%s, %s", get_field_special (inst, op),
        !           278:                   get_field_r1(inst));
        !           279:          break;
        !           280:        case INST_TYPE_RD_R1:
        !           281:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r1 (inst));
        !           282:          break;
        !           283:        case INST_TYPE_R1_R2:
        !           284:          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
        !           285:          break;
        !           286:        case INST_TYPE_R1_IMM:
        !           287:          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_imm (inst));
        !           288:          /* The non-pc relative instructions are returns, which shouldn't
        !           289:             have a label printed.  */
        !           290:          if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
        !           291:              && info->symbol_at_address_func)
        !           292:            {
        !           293:              if (immfound)
        !           294:                immval |= (get_int_field_imm (inst) & 0x0000ffff);
        !           295:              else
        !           296:                {
        !           297:                  immval = get_int_field_imm (inst);
        !           298:                  if (immval & 0x8000)
        !           299:                    immval |= 0xFFFF0000;
        !           300:                }
        !           301:              immval += memaddr;
        !           302:              if (immval > 0 && info->symbol_at_address_func (immval, info))
        !           303:                {
        !           304:                  print_func (stream, "\t// ");
        !           305:                  info->print_address_func (immval, info);
        !           306:                }
        !           307:              else
        !           308:                {
        !           309:                  print_func (stream, "\t\t// ");
        !           310:                  print_func (stream, "%x", immval);
        !           311:                }
        !           312:            }
        !           313:          break;
        !           314:         case INST_TYPE_RD_IMM:
        !           315:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm (inst));
        !           316:          if (info->print_address_func && info->symbol_at_address_func)
        !           317:            {
        !           318:            if (immfound)
        !           319:              immval |= (get_int_field_imm (inst) & 0x0000ffff);
        !           320:            else
        !           321:              {
        !           322:                immval = get_int_field_imm (inst);
        !           323:                if (immval & 0x8000)
        !           324:                  immval |= 0xFFFF0000;
        !           325:              }
        !           326:            if (op->inst_offset_type == INST_PC_OFFSET)
        !           327:              immval += (int) memaddr;
        !           328:            if (info->symbol_at_address_func (immval, info))
        !           329:              {
        !           330:                print_func (stream, "\t// ");
        !           331:                info->print_address_func (immval, info);
        !           332:              }
        !           333:            }
        !           334:          break;
        !           335:         case INST_TYPE_IMM:
        !           336:          print_func (stream, "\t%s", get_field_imm (inst));
        !           337:          if (info->print_address_func && info->symbol_at_address_func
        !           338:              && op->instr != imm)
        !           339:            {
        !           340:              if (immfound)
        !           341:                immval |= (get_int_field_imm (inst) & 0x0000ffff);
        !           342:              else
        !           343:                {
        !           344:                  immval = get_int_field_imm (inst);
        !           345:                  if (immval & 0x8000)
        !           346:                    immval |= 0xFFFF0000;
        !           347:                }
        !           348:              if (op->inst_offset_type == INST_PC_OFFSET)
        !           349:                immval += (int) memaddr;
        !           350:              if (immval > 0 && info->symbol_at_address_func (immval, info))
        !           351:                {
        !           352:                  print_func (stream, "\t// ");
        !           353:                  info->print_address_func (immval, info);
        !           354:                }
        !           355:              else if (op->inst_offset_type == INST_PC_OFFSET)
        !           356:                {
        !           357:                  print_func (stream, "\t\t// ");
        !           358:                  print_func (stream, "%x", immval);
        !           359:                }
        !           360:            }
        !           361:          break;
        !           362:         case INST_TYPE_RD_R2:
        !           363:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
        !           364:          break;
        !           365:        case INST_TYPE_R2:
        !           366:          print_func (stream, "\t%s", get_field_r2 (inst));
        !           367:          break;
        !           368:        case INST_TYPE_R1:
        !           369:          print_func (stream, "\t%s", get_field_r1 (inst));
        !           370:          break;
        !           371:        case INST_TYPE_RD_R1_SPECIAL:
        !           372:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
        !           373:          break;
        !           374:        case INST_TYPE_RD_IMM15:
        !           375:          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm15 (inst));
        !           376:          break;
        !           377:        /* For tuqula instruction */
        !           378:        case INST_TYPE_RD:
        !           379:          print_func (stream, "\t%s", get_field_rd (inst));
        !           380:          break;
        !           381:        case INST_TYPE_RFSL:
        !           382:          print_func (stream, "\t%s", get_field_rfsl (inst));
        !           383:          break;
        !           384:        default:
        !           385:          /* If the disassembler lags the instruction set.  */
        !           386:          print_func (stream, "\tundecoded operands, inst is 0x%04x", (unsigned int) inst);
        !           387:          break;
        !           388:        }
        !           389:     }
        !           390:
        !           391:   /* Say how many bytes we consumed.  */
        !           392:   return 4;
        !           393: }
        !           394:
        !           395: enum microblaze_instr
        !           396: get_insn_microblaze (long inst,
        !           397:                     bfd_boolean *isunsignedimm,
        !           398:                     enum microblaze_instr_type *insn_type,
        !           399:                     short *delay_slots)
        !           400: {
        !           401:   struct op_code_struct * op;
        !           402:   *isunsignedimm = FALSE;
        !           403:
        !           404:   /* Just a linear search of the table.  */
        !           405:   for (op = opcodes; op->name != 0; op ++)
        !           406:     if (op->bit_sequence == (inst & op->opcode_mask))
        !           407:       break;
        !           408:
        !           409:   if (op->name == 0)
        !           410:     return invalid_inst;
        !           411:   else
        !           412:     {
        !           413:       *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
        !           414:       *insn_type = op->instr_type;
        !           415:       *delay_slots = op->delay_slots;
        !           416:       return op->instr;
        !           417:     }
        !           418: }
        !           419:
        !           420: enum microblaze_instr
        !           421: microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
        !           422: {
        !           423:   enum microblaze_instr op;
        !           424:   bfd_boolean t1;
        !           425:   enum microblaze_instr_type t2;
        !           426:   short t3;
        !           427:
        !           428:   op = get_insn_microblaze (insn, &t1, &t2, &t3);
        !           429:   *rd = (insn & RD_MASK) >> RD_LOW;
        !           430:   *ra = (insn & RA_MASK) >> RA_LOW;
        !           431:   *rb = (insn & RB_MASK) >> RB_LOW;
        !           432:   t3 = (insn & IMM_MASK) >> IMM_LOW;
        !           433:   *immed = (int) t3;
        !           434:   return (op);
        !           435: }
        !           436:
        !           437: unsigned long
        !           438: microblaze_get_target_address (long inst, bfd_boolean immfound, int immval,
        !           439:                               long pcval, long r1val, long r2val,
        !           440:                               bfd_boolean *targetvalid,
        !           441:                               bfd_boolean *unconditionalbranch)
        !           442: {
        !           443:   struct op_code_struct * op;
        !           444:   long targetaddr = 0;
        !           445:
        !           446:   *unconditionalbranch = FALSE;
        !           447:   /* Just a linear search of the table.  */
        !           448:   for (op = opcodes; op->name != 0; op ++)
        !           449:     if (op->bit_sequence == (inst & op->opcode_mask))
        !           450:       break;
        !           451:
        !           452:   if (op->name == 0)
        !           453:     {
        !           454:       *targetvalid = FALSE;
        !           455:     }
        !           456:   else if (op->instr_type == branch_inst)
        !           457:     {
        !           458:       switch (op->inst_type)
        !           459:        {
        !           460:         case INST_TYPE_R2:
        !           461:           *unconditionalbranch = TRUE;
        !           462:         /* Fall through.  */
        !           463:         case INST_TYPE_RD_R2:
        !           464:         case INST_TYPE_R1_R2:
        !           465:           targetaddr = r2val;
        !           466:           *targetvalid = TRUE;
        !           467:           if (op->inst_offset_type == INST_PC_OFFSET)
        !           468:            targetaddr += pcval;
        !           469:           break;
        !           470:         case INST_TYPE_IMM:
        !           471:           *unconditionalbranch = TRUE;
        !           472:         /* Fall through.  */
        !           473:         case INST_TYPE_RD_IMM:
        !           474:         case INST_TYPE_R1_IMM:
        !           475:           if (immfound)
        !           476:            {
        !           477:              targetaddr = (immval << 16) & 0xffff0000;
        !           478:              targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
        !           479:            }
        !           480:          else
        !           481:            {
        !           482:              targetaddr = get_int_field_imm (inst);
        !           483:              if (targetaddr & 0x8000)
        !           484:                targetaddr |= 0xFFFF0000;
        !           485:             }
        !           486:           if (op->inst_offset_type == INST_PC_OFFSET)
        !           487:            targetaddr += pcval;
        !           488:           *targetvalid = TRUE;
        !           489:           break;
        !           490:        default:
        !           491:          *targetvalid = FALSE;
        !           492:          break;
        !           493:         }
        !           494:     }
        !           495:   else if (op->instr_type == return_inst)
        !           496:     {
        !           497:       if (immfound)
        !           498:        {
        !           499:          targetaddr = (immval << 16) & 0xffff0000;
        !           500:          targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
        !           501:        }
        !           502:       else
        !           503:        {
        !           504:          targetaddr = get_int_field_imm (inst);
        !           505:          if (targetaddr & 0x8000)
        !           506:            targetaddr |= 0xFFFF0000;
        !           507:        }
        !           508:       targetaddr += r1val;
        !           509:       *targetvalid = TRUE;
        !           510:     }
        !           511:   else
        !           512:     *targetvalid = FALSE;
        !           513:   return targetaddr;
        !           514: }

CVSweb <webmaster@jp.NetBSD.org>