1214571Sdim/* Disassembler code for CR16. 2214571Sdim Copyright 2007 Free Software Foundation, Inc. 3214571Sdim Contributed by M R Swami Reddy (MR.Swami.Reddy@nsc.com). 4214571Sdim 5214571Sdim This file is part of GAS, GDB and the GNU binutils. 6214571Sdim 7214571Sdim This program is free software; you can redistribute it and/or modify it under 8214571Sdim the terms of the GNU General Public License as published by the Free 9214571Sdim Software Foundation; either version 2, or (at your option) 10214571Sdim any later version. 11214571Sdim 12214571Sdim This program is distributed in the hope that it will be useful, but WITHOUT 13214571Sdim ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14214571Sdim FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15214571Sdim more details. 16214571Sdim 17214571Sdim You should have received a copy of the GNU General Public License 18214571Sdim along with this program; if not, write to the Free Software Foundation, 19214571Sdim Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 20214571Sdim 21214571Sdim#include "dis-asm.h" 22214571Sdim#include "sysdep.h" 23214571Sdim#include "opcode/cr16.h" 24214571Sdim#include "libiberty.h" 25214571Sdim 26214571Sdim/* String to print when opcode was not matched. */ 27214571Sdim#define ILLEGAL "illegal" 28214571Sdim /* Escape to 16-bit immediate. */ 29214571Sdim#define ESCAPE_16_BIT 0xB 30214571Sdim 31214571Sdim/* Extract 'n_bits' from 'a' starting from offset 'offs'. */ 32214571Sdim#define EXTRACT(a, offs, n_bits) \ 33214571Sdim (n_bits == 32 ? (((a) >> (offs)) & 0xffffffffL) \ 34214571Sdim : (((a) >> (offs)) & ((1 << (n_bits)) -1))) 35214571Sdim 36214571Sdim/* Set Bit Mask - a mask to set all bits starting from offset 'offs'. */ 37214571Sdim#define SBM(offs) ((((1 << (32 - offs)) -1) << (offs))) 38214571Sdim 39214571Sdimtypedef unsigned long dwordU; 40214571Sdimtypedef unsigned short wordU; 41214571Sdim 42214571Sdimtypedef struct 43214571Sdim{ 44214571Sdim dwordU val; 45214571Sdim int nbits; 46214571Sdim} parameter; 47214571Sdim 48214571Sdim/* Structure to map valid 'cinv' instruction options. */ 49214571Sdim 50214571Sdimtypedef struct 51214571Sdim { 52214571Sdim /* Cinv printed string. */ 53214571Sdim char *istr; 54214571Sdim /* Value corresponding to the string. */ 55214571Sdim char *ostr; 56214571Sdim } 57214571Sdimcinv_entry; 58214571Sdim 59214571Sdim/* CR16 'cinv' options mapping. */ 60214571Sdimconst cinv_entry cr16_cinvs[] = 61214571Sdim{ 62214571Sdim {"cinv[i]", "cinv [i]"}, 63214571Sdim {"cinv[i,u]", "cinv [i,u]"}, 64214571Sdim {"cinv[d]", "cinv [d]"}, 65214571Sdim {"cinv[d,u]", "cinv [d,u]"}, 66214571Sdim {"cinv[d,i]", "cinv [d,i]"}, 67214571Sdim {"cinv[d,i,u]", "cinv [d,i,u]"} 68214571Sdim}; 69214571Sdim 70214571Sdim/* Number of valid 'cinv' instruction options. */ 71214571Sdimstatic int NUMCINVS = ARRAY_SIZE (cr16_cinvs); 72214571Sdim 73214571Sdim/* Enum to distinguish different registers argument types. */ 74214571Sdimtypedef enum REG_ARG_TYPE 75214571Sdim { 76214571Sdim /* General purpose register (r<N>). */ 77214571Sdim REG_ARG = 0, 78214571Sdim /*Processor register */ 79214571Sdim P_ARG, 80214571Sdim } 81214571SdimREG_ARG_TYPE; 82214571Sdim 83214571Sdim/* Current opcode table entry we're disassembling. */ 84214571Sdimconst inst *instruction; 85214571Sdim/* Current instruction we're disassembling. */ 86214571Sdimins currInsn; 87214571Sdim/* The current instruction is read into 3 consecutive words. */ 88214571SdimwordU words[3]; 89214571Sdim/* Contains all words in appropriate order. */ 90214571SdimULONGLONG allWords; 91214571Sdim/* Holds the current processed argument number. */ 92214571Sdimint processing_argument_number; 93214571Sdim/* Nonzero means a IMM4 instruction. */ 94214571Sdimint imm4flag; 95214571Sdim/* Nonzero means the instruction's original size is 96214571Sdim incremented (escape sequence is used). */ 97214571Sdimint size_changed; 98214571Sdim 99214571Sdim 100214571Sdim/* Print the constant expression length. */ 101214571Sdim 102214571Sdimstatic char * 103214571Sdimprint_exp_len (int size) 104214571Sdim{ 105214571Sdim switch (size) 106214571Sdim { 107214571Sdim case 4: 108214571Sdim case 5: 109214571Sdim case 6: 110214571Sdim case 8: 111214571Sdim case 14: 112214571Sdim case 16: 113214571Sdim return ":s"; 114214571Sdim case 20: 115214571Sdim case 24: 116214571Sdim case 32: 117214571Sdim return ":m"; 118214571Sdim case 48: 119214571Sdim return ":l"; 120214571Sdim default: 121214571Sdim return ""; 122214571Sdim } 123214571Sdim} 124214571Sdim 125214571Sdim 126214571Sdim/* Retrieve the number of operands for the current assembled instruction. */ 127214571Sdim 128214571Sdimstatic int 129214571Sdimget_number_of_operands (void) 130214571Sdim{ 131214571Sdim int i; 132214571Sdim 133214571Sdim for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++) 134214571Sdim ; 135214571Sdim 136214571Sdim return i; 137214571Sdim} 138214571Sdim 139214571Sdim/* Return the bit size for a given operand. */ 140214571Sdim 141214571Sdimstatic int 142214571Sdimgetbits (operand_type op) 143214571Sdim{ 144214571Sdim if (op < MAX_OPRD) 145214571Sdim return cr16_optab[op].bit_size; 146214571Sdim 147214571Sdim return 0; 148214571Sdim} 149214571Sdim 150214571Sdim/* Return the argument type of a given operand. */ 151214571Sdim 152214571Sdimstatic argtype 153214571Sdimgetargtype (operand_type op) 154214571Sdim{ 155214571Sdim if (op < MAX_OPRD) 156214571Sdim return cr16_optab[op].arg_type; 157214571Sdim 158214571Sdim return nullargs; 159214571Sdim} 160214571Sdim 161214571Sdim/* Given a 'CC' instruction constant operand, return its corresponding 162214571Sdim string. This routine is used when disassembling the 'CC' instruction. */ 163214571Sdim 164214571Sdimstatic char * 165214571Sdimgetccstring (unsigned cc) 166214571Sdim{ 167214571Sdim return (char *) cr16_b_cond_tab[cc]; 168214571Sdim} 169214571Sdim 170214571Sdim 171214571Sdim/* Given a 'cinv' instruction constant operand, return its corresponding 172214571Sdim string. This routine is used when disassembling the 'cinv' instruction. */ 173214571Sdim 174214571Sdimstatic char * 175214571Sdimgetcinvstring (char *str) 176214571Sdim{ 177214571Sdim const cinv_entry *cinv; 178214571Sdim 179214571Sdim for (cinv = cr16_cinvs; cinv < (cr16_cinvs + NUMCINVS); cinv++) 180214571Sdim if (strcmp (cinv->istr, str) == 0) 181214571Sdim return cinv->ostr; 182214571Sdim 183214571Sdim return ILLEGAL; 184214571Sdim} 185214571Sdim 186214571Sdim/* Given the trap index in dispatch table, return its name. 187214571Sdim This routine is used when disassembling the 'excp' instruction. */ 188214571Sdim 189214571Sdimstatic char * 190214571Sdimgettrapstring (unsigned int index) 191214571Sdim{ 192214571Sdim const trap_entry *trap; 193214571Sdim 194214571Sdim for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++) 195214571Sdim if (trap->entry == index) 196214571Sdim return trap->name; 197214571Sdim 198214571Sdim return ILLEGAL; 199214571Sdim} 200214571Sdim 201214571Sdim/* Given a register enum value, retrieve its name. */ 202214571Sdim 203214571Sdimstatic char * 204214571Sdimgetregname (reg r) 205214571Sdim{ 206214571Sdim const reg_entry *reg = cr16_regtab + r; 207214571Sdim 208214571Sdim if (reg->type != CR16_R_REGTYPE) 209214571Sdim return ILLEGAL; 210214571Sdim 211214571Sdim return reg->name; 212214571Sdim} 213214571Sdim 214214571Sdim/* Given a register pair enum value, retrieve its name. */ 215214571Sdim 216214571Sdimstatic char * 217214571Sdimgetregpname (reg r) 218214571Sdim{ 219214571Sdim const reg_entry *reg = cr16_regptab + r; 220214571Sdim 221214571Sdim if (reg->type != CR16_RP_REGTYPE) 222214571Sdim return ILLEGAL; 223214571Sdim 224214571Sdim return reg->name; 225214571Sdim} 226214571Sdim 227214571Sdim/* Given a index register pair enum value, retrieve its name. */ 228214571Sdim 229214571Sdimstatic char * 230214571Sdimgetidxregpname (reg r) 231214571Sdim{ 232214571Sdim const reg_entry *reg; 233214571Sdim 234214571Sdim switch (r) 235214571Sdim { 236214571Sdim case 0: r = 0; break; 237214571Sdim case 1: r = 2; break; 238214571Sdim case 2: r = 4; break; 239214571Sdim case 3: r = 6; break; 240214571Sdim case 4: r = 8; break; 241214571Sdim case 5: r = 10; break; 242214571Sdim case 6: r = 3; break; 243214571Sdim case 7: r = 5; break; 244214571Sdim default: 245214571Sdim break; 246214571Sdim } 247214571Sdim 248214571Sdim reg = cr16_regptab + r; 249214571Sdim 250214571Sdim if (reg->type != CR16_RP_REGTYPE) 251214571Sdim return ILLEGAL; 252214571Sdim 253214571Sdim return reg->name; 254214571Sdim} 255214571Sdim 256214571Sdim/* Getting a processor register name. */ 257214571Sdim 258214571Sdimstatic char * 259214571Sdimgetprocregname (int index) 260214571Sdim{ 261214571Sdim const reg_entry *r; 262214571Sdim 263214571Sdim for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++) 264214571Sdim if (r->image == index) 265214571Sdim return r->name; 266214571Sdim 267214571Sdim return "ILLEGAL REGISTER"; 268214571Sdim} 269214571Sdim 270214571Sdim/* Getting a processor register name - 32 bit size. */ 271214571Sdim 272214571Sdimstatic char * 273214571Sdimgetprocpregname (int index) 274214571Sdim{ 275214571Sdim const reg_entry *r; 276214571Sdim 277214571Sdim for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++) 278214571Sdim if (r->image == index) 279214571Sdim return r->name; 280214571Sdim 281214571Sdim return "ILLEGAL REGISTER"; 282214571Sdim} 283214571Sdim 284214571Sdim/* START and END are relating 'allWords' struct, which is 48 bits size. 285214571Sdim 286214571Sdim START|--------|END 287214571Sdim +---------+---------+---------+---------+ 288214571Sdim | | V | A | L | 289214571Sdim +---------+---------+---------+---------+ 290214571Sdim 0 16 32 48 291214571Sdim words [0] [1] [2] */ 292214571Sdim 293214571Sdimstatic parameter 294214571Sdimmakelongparameter (ULONGLONG val, int start, int end) 295214571Sdim{ 296214571Sdim parameter p; 297214571Sdim 298214571Sdim p.val = (dwordU) EXTRACT (val, 48 - end, end - start); 299214571Sdim p.nbits = end - start; 300214571Sdim return p; 301214571Sdim} 302214571Sdim 303214571Sdim/* Build a mask of the instruction's 'constant' opcode, 304214571Sdim based on the instruction's printing flags. */ 305214571Sdim 306214571Sdimstatic unsigned long 307214571Sdimbuild_mask (void) 308214571Sdim{ 309214571Sdim unsigned long mask = SBM (instruction->match_bits); 310214571Sdim return mask; 311214571Sdim} 312214571Sdim 313214571Sdim/* Search for a matching opcode. Return 1 for success, 0 for failure. */ 314214571Sdim 315214571Sdimstatic int 316214571Sdimmatch_opcode (void) 317214571Sdim{ 318214571Sdim unsigned long mask; 319214571Sdim /* The instruction 'constant' opcode doewsn't exceed 32 bits. */ 320214571Sdim unsigned long doubleWord = words[1] + (words[0] << 16); 321214571Sdim 322214571Sdim /* Start searching from end of instruction table. */ 323214571Sdim instruction = &cr16_instruction[NUMOPCODES - 2]; 324214571Sdim 325214571Sdim /* Loop over instruction table until a full match is found. */ 326214571Sdim while (instruction >= cr16_instruction) 327214571Sdim { 328214571Sdim mask = build_mask (); 329214571Sdim if ((doubleWord & mask) == BIN (instruction->match, 330214571Sdim instruction->match_bits)) 331214571Sdim return 1; 332214571Sdim else 333214571Sdim instruction--; 334214571Sdim } 335214571Sdim return 0; 336214571Sdim} 337214571Sdim 338214571Sdim/* Set the proper parameter value for different type of arguments. */ 339214571Sdim 340214571Sdimstatic void 341214571Sdimmake_argument (argument * a, int start_bits) 342214571Sdim{ 343214571Sdim int inst_bit_size; 344214571Sdim parameter p; 345214571Sdim 346214571Sdim if ((instruction->size == 3) && a->size >= 16) 347214571Sdim inst_bit_size = 48; 348214571Sdim else 349214571Sdim inst_bit_size = 32; 350214571Sdim 351214571Sdim switch (a->type) 352214571Sdim { 353214571Sdim case arg_r: 354214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 355214571Sdim inst_bit_size - start_bits); 356214571Sdim a->r = p.val; 357214571Sdim break; 358214571Sdim 359214571Sdim case arg_rp: 360214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 361214571Sdim inst_bit_size - start_bits); 362214571Sdim a->rp = p.val; 363214571Sdim break; 364214571Sdim 365214571Sdim case arg_pr: 366214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 367214571Sdim inst_bit_size - start_bits); 368214571Sdim a->pr = p.val; 369214571Sdim break; 370214571Sdim 371214571Sdim case arg_prp: 372214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 373214571Sdim inst_bit_size - start_bits); 374214571Sdim a->prp = p.val; 375214571Sdim break; 376214571Sdim 377214571Sdim case arg_ic: 378214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 379214571Sdim inst_bit_size - start_bits); 380214571Sdim a->constant = p.val; 381214571Sdim break; 382214571Sdim 383214571Sdim case arg_cc: 384214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), 385214571Sdim inst_bit_size - start_bits); 386214571Sdim 387214571Sdim a->cc = p.val; 388214571Sdim break; 389214571Sdim 390214571Sdim case arg_idxr: 391214571Sdim if ((IS_INSN_MNEMONIC ("cbitb")) 392214571Sdim || (IS_INSN_MNEMONIC ("sbitb")) 393214571Sdim || (IS_INSN_MNEMONIC ("tbitb"))) 394214571Sdim p = makelongparameter (allWords, 8, 9); 395214571Sdim else 396214571Sdim p = makelongparameter (allWords, 9, 10); 397214571Sdim a->i_r = p.val; 398214571Sdim p = makelongparameter (allWords, inst_bit_size - a->size, inst_bit_size); 399214571Sdim a->constant = p.val; 400214571Sdim break; 401214571Sdim 402214571Sdim case arg_idxrp: 403214571Sdim p = makelongparameter (allWords, start_bits + 12, start_bits + 13); 404214571Sdim a->i_r = p.val; 405214571Sdim p = makelongparameter (allWords, start_bits + 13, start_bits + 16); 406214571Sdim a->rp = p.val; 407214571Sdim if (inst_bit_size > 32) 408214571Sdim { 409214571Sdim p = makelongparameter (allWords, inst_bit_size - start_bits - 12, 410214571Sdim inst_bit_size); 411214571Sdim a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000)); 412214571Sdim } 413214571Sdim else if (instruction->size == 2) 414214571Sdim { 415214571Sdim p = makelongparameter (allWords, inst_bit_size - 22, inst_bit_size); 416214571Sdim a->constant = (p.val & 0xf) | (((p.val >>20) & 0x3) << 4) 417214571Sdim | ((p.val >>14 & 0x3) << 6) | (((p.val >>7) & 0x1f) <<7); 418214571Sdim } 419214571Sdim else if (instruction->size == 1 && a->size == 0) 420214571Sdim a->constant = 0; 421214571Sdim 422214571Sdim break; 423214571Sdim 424214571Sdim case arg_rbase: 425214571Sdim p = makelongparameter (allWords, inst_bit_size, inst_bit_size); 426214571Sdim a->constant = p.val; 427214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + 4), 428214571Sdim inst_bit_size - start_bits); 429214571Sdim a->r = p.val; 430214571Sdim break; 431214571Sdim 432214571Sdim case arg_cr: 433214571Sdim p = makelongparameter (allWords, start_bits + 12, start_bits + 16); 434214571Sdim a->r = p.val; 435214571Sdim p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size); 436214571Sdim a->constant = p.val; 437214571Sdim break; 438214571Sdim 439214571Sdim case arg_crp: 440214571Sdim if (instruction->size == 1) 441214571Sdim p = makelongparameter (allWords, 12, 16); 442214571Sdim else 443214571Sdim p = makelongparameter (allWords, start_bits + 12, start_bits + 16); 444214571Sdim a->rp = p.val; 445214571Sdim 446214571Sdim if (inst_bit_size > 32) 447214571Sdim { 448214571Sdim p = makelongparameter (allWords, inst_bit_size - start_bits - 12, 449214571Sdim inst_bit_size); 450214571Sdim a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000)); 451214571Sdim } 452214571Sdim else if (instruction->size == 2) 453214571Sdim { 454214571Sdim p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size); 455214571Sdim a->constant = p.val; 456214571Sdim } 457214571Sdim else if (instruction->size == 1 && a->size != 0) 458214571Sdim { 459214571Sdim p = makelongparameter (allWords, 4, 8); 460214571Sdim if (IS_INSN_MNEMONIC ("loadw") 461214571Sdim || IS_INSN_MNEMONIC ("loadd") 462214571Sdim || IS_INSN_MNEMONIC ("storw") 463214571Sdim || IS_INSN_MNEMONIC ("stord")) 464214571Sdim a->constant = (p.val * 2); 465214571Sdim else 466214571Sdim a->constant = p.val; 467214571Sdim } 468214571Sdim else /* below case for 0x0(reg pair) */ 469214571Sdim a->constant = 0; 470214571Sdim 471214571Sdim break; 472214571Sdim 473214571Sdim case arg_c: 474214571Sdim 475214571Sdim if ((IS_INSN_TYPE (BRANCH_INS)) 476214571Sdim || (IS_INSN_MNEMONIC ("bal")) 477214571Sdim || (IS_INSN_TYPE (CSTBIT_INS)) 478214571Sdim || (IS_INSN_TYPE (LD_STOR_INS))) 479214571Sdim { 480214571Sdim switch (a->size) 481214571Sdim { 482214571Sdim case 8 : 483214571Sdim p = makelongparameter (allWords, 0, start_bits); 484214571Sdim a->constant = ((((p.val&0xf00)>>4)) | (p.val&0xf)); 485214571Sdim break; 486214571Sdim 487214571Sdim case 24: 488214571Sdim if (instruction->size == 3) 489214571Sdim { 490214571Sdim p = makelongparameter (allWords, 16, inst_bit_size); 491214571Sdim a->constant = ((((p.val>>16)&0xf) << 20) 492214571Sdim | (((p.val>>24)&0xf) << 16) 493214571Sdim | (p.val & 0xffff)); 494214571Sdim } 495214571Sdim else if (instruction->size == 2) 496214571Sdim { 497214571Sdim p = makelongparameter (allWords, 8, inst_bit_size); 498214571Sdim a->constant = p.val; 499214571Sdim } 500214571Sdim break; 501214571Sdim 502214571Sdim default: 503214571Sdim p = makelongparameter (allWords, inst_bit_size - (start_bits + 504214571Sdim a->size), inst_bit_size - start_bits); 505214571Sdim a->constant = p.val; 506214571Sdim break; 507214571Sdim } 508214571Sdim } 509214571Sdim else 510214571Sdim { 511214571Sdim p = makelongparameter (allWords, inst_bit_size - 512214571Sdim (start_bits + a->size), 513214571Sdim inst_bit_size - start_bits); 514214571Sdim a->constant = p.val; 515214571Sdim } 516214571Sdim break; 517214571Sdim 518214571Sdim default: 519214571Sdim break; 520214571Sdim } 521214571Sdim} 522214571Sdim 523214571Sdim/* Print a single argument. */ 524214571Sdim 525214571Sdimstatic void 526214571Sdimprint_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info) 527214571Sdim{ 528214571Sdim LONGLONG longdisp, mask; 529214571Sdim int sign_flag = 0; 530214571Sdim int relative = 0; 531214571Sdim bfd_vma number; 532214571Sdim PTR stream = info->stream; 533214571Sdim fprintf_ftype func = info->fprintf_func; 534214571Sdim 535214571Sdim switch (a->type) 536214571Sdim { 537214571Sdim case arg_r: 538214571Sdim func (stream, "%s", getregname (a->r)); 539214571Sdim break; 540214571Sdim 541214571Sdim case arg_rp: 542214571Sdim func (stream, "%s", getregpname (a->rp)); 543214571Sdim break; 544214571Sdim 545214571Sdim case arg_pr: 546214571Sdim func (stream, "%s", getprocregname (a->pr)); 547214571Sdim break; 548214571Sdim 549214571Sdim case arg_prp: 550214571Sdim func (stream, "%s", getprocpregname (a->prp)); 551214571Sdim break; 552214571Sdim 553214571Sdim case arg_cc: 554214571Sdim func (stream, "%s", getccstring (a->cc)); 555214571Sdim func (stream, "%s", "\t"); 556214571Sdim break; 557214571Sdim 558214571Sdim case arg_ic: 559214571Sdim if (IS_INSN_MNEMONIC ("excp")) 560214571Sdim { 561214571Sdim func (stream, "%s", gettrapstring (a->constant)); 562214571Sdim break; 563214571Sdim } 564214571Sdim else if ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS)) 565214571Sdim && ((instruction->size == 1) && (a->constant == 9))) 566214571Sdim func (stream, "$%d", -1); 567214571Sdim else if (INST_HAS_REG_LIST) 568214571Sdim func (stream, "$0x%lx", a->constant +1); 569214571Sdim else if (IS_INSN_TYPE (SHIFT_INS)) 570214571Sdim { 571214571Sdim longdisp = a->constant; 572214571Sdim mask = ((LONGLONG)1 << a->size) - 1; 573214571Sdim if (longdisp & ((LONGLONG)1 << (a->size -1))) 574214571Sdim { 575214571Sdim sign_flag = 1; 576214571Sdim longdisp = ~(longdisp) + 1; 577214571Sdim } 578214571Sdim a->constant = (unsigned long int) (longdisp & mask); 579214571Sdim func (stream, "$%d", ((int)(sign_flag ? -a->constant : 580214571Sdim a->constant))); 581214571Sdim } 582214571Sdim else 583214571Sdim func (stream, "$0x%lx", a->constant); 584214571Sdim switch (a->size) 585214571Sdim { 586214571Sdim case 4 : case 5 : case 6 : case 8 : 587214571Sdim func (stream, "%s", ":s"); break; 588214571Sdim case 16 : case 20 : func (stream, "%s", ":m"); break; 589214571Sdim case 24 : case 32 : func (stream, "%s", ":l"); break; 590214571Sdim default: break; 591214571Sdim } 592214571Sdim break; 593214571Sdim 594214571Sdim case arg_idxr: 595214571Sdim if (a->i_r == 0) func (stream, "[r12]"); 596214571Sdim if (a->i_r == 1) func (stream, "[r13]"); 597214571Sdim func (stream, "0x%lx", a->constant); 598214571Sdim func (stream, "%s", print_exp_len (instruction->size * 16)); 599214571Sdim break; 600214571Sdim 601214571Sdim case arg_idxrp: 602214571Sdim if (a->i_r == 0) func (stream, "[r12]"); 603214571Sdim if (a->i_r == 1) func (stream, "[r13]"); 604214571Sdim func (stream, "0x%lx", a->constant); 605214571Sdim func (stream, "%s", print_exp_len (instruction->size * 16)); 606214571Sdim func (stream, "%s", getidxregpname (a->rp)); 607214571Sdim break; 608214571Sdim 609214571Sdim case arg_rbase: 610214571Sdim func (stream, "(%s)", getregname (a->r)); 611214571Sdim break; 612214571Sdim 613214571Sdim case arg_cr: 614214571Sdim func (stream, "0x%lx", a->constant); 615214571Sdim func (stream, "%s", print_exp_len (instruction->size * 16)); 616214571Sdim func (stream, "(%s)", getregname (a->r)); 617214571Sdim break; 618214571Sdim 619214571Sdim case arg_crp: 620214571Sdim func (stream, "0x%lx", a->constant); 621214571Sdim func (stream, "%s", print_exp_len (instruction->size * 16)); 622214571Sdim func (stream, "%s", getregpname (a->rp)); 623214571Sdim break; 624214571Sdim 625214571Sdim case arg_c: 626214571Sdim /*Removed the *2 part as because implicit zeros are no more required. 627214571Sdim Have to fix this as this needs a bit of extension in terms of branch 628214571Sdim instructions. */ 629214571Sdim if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal")) 630214571Sdim { 631214571Sdim relative = 1; 632214571Sdim longdisp = a->constant; 633214571Sdim /* REVISIT: To sync with WinIDEA and CR16 4.1tools, the below 634214571Sdim line commented */ 635214571Sdim /* longdisp <<= 1; */ 636214571Sdim mask = ((LONGLONG)1 << a->size) - 1; 637214571Sdim switch (a->size) 638214571Sdim { 639214571Sdim case 8 : 640214571Sdim { 641214571Sdim longdisp <<= 1; 642214571Sdim if (longdisp & ((LONGLONG)1 << a->size)) 643214571Sdim { 644214571Sdim sign_flag = 1; 645214571Sdim longdisp = ~(longdisp) + 1; 646214571Sdim } 647214571Sdim break; 648214571Sdim } 649214571Sdim case 16 : 650214571Sdim case 24 : 651214571Sdim { 652214571Sdim if (longdisp & 1) 653214571Sdim { 654214571Sdim sign_flag = 1; 655214571Sdim longdisp = ~(longdisp) + 1; 656214571Sdim } 657214571Sdim break; 658214571Sdim } 659214571Sdim default: 660214571Sdim func (stream, "Wrong offset used in branch/bal instruction"); 661214571Sdim break; 662214571Sdim } 663214571Sdim a->constant = (unsigned long int) (longdisp & mask); 664214571Sdim } 665214571Sdim /* For branch Neq instruction it is 2*offset + 2. */ 666214571Sdim else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) 667214571Sdim a->constant = 2 * a->constant + 2; 668214571Sdim 669214571Sdim if ((!IS_INSN_TYPE (CSTBIT_INS)) && (!IS_INSN_TYPE (LD_STOR_INS))) 670214571Sdim (sign_flag) ? func (stream, "%s", "*-"): func (stream, "%s","*+"); 671214571Sdim 672214571Sdim func (stream, "%s", "0x"); 673214571Sdim number = ((relative ? memaddr : 0) + 674214571Sdim (sign_flag ? ((- a->constant) & 0xffffffe) : a->constant)); 675214571Sdim 676214571Sdim (*info->print_address_func) ((number & ((1 << 24) - 1)), info); 677214571Sdim 678214571Sdim func (stream, "%s", print_exp_len (instruction->size * 16)); 679214571Sdim break; 680214571Sdim 681214571Sdim default: 682214571Sdim break; 683214571Sdim } 684214571Sdim} 685214571Sdim 686214571Sdim/* Print all the arguments of CURRINSN instruction. */ 687214571Sdim 688214571Sdimstatic void 689214571Sdimprint_arguments (ins *currInsn, bfd_vma memaddr, struct disassemble_info *info) 690214571Sdim{ 691214571Sdim int i; 692214571Sdim 693214571Sdim /* For "pop/push/popret RA instruction only. */ 694214571Sdim if ((IS_INSN_MNEMONIC ("pop") 695214571Sdim || (IS_INSN_MNEMONIC ("popret") 696214571Sdim || (IS_INSN_MNEMONIC ("push")))) 697214571Sdim && currInsn->nargs == 1) 698214571Sdim { 699214571Sdim info->fprintf_func (info->stream, "RA"); 700214571Sdim return; 701214571Sdim } 702214571Sdim 703214571Sdim for (i = 0; i < currInsn->nargs; i++) 704214571Sdim { 705214571Sdim processing_argument_number = i; 706214571Sdim 707214571Sdim /* For "bal (ra), disp17" instruction only. */ 708214571Sdim if ((IS_INSN_MNEMONIC ("bal")) && (i == 0) && instruction->size == 2) 709214571Sdim { 710214571Sdim info->fprintf_func (info->stream, "(ra),"); 711214571Sdim continue; 712214571Sdim } 713214571Sdim 714214571Sdim if ((INST_HAS_REG_LIST) && (i == 2)) 715214571Sdim info->fprintf_func (info->stream, "RA"); 716214571Sdim else 717214571Sdim print_arg (&currInsn->arg[i], memaddr, info); 718214571Sdim 719214571Sdim if ((i != currInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b"))) 720214571Sdim info->fprintf_func (info->stream, ","); 721214571Sdim } 722214571Sdim} 723214571Sdim 724214571Sdim/* Build the instruction's arguments. */ 725214571Sdim 726214571Sdimstatic void 727214571Sdimmake_instruction (void) 728214571Sdim{ 729214571Sdim int i; 730214571Sdim unsigned int shift; 731214571Sdim 732214571Sdim for (i = 0; i < currInsn.nargs; i++) 733214571Sdim { 734214571Sdim argument a; 735214571Sdim 736214571Sdim memset (&a, 0, sizeof (a)); 737214571Sdim a.type = getargtype (instruction->operands[i].op_type); 738214571Sdim a.size = getbits (instruction->operands[i].op_type); 739214571Sdim shift = instruction->operands[i].shift; 740214571Sdim 741214571Sdim make_argument (&a, shift); 742214571Sdim currInsn.arg[i] = a; 743214571Sdim } 744214571Sdim 745214571Sdim /* Calculate instruction size (in bytes). */ 746214571Sdim currInsn.size = instruction->size + (size_changed ? 1 : 0); 747214571Sdim /* Now in bits. */ 748214571Sdim currInsn.size *= 2; 749214571Sdim} 750214571Sdim 751214571Sdim/* Retrieve a single word from a given memory address. */ 752214571Sdim 753214571Sdimstatic wordU 754214571Sdimget_word_at_PC (bfd_vma memaddr, struct disassemble_info *info) 755214571Sdim{ 756214571Sdim bfd_byte buffer[4]; 757214571Sdim int status; 758214571Sdim wordU insn = 0; 759214571Sdim 760214571Sdim status = info->read_memory_func (memaddr, buffer, 2, info); 761214571Sdim 762214571Sdim if (status == 0) 763214571Sdim insn = (wordU) bfd_getl16 (buffer); 764214571Sdim 765214571Sdim return insn; 766214571Sdim} 767214571Sdim 768214571Sdim/* Retrieve multiple words (3) from a given memory address. */ 769214571Sdim 770214571Sdimstatic void 771214571Sdimget_words_at_PC (bfd_vma memaddr, struct disassemble_info *info) 772214571Sdim{ 773214571Sdim int i; 774214571Sdim bfd_vma mem; 775214571Sdim 776214571Sdim for (i = 0, mem = memaddr; i < 3; i++, mem += 2) 777214571Sdim words[i] = get_word_at_PC (mem, info); 778214571Sdim 779214571Sdim allWords = 780214571Sdim ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2]; 781214571Sdim} 782214571Sdim 783214571Sdim/* Prints the instruction by calling print_arguments after proper matching. */ 784214571Sdim 785214571Sdimint 786214571Sdimprint_insn_cr16 (bfd_vma memaddr, struct disassemble_info *info) 787214571Sdim{ 788214571Sdim int is_decoded; /* Nonzero means instruction has a match. */ 789214571Sdim 790214571Sdim /* Initialize global variables. */ 791214571Sdim imm4flag = 0; 792214571Sdim size_changed = 0; 793214571Sdim 794214571Sdim /* Retrieve the encoding from current memory location. */ 795214571Sdim get_words_at_PC (memaddr, info); 796214571Sdim /* Find a matching opcode in table. */ 797214571Sdim is_decoded = match_opcode (); 798214571Sdim /* If found, print the instruction's mnemonic and arguments. */ 799214571Sdim if (is_decoded > 0 && (words[0] << 16 || words[1]) != 0) 800214571Sdim { 801214571Sdim if (strneq (instruction->mnemonic, "cinv", 4)) 802214571Sdim info->fprintf_func (info->stream,"%s", getcinvstring ((char *)instruction->mnemonic)); 803214571Sdim else 804214571Sdim info->fprintf_func (info->stream, "%s", instruction->mnemonic); 805214571Sdim 806214571Sdim if (((currInsn.nargs = get_number_of_operands ()) != 0) 807214571Sdim && ! (IS_INSN_MNEMONIC ("b"))) 808214571Sdim info->fprintf_func (info->stream, "\t"); 809214571Sdim make_instruction (); 810214571Sdim /* For push/pop/pushrtn with RA instructions. */ 811214571Sdim if ((INST_HAS_REG_LIST) && ((words[0] >> 7) & 0x1)) 812214571Sdim currInsn.nargs +=1; 813214571Sdim print_arguments (&currInsn, memaddr, info); 814214571Sdim return currInsn.size; 815214571Sdim } 816214571Sdim 817214571Sdim /* No match found. */ 818214571Sdim info->fprintf_func (info->stream,"%s ",ILLEGAL); 819214571Sdim return 2; 820214571Sdim} 821