]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/arm/thumbemu.c
Initial creation of sourceware repository
[thirdparty/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
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 }