1  /* Disassemble ft32 instructions.
       2     Copyright (C) 2013-2023 Free Software Foundation, Inc.
       3     Contributed by FTDI (support@ftdichip.com)
       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 program; if not, write to the Free Software
      19     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      20     MA 02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include <stdio.h>
      24  #define STATIC_TABLE
      25  #define DEFINE_TABLE
      26  
      27  #include "opcode/ft32.h"
      28  #include "disassemble.h"
      29  
      30  extern const ft32_opc_info_t ft32_opc_info[128];
      31  
      32  static fprintf_ftype fpr;
      33  static void *stream;
      34  
      35  static int
      36  sign_extend (int bit, int value)
      37  {
      38    int onebit = (1 << bit);
      39    return (value & (onebit - 1)) - (value & onebit);
      40  }
      41  
      42  static void
      43  ft32_opcode1 (unsigned int iword,
      44  	      struct disassemble_info *info)
      45  {
      46    const ft32_opc_info_t *oo;
      47  
      48    for (oo = ft32_opc_info; oo->name; oo++)
      49      if ((iword & oo->mask) == oo->bits)
      50        break;
      51  
      52    if (oo->name)
      53      {
      54        int f = oo->fields;
      55        int imm;
      56  
      57        fpr (stream, "%s", oo->name);
      58        if (oo->dw)
      59  	fpr (stream, ".%c ", "bsl"[(iword >> FT32_FLD_DW_BIT) & 3]);
      60        else
      61  	fpr (stream, " ");
      62  
      63        while (f)
      64  	{
      65  	  int lobit = f & -f;
      66  	  if (f & lobit)
      67  	    {
      68  	      switch (lobit)
      69  		{
      70  		case  FT32_FLD_CBCRCV:
      71  		  /* imm is {CB, CV}  */
      72  		  imm = ((iword >> FT32_FLD_CB_BIT) & ((1 << FT32_FLD_CB_SIZ) - 1)) << 4;
      73  		  imm |= ((iword >> FT32_FLD_CV_BIT) & ((1 << FT32_FLD_CV_SIZ) - 1));
      74  		  switch (imm)
      75  		    {
      76  		    case 0x00: fpr (stream, "nz");  break;
      77  		    case 0x01: fpr (stream, "z");   break;
      78  		    case 0x10: fpr (stream, "ae");  break;
      79  		    case 0x11: fpr (stream, "b");   break;
      80  		    case 0x20: fpr (stream, "no");  break;
      81  		    case 0x21: fpr (stream, "o");   break;
      82  		    case 0x30: fpr (stream, "ns");  break;
      83  		    case 0x31: fpr (stream, "s");   break;
      84  		    case 0x40: fpr (stream, "lt");  break;
      85  		    case 0x41: fpr (stream, "gte"); break;
      86  		    case 0x50: fpr (stream, "lte"); break;
      87  		    case 0x51: fpr (stream, "gt");  break;
      88  		    case 0x60: fpr (stream, "be");  break;
      89  		    case 0x61: fpr (stream, "a");   break;
      90  		    default:
      91  		      fpr (stream, "%d,$r30,%d", (imm >> 4), (imm & 1));
      92  		      break;
      93  		    }
      94  		  break;
      95  		case  FT32_FLD_CB:
      96  		  imm = (iword >> FT32_FLD_CB_BIT) & ((1 << FT32_FLD_CB_SIZ) - 1);
      97  		  fpr (stream, "%d", imm);
      98  		  break;
      99  		case  FT32_FLD_R_D:
     100  		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_D_BIT) & 0x1f);
     101  		  break;
     102  		case  FT32_FLD_CR:
     103  		  imm = (iword >> FT32_FLD_CR_BIT) & ((1 << FT32_FLD_CR_SIZ) - 1);
     104  		  fpr (stream, "$r%d", 28 + imm);
     105  		  break;
     106  		case  FT32_FLD_CV:
     107  		  imm = (iword >> FT32_FLD_CV_BIT) & ((1 << FT32_FLD_CV_SIZ) - 1);
     108  		  fpr (stream, "%d", imm);
     109  		  break;
     110  		case  FT32_FLD_R_1:
     111  		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_1_BIT) & 0x1f);
     112  		  break;
     113  		case  FT32_FLD_RIMM:
     114  		  imm = (iword >> FT32_FLD_RIMM_BIT) & ((1 << FT32_FLD_RIMM_SIZ) - 1);
     115  		  if (imm & 0x400)
     116  		    fpr (stream, "%d", sign_extend (9, imm));
     117  		  else
     118  		    fpr (stream, "$r%d", imm & 0x1f);
     119  		  break;
     120  		case  FT32_FLD_R_2:
     121  		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_2_BIT) & 0x1f);
     122  		  break;
     123  		case  FT32_FLD_K20:
     124  		  imm = iword & ((1 << FT32_FLD_K20_SIZ) - 1);
     125  		  fpr (stream, "%d", sign_extend (19, imm));
     126  		  break;
     127  		case  FT32_FLD_PA:
     128  		  imm = (iword & ((1 << FT32_FLD_PA_SIZ) - 1)) << 2;
     129  		  info->print_address_func ((bfd_vma) imm, info);
     130  		  break;
     131  		case  FT32_FLD_AA:
     132  		  imm = iword & ((1 << FT32_FLD_AA_SIZ) - 1);
     133  		  info->print_address_func ((1 << 23) | (bfd_vma) imm, info);
     134  		  break;
     135  		case  FT32_FLD_K16:
     136  		  imm = iword & ((1 << FT32_FLD_K16_SIZ) - 1);
     137  		  fpr (stream, "%d", imm);
     138  		  break;
     139  		case  FT32_FLD_K15:
     140  		  imm = iword & ((1 << FT32_FLD_K15_SIZ) - 1);
     141  		  fpr (stream, "%d", sign_extend (14, imm));
     142  		  break;
     143  		case  FT32_FLD_R_D_POST:
     144  		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_D_BIT) & 0x1f);
     145  		  break;
     146  		case  FT32_FLD_R_1_POST:
     147  		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_1_BIT) & 0x1f);
     148  		  break;
     149  		default:
     150  		  break;
     151  		}
     152  	      f &= ~lobit;
     153  	      if (f)
     154  		fpr (stream, ",");
     155  	    }
     156  	}
     157      }
     158    else
     159      fpr (stream, "!");
     160  }
     161  
     162  static void
     163  ft32_opcode (bfd_vma addr ATTRIBUTE_UNUSED,
     164  	     unsigned int iword,
     165  	     struct disassemble_info *info)
     166  {
     167    unsigned int sc[2];
     168    if (ft32_decode_shortcode ((unsigned int) addr, iword, sc))
     169      {
     170        ft32_opcode1 (sc[0], info);
     171        fpr (stream, " ; ");
     172        ft32_opcode1 (sc[1], info);
     173      }
     174    else
     175      ft32_opcode1 (iword, info);
     176  }
     177  
     178  int
     179  print_insn_ft32 (bfd_vma addr, struct disassemble_info *info)
     180  {
     181    int status;
     182    stream = info->stream;
     183    bfd_byte buffer[4];
     184    unsigned int iword;
     185  
     186    fpr = info->fprintf_func;
     187  
     188    if ((status = info->read_memory_func (addr, buffer, 4, info)))
     189      goto fail;
     190  
     191    iword = bfd_getl32 (buffer);
     192  
     193    fpr (stream, "%08x ", iword);
     194  
     195    ft32_opcode (addr, iword, info);
     196  
     197    return 4;
     198  
     199   fail:
     200    info->memory_error_func (status, addr, info);
     201    return -1;
     202  }