import gdb-1999-11-01 snapshot
[deliverable/binutils-gdb.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 }
This page took 0.068734 seconds and 4 git commands to generate.