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     // If call to Branch then follow branch; but only if original branch is in main FW (not code copied to RAM)
 398     if (w >= fw->base)
 399         w = followBranch(fw,w,1);
 400     osig *o = find_sig_val_by_type(fw->sv->stubs, w, TYPE_NHSTUB);
 401 
 402     if ((options.flags & disopt_patch_branch) && patch_func_name)
 403     {
 404         set_patch_old_values(w, (o) ? o->nm : 0);
 405         op += sprintf(op,"%s",patch_func_name);
 406     }
 407     else
 408     {
 409         if (o && !o->is_comment)
 410         {
 411             op += sprintf(op,"_%s",o->nm);
 412         }
 413         else
 414         {
 415             if (( w >= options.start_address )&&( w <= options.end_address ))
 416             {
 417                 op += sprintf(op,"loc_%08X",w);
 418             }
 419             else
 420             {
 421                 if (options.flags & disopt_comment_lines)
 422                     op += sprintf(op,"_sub_%08X",w);     // prevent sub from appearing in stubs_auto.S
 423                 else
 424                 {
 425                     // Get 1st instruction in sub_XXXXXXXX
 426                     t_value v = fwval(fw,adr2idx(fw,w));
 427                     if (v == 0xE12FFF1E)    // BX LR?
 428                     {
 429                         // Comment out 'nullsub' calls
 430                         op += sprintf(op,"_sub_%08X",w);
 431                         options.flags |= disopt_nullsub_call;
 432                     }
 433                     else
 434                     {
 435                         op += sprintf(op,"sub_%08X",w);
 436                         if (o && o->is_comment)
 437                         op += sprintf(op," /*_%s*/",o->nm);
 438                     }
 439                 }
 440             }
 441             if (options.flags & disopt_patch_branch)
 442             {
 443                 set_patch_old_values(w, 0);
 444                 op += sprintf(op,"_my");
 445             }
 446         }
 447     }
 448 
 449     if ((save_patch_ref >= 0) && (options.flags & disopt_patch_branch))
 450     {
 451         *op = 0;
 452         patch_ref_address[save_patch_ref] = w;
 453         strcpy(patch_ref_name[save_patch_ref],s);
 454     }
 455 
 456     return op;
 457 }
 458 
 459 static char * sub_ahex8(firmware *fw, char * op, t_value w)
 460 {
 461     struct lnode * lptr ;
 462     lptr = l_search( dcd_list, w) ;             // does this DCD address exist already ?
 463 
 464     if ( !lptr )
 465         l_insert(dcd_list, w, 0) ;      // add node if not found - typically on pass 1
 466 
 467     w = fwval(fw,adr2idx(fw,w));
 468     return sub_hex8(fw, op, w);
 469 }
 470 
 471 /* op = reg(op,'x',n) === op += sprintf(op,"x%lu",n&15).
 472  */
 473 static char * reg(char * op, char c, t_value n) {
 474     *op++=c;
 475     n&=15;
 476     if (n>=10) { *op++='1'; n+='0'-10; } else n+='0';
 477     *op++=(char)n;
 478 
 479     return op;
 480 }
 481 
 482 /* op = num(op,n) appends n in decimal or &n in hex
 483  * depending on whether n<decmax. It's assumed that n>=0.
 484  */
 485 static char * num(char * op, t_value w, int decmax)
 486 {
 487     char tmpbuf[16] ;
 488     char * tptr ;
 489     tptr = tmpbuf ;
 490 
 491     if (options.flags & disopt_patch_value)
 492     {
 493         set_patch_old_values(w, 0);
 494         w = patch_new_val;
 495     }
 496 
 497     if ( w<decmax ) sprintf( tptr, "%d", w) ;
 498     else
 499     {
 500         if (w < 16)
 501             sprintf( tptr, "0x%X", w);
 502         else
 503             sprintf( tptr, "0x%X", w);
 504     }
 505     tptr = tmpbuf ;
 506     while(*tptr) *op++ = *tptr++ ;
 507     return op;
 508 }
 509 
 510 /* instr_disassemble
 511  * Disassemble a single instruction.
 512  *
 513  * args:   instr   a single ARM instruction
 514  *         addr    the address it's presumed to have come from
 515  *         opts    cosmetic preferences for our output
 516  *
 517  * reqs:   opts must be filled in right. In particular, it must contain
 518  *         a list of register names.
 519  *
 520  * return: a pointer to a structure containing the disassembled instruction
 521  *         and some other information about it.
 522  *
 523  *
 524  * This function proceeds in two phases. The first is very simple:
 525  * it works out what sort of instruction it's looking at and sets up
 526  * three strings:
 527  *   - |mnemonic|  (the basic mnemonic: LDR or whatever)
 528  *   - |flagchars| (things to go after the cond code: B or whatever)
 529  *   - |format|    (a string describing how to display the instruction)
 530  
 531  * The second phase consists of interpreting |format|, character by
 532  * character. Some characters (e.g., letters) just mean `append this
 533  * character to the output string'; some mean more complicated things
 534  * like `append the name of the register whose number is in bits 12..15'
 535  * or, worse, `append a description of the <op2> field'.
 536  *
 537  * I'm afraid the magic characters in |format| are rather arbitrary.
 538  * One criterion in choosing them was that they should form a contiguous
 539  * subrange of the character set! Sorry.
 540  *
 541  * Format characters:
 542  *
 543  *   \01..\05 copro register number from nybble (\001 == nybble 0, sorry)
 544  *   $        SWI number
 545  *   %        register set for LDM/STM (takes note of bit 22 for ^)
 546  *   &        address for B/BL
 547  *   '        ! if bit 21 set, else nothing (mnemonic: half a !)
 548  *   (        #regs for SFM (bits 22,15 = fpn, assumed already tweaked)
 549  *   )        copro opcode in bits 20..23 (for CDP)
 550  *   *        op2 (takes note of bottom 12 bits, and bit 25)
 551  *   +        FP register or immediate value: bits 0..3
 552  *   ,        comma or comma-space
 553  *   -        copro extra info in bits 5..7 preceded by , omitted if 0
 554  *   .        address in ADR instruction
 555  *   /        address for LDR/STR (takes note of bit 23 & reg in bits 16..19)
 556  *   0..4     register number from nybble
 557  *   5..9     FP register number from nybble
 558  *   :        copro opcode in bits 21..23 (for MRC/MCR)
 559  *   ;        copro number in bits 8..11
 560  *   =        32 constant (address or data)
 561  *
 562  * NB that / takes note of bit 22, too, and does its own ! when appropriate.
 563  *
 564  */
 565 
 566 
 567 extern pInstruction instr_disassemble(firmware *fw, t_value instr, t_address addr, pDisOptions opts) {
 568     static char         flagchars[4];
 569     static sInstruction result;
 570     const char * mnemonic  = 0;
 571     char * flagp     = flagchars;
 572     const char * format    = 0;
 573     t_value         fpn;
 574     eTargetType  poss_tt = target_None;
 575     int is_v4 = 0;
 576 
 577     options.flags &= ~disopt_nullsub_call;
 578 
 579     /* PHASE 0. Set up default values for |result|. */
 580 
 581     fpn = ((instr>>15)&1) + ((instr>>21)&2);
 582 
 583     result.undefined =
 584         result.badbits =
 585         result.oddbits =
 586         result.instr =
 587         result.is_SWI = 0;
 588     result.target_type = target_None;
 589     result.offset = 0x80000000;
 590     result.addrstart = 0;
 591 
 592     /* PHASE 1. Decode and classify instruction. */
 593     static char _i_mul[4][6] = { "UMULL", "UMLAL", "SMULL", "SMLAL" };
 594     static char _i_ldr_str[2][4] = { "LDR", "STR" };
 595     static char _i_str_ldr[2][4] = { "STR", "LDR" };
 596     static char _i_stm_ldm[2][4] = { "STM", "LDM" };
 597     static char _i_stf_ldf[2][4] = { "STF", "LDF" };
 598     static char _i_stc_ldc[2][4] = { "STC", "LDC" };
 599     static char _i_sfm_lfm[2][4] = { "SFM", "LFM" };
 600     static char _i_b_bl[2][3] = { "B", "BL" };
 601     static char _i_alu[16][4] = {
 602         "AND","EOR","SUB","RSB","ADD","ADC","SBC","RSC",
 603         "TST","TEQ","CMP","CMN","ORR","MOV","BIC","MVN"
 604     };
 605     static char _i_cmf[4][5] = { "CMF","CNF","CMFE","CNFE" };
 606     static char _i_flt[6][4] = { "FLT","FIX","WFS","RFS","WFC","RFC" };
 607     static char _i_mcr_mrc[2][4] = { "MCR","MRC" };
 608     static char _i_copro[32][4] = {
 609         /* dyadics: */
 610         "ADF","MUF","SUF","RSF",
 611         "DVF","RDF","POW","RPW",
 612         "RMF","FML","FDV","FRD",
 613         "POL","***","***","***",
 614         /* monadics: */
 615         "MVF","MNF","ABS","RND",
 616         "SQT","LOG","LGN","EXP",
 617         "SIN","COS","TAN","ASN",
 618         "ACS","ATN","URD","NRM"
 619     };
 620     static char _i_lsl_lsr[4][4] = { "LSL","LSR","ASR","ROR" };
 621     static char _i_stk[4][2] = { "ED","EA","FD","FA" };
 622     static char _i_cond[16][2] = { "EQ","NE","CS","CC","MI","PL","VS","VC","HI","LS","GE","LT","GT","LE","AL","NV" };
 623 
 624     switch ((instr>>24)&15) {
 625 
 626     case 0:                                             /* multiply or data processing, or LDRH etc */
 627         if ((instr&(15<<4))!=(9<<4)) goto lMaybeLDRHetc;   // F0  90
 628 
 629         if (instr&(1<<23)) {                    /* long multiply */
 630             mnemonic = _i_mul[(instr>>21)&3];
 631             format = "3,4,0,2";
 632         }
 633         else {                                          
 634             if (instr&(1<<22)) goto laUndefined;        /* "class C" */
 635 
 636             if (instr&(1<<21)) {                /* short multiply */
 637                 mnemonic = "MLA";
 638                 format   = "4,0,2,3";
 639             }
 640             else {
 641                 mnemonic = "MUL";
 642                 format   = "4,0,2";
 643             }
 644         }
 645         if (instr&Sbit) *flagp++='S';
 646         break;
 647 
 648     case 1:                                     /* SWP or MRS/MSR or BX or data processing */
 649     case 3:
 650 
 651         if ((instr&0x0FF000F0)==0x01200010) {                   /* BX */
 652             mnemonic = "BX";
 653             format = "0";
 654             break;
 655         }
 656         if ((instr&0x0FF000F0)==0x01200030) {              /* BLX */
 657             mnemonic = "BLX";
 658             format = "0";
 659             break;
 660         }
 661         if ((instr&0x02B00FF0)==0x00000090) {        /* SWP */
 662             mnemonic = "SWP";
 663             format   = "3,0,[4]";
 664             if (instr&Bbit) *flagp++='B';
 665             break;
 666         }
 667         if ((instr&0x02BF0FFF)==0x000F0000) {        /* MRS */
 668             mnemonic = "MRS";
 669             format   = (instr&SPSRbit) ? "3,SPSR" : "3,CPSR";
 670             break;
 671         }
 672 
 673         if ((instr&0x0FB00010)==0x03200000) {      /* MSR psr<P=0/1...>,Rm */
 674             mnemonic = "MSR";
 675             format   = (instr&SPSRbit) ? "SPSR,0" : "CPSR,0";
 676             break;
 677         }
 678 
 679         if ((instr&0x0FB00010)==0x01200000) {     /* MSR {C,S}PSR_flag,op2 */
 680             mnemonic = "MSR";
 681             format   = (instr&SPSRbit) ? "SPSR_cxsf,*" : "CPSR_cxsf,*";
 682             if (!(instr&Ibit) && (instr&(15<<4)))
 683                 goto lMaybeLDRHetc;
 684             break;
 685         }
 686 
 687 
 688 lMaybeLDRHetc:                                                                                                  /* fall through here */
 689         if ( (instr&(14<<24))==0 && ((instr&(9<<4))==(9<<4)) ) 
 690         {                                                                                                               /* Might well be LDRH or similar. */
 691             if ((instr&(Wbit+Pbit))==Wbit) goto lbUndefined;            /* "class E", case 1 */
 692             if ((instr&(Lbit+(1<<6)))==(1<<6))                                          /* is it LDRD/STRD or LDRSH/STRSH */
 693             {
 694                 if ((instr&(1<<6))!=(1<<6))     goto lcUndefined ;
 695                 mnemonic = _i_ldr_str[(instr & 0x0000020) >> 5];    /*  */
 696                 if (instr&(1<<6)) *flagp++='D';
 697                 format = "3,/";
 698                 if (!(instr&(1<<22))) instr |= Ibit;
 699                 is_v4=1;
 700             }
 701             else
 702             {
 703                 mnemonic = _i_str_ldr[(instr&Lbit) >> 20];
 704                 if (instr&(1<<6)) *flagp++='S';
 705                 *flagp++ = (instr&(1<<5)) ? 'H' : 'B';                                  /* fixed 2011/03/27 - B & H reversed */
 706                 format = "3,/";                                                                         /* aargh: */
 707                 if (!(instr&(1<<22))) instr |= Ibit;
 708                 is_v4=1;
 709             }
 710             break;
 711         }
 712 
 713     case 2:                                                                                                   /* data processing */
 714         { t_value op21 = instr&(15<<21);
 715         if ((op21==(2<<21) || (op21==(4<<21)))                          /* ADD or SUB */
 716             && ((instr&(RNbits+Ibit+Sbit))==RN(15)+Ibit)        /* imm, no S */
 717             /*&& ((instr&(30<<7))==0 || (instr&3))*/) {         /* normal rot */
 718                 /* ADD ...,pc,#... or SUB ...,pc,#...: turn into ADR */
 719                 mnemonic = "LDR";                                                                       //** 2011/03/27 changed from "ADR" to "LDR" for gcc assembler compatability 
 720                 format   = "3,.";
 721                 if ((instr&(30<<7))!=0 && !(instr&3)) result.oddbits=1;
 722                 break;
 723         }
 724         if ((op21==(4<<21))                                                 /* ADD */
 725             && ((instr&(Ibit))==Ibit)                           /* imm */
 726             && ((instr&0xFFF)==0)                           /* 0 offset */
 727             ) {
 728                 /* ADD Rn, Rd, #0 --> MOV */
 729                 mnemonic = "MOV";
 730                 format   = "3,4";
 731                 if (instr&Sbit && (op21<(8<<21) || op21>=(12<<21))) *flagp++='S';
 732                 break;
 733         }
 734         mnemonic = _i_alu[op21 >> 21];
 735         /* Rd needed for all but TST,TEQ,CMP,CMN (8..11) */
 736         /* Rn needed for all but MOV,MVN (13,15) */
 737         if (op21 < ( 8<<21)) format = "3,4,*";
 738         else if (op21 < (12<<21)) {
 739             format = "4,*";
 740             if (instr&RDbits) {
 741                 if ((instr&Sbit) && RD_is(15))
 742                     *flagp++='P';
 743                 else result.oddbits=1;
 744             }
 745             if (!(instr&Sbit)) goto ldUndefined;        /* CMP etc, no S bit */
 746         }
 747         else if (op21 & (1<<21)) {
 748             format = "3,*";
 749             if (instr&RNbits) result.oddbits=1;
 750         }
 751         else format = "3,4,*";
 752         if (instr&Sbit && (op21<(8<<21) || op21>=(12<<21))) *flagp++='S';
 753         }
 754         break;
 755 
 756     case 4:                                                                  /* undefined or STR/LDR */
 757     case 5:
 758     case 6:
 759     case 7:
 760         if ((instr&Ibit) && (instr&(1<<4))) goto leUndefined;   /* "class A" */
 761         mnemonic = _i_str_ldr[(instr&Lbit) >> 20];
 762         format   = "3,/";
 763         if (instr&Bbit) *flagp++='B';
 764         if ((instr&(Wbit+Pbit))==Wbit) *flagp++='T';
 765         poss_tt = target_Data;
 766         break;
 767 
 768     case 8:                                                                                              /* STM/LDM */
 769     case 9:
 770         mnemonic = _i_stm_ldm[(instr&Lbit) >> 20];
 771         if (RN_is(13)) {                                                                /* r13, so treat as stack */
 772             t_value x = (instr&(3<<23)) >> 23;
 773             if (instr&Lbit) x^=3;
 774             {
 775                 const char * foo = _i_stk[x];
 776                 *flagp++ = *foo++;
 777                 *flagp++ = *foo;
 778             }
 779         }
 780         else {                                                                          /* not r13, so don't treat as stack */
 781             *flagp++ = (instr&Ubit) ? 'I' : 'D';
 782             *flagp++ = (instr&Pbit) ? 'B' : 'A';
 783         }
 784         format = "4',%";
 785         break;
 786 
 787     case 10:                                                                                     /* B or BL */
 788     case 11:
 789         mnemonic = _i_b_bl[(instr&(1<<24))>>24];
 790         format   = "&";
 791         break;
 792 
 793     case 12:                                                                                    /* STC or LDC */
 794     case 13:   
 795         if (CP_is(1)) {                                                         /* copro 1: FPU. This is STF or LDF. */
 796             mnemonic = _i_stf_ldf[(instr&Lbit) >> 20];
 797             format   = "8,/";
 798             *flagp++ = "SDEP"[fpn];
 799             poss_tt = (eTargetType)(target_FloatS+fpn);
 800         }
 801         else if (CP_is(2)) {                                                    /* copro 2: this is LFM or SFM. */
 802             mnemonic = _i_sfm_lfm[(instr&Lbit) >> 20];
 803             if (!fpn) fpn=4;
 804             if (RN_is(13) && BitsDiffer(23,24)) {
 805                 if ((instr&255)!=fpn) goto lNonStackLFM;                /* r13 and U!=P, so treat as stack */
 806                 if (BitsDiffer(20,24)) {                                /* L != P, so FD */
 807                     *flagp++ = 'F'; *flagp++ = 'D';
 808                 }
 809                 else {                                                              /* L == P, so EA */
 810                     *flagp++ = 'E'; *flagp++ = 'A';
 811                 }
 812                 format = "8,(,[4]'";
 813             }
 814             else {
 815 lNonStackLFM:                                                                                   /* not r13 or U=P or wrong offset, so don't treat as stack */
 816                 format = "8,(,/";
 817                 poss_tt = target_FloatE;
 818             }
 819         }
 820         else {                                                                          /* some other copro number: STC or LDC. */
 821             mnemonic = _i_stc_ldc[(instr&Lbit) >> 20];
 822             format   = ";,\004,/";
 823             if (instr&(1<<22)) *flagp++ = 'L';
 824             poss_tt = target_Unknown;
 825         }
 826         break;
 827 
 828     case 14:                                                                                    /* CDP or MRC/MCR */
 829         if (instr&(1<<4)) {                                                             /* MRC/MCR. */
 830             if (CP_is(1)) {                                                             /* copro 1: FPU. */
 831                 if ((instr&Lbit) && RD_is(15)) {                        /* MCR in FPU with Rd=r15: comparison (ugh) */
 832                     if (!(instr&(1<<23))) goto lfUndefined;             /* unused operation */
 833                     mnemonic = _i_cmf[(instr&(3<<21)) >> 21];
 834                     format   = "9,+";
 835                     if (instr&((1<<19)+(7<<5)))
 836                         result.badbits=1;                                                       /* size,rmode reseved */
 837                 }
 838                 else {                                                              /* normal FPU MCR/MRC */
 839                     t_value op20 = instr&(15<<20);
 840                     if (op20>=6<<20) goto lgUndefined;
 841                     mnemonic = _i_flt[op20>>20];
 842                     if (op20==0) {                                                   /* FLT instruction */
 843                         format = "9,3";
 844                         { char c = "SDE*"[((instr>>7)&1) + ((instr>>18)&2)];
 845                         if (c=='*') goto lhUndefined; else *flagp++=c;
 846                         }
 847                         if (instr&15) result.oddbits=1;                 /* Fm and const flag unused */
 848                     }
 849                     else {                                                              /* not FLT instruction */
 850                         if (instr&((1<<7)+(1<<19)))
 851                             result.badbits=1;                                           /* size bits reserved */
 852                         if (op20==1<<20) {                              /* FIX instruction */
 853                             format = "3,+";
 854                             if (opts->flags&disopt_FIXS)
 855                                 *flagp++ = "SDEP"[((instr>>7)&1) + ((instr>>18)&2)];
 856                             *flagp++ = "\0PMZ"[(instr&(3<<5))>>5];
 857                             if (instr&(7<<15)) result.oddbits=1;        /* Fn unused */
 858                             if (instr&(1<<3)) result.badbits=1;         /* no immediate consts */
 859                         }
 860                         else {                                                  /* neither FLT nor FIX */
 861                             format = "3";
 862                             if (instr&(3<<5)) result.badbits=1;         /* rmode reserved */
 863                             if (instr&(15+(7<<15))) result.oddbits=1; /* iFm, Fn unused */
 864                         }
 865                     }
 866                 }
 867             }
 868             else {                                                                        /* some other copro number. Not FPU. */
 869                 mnemonic = _i_mcr_mrc[(instr&Lbit)>>20];
 870                 format = ";,:,3,\005,\001-";
 871             }
 872         }
 873         else {                                                                                  /* CDP. */
 874             if (CP_is(1)) {                                                             /* copro 1: FPU. */
 875                 mnemonic = _i_copro[
 876                           ((instr&(15<<20)) >> 20)                      /* opcode   -> bits 5432 */
 877                         + ((instr&(1<<15)) >> 11)];                     /* monadicP -> bit 6 */
 878                 format = (instr&(1<<15)) ? "8,+" : "8,9,+";
 879                 *flagp++ = "SDE*"[((instr>>7)&1) + ((instr>>18)&2)];
 880                 *flagp++ = "\0PMZ"[(instr&(3<<5))>>5];        /* foregoing relies on this being the last flag! */
 881                 if (*mnemonic=='*' || *flagchars=='*') goto liUndefined;
 882             }
 883             else {                                                                                /* some other copro number. Not FPU. */
 884                 mnemonic = "CDP";
 885                 format   = ";,),\004,\005,\001-";
 886             }
 887         }
 888         break;
 889     case 15:                                                                                  /* SWI */
 890        // not used in Canon firmware, treat as data
 891        /*
 892        mnemonic = "SWI";
 893        format   = "$";
 894        break;
 895        */
 896        goto lUndefined;
 897       
 898 
 899 /* Nasty hack: this is code that won't be reached in the normal
 900  * course of events, and after the last case of the switch is a
 901  * convenient place for it.
 902  */
 903 laUndefined:
 904         strcpy(result.text, "Undefined instruction a");           goto lUndefined ;
 905 lbUndefined:
 906         strcpy(result.text, "Undefined instruction b");           goto lUndefined ;
 907 lcUndefined:
 908         strcpy(result.text, "Undefined instruction c");           goto lUndefined ;
 909 ldUndefined:
 910         strcpy(result.text, "Undefined instruction d");           goto lUndefined ;
 911 leUndefined:
 912         strcpy(result.text, "Undefined instruction e");           goto lUndefined ;
 913 lfUndefined:
 914         strcpy(result.text, "Undefined instruction f");           goto lUndefined ;
 915 lgUndefined:
 916         strcpy(result.text, "Undefined instruction g");           goto lUndefined ;
 917 lhUndefined:
 918         strcpy(result.text, "Undefined instruction h");           goto lUndefined ;
 919 liUndefined:
 920         strcpy(result.text, "Undefined instruction i");           goto lUndefined ;
 921 ljUndefined:
 922         strcpy(result.text, "Undefined instruction j");           goto lUndefined ;
 923 lkUndefined:
 924         strcpy(result.text, "Undefined instruction k");           goto lUndefined ;
 925 llUndefined:
 926         strcpy(result.text, "Undefined instruction l");           goto lUndefined ;
 927 lUndefined:       
 928         // treat every undefined instruction as data
 929         /*
 930         result.undefined = 1;
 931             result.instr = instr ;
 932         return &result;
 933         */
 934         result.badbits = 1;     // cause 'erroneous instructions' check below to convert this to data
 935         break;
 936     }
 937 
 938     if (result.oddbits || result.badbits) { // treat erroneous instructions as data
 939         result.instr = instr ;
 940         mnemonic = ".long";
 941         format = "=";
 942         instr = 14 << 28; // no condition code please, see below
 943         result.oddbits = result.badbits = 0; // no need for error display
 944         result.text[0] = flagchars[0] = 0;
 945     }
 946 
 947     *flagp=0;
 948 
 949     /* PHASE 2. Produce string. */
 950 
 951     { char * op = result.text;
 952 
 953     /* 2a. Mnemonic. */
 954 
 955     op = append(op,mnemonic);
 956 
 957     /* 2b. Condition code. */
 958 
 959     {
 960         t_value cond = instr>>28;
 961         if (cond!=14) {
 962             const char * ip = _i_cond[cond];
 963             *op++ = *ip++;
 964             *op++ = *ip;
 965         }
 966     }
 967 
 968     /* 2c. Flags. */
 969 
 970     { const char * ip = flagchars;
 971     while (*ip) *op++ = *ip++;
 972     }
 973 
 974     /* 2d. A tab character. */
 975 
 976     do {
 977         *op++ = ' ';
 978         *op = 0 ;
 979     } while ( strlen( result.text ) < 8 ) ;
 980 
 981     /* 2e. Other stuff, determined by format string. */
 982 
 983     { const char * ip = format;
 984     char c;
 985 
 986     char * * regnames = opts->regnames;
 987     t_value     oflags   = opts->flags;
 988 
 989     while ((c=*ip++) != 0) {
 990         switch(c) {
 991           case '=':
 992             if (((unsigned long)result.instr > (unsigned long)addr) && ((unsigned long)result.instr < (unsigned long)addr+0x1000)) { // looks like a jumptable
 993                 result.addrstart = op;
 994                 op = sub_hex8(fw, op, result.instr);
 995             }
 996             else {
 997                 op = yhex8(fw, op, result.instr);
 998             }
 999             break;
1000     case '$':
1001         result.is_SWI = 1;
1002         result.swinum = instr&0x00FFFFFF;
1003         result.addrstart = op;
1004         if (oflags&disopt_SWInames) {
1005             swiname(result.swinum, op, 128-(op-result.text));
1006             op += strlen(op);
1007         }
1008         else
1009             op += sprintf(op, "&%X", result.swinum);
1010         break;
1011     case '%':
1012         *op++='{';
1013         { t_value w = instr&0xFFFF;
1014         int i=0;
1015         while (w) {
1016             int j;
1017             while (!(w&(1ul<<i))) ++i;
1018             for (j=i+1; w&(1ul<<j); ++j) ;
1019             --j;
1020             /* registers [i..j] */
1021             op = append(op, regnames[i]);
1022             if (j-i) {
1023                 *op++ = (j-i>1) ? '-' : ',';
1024                 op = append(op, regnames[j]);
1025             }
1026             i=j; w=(w>>(j+1))<<(j+1);
1027             if (w) *op++=',';
1028         }
1029         }
1030         *op++='}';
1031         if (instr&(1<<22)) *op++='^';
1032         break;
1033     case '&':
1034         // address target = ((addr+8 + ((((int)instr)<<8)>>6)) & 0x03FFFFFC) | ( addr&0xFC000000) ;
1035         { t_address target = ((t_address) addr ) + 8 + ((t_address) ((((int)instr)<<8) >>6 )) ;
1036         result.addrstart = op;
1037         op = sub_hex8(fw, op, target);
1038         result.target_type = target_Code;
1039         result.target      = target;
1040         }
1041         break;
1042     case '\'':
1043 lPling:
1044         if (instr&Wbit) *op++='!';
1045         break;
1046     case '(':
1047         *op++ = (char)('0'+fpn);
1048         break;
1049     case ')':
1050         { t_value w = (instr>>20)&15;
1051         if (w>=10) { *op++='1'; *op++=(char)('0'-10+w); }
1052         else *op++=(char)(w+'0');
1053         }
1054         break;
1055 
1056     case '*':
1057     case '.':
1058         if (instr&Ibit) {
1059             /* immediate constant */
1060             t_value imm8 = (instr&255);
1061             t_value rot  = (instr>>7)&30;
1062             //if (rot && !(imm8&3) && c=='*') {
1063             //  /* Funny immediate const. Guaranteed not '.', btw */
1064             //  *op++='#'; // *op++='&';
1065             //  *op++='0'; // added in 2.04 to indicate this is a hex value
1066             //  *op++='x'; //   ditto
1067             //  *op++="0123456789ABCDEF"[imm8>>4];
1068             //  *op++="0123456789ABCDEF"[imm8&15];
1069             //  *op++=',';
1070             //  op = num(op, rot, 10);
1071             //}
1072             //else {
1073             imm8 = (imm8>>rot) | (imm8<<(32-rot));
1074             if (c=='*') {
1075                 *op++='#';
1076                 if (imm8>256 && ((imm8&(imm8-1))==0)) {
1077                     /* only one bit set, and that later than bit 8.
1078                     * Represent as 1<<... .
1079                     */
1080                     //op = append(op,"1<<");
1081                     { int n=0;
1082                     while (!(imm8&15)) { n+=4; imm8=imm8>>4; }
1083                     /* Now imm8 is 1, 2, 4 or 8. */
1084                     n += (0x30002010 >> 4*(imm8-1))&15;
1085                     n= 1<<n ;
1086                     op = yhex8(fw, op, n);
1087                     }
1088 
1089                 }
1090                 else {
1091                     if (((int)imm8)<0 && ((int)imm8)>-100) {
1092                         *op++='-'; imm8=-imm8;
1093                     }
1094                     op = num(op, imm8, 10);
1095                 }
1096             }
1097             else {
1098                 t_address a = addr+8;
1099                 if (instr&(1<<22)) a-=imm8; else a+=imm8;
1100                 result.addrstart=op;
1101                 op = xhex8(fw, op, a);
1102                 result.target=a; result.target_type=target_Unknown;
1103             }
1104             //}
1105         }
1106         else {
1107             /* rotated register */
1108             const char * rot = _i_lsl_lsr[(instr&(3<<5)) >> 5];
1109             op = append(op, regnames[instr&15]);
1110             if (instr&(1<<4)) {
1111                 /* register rotation */
1112                 if (instr&(1<<7)) goto ljUndefined;
1113                 *op++=','; if (oflags&disopt_CommaSpace) *op++=' ';
1114                 op = append(op,rot); *op++=' ';
1115                 op = append(op,regnames[(instr&(15<<8))>>8]);
1116             }
1117             else {
1118                 /* constant rotation */
1119                 t_value n = instr&(31<<7);
1120                 if (!n) {
1121                     if (!(instr&(3<<5))) break;
1122                     else if ((instr&(3<<5))==(3<<5)) {
1123                         op = append(op, ",RRX");
1124                         break;
1125                     }
1126                     else n=32<<7;
1127                 }
1128                 *op++ = ','; if (oflags&disopt_CommaSpace) *op++=' ';
1129                 op = num(append(append(op,rot),"#"),n>>7,32);
1130             }
1131         }
1132         break;
1133     case '+':
1134         if (instr&(1<<3)) {
1135             t_value w = instr&7;
1136             *op++='#';
1137             if (w<6) *op++=(char)('0'+w);
1138             else op = append(op, w==6 ? "0.5" : "10");
1139         }
1140         else {
1141             *op++='f';
1142             *op++=(char)('0'+(instr&7));
1143         }
1144         break;
1145     case ',':
1146         *op++=',';
1147         if (oflags&disopt_CommaSpace) *op++=' ';
1148         break;
1149     case '-':
1150         { t_value w = instr&(7<<5);
1151         if (w) {
1152             *op++=',';
1153             if (oflags&disopt_CommaSpace) *op++=' ';
1154             *op++ = (char)('0'+(w>>5));
1155         }
1156         }
1157         break;
1158     case '/':
1159         result.addrstart = op;
1160         *op++='[';
1161 
1162         op = append(op, regnames[(instr&RNbits)>>16]);
1163 
1164         if (!(instr&Pbit)) *op++=']';
1165 
1166         *op++=','; 
1167 
1168         if (oflags&disopt_CommaSpace) *op++=' ';
1169 
1170         /* For following, NB that bit 25 is always 0 for LDC, SFM etc */
1171         if (instr&Ibit) {
1172             /* shifted offset */
1173             if (!(instr&Ubit)) *op++='-';
1174             /* We're going to transfer to '*', basically. The stupid
1175             * thing is that the meaning of bit 25 is reversed there;
1176             * I don't know why the designers of the ARM did that.
1177             */
1178             instr ^= Ibit;
1179             if (instr&(1<<4)) {
1180 
1181                 if (is_v4 && !(instr&(15<<8))) {
1182                     ip = (instr&Pbit) ? "0]" : "0";
1183                     break;
1184                 }
1185             }
1186             /* Need a ] iff it was pre-indexed; and an optional ! iff
1187             * it's pre-indexed *or* a copro instruction,
1188             * except that FPU operations don't need the !. Bletch.
1189             */
1190             if (instr&Pbit) ip="*]'";
1191             else if (instr&(1<<27)) {
1192                 if (CP_is(1) || CP_is(2)) {
1193                     if (!(instr&Wbit)) goto lkUndefined;
1194                     ip="*";
1195                 }
1196                 else ip="*'";
1197             }
1198             else ip="*";
1199         }
1200         else {
1201             /* immediate offset */
1202             t_value offset;
1203             if (instr&(1<<27)) {      /* LDF or LFM or similar */
1204                 offset = (instr&255)<<2;
1205             }
1206 
1207             else if (is_v4) offset = (instr&15) + ((instr&(15<<8))>>4);
1208             else {            /* LDR or STR */
1209                 offset = instr&0xFFF;
1210             }
1211 
1212             if ( offset == 0 ){
1213                 if (oflags&disopt_CommaSpace) op-- ;
1214                 op-- ; *op++=']'; goto lPling; }
1215 
1216             *op++='#';
1217             if (!(instr&Ubit)) 
1218             {
1219                 if (offset) *op++='-';
1220                 else result.oddbits=1;
1221                 result.offset = -offset;
1222             }
1223             else result.offset = offset;
1224 
1225             op = num(op, offset, 10);
1226             if (RN_is(15) && (instr&Pbit)) 
1227             {
1228                 /* Immediate, pre-indexed and PC-relative. Set target. */
1229                 result.target_type = poss_tt;
1230                 result.target      = (instr&Ubit) ? addr+8 + offset
1231                     : addr+8 - offset;
1232                 if (!(instr&Wbit)) 
1233                 {
1234                     /* no writeback, either. Use friendly form. */
1235                     if (RD_is(15))
1236                         op = sub_ahex8(fw, result.addrstart, result.target);
1237                     else
1238                     op = ahex8(fw, result.addrstart, result.target);
1239                     break;
1240                 }
1241             }
1242             if (instr&Pbit) { *op++=']'; goto lPling; }
1243             else if (instr&(1<<27)) {
1244                 if (CP_is(1) || CP_is(2)) {
1245                     if (!(instr&Wbit)) goto llUndefined;
1246                 }
1247                 else goto lPling;
1248             }
1249         }
1250         break;
1251 
1252     case '0': case '1': case '2': case '3': case '4':
1253         op = append(op, regnames[(instr>>(4*(c-'0')))&15]);
1254         break;
1255     case '5': case '6': case '7': case '8': case '9':
1256         *op++='f';
1257         *op++=(char)('0' + ((instr>>(4*(c-'5')))&7));
1258         break;
1259     case ':':
1260         *op++ = (char)('0' + ((instr>>21)&7));
1261         break;
1262     case ';':
1263         op = reg(op, 'p', instr>>8);
1264         break;
1265     default:
1266         if (c<=5)
1267             op = reg(op, 'c', instr >> (4*(c-1)));
1268         else *op++ = c;
1269         }
1270     }
1271     *op=0;
1272     }
1273     }
1274 
1275     /* DONE! */
1276 
1277     return &result;
1278 }
1279 
1280 //------------------------------------------------------------------------------------------------------------
1281 t_address addr, last_used_addr;
1282 
1283 void disassemble1(firmware *fw, t_address start, t_value length)
1284 {
1285     t_value w;
1286 
1287     free(dcd_list);
1288     dcd_list = new_list();
1289     free(branch_list);
1290     branch_list = new_list();
1291 
1292     // Do three passes; but don't generate any code
1293     int pass;
1294     for ( pass = 1 ; pass <=3 ; pass++ )
1295     {
1296         if ( pass == 2 ) 
1297         {
1298             struct lnode* lptr = dcd_list->head;
1299             while ( lptr != NULL  ) 
1300             {           
1301                 addr = (t_address) lptr->address ;
1302                 w = fwval(fw,adr2idx(fw,addr));
1303                 lptr->data = w ;
1304                 lptr = lptr->next ;
1305             }
1306         }
1307         else    // pass 1 & 3
1308         {
1309             addr = start ;
1310             t_value word_count = 0 ;
1311 
1312             while (word_count < length )
1313             {
1314                 w = fwval(fw,adr2idx(fw,addr));
1315                 instr_disassemble(fw, w, addr, &options);
1316 
1317                 struct lnode* lptr = l_search(dcd_list,addr);
1318                 if (!lptr) 
1319                     last_used_addr = addr;
1320 
1321                 word_count++ ;
1322                 addr += 4;
1323             }
1324         }
1325     }
1326 }
1327 
1328 void disassemble(firmware *fw, FILE *outfile, t_address start, t_value length)
1329 {
1330     t_value w;
1331 
1332     int dcd_mode_on = 0;
1333 
1334     // Only need 1 pass here - assumes disassemble1 called previously
1335     addr = start ;
1336     t_value word_count = 0 ;
1337 
1338     while (word_count < length )
1339     {
1340         w = fwval(fw,adr2idx(fw,addr));
1341 
1342         pInstruction instr = instr_disassemble(fw, w, addr, &options);
1343 
1344         if (l_search(branch_list, addr))
1345         {
1346             fprintf(outfile,"\n\"loc_%08X:\\n\"\n", addr);
1347             dcd_mode_on = 0;
1348         }       
1349         struct lnode* lptr = l_search(dcd_list,addr);
1350         if ( lptr  || dcd_mode_on ) 
1351         {
1352             if ((options.flags & disopt_exclude_dcd) == 0)
1353                 fprintf(outfile,"\"dword_%8.8X  DCD 0x%X \\n\"\n", addr , w);
1354             dcd_mode_on = 1;
1355             /*
1356             t_value aword ;
1357             int i ;
1358             unsigned char ch ;
1359             aword = lptr->data ;
1360             for ( i=0 ; i< 4 ; i++ )
1361             {
1362             ch = aword & 0xFF ;
1363             if ( (ch>=0x20) && ( ch < 0x80) ) fprintf(outfile," %c" , ch );
1364             else fprintf(outfile,"_" );
1365             aword = aword >> 8 ;
1366             }
1367             fprintf(outfile, "\n" ) ;
1368             */
1369         }       
1370         else 
1371         {
1372             if (instr->undefined || instr->badbits || instr->oddbits) {
1373                 fprintf(outfile,"Error: ");
1374                 if (instr->undefined) fprintf(outfile,"[---undefined instr---] 0x%8.8X     ", w);
1375                 if (instr->badbits) fprintf(outfile,  "[---illegal bits---] 0x%8.8X        ", w);
1376                 if (instr->oddbits) fprintf(outfile,  "[---unexpected bits---] 0x%8.8X     ", w);
1377                 if ( !((instr->undefined) || (instr->badbits) || (instr->oddbits)) ) 
1378                     fprintf(outfile,  "[---unknown error---] 0x%8.8X       ", w);
1379                 if ( options.flags & disopt_print_address_mode)
1380                 {
1381                     fprintf(outfile,"// rom:%.8x  0x%8.8X \n", addr, w);
1382                 }                                                               
1383                 else fprintf(outfile,"\n");                                                                                                     
1384             }
1385             else
1386             {
1387                 strcat( instr->text, " \\n\"") ;
1388                 if (options.flags & disopt_line_numbers) fprintf(outfile,"/*%3d*/",(addr - options.start_address) / 4 + 1);
1389                 char *indent = "\"    ";
1390                 if (options.flags & (disopt_comment_lines|disopt_nullsub_call))
1391                     indent = "//\"  ";
1392                 if (options.flags & disopt_indent_mneumonics_mode)
1393                     fprintf(outfile,"      ");
1394                 if (options.flags & disopt_print_address_mode)
1395                 {
1396                     fprintf(outfile,"%s%-40s // rom:%.8x  0x%8.8X", indent, instr->text, addr, w);
1397                 }                                                               
1398                 else fprintf(outfile,"%s%s", indent, instr->text);
1399 
1400                 if ((options.flags & disopt_patch_branch) || (options.flags & disopt_patch_value))
1401                 {
1402                     if (patch_old_func_name)
1403                         fprintf(outfile,"  // --> Patched. Old value = _%s.", patch_old_func_name);
1404                     else
1405                         fprintf(outfile,"  // --> Patched. Old value = 0x%X.", patch_old_val);
1406                     if ((options.flags & disopt_patch_comment) && patch_comment)
1407                     {
1408                         fprintf(outfile, " %s", patch_comment);
1409                         patch_comment = 0;
1410                     }
1411                 }
1412                 else if ((options.flags & disopt_patch_comment) && patch_comment)
1413                 {
1414                     fprintf(outfile, "  // %s", patch_comment);
1415                     patch_comment = 0;
1416                 }
1417                 else if (options.flags & disopt_nullsub_call)
1418                 {
1419                     fprintf(outfile,"  // --> Nullsub call removed.");
1420                 }
1421                 fprintf(outfile,"\n");
1422             }
1423         }
1424 
1425         word_count++ ;
1426         addr += 4;
1427     }
1428 }
1429 
1430 t_address find_end(firmware *fw, t_address start)
1431 {
1432     int i;
1433     start = adr2idx(fw,start);
1434     for (i=0; i<500; i++, start++)
1435         if ((fwval(fw,start+1) & 0xFFFF4000) == 0xE92D4000)  // STMFD SP!, {...,LR}
1436         {
1437             int j;
1438             for (j=0; j<50; j++, start--)
1439             {
1440                 if ((fwval(fw,start) & 0xFF000000) == 0xEA000000)  // B
1441                 {
1442                     return idx2adr(fw,start);
1443                 }
1444                 if ((fwval(fw,start) & 0xFFFF8000) == 0xE8BD8000)  // LDMFD SP!, {...,PC}
1445                 {
1446                     return idx2adr(fw,start);
1447                 }
1448                 if ((fwval(fw,start) & 0xFFFFFFF0) == 0xE12FFF10)  // BX
1449                 {
1450                     return idx2adr(fw,start);
1451                 }
1452                 if ((fwval(fw,start) & 0xFFFFF000) == 0xE49DF000)  // LDR PC,[SP,...
1453                 {
1454                     return idx2adr(fw,start);
1455                 }
1456             }
1457             return 0;
1458         }
1459     return 0;
1460 }
1461 
1462 //------------------------------------------------------------------------------------------------------------
1463 
1464 void swiname(t_value w, char * s, size_t sz) { return; }
1465 
1466 //------------------------------------------------------------------------------------------------------------

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