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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [sim/] [arm/] [thumbemu.c] - Blame information for rev 106

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

Line No. Rev Author Line
1 106 markom
/*  thumbemu.c -- Thumb instruction emulation.
2
    Copyright (C) 1996, Cygnus Software Technologies Ltd.
3
 
4
    This program is free software; you can redistribute it and/or modify
5
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation; either version 2 of the License, or
7
    (at your option) any later version.
8
 
9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU General Public License for more details.
13
 
14
    You should have received a copy of the GNU General Public License
15
    along with this program; if not, write to the Free Software
16
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
 
18
/* We can provide simple Thumb simulation by decoding the Thumb
19
instruction into its corresponding ARM instruction, and using the
20
existing ARM simulator.  */
21
 
22
#ifndef MODET                   /* required for the Thumb instruction support */
23
#if 1
24
#error "MODET needs to be defined for the Thumb world to work"
25
#else
26
#define MODET (1)
27
#endif
28
#endif
29
 
30
#include "armdefs.h"
31
#include "armemu.h"
32
#include "armos.h"
33
 
34
/* Decode a 16bit Thumb instruction.  The instruction is in the low
35
   16-bits of the tinstr field, with the following Thumb instruction
36
   held in the high 16-bits.  Passing in two Thumb instructions allows
37
   easier simulation of the special dual BL instruction.  */
38
 
39
tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
40
     ARMul_State *
41
       state;
42
     ARMword
43
       pc;
44
     ARMword
45
       tinstr;
46
     ARMword *
47
       ainstr;
48
{
49
  tdstate valid = t_decoded;    /* default assumes a valid instruction */
50
  ARMword next_instr;
51
 
52
  if (state->bigendSig)
53
    {
54
      next_instr = tinstr & 0xFFFF;
55
      tinstr >>= 16;
56
    }
57
  else
58
    {
59
      next_instr = tinstr >> 16;
60
      tinstr &= 0xFFFF;
61
    }
62
 
63
#if 1                           /* debugging to catch non updates */
64
  *ainstr = 0xDEADC0DE;
65
#endif
66
 
67
  switch ((tinstr & 0xF800) >> 11)
68
    {
69
    case 0:                      /* LSL */
70
    case 1:                     /* LSR */
71
    case 2:                     /* ASR */
72
      /* Format 1 */
73
      *ainstr = 0xE1B00000      /* base opcode */
74
        | ((tinstr & 0x1800) >> (11 - 5))       /* shift type */
75
        | ((tinstr & 0x07C0) << (7 - 6))        /* imm5 */
76
        | ((tinstr & 0x0038) >> 3)      /* Rs */
77
        | ((tinstr & 0x0007) << 12);    /* Rd */
78
      break;
79
    case 3:                     /* ADD/SUB */
80
      /* Format 2 */
81
      {
82
        ARMword subset[4] = {
83
          0xE0900000,           /* ADDS Rd,Rs,Rn    */
84
          0xE0500000,           /* SUBS Rd,Rs,Rn    */
85
          0xE2900000,           /* ADDS Rd,Rs,#imm3 */
86
          0xE2500000            /* SUBS Rd,Rs,#imm3 */
87
        };
88
        /* It is quicker indexing into a table, than performing switch
89
           or conditionals: */
90
        *ainstr = subset[(tinstr & 0x0600) >> 9]        /* base opcode */
91
          | ((tinstr & 0x01C0) >> 6)    /* Rn or imm3 */
92
          | ((tinstr & 0x0038) << (16 - 3))     /* Rs */
93
          | ((tinstr & 0x0007) << (12 - 0));     /* Rd */
94
      }
95
      break;
96
    case 4:                     /* MOV */
97
    case 5:                     /* CMP */
98
    case 6:                     /* ADD */
99
    case 7:                     /* SUB */
100
      /* Format 3 */
101
      {
102
        ARMword subset[4] = {
103
          0xE3B00000,           /* MOVS Rd,#imm8    */
104
          0xE3500000,           /* CMP  Rd,#imm8    */
105
          0xE2900000,           /* ADDS Rd,Rd,#imm8 */
106
          0xE2500000,           /* SUBS Rd,Rd,#imm8 */
107
        };
108
        *ainstr = subset[(tinstr & 0x1800) >> 11]       /* base opcode */
109
          | ((tinstr & 0x00FF) >> 0)     /* imm8 */
110
          | ((tinstr & 0x0700) << (16 - 8))     /* Rn */
111
          | ((tinstr & 0x0700) << (12 - 8));    /* Rd */
112
      }
113
      break;
114
    case 8:                     /* Arithmetic and high register transfers */
115
      /* TODO: Since the subsets for both Format 4 and Format 5
116
         instructions are made up of different ARM encodings, we could
117
         save the following conditional, and just have one large
118
         subset. */
119
      if ((tinstr & (1 << 10)) == 0)
120
        {
121
          /* Format 4 */
122
          struct
123
          {
124
            ARMword opcode;
125
            enum
126
            { t_norm, t_shift, t_neg, t_mul }
127
            otype;
128
          }
129
          subset[16] =
130
          {
131
            { 0xE0100000, t_norm},                      /* ANDS Rd,Rd,Rs     */
132
            { 0xE0300000, t_norm},                      /* EORS Rd,Rd,Rs     */
133
            { 0xE1B00010, t_shift},                     /* MOVS Rd,Rd,LSL Rs */
134
            { 0xE1B00030, t_shift},                     /* MOVS Rd,Rd,LSR Rs */
135
            { 0xE1B00050, t_shift},                     /* MOVS Rd,Rd,ASR Rs */
136
            { 0xE0B00000, t_norm},                      /* ADCS Rd,Rd,Rs     */
137
            { 0xE0D00000, t_norm},                      /* SBCS Rd,Rd,Rs     */
138
            { 0xE1B00070, t_shift},                     /* MOVS Rd,Rd,ROR Rs */
139
            { 0xE1100000, t_norm},                      /* TST  Rd,Rs        */
140
            { 0xE2700000, t_neg},                       /* RSBS Rd,Rs,#0     */
141
            { 0xE1500000, t_norm},                      /* CMP  Rd,Rs        */
142
            { 0xE1700000, t_norm},                      /* CMN  Rd,Rs        */
143
            { 0xE1900000, t_norm},                      /* ORRS Rd,Rd,Rs     */
144
            { 0xE0100090, t_mul} ,                      /* MULS Rd,Rd,Rs     */
145
            { 0xE1D00000, t_norm},                      /* BICS Rd,Rd,Rs     */
146
            { 0xE1F00000, t_norm}       /* MVNS Rd,Rs        */
147
          };
148
          *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode;      /* base */
149
          switch (subset[(tinstr & 0x03C0) >> 6].otype)
150
            {
151
            case t_norm:
152
              *ainstr |= ((tinstr & 0x0007) << 16)      /* Rn */
153
                | ((tinstr & 0x0007) << 12)     /* Rd */
154
                | ((tinstr & 0x0038) >> 3);     /* Rs */
155
              break;
156
            case t_shift:
157
              *ainstr |= ((tinstr & 0x0007) << 12)      /* Rd */
158
                | ((tinstr & 0x0007) >> 0)       /* Rm */
159
                | ((tinstr & 0x0038) << (8 - 3));       /* Rs */
160
              break;
161
            case t_neg:
162
              *ainstr |= ((tinstr & 0x0007) << 12)      /* Rd */
163
                | ((tinstr & 0x0038) << (16 - 3));      /* Rn */
164
              break;
165
            case t_mul:
166
              *ainstr |= ((tinstr & 0x0007) << 16)      /* Rd */
167
                | ((tinstr & 0x0007) << 8)      /* Rs */
168
                | ((tinstr & 0x0038) >> 3);     /* Rm */
169
              break;
170
            }
171
        }
172
      else
173
        {
174
          /* Format 5 */
175
          ARMword Rd = ((tinstr & 0x0007) >> 0);
176
          ARMword Rs = ((tinstr & 0x0038) >> 3);
177
          if (tinstr & (1 << 7))
178
            Rd += 8;
179
          if (tinstr & (1 << 6))
180
            Rs += 8;
181
          switch ((tinstr & 0x03C0) >> 6)
182
            {
183
            case 0x1:           /* ADD Rd,Rd,Hs */
184
            case 0x2:           /* ADD Hd,Hd,Rs */
185
            case 0x3:           /* ADD Hd,Hd,Hs */
186
              *ainstr = 0xE0800000      /* base */
187
                | (Rd << 16)    /* Rn */
188
                | (Rd << 12)    /* Rd */
189
                | (Rs << 0);     /* Rm */
190
              break;
191
            case 0x5:           /* CMP Rd,Hs */
192
            case 0x6:           /* CMP Hd,Rs */
193
            case 0x7:           /* CMP Hd,Hs */
194
              *ainstr = 0xE1500000      /* base */
195
                | (Rd << 16)    /* Rn */
196
                | (Rd << 12)    /* Rd */
197
                | (Rs << 0);     /* Rm */
198
              break;
199
            case 0x9:           /* MOV Rd,Hs */
200
            case 0xA:           /* MOV Hd,Rs */
201
            case 0xB:           /* MOV Hd,Hs */
202
              *ainstr = 0xE1A00000      /* base */
203
                | (Rd << 16)    /* Rn */
204
                | (Rd << 12)    /* Rd */
205
                | (Rs << 0);     /* Rm */
206
              break;
207
            case 0xC:           /* BX Rs */
208
            case 0xD:           /* BX Hs */
209
              *ainstr = 0xE12FFF10      /* base */
210
                | ((tinstr & 0x0078) >> 3);     /* Rd */
211
              break;
212
            case 0x0:           /* UNDEFINED */
213
            case 0x4:           /* UNDEFINED */
214
            case 0x8:           /* UNDEFINED */
215
            case 0xE:           /* UNDEFINED */
216
            case 0xF:           /* UNDEFINED */
217
              valid = t_undefined;
218
              break;
219
            }
220
        }
221
      break;
222
    case 9:                     /* LDR Rd,[PC,#imm8] */
223
      /* Format 6 */
224
      *ainstr = 0xE59F0000      /* base */
225
        | ((tinstr & 0x0700) << (12 - 8))       /* Rd */
226
        | ((tinstr & 0x00FF) << (2 - 0));        /* off8 */
227
      break;
228
    case 10:
229
    case 11:
230
      /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
231
         the following could be merged into a single subset, saving on
232
         the following boolean: */
233
      if ((tinstr & (1 << 9)) == 0)
234
        {
235
          /* Format 7 */
236
          ARMword subset[4] = {
237
            0xE7800000,         /* STR  Rd,[Rb,Ro] */
238
            0xE7C00000,         /* STRB Rd,[Rb,Ro] */
239
            0xE7900000,         /* LDR  Rd,[Rb,Ro] */
240
            0xE7D00000          /* LDRB Rd,[Rb,Ro] */
241
          };
242
          *ainstr = subset[(tinstr & 0x0C00) >> 10]     /* base */
243
            | ((tinstr & 0x0007) << (12 - 0))    /* Rd */
244
            | ((tinstr & 0x0038) << (16 - 3))   /* Rb */
245
            | ((tinstr & 0x01C0) >> 6); /* Ro */
246
        }
247
      else
248
        {
249
          /* Format 8 */
250
          ARMword subset[4] = {
251
            0xE18000B0,         /* STRH  Rd,[Rb,Ro] */
252
            0xE19000D0,         /* LDRSB Rd,[Rb,Ro] */
253
            0xE19000B0,         /* LDRH  Rd,[Rb,Ro] */
254
            0xE19000F0          /* LDRSH Rd,[Rb,Ro] */
255
          };
256
          *ainstr = subset[(tinstr & 0x0C00) >> 10]     /* base */
257
            | ((tinstr & 0x0007) << (12 - 0))    /* Rd */
258
            | ((tinstr & 0x0038) << (16 - 3))   /* Rb */
259
            | ((tinstr & 0x01C0) >> 6); /* Ro */
260
        }
261
      break;
262
    case 12:                    /* STR Rd,[Rb,#imm5] */
263
    case 13:                    /* LDR Rd,[Rb,#imm5] */
264
    case 14:                    /* STRB Rd,[Rb,#imm5] */
265
    case 15:                    /* LDRB Rd,[Rb,#imm5] */
266
      /* Format 9 */
267
      {
268
        ARMword subset[4] = {
269
          0xE5800000,           /* STR  Rd,[Rb,#imm5] */
270
          0xE5900000,           /* LDR  Rd,[Rb,#imm5] */
271
          0xE5C00000,           /* STRB Rd,[Rb,#imm5] */
272
          0xE5D00000            /* LDRB Rd,[Rb,#imm5] */
273
        };
274
        /* The offset range defends on whether we are transferring a
275
           byte or word value: */
276
        *ainstr = subset[(tinstr & 0x1800) >> 11]       /* base */
277
          | ((tinstr & 0x0007) << (12 - 0))      /* Rd */
278
          | ((tinstr & 0x0038) << (16 - 3))     /* Rb */
279
          | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
280
      }
281
      break;
282
    case 16:                    /* STRH Rd,[Rb,#imm5] */
283
    case 17:                    /* LDRH Rd,[Rb,#imm5] */
284
      /* Format 10 */
285
      *ainstr = ((tinstr & (1 << 11))   /* base */
286
                 ? 0xE1D000B0   /* LDRH */
287
                 : 0xE1C000B0)  /* STRH */
288
        | ((tinstr & 0x0007) << (12 - 0))        /* Rd */
289
        | ((tinstr & 0x0038) << (16 - 3))       /* Rb */
290
        | ((tinstr & 0x01C0) >> (6 - 1))        /* off5, low nibble */
291
        | ((tinstr & 0x0600) >> (9 - 8));       /* off5, high nibble */
292
      break;
293
    case 18:                    /* STR Rd,[SP,#imm8] */
294
    case 19:                    /* LDR Rd,[SP,#imm8] */
295
      /* Format 11 */
296
      *ainstr = ((tinstr & (1 << 11))   /* base */
297
                 ? 0xE59D0000   /* LDR */
298
                 : 0xE58D0000)  /* STR */
299
        | ((tinstr & 0x0700) << (12 - 8))       /* Rd */
300
        | ((tinstr & 0x00FF) << 2);     /* off8 */
301
      break;
302
    case 20:                    /* ADD Rd,PC,#imm8 */
303
    case 21:                    /* ADD Rd,SP,#imm8 */
304
      /* Format 12 */
305
      if ((tinstr & (1 << 11)) == 0)
306
        {
307
          /* NOTE: The PC value used here should by word aligned */
308
          /* We encode shift-left-by-2 in the rotate immediate field,
309
             so no shift of off8 is needed.  */
310
          *ainstr = 0xE28F0F00  /* base */
311
            | ((tinstr & 0x0700) << (12 - 8))   /* Rd */
312
            | (tinstr & 0x00FF);        /* off8 */
313
        }
314
      else
315
        {
316
          /* We encode shift-left-by-2 in the rotate immediate field,
317
             so no shift of off8 is needed.  */
318
          *ainstr = 0xE28D0F00  /* base */
319
            | ((tinstr & 0x0700) << (12 - 8))   /* Rd */
320
            | (tinstr & 0x00FF);        /* off8 */
321
        }
322
      break;
323
    case 22:
324
    case 23:
325
      if ((tinstr & 0x0F00) == 0x0000)
326
        {
327
          /* Format 13 */
328
          /* NOTE: The instruction contains a shift left of 2
329
             equivalent (implemented as ROR #30): */
330
          *ainstr = ((tinstr & (1 << 7))        /* base */
331
                     ? 0xE24DDF00       /* SUB */
332
                     : 0xE28DDF00)      /* ADD */
333
            | (tinstr & 0x007F);        /* off7 */
334
        }
335
      else if ((tinstr & 0x0F00) == 0x0e00)
336
        *ainstr = 0xEF000000 | SWI_Breakpoint;
337
      else
338
        {
339
          /* Format 14 */
340
          ARMword subset[4] = {
341
            0xE92D0000,         /* STMDB sp!,{rlist}    */
342
            0xE92D4000,         /* STMDB sp!,{rlist,lr} */
343
            0xE8BD0000,         /* LDMIA sp!,{rlist}    */
344
            0xE8BD8000          /* LDMIA sp!,{rlist,pc} */
345
          };
346
          *ainstr = subset[((tinstr & (1 << 11)) >> 10)
347
                           | ((tinstr & (1 << 8)) >> 8)]        /* base */
348
            | (tinstr & 0x00FF);        /* mask8 */
349
        }
350
      break;
351
    case 24:                    /* STMIA */
352
    case 25:                    /* LDMIA */
353
      /* Format 15 */
354
      *ainstr = ((tinstr & (1 << 11))   /* base */
355
                 ? 0xE8B00000   /* LDMIA */
356
                 : 0xE8A00000)  /* STMIA */
357
        | ((tinstr & 0x0700) << (16 - 8))       /* Rb */
358
        | (tinstr & 0x00FF);    /* mask8 */
359
      break;
360
    case 26:                    /* Bcc */
361
    case 27:                    /* Bcc/SWI */
362
      if ((tinstr & 0x0F00) == 0x0F00)
363
        {
364
          /* Format 17 : SWI */
365
          *ainstr = 0xEF000000;
366
          /* Breakpoint must be handled specially.  */
367
          if ((tinstr & 0x00FF) == 0x18)
368
            *ainstr |= ((tinstr & 0x00FF) << 16);
369
          /* New breakpoint value.  See gdb/arm-tdep.c  */
370
          else if ((tinstr & 0x00FF) == 0xFE)
371
            *ainstr |= SWI_Breakpoint;
372
          else
373
            *ainstr |= (tinstr & 0x00FF);
374
        }
375
      else if ((tinstr & 0x0F00) != 0x0E00)
376
        {
377
          /* Format 16 */
378
          int doit = FALSE;
379
          /* TODO: Since we are doing a switch here, we could just add
380
             the SWI and undefined instruction checks into this
381
             switch to same on a couple of conditionals: */
382
          switch ((tinstr & 0x0F00) >> 8)
383
            {
384
            case EQ:
385
              doit = ZFLAG;
386
              break;
387
            case NE:
388
              doit = !ZFLAG;
389
              break;
390
            case VS:
391
              doit = VFLAG;
392
              break;
393
            case VC:
394
              doit = !VFLAG;
395
              break;
396
            case MI:
397
              doit = NFLAG;
398
              break;
399
            case PL:
400
              doit = !NFLAG;
401
              break;
402
            case CS:
403
              doit = CFLAG;
404
              break;
405
            case CC:
406
              doit = !CFLAG;
407
              break;
408
            case HI:
409
              doit = (CFLAG && !ZFLAG);
410
              break;
411
            case LS:
412
              doit = (!CFLAG || ZFLAG);
413
              break;
414
            case GE:
415
              doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
416
              break;
417
            case LT:
418
              doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
419
              break;
420
            case GT:
421
              doit = ((!NFLAG && !VFLAG && !ZFLAG)
422
                      || (NFLAG && VFLAG && !ZFLAG));
423
              break;
424
            case LE:
425
              doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
426
              break;
427
            }
428
          if (doit)
429
            {
430
              state->Reg[15] = (pc + 4
431
                                + (((tinstr & 0x7F) << 1)
432
                                   | ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
433
              FLUSHPIPE;
434
            }
435
          valid = t_branch;
436
        }
437
      else                      /* UNDEFINED : cc=1110(AL) uses different format */
438
        valid = t_undefined;
439
      break;
440
    case 28:                    /* B */
441
      /* Format 18 */
442
      state->Reg[15] = (pc + 4
443
                        + (((tinstr & 0x3FF) << 1)
444
                           | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
445
      FLUSHPIPE;
446
      valid = t_branch;
447
      break;
448
    case 29:                    /* UNDEFINED */
449
      valid = t_undefined;
450
      break;
451
    case 30:                    /* BL instruction 1 */
452
      /* Format 19 */
453
      /* There is no single ARM instruction equivalent for this Thumb
454
         instruction. To keep the simulation simple (from the user
455
         perspective) we check if the following instruction is the
456
         second half of this BL, and if it is we simulate it
457
         immediately.  */
458
      state->Reg[14] = state->Reg[15] \
459
        +(((tinstr & 0x07FF) << 12) \
460
          |((tinstr & (1 << 10)) ? 0xFF800000 : 0));
461
      valid = t_branch;         /* in-case we don't have the 2nd half */
462
      tinstr = next_instr;      /* move the instruction down */
463
      if (((tinstr & 0xF800) >> 11) != 31)
464
        break;                  /* exit, since not correct instruction */
465
      /* else we fall through to process the second half of the BL */
466
      pc += 2;                  /* point the pc at the 2nd half */
467
    case 31:                    /* BL instruction 2 */
468
      /* Format 19 */
469
      /* There is no single ARM instruction equivalent for this
470
         instruction. Also, it should only ever be matched with the
471
         fmt19 "BL instruction 1" instruction. However, we do allow
472
         the simulation of it on its own, with undefined results if
473
         r14 is not suitably initialised.  */
474
      {
475
        ARMword tmp = (pc + 2);
476
        state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
477
        state->Reg[14] = (tmp | 1);
478
        valid = t_branch;
479
        FLUSHPIPE;
480
      }
481
      break;
482
    }
483
 
484
  return valid;
485
}

powered by: WebSVN 2.1.0

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