root/tools/chdk_dasm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. defstruct
  2. new_list
  3. free_list
  4. new_node
  5. l_search
  6. l_insert
  7. l_remove
  8. set_patch_old_values
  9. append
  10. print_ascii_str
  11. xhex8
  12. ahex8
  13. yhex8
  14. sub_hex8
  15. sub_ahex8
  16. reg
  17. num
  18. instr_disassemble
  19. disassemble1
  20. disassemble
  21. find_end
  22. swiname

   1 /*=====================================================================================================
   2         chdk_dasm.c
   3         
   4         This sofware is provided "as is" with no warantee or representation of any "fitness for use"/
   5         
   6         This software contains code included under the license included below. The code was changed to
   7                         - provide formatting compatible with gcc as used for CHDK development
   8                         - provide a multi-pass approach was added to allow the generation and handling of labels.  
   9                         - expanded command line options
  10                         - correction to dissassembly bugs and added support for the STRD instruction.
  11                         
  12         None of these modifications are the work of the original author.
  13 
  14         And if you are wondering,  the original dissassembler code appears to have been optimized to 
  15         run on an ARM process, which explains all the goofy use of left and right shifts.  Those compile
  16         nicely to a single instrucion on the ARM processor.
  17         
  18 =====================================================================================================*/
  19 
  20 /* disarm -- a simple disassembler for ARM instructions
  21  * (c) 2000 Gareth McCaughan
  22  *
  23  * This file may be distributed and used freely provided:
  24  * 1. You do not distribute any version that lacks this
  25  *    copyright notice (exactly as it appears here, extending
  26  *    from the start to the end of the C-language comment
  27  *    containing these words)); and,
  28  * 2. If you distribute any modified version, its source
  29  *    contains a clear description of the ways in which
  30  *    it differs from the original version, and a clear
  31  *    indication that the changes are not mine.
  32  * There is no restriction on your permission to use and
  33  * distribute object code or executable code derived from
  34  * this.
  35  *
  36  * The original version of this file (or perhaps a later
  37  * version by the original author) may or may not be
  38  * available at http://web.ukonline.co.uk/g.mccaughan/g/software.html .
  39  *
  40  * Share and enjoy!    -- g
  41  */
  42 
  43 #include <stdio.h>
  44 #include <stdlib.h>
  45 #include <stdint.h>
  46 #include <string.h>
  47 #include <ctype.h>
  48 #include <sys/stat.h>
  49 
  50 #include "stubs_load.h"
  51 #include "firmware_load.h"
  52 #include "chdk_dasm.h"
  53 
  54 //------------------------------------------------------------------------------------------------------------
  55 
  56 declstruct(Instruction);
  57 
  58 typedef enum {
  59     target_None,                /* instruction doesn't refer to an address */
  60     target_Data,                /* instruction refers to address of data */
  61     target_FloatS,      /* instruction refers to address of single-float */
  62     target_FloatD,      /* instruction refers to address of double-float */
  63     target_FloatE,      /* blah blah extended-float */
  64     target_FloatP,      /* blah blah packed decimal float */
  65     target_Code,                /* instruction refers to address of code */
  66     target_Unknown      /* instruction refers to address of *something* */
  67 } eTargetType;
  68 
  69 defstruct(Instruction) {
  70     char text[128];                     /* the disassembled instruction */
  71     int undefined;                      /* non-0 iff it's an undefined instr */
  72     int badbits;                                /* non-0 iff something reserved has the wrong value */
  73     int oddbits;                                /* non-0 iff something unspecified isn't 0 */
  74     int is_SWI;                         /* non-0 iff it's a SWI */
  75     t_value swinum;             /* only set for SWIs */
  76     t_address target;                   /* address instr refers to */
  77     eTargetType target_type;    /* and what we expect to be there */
  78     int offset;                         /* offset from register in LDR or STR or similar */
  79     char * addrstart;                   /* start of address part of instruction, or 0 */
  80     t_value instr ;                             /* the raw instruction data */
  81 };
  82 
  83 char *patch_func_name;
  84 t_address patch_new_val;
  85 t_address patch_old_val;
  86 char *patch_old_func_name;      // if old patched value found in stubs
  87 int patch_ref_address[20];
  88 char patch_ref_name[20][256];
  89 int save_patch_ref;
  90 char *patch_comment;
  91 
  92 static char * reg_names[16] = {
  93     "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",  "R8", "R9", "R10", "R11", "R12", "SP", "LR", "PC"
  94 };
  95 
  96 sDisOptions options = {
  97     disopt_CommaSpace|disopt_exclude_dcd,
  98     reg_names
  99 };
 100 
 101 /* Some important single-bit fields. */
 102 
 103 #define Sbit    (1<<20)         /* set condition codes (data processing) */
 104 #define Lbit    (1<<20)         /* load, not store (data transfer) */
 105 #define Wbit    (1<<21)         /* writeback (data transfer) */
 106 #define Bbit    (1<<22)         /* single byte (data transfer, SWP) */
 107 #define Ubit    (1<<23)         /* up, not down (data transfer) */
 108 #define Pbit    (1<<24)         /* pre-, not post-, indexed (data transfer) */
 109 #define Ibit    (1<<25)         /* non-immediate (data transfer) */
 110 /* immediate (data processing) */
 111 #define SPSRbit (1<<22)         /* SPSR, not CPSR (MRS, MSR) */
 112 
 113 /* Some important 4-bit fields. */
 114 
 115 #define RD(x)   ((x)<<12)       /* destination register */
 116 #define RN(x)   ((x)<<16)       /* operand/base register */
 117 #define CP(x)   ((x)<<8)        /* coprocessor number */
 118 #define RDbits  RD(15)
 119 #define RNbits  RN(15)
 120 #define CPbits  CP(15)
 121 #define RD_is(x)        ((instr&RDbits)==RD(x))
 122 #define RN_is(x)        ((instr&RNbits)==RN(x))
 123 #define CP_is(x)        ((instr&CPbits)==CP(x))
 124 
 125 /* A slightly efficient way of telling whether two bits are the same
 126  * or not. It's assumed that a<b.
 127  */
 128 #define BitsDiffer(a,b) ((instr^(instr>>(b-a)))&(1<<a))
 129 
 130 //------------------------------------------------------------------------------------------------------------
 131 
 132 /* -----------------------------------------------------------------
 133  * Linked List Routines
 134  * ----------------------------------------------------------------- */
 135  
 136 struct lnode {                                  // linked list node - Storage memory address / memory data pairs
 137     struct lnode *next;
 138     t_address address;
 139     t_value data ;
 140 }; 
 141 
 142 struct llist {                                  // Head of linked list
 143     struct lnode *head;
 144     int size;
 145 };
 146 
 147 /* -----------------------------------------------------------------
 148  * struct llist * new_list(void)
 149  * ----------------------------------------------------------------- */
 150 struct llist * new_list()
 151 { 
 152     struct llist *lst;
 153 
 154     lst = (struct llist *) malloc(sizeof(struct llist));
 155     if (lst == NULL) {
 156         printf("\n **new_list() : malloc error");
 157         return NULL;
 158     }
 159     lst->head = 0;
 160     lst->size = 0;
 161 
 162     return lst;
 163 }
 164 
 165 void free_list(struct llist *lst)
 166 {
 167     if (lst)
 168     {
 169         struct lnode *p, *n;
 170         p = lst->head;
 171         while (p)
 172         {
 173             n = p->next;
 174             free(p);
 175             p = n;
 176         }
 177         free(lst);
 178     }
 179 }
 180 
 181 /* -----------------------------------------------------------------
 182  * struct new_node * new_node(void * item, t_value data)
 183  * ----------------------------------------------------------------- */
 184 struct lnode * new_node(t_address address, t_value data) {
 185     struct lnode *node;
 186 
 187     node = (struct lnode *) malloc (sizeof (struct lnode));
 188     if (node == NULL) {
 189         printf("\n **new_node() : malloc error");
 190         return NULL;
 191     }
 192     node->address = address;
 193     node->data = data;
 194     node->next = 0;
 195 
 196     return node;
 197 }  
 198 
 199 /* -----------------------------------------------------------------
 200  * int l_search(struct llist *ls, void *address) {
 201  * ----------------------------------------------------------------- */
 202 struct lnode * l_search(struct llist *ls, t_address address) {
 203     struct lnode *node;
 204 
 205     node = ls->head;
 206     while ( node != NULL && node->address != address ) {
 207         node = node->next ;
 208     }
 209     if (node == NULL) {
 210         return 0; /* 'item' not found */
 211     }
 212 
 213     return node;
 214 }
 215 
 216 /* -----------------------------------------------------------------
 217  * int l_insert(struct llist *ls, void *item)
 218  * ----------------------------------------------------------------- */
 219 int l_insert(struct llist *ls, t_address address, t_value data)
 220 {
 221     struct lnode *node;
 222 
 223     if( l_search(ls, address)) return -1 ;
 224     node = new_node(address, data);
 225     if (node == NULL) return 0;
 226     node->next = ls->head;
 227     ls->head = node;  
 228     (ls->size)++;
 229 
 230     return 1;
 231 }
 232 
 233 void l_remove(struct llist *ls, t_address addr)
 234 {
 235     if (ls)
 236     {
 237         struct lnode *p, *l;
 238         l = 0;
 239         p = ls->head;
 240         while (p)
 241         {
 242             if (p->address == addr)
 243             {
 244                 if (l)
 245                     l->next = p->next;
 246                 else
 247                     ls->head = p->next;
 248                 (ls->size)--;
 249                 return;
 250             }
 251             l = p;
 252             p = p->next;
 253         }
 254     }
 255 }
 256  
 257 /* -----------------------------------------------------------------
 258  *  Create Linked Lists
 259  * ----------------------------------------------------------------- */
 260  
 261 struct llist *dcd_list;                         // create list of DCD addresses
 262 struct llist *branch_list;                      // create list of branch instruction target addresses
 263 
 264 /* -----------------------------------------------------------------
 265  *  Dissassembler Code
 266  * ----------------------------------------------------------------- */
 267 
 268 static void set_patch_old_values(t_address w, char *nm)
 269 {
 270     patch_old_val = w;
 271     patch_old_func_name = nm;
 272 }
 273 
 274 extern void swiname(t_value, char *, size_t);
 275 
 276 /* op = append(op,ip) === op += sprintf(op,"%s",ip),
 277  * except that it's faster.
 278  */
 279 static char * append(char * op, const char *ip) {
 280     char c;
 281     while ((c=*ip++)!=0) *op++=c;
 282     return op;
 283 }
 284 
 285 static char * print_ascii_str(firmware *fw, char *op, t_value w)
 286 {
 287     if (isASCIIstring(fw, w))
 288     {
 289         char s[500];
 290         char *p = adr2ptr(fw, w);
 291         int i = 0;
 292         while (*p)
 293         {
 294             switch (*p)
 295             {
 296             case '\r':
 297                 s[i++] = '\\';
 298                 s[i++] = 'r';
 299                 break;
 300             case '\n':
 301                 s[i++] = '\\';
 302                 s[i++] = 'n';
 303                 break;
 304             case '\t':
 305                 s[i++] = '\\';
 306                 s[i++] = 't';
 307                 break;
 308             default:
 309                 s[i++] = *p;
 310                 break;
 311             }
 312             p++;
 313         }
 314         s[i] = 0;
 315         op += sprintf(op," /*'%s'*/",s);
 316     }
 317     return op;
 318 }
 319 
 320 /* op = xhex8(op,w) === op += sprintf(op,"&%08lX",w)
 321  */
 322 static char * xhex8(firmware *fw, char * op, t_value w)
 323 {
 324     char *s = op;
 325 
 326     if (options.flags & disopt_patch_value)
 327     {
 328         set_patch_old_values(w, 0);
 329         w = patch_new_val;
 330     }
 331 
 332     if (options.flags & disopt_patch_branch)
 333     {
 334         set_patch_old_values(w, 0);
 335         if (patch_func_name)
 336             op += sprintf(op,"=%s",patch_func_name) ;
 337         else
 338         {
 339             if (options.flags & disopt_comment_lines)
 340                 op += sprintf(op,"=_sub_%08X_my",w);     // prepend '_' to prevent sub from appearing in stubs_auto.S
 341             else
 342                 op += sprintf(op,"=sub_%08X_my",w);
 343         }
 344         if (save_patch_ref >= 0)
 345         {
 346             *op = 0;
 347             patch_ref_address[save_patch_ref] = w;
 348             strcpy(patch_ref_name[save_patch_ref],s+1);
 349         }
 350     }
 351     else
 352     {
 353         op += sprintf(op,"=0x%X",w);
 354         op = print_ascii_str(fw, op, w);
 355     }
 356 
 357     return op;
 358 }
 359 
 360 /* op = ahex8(op,w) === op += sprintf(op,"&%08lX",w)
 361   --> xhex hacked to insert addresses into linked list for use on pass 3
 362  */
 363 static char * ahex8(firmware *fw, char * op, t_value w)
 364 {
 365     struct lnode * lptr ;
 366     lptr = l_search( dcd_list, w) ;             // does this DCD address exist already ?
 367 
 368     if ( lptr ) w = lptr->data ;                                        // dereference indirect address (typically pass 3)
 369     else        l_insert(dcd_list, w, 0) ;      // add node if not found - typically on pass 1
 370 
 371     return xhex8(fw, op, w);
 372 }
 373 
 374 /* op = yhex8(op,w) === op += sprintf(op,"&%08lX",w)
 375  */
 376 static char * yhex8(firmware *fw, char * op, t_value w)
 377 {
 378     if (options.flags & disopt_patch_value)
 379     {
 380         set_patch_old_values(w, 0);
 381         w = patch_new_val;
 382     }
 383     op += sprintf(op,"0x%X",w) ;
 384     op = print_ascii_str(fw, op, w);
 385     return op;
 386 }
 387 
 388 /* op = sub_hex8(op,w) === op += sprintf(op,"&%08lX",w), but faster.
 389  */
 390 static char * sub_hex8(firmware *fw, char * op, t_value w)
 391 {
 392     if (options.flags & disopt_remember_branches)
 393         l_insert(branch_list, w, 0) ;
 394 
 395     char *s = op;
 396 
 397     w = followBranch(fw,w,1);           // If call to Branch then follow branch
 398     osig *o = find_sig_val_by_type(fw->sv->stubs, w, TYPE_NHSTUB);
 399 
 400     if ((options.flags & disopt_patch_branch) && patch_func_name)
 401     {
 402         set_patch_old_values(w, (o) ? o->nm : 0);
 403         op += sprintf(op,"%s",patch_func_name);
 404     }
 405     else
 406     {
 407         if (o && !o->is_comment)
 408         {
 409             op += sprintf(op,"_%s",o->nm);
 410         }
 411         else
 412         {
 413             if (( w >= options.start_address )&&( w <= options.end_address ))
 414             {
 415                 op += sprintf(op,"loc_%08X",w);
 416             }
 417             else
 418             {
 419                 if (options.flags & disopt_comment_lines)
 420                     op += sprintf(op,"_sub_%08X",w);     // prevent sub from appearing in stubs_auto.S
 421                 else
 422                 {
 423                     // Get 1st instruction in sub_XXXXXXXX
 424                     t_value v = fwval(fw,adr2idx(fw,w));
 425                     if (v == 0xE12FFF1E)    // BX LR?
 426                     {
 427                         // Comment out 'nullsub' calls
 428                         op += sprintf(op,"_sub_%08X",w);
 429                         options.flags |= disopt_nullsub_call;
 430                     }
 431                     else
 432                     {
 433                         op += sprintf(op,"sub_%08X",w);
 434                         if (o && o->is_comment)
 435                         op += sprintf(op," /*_%s*/",o->nm);
 436                     }
 437                 }
 438             }
 439             if (options.flags & disopt_patch_branch)
 440             {
 441                 set_patch_old_values(w, 0);
 442                 op += sprintf(op,"_my");
 443             }
 444         }
 445     }
 446 
 447     if ((save_patch_ref >= 0) && (options.flags & disopt_patch_branch))
 448     {
 449         *op = 0;
 450         patch_ref_address[save_patch_ref] = w;
 451         strcpy(patch_ref_name[save_patch_ref],s);
 452     }
 453 
 454     return op;
 455 }
 456 
 457 static char * sub_ahex8(firmware *fw, char * op, t_value w)
 458 {
 459     struct lnode * lptr ;
 460     lptr = l_search( dcd_list, w) ;             // does this DCD address exist already ?
 461 
 462     if ( !lptr )
 463         l_insert(dcd_list, w, 0) ;      // add node if not found - typically on pass 1
 464 
 465     w = fwval(fw,adr2idx(fw,w));
 466     return sub_hex8(fw, op, w);
 467 }
 468 
 469 /* op = reg(op,'x',n) === op += sprintf(op,"x%lu",n&15).
 470  */
 471 static char * reg(char * op, char c, t_value n) {
 472     *op++=c;
 473     n&=15;
 474     if (n>=10) { *op++='1'; n+='0'-10; } else n+='0';
 475     *op++=(char)n;
 476 
 477     return op;
 478 }
 479 
 480 /* op = num(op,n) appends n in decimal or &n in hex
 481  * depending on whether n<decmax. It's assumed that n>=0.
 482  */
 483 static char * num(char * op, t_value w, int decmax)
 484 {
 485     char tmpbuf[16] ;
 486     char * tptr ;
 487     tptr = tmpbuf ;
 488 
 489     if (options.flags & disopt_patch_value)
 490     {
 491         set_patch_old_values(w, 0);
 492         w = patch_new_val;
 493     }
 494 
 495     if ( w<decmax ) sprintf( tptr, "%d", w) ;
 496     else
 497     {
 498         if (w < 16)
 499             sprintf( tptr, "0x%X", w);
 500         else
 501             sprintf( tptr, "0x%X", w);
 502     }
 503     tptr = tmpbuf ;
 504     while(*tptr) *op++ = *tptr++ ;
 505     return op;
 506 }
 507 
 508 /* instr_disassemble
 509  * Disassemble a single instruction.
 510  *
 511  * args:   instr   a single ARM instruction
 512  *         addr    the address it's presumed to have come from
 513  *         opts    cosmetic preferences for our output
 514  *
 515  * reqs:   opts must be filled in right. In particular, it must contain
 516  *         a list of register names.
 517  *
 518  * return: a pointer to a structure containing the disassembled instruction
 519  *         and some other information about it.
 520  *
 521  *
 522  * This function proceeds in two phases. The first is very simple:
 523  * it works out what sort of instruction it's looking at and sets up
 524  * three strings:
 525  *   - |mnemonic|  (the basic mnemonic: LDR or whatever)
 526  *   - |flagchars| (things to go after the cond code: B or whatever)
 527  *   - |format|    (a string describing how to display the instruction)
 528  
 529  * The second phase consists of interpreting |format|, character by
 530  * character. Some characters (e.g., letters) just mean `append this
 531  * character to the output string'; some mean more complicated things
 532  * like `append the name of the register whose number is in bits 12..15'
 533  * or, worse, `append a description of the <op2> field'.
 534  *
 535  * I'm afraid the magic characters in |format| are rather arbitrary.
 536  * One criterion in choosing them was that they should form a contiguous
 537  * subrange of the character set! Sorry.
 538  *
 539  * Format characters:
 540  *
 541  *   \01..\05 copro register number from nybble (\001 == nybble 0, sorry)
 542  *   $        SWI number
 543  *   %        register set for LDM/STM (takes note of bit 22 for ^)
 544  *   &        address for B/BL
 545  *   '        ! if bit 21 set, else nothing (mnemonic: half a !)
 546  *   (        #regs for SFM (bits 22,15 = fpn, assumed already tweaked)
 547  *   )        copro opcode in bits 20..23 (for CDP)
 548  *   *        op2 (takes note of bottom 12 bits, and bit 25)
 549  *   +        FP register or immediate value: bits 0..3
 550  *   ,        comma or comma-space
 551  *   -        copro extra info in bits 5..7 preceded by , omitted if 0
 552  *   .        address in ADR instruction
 553  *   /        address for LDR/STR (takes note of bit 23 & reg in bits 16..19)
 554  *   0..4     register number from nybble
 555  *   5..9     FP register number from nybble
 556  *   :        copro opcode in bits 21..23 (for MRC/MCR)
 557  *   ;        copro number in bits 8..11
 558  *   =        32 constant (address or data)
 559  *
 560  * NB that / takes note of bit 22, too, and does its own ! when appropriate.
 561  *
 562  */
 563 
 564 
 565 extern pInstruction instr_disassemble(firmware *fw, t_value instr, t_address addr, pDisOptions opts) {
 566     static char         flagchars[4];
 567     static sInstruction result;
 568     const char * mnemonic  = 0;
 569     char * flagp     = flagchars;
 570     const char * format    = 0;
 571     t_value         fpn;
 572     eTargetType  poss_tt = target_None;
 573     int is_v4 = 0;
 574 
 575     options.flags &= ~disopt_nullsub_call;
 576 
 577     /* PHASE 0. Set up default values for |result|. */
 578 
 579     fpn = ((instr>>15)&1) + ((instr>>21)&2);
 580 
 581     result.undefined =
 582         result.badbits =
 583         result.oddbits =
 584         result.instr =
 585         result.is_SWI = 0;
 586     result.target_type = target_None;
 587     result.offset = 0x80000000;
 588     result.addrstart = 0;
 589 
 590     /* PHASE 1. Decode and classify instruction. */
 591     static char _i_mul[4][6] = { "UMULL", "UMLAL", "SMULL", "SMLAL" };
 592     static char _i_ldr_str[2][4] = { "LDR", "STR" };
 593     static char _i_str_ldr[2][4] = { "STR", "LDR" };
 594     static char _i_stm_ldm[2][4] = { "STM", "LDM" };
 595     static char _i_stf_ldf[2][4] = { "STF", "LDF" };
 596     static char _i_stc_ldc[2][4] = { "STC", "LDC" };
 597     static char _i_sfm_lfm[2][4] = { "SFM", "LFM" };
 598     static char _i_b_bl[2][3] = { "B", "BL" };
 599     static char _i_alu[16][4] = {
 600         "AND","EOR","SUB","RSB","ADD","ADC","SBC","RSC",
 601         "TST","TEQ","CMP","CMN","ORR","MOV","BIC","MVN"
 602     };
 603     static char _i_cmf[4][5] = { "CMF","CNF","CMFE","CNFE" };
 604     static char _i_flt[6][4] = { "FLT","FIX","WFS","RFS","WFC","RFC" };
 605     static char _i_mcr_mrc[2][4] = { "MCR","MRC" };
 606     static char _i_copro[32][4] = {
 607         /* dyadics: */
 608         "ADF","MUF","SUF","RSF",
 609         "DVF","RDF","POW","RPW",
 610         "RMF","FML","FDV","FRD",
 611         "POL","***","***","***",
 612         /* monadics: */
 613         "MVF","MNF","ABS","RND",
 614         "SQT","LOG","LGN","EXP",
 615         "SIN","COS","TAN","ASN",
 616         "ACS","ATN","URD","NRM"
 617     };
 618     static char _i_lsl_lsr[4][4] = { "LSL","LSR","ASR","ROR" };
 619     static char _i_stk[4][2] = { "ED","EA","FD","FA" };
 620     static char _i_cond[16][2] = { "EQ","NE","CS","CC","MI","PL","VS","VC","HI","LS","GE","LT","GT","LE","AL","NV" };
 621 
 622     switch ((instr>>24)&15) {
 623 
 624     case 0:                                             /* multiply or data processing, or LDRH etc */
 625         if ((instr&(15<<4))!=(9<<4)) goto lMaybeLDRHetc;   // F0  90
 626 
 627         if (instr&(1<<23)) {                    /* long multiply */
 628             mnemonic = _i_mul[(instr>>21)&3];
 629             format = "3,4,0,2";
 630         }
 631         else {                                          
 632             if (instr&(1<<22)) goto laUndefined;        /* "class C" */
 633 
 634             if (instr&(1<<21)) {                /* short multiply */
 635                 mnemonic = "MLA";
 636                 format   = "4,0,2,3";
 637             }
 638             else {
 639                 mnemonic = "MUL";
 640                 format   = "4,0,2";
 641             }
 642         }
 643         if (instr&Sbit) *flagp++='S';
 644         break;
 645 
 646     case 1:                                     /* SWP or MRS/MSR or BX or data processing */
 647     case 3:
 648 
 649         if ((instr&0x0FF000F0)==0x01200010) {                   /* BX */
 650             mnemonic = "BX";
 651             format = "0";
 652             break;
 653         }
 654         if ((instr&0x0FF000F0)==0x01200030) {              /* BLX */
 655             mnemonic = "BLX";
 656             format = "0";
 657             break;
 658         }
 659         if ((instr&0x02B00FF0)==0x00000090) {        /* SWP */
 660             mnemonic = "SWP";
 661             format   = "3,0,[4]";
 662             if (instr&Bbit) *flagp++='B';
 663             break;
 664         }
 665         if ((instr&0x02BF0FFF)==0x000F0000) {        /* MRS */
 666             mnemonic = "MRS";
 667             format   = (instr&SPSRbit) ? "3,SPSR" : "3,CPSR";
 668             break;
 669         }
 670 
 671         if ((instr&0x0FB00010)==0x03200000) {      /* MSR psr<P=0/1...>,Rm */
 672             mnemonic = "MSR";
 673             format   = (instr&SPSRbit) ? "SPSR,0" : "CPSR,0";
 674             break;
 675         }
 676 
 677         if ((instr&0x0FB00010)==0x01200000) {     /* MSR {C,S}PSR_flag,op2 */
 678             mnemonic = "MSR";
 679             format   = (instr&SPSRbit) ? "SPSR_cxsf,*" : "CPSR_cxsf,*";
 680             if (!(instr&Ibit) && (instr&(15<<4)))
 681                 goto lMaybeLDRHetc;
 682             break;
 683         }
 684 
 685 
 686 lMaybeLDRHetc:                                                                                                  /* fall through here */
 687         if ( (instr&(14<<24))==0 && ((instr&(9<<4))==(9<<4)) ) 
 688         {                                                                                                               /* Might well be LDRH or similar. */
 689             if ((instr&(Wbit+Pbit))==Wbit) goto lbUndefined;            /* "class E", case 1 */
 690             if ((instr&(Lbit+(1<<6)))==(1<<6))                                          /* is it LDRD/STRD or LDRSH/STRSH */
 691             {
 692                 if ((instr&(1<<6))!=(1<<6))     goto lcUndefined ;
 693                 mnemonic = _i_ldr_str[(instr & 0x0000020) >> 5];    /*  */
 694                 if (instr&(1<<6)) *flagp++='D';
 695                 format = "3,/";
 696                 if (!(instr&(1<<22))) instr |= Ibit;
 697                 is_v4=1;
 698             }
 699             else
 700             {
 701                 mnemonic = _i_str_ldr[(instr&Lbit) >> 20];
 702                 if (instr&(1<<6)) *flagp++='S';
 703                 *flagp++ = (instr&(1<<5)) ? 'H' : 'B';                                  /* fixed 2011/03/27 - B & H reversed */
 704                 format = "3,/";                                                                         /* aargh: */
 705                 if (!(instr&(1<<22))) instr |= Ibit;
 706                 is_v4=1;
 707             }
 708             break;
 709         }
 710 
 711     case 2:                                                                                                   /* data processing */
 712         { t_value op21 = instr&(15<<21);
 713         if ((op21==(2<<21) || (op21==(4<<21)))                          /* ADD or SUB */
 714             && ((instr&(RNbits+Ibit+Sbit))==RN(15)+Ibit)        /* imm, no S */
 715             /*&& ((instr&(30<<7))==0 || (instr&3))*/) {         /* normal rot */
 716                 /* ADD ...,pc,#... or SUB ...,pc,#...: turn into ADR */
 717                 mnemonic = "LDR";                                                                       //** 2011/03/27 changed from "ADR" to "LDR" for gcc assembler compatability 
 718                 format   = "3,.";
 719                 if ((instr&(30<<7))!=0 && !(instr&3)) result.oddbits=1;
 720                 break;
 721         }
 722         if ((op21==(4<<21))                                                 /* ADD */
 723             && ((instr&(Ibit))==Ibit)                           /* imm */
 724             && ((instr&0xFFF)==0)                           /* 0 offset */
 725             ) {
 726                 /* ADD Rn, Rd, #0 --> MOV */
 727                 mnemonic = "MOV";
 728                 format   = "3,4";
 729                 if (instr&Sbit && (op21<(8<<21) || op21>=(12<<21))) *flagp++='S';
 730                 break;
 731         }
 732         mnemonic = _i_alu[op21 >> 21];
 733         /* Rd needed for all but TST,TEQ,CMP,CMN (8..11) */
 734         /* Rn needed for all but MOV,MVN (13,15) */
 735         if (op21 < ( 8<<21)) format = "3,4,*";
 736         else if (op21 < (12<<21)) {
 737             format = "4,*";
 738             if (instr&RDbits) {
 739                 if ((instr&Sbit) && RD_is(15))
 740                     *flagp++='P';
 741                 else result.oddbits=1;
 742             }
 743             if (!(instr&Sbit)) goto ldUndefined;        /* CMP etc, no S bit */
 744         }
 745         else if (op21 & (1<<21)) {
 746             format = "3,*";
 747             if (instr&RNbits) result.oddbits=1;
 748         }
 749         else format = "3,4,*";
 750         if (instr&Sbit && (op21<(8<<21) || op21>=(12<<21))) *flagp++='S';
 751         }
 752         break;
 753 
 754     case 4:                                                                  /* undefined or STR/LDR */
 755     case 5:
 756     case 6:
 757     case 7:
 758         if ((instr&Ibit) && (instr&(1<<4))) goto leUndefined;   /* "class A" */
 759         mnemonic = _i_str_ldr[(instr&Lbit) >> 20];
 760         format   = "3,/";
 761         if (instr&Bbit) *flagp++='B';
 762         if ((instr&(Wbit+Pbit))==Wbit) *flagp++='T';
 763         poss_tt = target_Data;
 764         break;
 765 
 766     case 8:                                                                                              /* STM/LDM */
 767     case 9:
 768         mnemonic = _i_stm_ldm[(instr&Lbit) >> 20];
 769         if (RN_is(13)) {                                                                /* r13, so treat as stack */
 770             t_value x = (instr&(3<<23)) >> 23;
 771             if (instr&Lbit) x^=3;
 772             {
 773                 const char * foo = _i_stk[x];
 774                 *flagp++ = *foo++;
 775                 *flagp++ = *foo;
 776             }
 777         }
 778         else {                                                                          /* not r13, so don't treat as stack */
 779             *flagp++ = (instr&Ubit) ? 'I' : 'D';
 780             *flagp++ = (instr&Pbit) ? 'B' : 'A';
 781         }
 782         format = "4',%";
 783         break;
 784 
 785     case 10:                                                                                     /* B or BL */
 786     case 11:
 787         mnemonic = _i_b_bl[(instr&(1<<24))>>24];
 788         format   = "&";
 789         break;
 790 
 791     case 12:                                                                                    /* STC or LDC */
 792     case 13:   
 793         if (CP_is(1)) {                                                         /* copro 1: FPU. This is STF or LDF. */
 794             mnemonic = _i_stf_ldf[(instr&Lbit) >> 20];
 795             format   = "8,/";
 796             *flagp++ = "SDEP"[fpn];
 797             poss_tt = (eTargetType)(target_FloatS+fpn);
 798         }
 799         else if (CP_is(2)) {                                                    /* copro 2: this is LFM or SFM. */
 800             mnemonic = _i_sfm_lfm[(instr&Lbit) >> 20];
 801             if (!fpn) fpn=4;
 802             if (RN_is(13) && BitsDiffer(23,24)) {
 803                 if ((instr&255)!=fpn) goto lNonStackLFM;                /* r13 and U!=P, so treat as stack */
 804                 if (BitsDiffer(20,24)) {                                /* L != P, so FD */
 805                     *flagp++ = 'F'; *flagp++ = 'D';
 806                 }
 807                 else {                                                              /* L == P, so EA */
 808                     *flagp++ = 'E'; *flagp++ = 'A';
 809                 }
 810                 format = "8,(,[4]'";
 811             }
 812             else {
 813 lNonStackLFM:                                                                                   /* not r13 or U=P or wrong offset, so don't treat as stack */
 814                 format = "8,(,/";
 815                 poss_tt = target_FloatE;
 816             }
 817         }
 818         else {                                                                          /* some other copro number: STC or LDC. */
 819             mnemonic = _i_stc_ldc[(instr&Lbit) >> 20];
 820             format   = ";,\004,/";
 821             if (instr&(1<<22)) *flagp++ = 'L';
 822             poss_tt = target_Unknown;
 823         }
 824         break;
 825 
 826     case 14:                                                                                    /* CDP or MRC/MCR */
 827         if (instr&(1<<4)) {                                                             /* MRC/MCR. */
 828             if (CP_is(1)) {                                                             /* copro 1: FPU. */
 829                 if ((instr&Lbit) && RD_is(15)) {                        /* MCR in FPU with Rd=r15: comparison (ugh) */
 830                     if (!(instr&(1<<23))) goto lfUndefined;             /* unused operation */
 831                     mnemonic = _i_cmf[(instr&(3<<21)) >> 21];
 832                     format   = "9,+";
 833                     if (instr&((1<<19)+(7<<5)))
 834                         result.badbits=1;                                                       /* size,rmode reseved */
 835                 }
 836                 else {                                                              /* normal FPU MCR/MRC */
 837                     t_value op20 = instr&(15<<20);
 838                     if (op20>=6<<20) goto lgUndefined;
 839                     mnemonic = _i_flt[op20>>20];
 840                     if (op20==0) {                                                   /* FLT instruction */
 841                         format = "9,3";
 842                         { char c = "SDE*"[((instr>>7)&1) + ((instr>>18)&2)];
 843                         if (c=='*') goto lhUndefined; else *flagp++=c;
 844                         }
 845                         if (instr&15) result.oddbits=1;                 /* Fm and const flag unused */
 846                     }
 847                     else {                                                              /* not FLT instruction */
 848                         if (instr&((1<<7)+(1<<19)))
 849                             result.badbits=1;                                           /* size bits reserved */
 850                         if (op20==1<<20) {                              /* FIX instruction */
 851                             format = "3,+";
 852                             if (opts->flags&disopt_FIXS)
 853                                 *flagp++ = "SDEP"[((instr>>7)&1) + ((instr>>18)&2)];
 854                             *flagp++ = "\0PMZ"[(instr&(3<<5))>>5];
 855                             if (instr&(7<<15)) result.oddbits=1;        /* Fn unused */
 856                             if (instr&(1<<3)) result.badbits=1;         /* no immediate consts */
 857                         }
 858                         else {                                                  /* neither FLT nor FIX */
 859                             format = "3";
 860                             if (instr&(3<<5)) result.badbits=1;         /* rmode reserved */
 861                             if (instr&(15+(7<<15))) result.oddbits=1; /* iFm, Fn unused */
 862                         }
 863                     }
 864                 }
 865             }
 866             else {                                                                        /* some other copro number. Not FPU. */
 867                 mnemonic = _i_mcr_mrc[(instr&Lbit)>>20];
 868                 format = ";,:,3,\005,\001-";
 869             }
 870         }
 871         else {                                                                                  /* CDP. */
 872             if (CP_is(1)) {                                                             /* copro 1: FPU. */
 873                 mnemonic = _i_copro[
 874                           ((instr&(15<<20)) >> 20)                      /* opcode   -> bits 5432 */
 875                         + ((instr&(1<<15)) >> 11)];                     /* monadicP -> bit 6 */
 876                 format = (instr&(1<<15)) ? "8,+" : "8,9,+";
 877                 *flagp++ = "SDE*"[((instr>>7)&1) + ((instr>>18)&2)];
 878                 *flagp++ = "\0PMZ"[(instr&(3<<5))>>5];        /* foregoing relies on this being the last flag! */
 879                 if (*mnemonic=='*' || *flagchars=='*') goto liUndefined;
 880             }
 881             else {                                                                                /* some other copro number. Not FPU. */
 882                 mnemonic = "CDP";
 883                 format   = ";,),\004,\005,\001-";
 884             }
 885         }
 886         break;
 887     case 15:                                                                                  /* SWI */
 888        // not used in Canon firmware, treat as data
 889        /*
 890        mnemonic = "SWI";
 891        format   = "$";
 892        break;
 893        */
 894        goto lUndefined;
 895       
 896 
 897 /* Nasty hack: this is code that won't be reached in the normal
 898  * course of events, and after the last case of the switch is a
 899  * convenient place for it.
 900  */
 901 laUndefined:
 902         strcpy(result.text, "Undefined instruction a");           goto lUndefined ;
 903 lbUndefined:
 904         strcpy(result.text, "Undefined instruction b");           goto lUndefined ;
 905 lcUndefined:
 906         strcpy(result.text, "Undefined instruction c");           goto lUndefined ;
 907 ldUndefined:
 908         strcpy(result.text, "Undefined instruction d");           goto lUndefined ;
 909 leUndefined:
 910         strcpy(result.text, "Undefined instruction e");           goto lUndefined ;
 911 lfUndefined:
 912         strcpy(result.text, "Undefined instruction f");           goto lUndefined ;
 913 lgUndefined:
 914         strcpy(result.text, "Undefined instruction g");           goto lUndefined ;
 915 lhUndefined:
 916         strcpy(result.text, "Undefined instruction h");           goto lUndefined ;
 917 liUndefined:
 918         strcpy(result.text, "Undefined instruction i");           goto lUndefined ;
 919 ljUndefined:
 920         strcpy(result.text, "Undefined instruction j");           goto lUndefined ;
 921 lkUndefined:
 922         strcpy(result.text, "Undefined instruction k");           goto lUndefined ;
 923 llUndefined:
 924         strcpy(result.text, "Undefined instruction l");           goto lUndefined ;
 925 lUndefined:       
 926         // treat every undefined instruction as data
 927         /*
 928         result.undefined = 1;
 929             result.instr = instr ;
 930         return &result;
 931         */
 932         result.badbits = 1;     // cause 'erroneous instructions' check below to convert this to data
 933         break;
 934     }
 935 
 936     if (result.oddbits || result.badbits) { // treat erroneous instructions as data
 937         result.instr = instr ;
 938         mnemonic = ".long";
 939         format = "=";
 940         instr = 14 << 28; // no condition code please, see below
 941         result.oddbits = result.badbits = 0; // no need for error display
 942         result.text[0] = flagchars[0] = 0;
 943     }
 944 
 945     *flagp=0;
 946 
 947     /* PHASE 2. Produce string. */
 948 
 949     { char * op = result.text;
 950 
 951     /* 2a. Mnemonic. */
 952 
 953     op = append(op,mnemonic);
 954 
 955     /* 2b. Condition code. */
 956 
 957     {
 958         t_value cond = instr>>28;
 959         if (cond!=14) {
 960             const char * ip = _i_cond[cond];
 961             *op++ = *ip++;
 962             *op++ = *ip;
 963         }
 964     }
 965 
 966     /* 2c. Flags. */
 967 
 968     { const char * ip = flagchars;
 969     while (*ip) *op++ = *ip++;
 970     }
 971 
 972     /* 2d. A tab character. */
 973 
 974     do {
 975         *op++ = ' ';
 976         *op = 0 ;
 977     } while ( strlen( result.text ) < 8 ) ;
 978 
 979     /* 2e. Other stuff, determined by format string. */
 980 
 981     { const char * ip = format;
 982     char c;
 983 
 984     char * * regnames = opts->regnames;
 985     t_value     oflags   = opts->flags;
 986 
 987     while ((c=*ip++) != 0) {
 988         switch(c) {
 989           case '=':
 990             if (((unsigned long)result.instr > (unsigned long)addr) && ((unsigned long)result.instr < (unsigned long)addr+0x1000)) { // looks like a jumptable
 991                 result.addrstart = op;
 992                 op = sub_hex8(fw, op, result.instr);
 993             }
 994             else {
 995                 op = yhex8(fw, op, result.instr);
 996             }
 997             break;
 998     case '$':
 999         result.is_SWI = 1;
1000         result.swinum = instr&0x00FFFFFF;
1001         result.addrstart = op;
1002         if (oflags&disopt_SWInames) {
1003             swiname(result.swinum, op, 128-(op-result.text));
1004             op += strlen(op);
1005         }
1006         else
1007             op += sprintf(op, "&%X", result.swinum);
1008         break;
1009     case '%':
1010         *op++='{';
1011         { t_value w = instr&0xFFFF;
1012         int i=0;
1013         while (w) {
1014             int j;
1015             while (!(w&(1ul<<i))) ++i;
1016             for (j=i+1; w&(1ul<<j); ++j) ;
1017             --j;
1018             /* registers [i..j] */
1019             op = append(op, regnames[i]);
1020             if (j-i) {
1021                 *op++ = (j-i>1) ? '-' : ',';
1022                 op = append(op, regnames[j]);
1023             }
1024             i=j; w=(w>>(j+1))<<(j+1);
1025             if (w) *op++=',';
1026         }
1027         }
1028         *op++='}';
1029         if (instr&(1<<22)) *op++='^';
1030         break;
1031     case '&':
1032         // address target = ((addr+8 + ((((int)instr)<<8)>>6)) & 0x03FFFFFC) | ( addr&0xFC000000) ;
1033         { t_address target = ((t_address) addr ) + 8 + ((t_address) ((((int)instr)<<8) >>6 )) ;
1034         result.addrstart = op;
1035         op = sub_hex8(fw, op, target);
1036         result.target_type = target_Code;
1037         result.target      = target;
1038         }
1039         break;
1040     case '\'':
1041 lPling:
1042         if (instr&Wbit) *op++='!';
1043         break;
1044     case '(':
1045         *op++ = (char)('0'+fpn);
1046         break;
1047     case ')':
1048         { t_value w = (instr>>20)&15;
1049         if (w>=10) { *op++='1'; *op++=(char)('0'-10+w); }
1050         else *op++=(char)(w+'0');
1051         }
1052         break;
1053 
1054     case '*':
1055     case '.':
1056         if (instr&Ibit) {
1057             /* immediate constant */
1058             t_value imm8 = (instr&255);
1059             t_value rot  = (instr>>7)&30;
1060             //if (rot && !(imm8&3) && c=='*') {
1061             //  /* Funny immediate const. Guaranteed not '.', btw */
1062             //  *op++='#'; // *op++='&';
1063             //  *op++='0'; // added in 2.04 to indicate this is a hex value
1064             //  *op++='x'; //   ditto
1065             //  *op++="0123456789ABCDEF"[imm8>>4];
1066             //  *op++="0123456789ABCDEF"[imm8&15];
1067             //  *op++=',';
1068             //  op = num(op, rot, 10);
1069             //}
1070             //else {
1071             imm8 = (imm8>>rot) | (imm8<<(32-rot));
1072             if (c=='*') {
1073                 *op++='#';
1074                 if (imm8>256 && ((imm8&(imm8-1))==0)) {
1075                     /* only one bit set, and that later than bit 8.
1076                     * Represent as 1<<... .
1077                     */
1078                     //op = append(op,"1<<");
1079                     { int n=0;
1080                     while (!(imm8&15)) { n+=4; imm8=imm8>>4; }
1081                     /* Now imm8 is 1, 2, 4 or 8. */
1082                     n += (0x30002010 >> 4*(imm8-1))&15;
1083                     n= 1<<n ;
1084                     op = yhex8(fw, op, n);
1085                     }
1086 
1087                 }
1088                 else {
1089                     if (((int)imm8)<0 && ((int)imm8)>-100) {
1090                         *op++='-'; imm8=-imm8;
1091                     }
1092                     op = num(op, imm8, 10);
1093                 }
1094             }
1095             else {
1096                 t_address a = addr+8;
1097                 if (instr&(1<<22)) a-=imm8; else a+=imm8;
1098                 result.addrstart=op;
1099                 op = xhex8(fw, op, a);
1100                 result.target=a; result.target_type=target_Unknown;
1101             }
1102             //}
1103         }
1104         else {
1105             /* rotated register */
1106             const char * rot = _i_lsl_lsr[(instr&(3<<5)) >> 5];
1107             op = append(op, regnames[instr&15]);
1108             if (instr&(1<<4)) {
1109                 /* register rotation */
1110                 if (instr&(1<<7)) goto ljUndefined;
1111                 *op++=','; if (oflags&disopt_CommaSpace) *op++=' ';
1112                 op = append(op,rot); *op++=' ';
1113                 op = append(op,regnames[(instr&(15<<8))>>8]);
1114             }
1115             else {
1116                 /* constant rotation */
1117                 t_value n = instr&(31<<7);
1118                 if (!n) {
1119                     if (!(instr&(3<<5))) break;
1120                     else if ((instr&(3<<5))==(3<<5)) {
1121                         op = append(op, ",RRX");
1122                         break;
1123                     }
1124                     else n=32<<7;
1125                 }
1126                 *op++ = ','; if (oflags&disopt_CommaSpace) *op++=' ';
1127                 op = num(append(append(op,rot),"#"),n>>7,32);
1128             }
1129         }
1130         break;
1131     case '+':
1132         if (instr&(1<<3)) {
1133             t_value w = instr&7;
1134             *op++='#';
1135             if (w<6) *op++=(char)('0'+w);
1136             else op = append(op, w==6 ? "0.5" : "10");
1137         }
1138         else {
1139             *op++='f';
1140             *op++=(char)('0'+(instr&7));
1141         }
1142         break;
1143     case ',':
1144         *op++=',';
1145         if (oflags&disopt_CommaSpace) *op++=' ';
1146         break;
1147     case '-':
1148         { t_value w = instr&(7<<5);
1149         if (w) {
1150             *op++=',';
1151             if (oflags&disopt_CommaSpace) *op++=' ';
1152             *op++ = (char)('0'+(w>>5));
1153         }
1154         }
1155         break;
1156     case '/':
1157         result.addrstart = op;
1158         *op++='[';
1159 
1160         op = append(op, regnames[(instr&RNbits)>>16]);
1161 
1162         if (!(instr&Pbit)) *op++=']';
1163 
1164         *op++=','; 
1165 
1166         if (oflags&disopt_CommaSpace) *op++=' ';
1167 
1168         /* For following, NB that bit 25 is always 0 for LDC, SFM etc */
1169         if (instr&Ibit) {
1170             /* shifted offset */
1171             if (!(instr&Ubit)) *op++='-';
1172             /* We're going to transfer to '*', basically. The stupid
1173             * thing is that the meaning of bit 25 is reversed there;
1174             * I don't know why the designers of the ARM did that.
1175             */
1176             instr ^= Ibit;
1177             if (instr&(1<<4)) {
1178 
1179                 if (is_v4 && !(instr&(15<<8))) {
1180                     ip = (instr&Pbit) ? "0]" : "0";
1181                     break;
1182                 }
1183             }
1184             /* Need a ] iff it was pre-indexed; and an optional ! iff
1185             * it's pre-indexed *or* a copro instruction,
1186             * except that FPU operations don't need the !. Bletch.
1187             */
1188             if (instr&Pbit) ip="*]'";
1189             else if (instr&(1<<27)) {
1190                 if (CP_is(1) || CP_is(2)) {
1191                     if (!(instr&Wbit)) goto lkUndefined;
1192                     ip="*";
1193                 }
1194                 else ip="*'";
1195             }
1196             else ip="*";
1197         }
1198         else {
1199             /* immediate offset */
1200             t_value offset;
1201             if (instr&(1<<27)) {      /* LDF or LFM or similar */
1202                 offset = (instr&255)<<2;
1203             }
1204 
1205             else if (is_v4) offset = (instr&15) + ((instr&(15<<8))>>4);
1206             else {            /* LDR or STR */
1207                 offset = instr&0xFFF;
1208             }
1209 
1210             if ( offset == 0 ){
1211                 if (oflags&disopt_CommaSpace) op-- ;
1212                 op-- ; *op++=']'; goto lPling; }
1213 
1214             *op++='#';
1215             if (!(instr&Ubit)) 
1216             {
1217                 if (offset) *op++='-';
1218                 else result.oddbits=1;
1219                 result.offset = -offset;
1220             }
1221             else result.offset = offset;
1222 
1223             op = num(op, offset, 10);
1224             if (RN_is(15) && (instr&Pbit)) 
1225             {
1226                 /* Immediate, pre-indexed and PC-relative. Set target. */
1227                 result.target_type = poss_tt;
1228                 result.target      = (instr&Ubit) ? addr+8 + offset
1229                     : addr+8 - offset;
1230                 if (!(instr&Wbit)) 
1231                 {
1232                     /* no writeback, either. Use friendly form. */
1233                     if (RD_is(15))
1234                         op = sub_ahex8(fw, result.addrstart, result.target);
1235                     else
1236                     op = ahex8(fw, result.addrstart, result.target);
1237                     break;
1238                 }
1239             }
1240             if (instr&Pbit) { *op++=']'; goto lPling; }
1241             else if (instr&(1<<27)) {
1242                 if (CP_is(1) || CP_is(2)) {
1243                     if (!(instr&Wbit)) goto llUndefined;
1244                 }
1245                 else goto lPling;
1246             }
1247         }
1248         break;
1249 
1250     case '0': case '1': case '2': case '3': case '4':
1251         op = append(op, regnames[(instr>>(4*(c-'0')))&15]);
1252         break;
1253     case '5': case '6': case '7': case '8': case '9':
1254         *op++='f';
1255         *op++=(char)('0' + ((instr>>(4*(c-'5')))&7));
1256         break;
1257     case ':':
1258         *op++ = (char)('0' + ((instr>>21)&7));
1259         break;
1260     case ';':
1261         op = reg(op, 'p', instr>>8);
1262         break;
1263     default:
1264         if (c<=5)
1265             op = reg(op, 'c', instr >> (4*(c-1)));
1266         else *op++ = c;
1267         }
1268     }
1269     *op=0;
1270     }
1271     }
1272 
1273     /* DONE! */
1274 
1275     return &result;
1276 }
1277 
1278 //------------------------------------------------------------------------------------------------------------
1279 t_address addr, last_used_addr;
1280 
1281 void disassemble1(firmware *fw, t_address start, t_value length)
1282 {
1283     t_value w;
1284 
1285     free(dcd_list);
1286     dcd_list = new_list();
1287     free(branch_list);
1288     branch_list = new_list();
1289 
1290     // Do three passes; but don't generate any code
1291     int pass;
1292     for ( pass = 1 ; pass <=3 ; pass++ )
1293     {
1294         if ( pass == 2 ) 
1295         {
1296             struct lnode* lptr = dcd_list->head;
1297             while ( lptr != NULL  ) 
1298             {           
1299                 addr = (t_address) lptr->address ;
1300                 w = fwval(fw,adr2idx(fw,addr));
1301                 lptr->data = w ;
1302                 lptr = lptr->next ;
1303             }
1304         }
1305         else    // pass 1 & 3
1306         {
1307             addr = start ;
1308             t_value word_count = 0 ;
1309 
1310             while (word_count < length )
1311             {
1312                 w = fwval(fw,adr2idx(fw,addr));
1313                 instr_disassemble(fw, w, addr, &options);
1314 
1315                 struct lnode* lptr = l_search(dcd_list,addr);
1316                 if (!lptr) 
1317                     last_used_addr = addr;
1318 
1319                 word_count++ ;
1320                 addr += 4;
1321             }
1322         }
1323     }
1324 }
1325 
1326 void disassemble(firmware *fw, FILE *outfile, t_address start, t_value length)
1327 {
1328     t_value w;
1329 
1330     int dcd_mode_on = 0;
1331 
1332     // Only need 1 pass here - assumes disassemble1 called previously
1333     addr = start ;
1334     t_value word_count = 0 ;
1335 
1336     while (word_count < length )
1337     {
1338         w = fwval(fw,adr2idx(fw,addr));
1339 
1340         pInstruction instr = instr_disassemble(fw, w, addr, &options);
1341 
1342         if (l_search(branch_list, addr))
1343         {
1344             fprintf(outfile,"\n\"loc_%08X:\\n\"\n", addr);
1345             dcd_mode_on = 0;
1346         }       
1347         struct lnode* lptr = l_search(dcd_list,addr);
1348         if ( lptr  || dcd_mode_on ) 
1349         {
1350             if ((options.flags & disopt_exclude_dcd) == 0)
1351                 fprintf(outfile,"\"dword_%8.8X  DCD 0x%X \\n\"\n", addr , w);
1352             dcd_mode_on = 1;
1353             /*
1354             t_value aword ;
1355             int i ;
1356             unsigned char ch ;
1357             aword = lptr->data ;
1358             for ( i=0 ; i< 4 ; i++ )
1359             {
1360             ch = aword & 0xFF ;
1361             if ( (ch>=0x20) && ( ch < 0x80) ) fprintf(outfile," %c" , ch );
1362             else fprintf(outfile,"_" );
1363             aword = aword >> 8 ;
1364             }
1365             fprintf(outfile, "\n" ) ;
1366             */
1367         }       
1368         else 
1369         {
1370             if (instr->undefined || instr->badbits || instr->oddbits) {
1371                 fprintf(outfile,"Error: ");
1372                 if (instr->undefined) fprintf(outfile,"[---undefined instr---] 0x%8.8X     ", w);
1373                 if (instr->badbits) fprintf(outfile,  "[---illegal bits---] 0x%8.8X        ", w);
1374                 if (instr->oddbits) fprintf(outfile,  "[---unexpected bits---] 0x%8.8X     ", w);
1375                 if ( !((instr->undefined) || (instr->badbits) || (instr->oddbits)) ) 
1376                     fprintf(outfile,  "[---unknown error---] 0x%8.8X       ", w);
1377                 if ( options.flags & disopt_print_address_mode)
1378                 {
1379                     fprintf(outfile,"// rom:%.8x  0x%8.8X \n", addr, w);
1380                 }                                                               
1381                 else fprintf(outfile,"\n");                                                                                                     
1382             }
1383             else
1384             {
1385                 strcat( instr->text, " \\n\"") ;
1386                 if (options.flags & disopt_line_numbers) fprintf(outfile,"/*%3d*/",(addr - options.start_address) / 4 + 1);
1387                 char *indent = "\"    ";
1388                 if (options.flags & (disopt_comment_lines|disopt_nullsub_call))
1389                     indent = "//\"  ";
1390                 if (options.flags & disopt_indent_mneumonics_mode)
1391                     fprintf(outfile,"      ");
1392                 if (options.flags & disopt_print_address_mode)
1393                 {
1394                     fprintf(outfile,"%s%-40s // rom:%.8x  0x%8.8X", indent, instr->text, addr, w);
1395                 }                                                               
1396                 else fprintf(outfile,"%s%s", indent, instr->text);
1397 
1398                 if ((options.flags & disopt_patch_branch) || (options.flags & disopt_patch_value))
1399                 {
1400                     if (patch_old_func_name)
1401                         fprintf(outfile,"  // --> Patched. Old value = _%s.", patch_old_func_name);
1402                     else
1403                         fprintf(outfile,"  // --> Patched. Old value = 0x%X.", patch_old_val);
1404                     if ((options.flags & disopt_patch_comment) && patch_comment)
1405                     {
1406                         fprintf(outfile, " %s", patch_comment);
1407                         patch_comment = 0;
1408                     }
1409                 }
1410                 else if ((options.flags & disopt_patch_comment) && patch_comment)
1411                 {
1412                     fprintf(outfile, "  // %s", patch_comment);
1413                     patch_comment = 0;
1414                 }
1415                 else if (options.flags & disopt_nullsub_call)
1416                 {
1417                     fprintf(outfile,"  // --> Nullsub call removed.");
1418                 }
1419                 fprintf(outfile,"\n");
1420             }
1421         }
1422 
1423         word_count++ ;
1424         addr += 4;
1425     }
1426 }
1427 
1428 t_address find_end(firmware *fw, t_address start)
1429 {
1430     int i;
1431     start = adr2idx(fw,start);
1432     for (i=0; i<500; i++, start++)
1433         if ((fwval(fw,start+1) & 0xFFFF4000) == 0xE92D4000)  // STMFD SP!, {...,LR}
1434         {
1435             int j;
1436             for (j=0; j<50; j++, start--)
1437             {
1438                 if ((fwval(fw,start) & 0xFF000000) == 0xEA000000)  // B
1439                 {
1440                     return idx2adr(fw,start);
1441                 }
1442                 if ((fwval(fw,start) & 0xFFFF8000) == 0xE8BD8000)  // LDMFD SP!, {...,PC}
1443                 {
1444                     return idx2adr(fw,start);
1445                 }
1446                 if ((fwval(fw,start) & 0xFFFFFFF0) == 0xE12FFF10)  // BX
1447                 {
1448                     return idx2adr(fw,start);
1449                 }
1450                 if ((fwval(fw,start) & 0xFFFFF000) == 0xE49DF000)  // LDR PC,[SP,...
1451                 {
1452                     return idx2adr(fw,start);
1453                 }
1454             }
1455             return 0;
1456         }
1457     return 0;
1458 }
1459 
1460 //------------------------------------------------------------------------------------------------------------
1461 
1462 void swiname(t_value w, char * s, size_t sz) { return; }
1463 
1464 //------------------------------------------------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */