import gdb-2000-02-04 snapshot
[external/binutils.git] / sim / arm / thumbemu.c
1 /*  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 }