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