OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [opcodes/] [m68hc11-dis.c] - Blame information for rev 1776

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* m68hc11-dis.c -- Motorola 68HC11 & 68HC12 disassembly
2
   Copyright 1999, 2000 Free Software Foundation, Inc.
3
   Written by Stephane Carrez (stcarrez@worldnet.fr)
4
 
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
9
 
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
 
19
#include <stdio.h>
20
 
21
#include "ansidecl.h"
22
#include "opcode/m68hc11.h"
23
#include "dis-asm.h"
24
 
25
static const char *const reg_name[] = {
26
  "X", "Y", "SP", "PC"
27
};
28
 
29
static const char *const reg_src_table[] = {
30
  "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
31
};
32
 
33
static const char *const reg_dst_table[] = {
34
  "A", "B", "CCR", "TMP2", "D", "X", "Y", "SP"
35
};
36
 
37
#define OP_PAGE_MASK (M6811_OP_PAGE2|M6811_OP_PAGE3|M6811_OP_PAGE4)
38
 
39
static int
40
read_memory (memaddr, buffer, size, info)
41
     bfd_vma memaddr;
42
     bfd_byte *buffer;
43
     int size;
44
     struct disassemble_info *info;
45
{
46
  int status;
47
 
48
  /* Get first byte.  Only one at a time because we don't know the
49
     size of the insn.  */
50
  status = (*info->read_memory_func) (memaddr, buffer, size, info);
51
  if (status != 0)
52
    {
53
      (*info->memory_error_func) (status, memaddr, info);
54
      return -1;
55
    }
56
  return 0;
57
}
58
 
59
 
60
/* Read the 68HC12 indexed operand byte and print the corresponding mode.
61
   Returns the number of bytes read or -1 if failure.  */
62
static int
63
print_indexed_operand (memaddr, info, mov_insn)
64
     bfd_vma memaddr;
65
     struct disassemble_info *info;
66
     int mov_insn;
67
{
68
  bfd_byte buffer[4];
69
  int reg;
70
  int status;
71
  short sval;
72
  int pos = 1;
73
 
74
  status = read_memory (memaddr, &buffer[0], 1, info);
75
  if (status != 0)
76
    {
77
      return status;
78
    }
79
 
80
  /* n,r with 5-bits signed constant.  */
81
  if ((buffer[0] & 0x20) == 0)
82
    {
83
      reg = (buffer[0] >> 6) & 3;
84
      sval = (buffer[0] & 0x1f);
85
      if (sval & 0x10)
86
        sval |= 0xfff0;
87
      (*info->fprintf_func) (info->stream, "%d,%s",
88
                             (int) sval, reg_name[reg]);
89
    }
90
 
91
  /* Auto pre/post increment/decrement.  */
92
  else if ((buffer[0] & 0xc0) != 0xc0)
93
    {
94
      const char *mode;
95
 
96
      reg = (buffer[0] >> 6) & 3;
97
      sval = (buffer[0] & 0x0f);
98
      if (sval & 0x8)
99
        {
100
          sval |= 0xfff0;
101
          sval = -sval;
102
          mode = "-";
103
        }
104
      else
105
        {
106
          sval = sval + 1;
107
          mode = "+";
108
        }
109
      (*info->fprintf_func) (info->stream, "%d,%s%s%s",
110
                             (int) sval,
111
                             (buffer[0] & 0x10 ? "" : mode),
112
                             reg_name[reg], (buffer[0] & 0x10 ? mode : ""));
113
    }
114
 
115
  /* [n,r] 16-bits offset indexed indirect.  */
116
  else if ((buffer[0] & 0x07) == 3)
117
    {
118
      if (mov_insn)
119
        {
120
          (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
121
                                 buffer[0] & 0x0ff);
122
          return 0;
123
        }
124
      reg = (buffer[0] >> 3) & 0x03;
125
      status = read_memory (memaddr + pos, &buffer[0], 2, info);
126
      if (status != 0)
127
        {
128
          return status;
129
        }
130
 
131
      pos += 2;
132
      sval = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
133
      (*info->fprintf_func) (info->stream, "[%u,%s]",
134
                             sval & 0x0ffff, reg_name[reg]);
135
    }
136
  else if ((buffer[0] & 0x4) == 0)
137
    {
138
      if (mov_insn)
139
        {
140
          (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
141
                                 buffer[0] & 0x0ff);
142
          return 0;
143
        }
144
      reg = (buffer[0] >> 3) & 0x03;
145
      status = read_memory (memaddr + pos,
146
                            &buffer[1], (buffer[0] & 0x2 ? 2 : 1), info);
147
      if (status != 0)
148
        {
149
          return status;
150
        }
151
      if (buffer[0] & 2)
152
        {
153
          sval = ((buffer[1] << 8) | (buffer[2] & 0x0FF));
154
          sval &= 0x0FFFF;
155
          pos += 2;
156
        }
157
      else
158
        {
159
          sval = buffer[1] & 0x00ff;
160
          if (buffer[0] & 0x01)
161
            sval |= 0xff00;
162
          pos++;
163
        }
164
      (*info->fprintf_func) (info->stream, "%d,%s",
165
                             (int) sval, reg_name[reg]);
166
    }
167
  else
168
    {
169
      reg = (buffer[0] >> 3) & 0x03;
170
      switch (buffer[0] & 3)
171
        {
172
        case 0:
173
          (*info->fprintf_func) (info->stream, "A,%s", reg_name[reg]);
174
          break;
175
        case 1:
176
          (*info->fprintf_func) (info->stream, "B,%s", reg_name[reg]);
177
          break;
178
        case 2:
179
          (*info->fprintf_func) (info->stream, "D,%s", reg_name[reg]);
180
          break;
181
        case 3:
182
        default:
183
          (*info->fprintf_func) (info->stream, "[D,%s]", reg_name[reg]);
184
          break;
185
        }
186
    }
187
 
188
  return pos;
189
}
190
 
191
/* Disassemble one instruction at address 'memaddr'.  Returns the number
192
   of bytes used by that instruction.  */
193
static int
194
print_insn (memaddr, info, arch)
195
     bfd_vma memaddr;
196
     struct disassemble_info *info;
197
     int arch;
198
{
199
  int status;
200
  bfd_byte buffer[4];
201
  unsigned char code;
202
  long format, pos, i;
203
  short sval;
204
  const struct m68hc11_opcode *opcode;
205
 
206
  /* Get first byte.  Only one at a time because we don't know the
207
     size of the insn.  */
208
  status = read_memory (memaddr, buffer, 1, info);
209
  if (status != 0)
210
    {
211
      return status;
212
    }
213
 
214
  format = 0;
215
  code = buffer[0];
216
  pos = 0;
217
 
218
  /* Look for page2,3,4 opcodes.  */
219
  if (code == M6811_OPCODE_PAGE2)
220
    {
221
      pos++;
222
      format = M6811_OP_PAGE2;
223
    }
224
  else if (code == M6811_OPCODE_PAGE3 && arch == cpu6811)
225
    {
226
      pos++;
227
      format = M6811_OP_PAGE3;
228
    }
229
  else if (code == M6811_OPCODE_PAGE4 && arch == cpu6811)
230
    {
231
      pos++;
232
      format = M6811_OP_PAGE4;
233
    }
234
 
235
  /* We are in page2,3,4; get the real opcode.  */
236
  if (pos == 1)
237
    {
238
      status = read_memory (memaddr + pos, &buffer[1], 1, info);
239
      if (status != 0)
240
        {
241
          return status;
242
        }
243
      code = buffer[1];
244
    }
245
 
246
 
247
  /* Look first for a 68HC12 alias.  All of them are 2-bytes long and
248
     in page 1.  There is no operand to print.  We read the second byte
249
     only when we have a possible match.  */
250
  if ((arch & cpu6812) && format == 0)
251
    {
252
      int must_read = 1;
253
 
254
      /* Walk the alias table to find a code1+code2 match.  */
255
      for (i = 0; i < m68hc12_num_alias; i++)
256
        {
257
          if (m68hc12_alias[i].code1 == code)
258
            {
259
              if (must_read)
260
                {
261
                  status = read_memory (memaddr + pos + 1,
262
                                        &buffer[1], 1, info);
263
                  if (status != 0)
264
                    break;
265
 
266
                  must_read = 1;
267
                }
268
              if (m68hc12_alias[i].code2 == (unsigned char) buffer[1])
269
                {
270
                  (*info->fprintf_func) (info->stream, "%s",
271
                                         m68hc12_alias[i].name);
272
                  return 2;
273
                }
274
            }
275
        }
276
    }
277
 
278
  pos++;
279
 
280
  /* Scan the opcode table until we find the opcode
281
     with the corresponding page.  */
282
  opcode = m68hc11_opcodes;
283
  for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
284
    {
285
      int offset;
286
 
287
      if ((opcode->arch & arch) == 0)
288
        continue;
289
      if (opcode->opcode != code)
290
        continue;
291
      if ((opcode->format & OP_PAGE_MASK) != format)
292
        continue;
293
 
294
      if (opcode->format & M6812_OP_REG)
295
        {
296
          int j;
297
          int is_jump;
298
 
299
          if (opcode->format & M6811_OP_JUMP_REL)
300
            is_jump = 1;
301
          else
302
            is_jump = 0;
303
 
304
          status = read_memory (memaddr + pos, &buffer[0], 1, info);
305
          if (status != 0)
306
            {
307
              return status;
308
            }
309
          for (j = 0; i + j < m68hc11_num_opcodes; j++)
310
            {
311
              if ((opcode[j].arch & arch) == 0)
312
                continue;
313
              if (opcode[j].opcode != code)
314
                continue;
315
              if (is_jump)
316
                {
317
                  if (!(opcode[j].format & M6811_OP_JUMP_REL))
318
                    continue;
319
 
320
                  if ((opcode[j].format & M6812_OP_IBCC_MARKER)
321
                      && (buffer[0] & 0xc0) != 0x80)
322
                    continue;
323
                  if ((opcode[j].format & M6812_OP_TBCC_MARKER)
324
                      && (buffer[0] & 0xc0) != 0x40)
325
                    continue;
326
                  if ((opcode[j].format & M6812_OP_DBCC_MARKER)
327
                      && (buffer[0] & 0xc0) != 0)
328
                    continue;
329
                  if ((opcode[j].format & M6812_OP_EQ_MARKER)
330
                      && (buffer[0] & 0x20) == 0)
331
                    break;
332
                  if (!(opcode[j].format & M6812_OP_EQ_MARKER)
333
                      && (buffer[0] & 0x20) != 0)
334
                    break;
335
                  continue;
336
                }
337
              if (opcode[j].format & M6812_OP_EXG_MARKER && buffer[0] & 0x80)
338
                break;
339
              if ((opcode[j].format & M6812_OP_SEX_MARKER)
340
                  && (((buffer[0] & 0x07) >= 3 && (buffer[0] & 7) <= 7))
341
                  && ((buffer[0] & 0x0f0) <= 0x20))
342
                break;
343
              if (opcode[j].format & M6812_OP_TFR_MARKER
344
                  && !(buffer[0] & 0x80))
345
                break;
346
            }
347
          if (i + j < m68hc11_num_opcodes)
348
            opcode = &opcode[j];
349
        }
350
 
351
      /* We have found the opcode.  Extract the operand and print it.  */
352
      (*info->fprintf_func) (info->stream, "%s", opcode->name);
353
 
354
      format = opcode->format;
355
      if (format & (M6811_OP_MASK | M6811_OP_BITMASK
356
                    | M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
357
        {
358
          (*info->fprintf_func) (info->stream, "\t");
359
        }
360
 
361
      /* The movb and movw must be handled in a special way...  */
362
      offset = 0;
363
      if (format & (M6812_OP_IDX_P2 | M6812_OP_IND16_P2))
364
        {
365
          if ((format & M6812_OP_IDX_P2)
366
              && (format & (M6811_OP_IMM8 | M6811_OP_IMM16 | M6811_OP_IND16)))
367
            offset = 1;
368
        }
369
 
370
      /* Operand with one more byte: - immediate, offset,
371
         direct-low address.  */
372
      if (format &
373
          (M6811_OP_IMM8 | M6811_OP_IX | M6811_OP_IY | M6811_OP_DIRECT))
374
        {
375
          status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
376
          if (status != 0)
377
            {
378
              return status;
379
            }
380
 
381
          pos++;
382
          offset = -1;
383
          if (format & M6811_OP_IMM8)
384
            {
385
              (*info->fprintf_func) (info->stream, "#%d", (int) buffer[0]);
386
              format &= ~M6811_OP_IMM8;
387
            }
388
          else if (format & M6811_OP_IX)
389
            {
390
              /* Offsets are in range 0..255, print them unsigned.  */
391
              (*info->fprintf_func) (info->stream, "%u,x", buffer[0] & 0x0FF);
392
              format &= ~M6811_OP_IX;
393
            }
394
          else if (format & M6811_OP_IY)
395
            {
396
              (*info->fprintf_func) (info->stream, "%u,y", buffer[0] & 0x0FF);
397
              format &= ~M6811_OP_IY;
398
            }
399
          else if (format & M6811_OP_DIRECT)
400
            {
401
              (*info->fprintf_func) (info->stream, "*");
402
              (*info->print_address_func) (buffer[0] & 0x0FF, info);
403
              format &= ~M6811_OP_DIRECT;
404
            }
405
        }
406
 
407
#define M6812_INDEXED_FLAGS (M6812_OP_IDX|M6812_OP_IDX_1|M6812_OP_IDX_2)
408
      /* Analyze the 68HC12 indexed byte.  */
409
      if (format & M6812_INDEXED_FLAGS)
410
        {
411
          status = print_indexed_operand (memaddr + pos, info, 0);
412
          if (status < 0)
413
            {
414
              return status;
415
            }
416
          pos += status;
417
        }
418
 
419
      /* 68HC12 dbcc/ibcc/tbcc operands.  */
420
      if ((format & M6812_OP_REG) && (format & M6811_OP_JUMP_REL))
421
        {
422
          status = read_memory (memaddr + pos, &buffer[0], 2, info);
423
          if (status != 0)
424
            {
425
              return status;
426
            }
427
          (*info->fprintf_func) (info->stream, "%s,",
428
                                 reg_src_table[buffer[0] & 0x07]);
429
          sval = buffer[1] & 0x0ff;
430
          if (buffer[0] & 0x10)
431
            sval |= 0xff00;
432
 
433
          pos += 2;
434
          (*info->print_address_func) (memaddr + pos + sval, info);
435
          format &= ~(M6812_OP_REG | M6811_OP_JUMP_REL);
436
        }
437
      else if (format & (M6812_OP_REG | M6812_OP_REG_2))
438
        {
439
          status = read_memory (memaddr + pos, &buffer[0], 1, info);
440
          if (status != 0)
441
            {
442
              return status;
443
            }
444
 
445
          pos++;
446
          (*info->fprintf_func) (info->stream, "%s,%s",
447
                                 reg_src_table[(buffer[0] >> 4) & 7],
448
                                 reg_dst_table[(buffer[0] & 7)]);
449
        }
450
 
451
      /* M6811_OP_BITMASK and M6811_OP_JUMP_REL must be treated separately
452
         and in that order.  The brset/brclr insn have a bitmask and then
453
         a relative branch offset.  */
454
      if (format & M6811_OP_BITMASK)
455
        {
456
          status = read_memory (memaddr + pos, &buffer[0], 1, info);
457
          if (status != 0)
458
            {
459
              return status;
460
            }
461
          pos++;
462
          (*info->fprintf_func) (info->stream, " #$%02x%s",
463
                                 buffer[0] & 0x0FF,
464
                                 (format & M6811_OP_JUMP_REL ? " " : ""));
465
          format &= ~M6811_OP_BITMASK;
466
        }
467
      if (format & M6811_OP_JUMP_REL)
468
        {
469
          int val;
470
 
471
          status = read_memory (memaddr + pos, &buffer[0], 1, info);
472
          if (status != 0)
473
            {
474
              return status;
475
            }
476
 
477
          pos++;
478
          val = (buffer[0] & 0x80) ? buffer[0] | 0xFFFFFF00 : buffer[0];
479
          (*info->print_address_func) (memaddr + pos + val, info);
480
          format &= ~M6811_OP_JUMP_REL;
481
        }
482
      else if (format & M6812_OP_JUMP_REL16)
483
        {
484
          int val;
485
 
486
          status = read_memory (memaddr + pos, &buffer[0], 2, info);
487
          if (status != 0)
488
            {
489
              return status;
490
            }
491
 
492
          pos += 2;
493
          val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
494
          if (val & 0x8000)
495
            val |= 0xffff0000;
496
 
497
          (*info->print_address_func) (memaddr + pos + val, info);
498
          format &= ~M6812_OP_JUMP_REL16;
499
        }
500
      if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
501
        {
502
          int val;
503
 
504
          status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
505
          if (status != 0)
506
            {
507
              return status;
508
            }
509
          if (format & M6812_OP_IDX_P2)
510
            offset = -2;
511
          else
512
            offset = 0;
513
          pos += 2;
514
 
515
          val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
516
          val &= 0x0FFFF;
517
          if (format & M6811_OP_IMM16)
518
            {
519
              format &= ~M6811_OP_IMM16;
520
              (*info->fprintf_func) (info->stream, "#");
521
            }
522
          else
523
            format &= ~M6811_OP_IND16;
524
 
525
          (*info->print_address_func) (val, info);
526
        }
527
 
528
      if (format & M6812_OP_IDX_P2)
529
        {
530
          (*info->fprintf_func) (info->stream, ", ");
531
          status = print_indexed_operand (memaddr + pos + offset, info, 1);
532
          if (status < 0)
533
            return status;
534
          pos += status;
535
        }
536
 
537
      if (format & M6812_OP_IND16_P2)
538
        {
539
          int val;
540
 
541
          (*info->fprintf_func) (info->stream, ", ");
542
 
543
          status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
544
          if (status != 0)
545
            {
546
              return status;
547
            }
548
          pos += 2;
549
 
550
          val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
551
          val &= 0x0FFFF;
552
          (*info->print_address_func) (val, info);
553
        }
554
 
555
#ifdef DEBUG
556
      /* Consistency check.  'format' must be 0, so that we have handled
557
         all formats; and the computed size of the insn must match the
558
         opcode table content.  */
559
      if (format & ~(M6811_OP_PAGE4 | M6811_OP_PAGE3 | M6811_OP_PAGE2))
560
        {
561
          (*info->fprintf_func) (info->stream, "; Error, format: %x", format);
562
        }
563
      if (pos != opcode->size)
564
        {
565
          (*info->fprintf_func) (info->stream, "; Error, size: %d expect %d",
566
                                 pos, opcode->size);
567
        }
568
#endif
569
      return pos;
570
    }
571
 
572
  /* Opcode not recognized.  */
573
  if (format == M6811_OP_PAGE2 && arch & cpu6812
574
      && ((code >= 0x30 && code <= 0x39) || (code >= 0x40 && code <= 0xff)))
575
    (*info->fprintf_func) (info->stream, "trap\t#%d", code & 0x0ff);
576
 
577
  else if (format == M6811_OP_PAGE2)
578
    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
579
                           M6811_OPCODE_PAGE2, code);
580
  else if (format == M6811_OP_PAGE3)
581
    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
582
                           M6811_OPCODE_PAGE3, code);
583
  else if (format == M6811_OP_PAGE4)
584
    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
585
                           M6811_OPCODE_PAGE4, code);
586
  else
587
    (*info->fprintf_func) (info->stream, ".byte\t0x%02x", code);
588
 
589
  return pos;
590
}
591
 
592
/* Disassemble one instruction at address 'memaddr'.  Returns the number
593
   of bytes used by that instruction.  */
594
int
595
print_insn_m68hc11 (memaddr, info)
596
     bfd_vma memaddr;
597
     struct disassemble_info *info;
598
{
599
  return print_insn (memaddr, info, cpu6811);
600
}
601
 
602
int
603
print_insn_m68hc12 (memaddr, info)
604
     bfd_vma memaddr;
605
     struct disassemble_info *info;
606
{
607
  return print_insn (memaddr, info, cpu6812);
608
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.