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