* memory corruption fix
[deliverable/binutils-gdb.git] / sim / arm / thumbemu.c
CommitLineData
c906108c
SS
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
19instruction into its corresponding ARM instruction, and using the
20existing ARM simulator. */
21
dfcd3bfb 22#ifndef MODET /* required for the Thumb instruction support */
c906108c
SS
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"
7a292a7a 32#include "armos.h"
c906108c
SS
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
dfcd3bfb
JM
39tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
40 ARMul_State *
41 state;
42 ARMword
43 pc;
44 ARMword
45 tinstr;
46 ARMword *
47 ainstr;
c906108c 48{
dfcd3bfb 49 tdstate valid = t_decoded; /* default assumes a valid instruction */
c906108c 50 ARMword next_instr;
dfcd3bfb 51
c906108c
SS
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 }
dfcd3bfb
JM
62
63#if 1 /* debugging to catch non updates */
c906108c
SS
64 *ainstr = 0xDEADC0DE;
65#endif
66
67 switch ((tinstr & 0xF800) >> 11)
68 {
dfcd3bfb
JM
69 case 0: /* LSL */
70 case 1: /* LSR */
71 case 2: /* ASR */
c906108c 72 /* Format 1 */
dfcd3bfb
JM
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 */
c906108c 78 break;
dfcd3bfb 79 case 3: /* ADD/SUB */
c906108c
SS
80 /* Format 2 */
81 {
dfcd3bfb
JM
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 */
c906108c
SS
94 }
95 break;
dfcd3bfb
JM
96 case 4: /* MOV */
97 case 5: /* CMP */
98 case 6: /* ADD */
99 case 7: /* SUB */
c906108c
SS
100 /* Format 3 */
101 {
dfcd3bfb
JM
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 */
c906108c 112 }
dfcd3bfb
JM
113 break;
114 case 8: /* Arithmetic and high register transfers */
c906108c
SS
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)
dfcd3bfb
JM
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 }
c906108c 172 else
dfcd3bfb
JM
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 }
c906108c 221 break;
dfcd3bfb 222 case 9: /* LDR Rd,[PC,#imm8] */
c906108c 223 /* Format 6 */
dfcd3bfb
JM
224 *ainstr = 0xE59F0000 /* base */
225 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
226 | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
c906108c
SS
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)
dfcd3bfb
JM
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 }
c906108c 247 else
dfcd3bfb
JM
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 }
c906108c 261 break;
dfcd3bfb
JM
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] */
c906108c
SS
266 /* Format 9 */
267 {
dfcd3bfb
JM
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 */
c906108c
SS
280 }
281 break;
dfcd3bfb
JM
282 case 16: /* STRH Rd,[Rb,#imm5] */
283 case 17: /* LDRH Rd,[Rb,#imm5] */
c906108c 284 /* Format 10 */
dfcd3bfb
JM
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 */
c906108c 292 break;
dfcd3bfb
JM
293 case 18: /* STR Rd,[SP,#imm8] */
294 case 19: /* LDR Rd,[SP,#imm8] */
c906108c 295 /* Format 11 */
dfcd3bfb
JM
296 *ainstr = ((tinstr & (1 << 11)) /* base */
297 ? 0xE59D0000 /* LDR */
298 : 0xE58D0000) /* STR */
299 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
300 | ((tinstr & 0x00FF) << 2); /* off8 */
c906108c 301 break;
dfcd3bfb
JM
302 case 20: /* ADD Rd,PC,#imm8 */
303 case 21: /* ADD Rd,SP,#imm8 */
c906108c
SS
304 /* Format 12 */
305 if ((tinstr & (1 << 11)) == 0)
dfcd3bfb
JM
306 {
307 /* NOTE: The PC value used here should by word aligned */
c906108c
SS
308 /* We encode shift-left-by-2 in the rotate immediate field,
309 so no shift of off8 is needed. */
dfcd3bfb
JM
310 *ainstr = 0xE28F0F00 /* base */
311 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
312 | (tinstr & 0x00FF); /* off8 */
313 }
c906108c 314 else
dfcd3bfb 315 {
c906108c
SS
316 /* We encode shift-left-by-2 in the rotate immediate field,
317 so no shift of off8 is needed. */
dfcd3bfb
JM
318 *ainstr = 0xE28D0F00 /* base */
319 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
320 | (tinstr & 0x00FF); /* off8 */
321 }
c906108c
SS
322 break;
323 case 22:
324 case 23:
325 if ((tinstr & 0x0F00) == 0x0000)
dfcd3bfb
JM
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 }
5c44784c 335 else if ((tinstr & 0x0F00) == 0x0e00)
dfcd3bfb 336 *ainstr = 0xEF000000 | SWI_Breakpoint;
c906108c 337 else
dfcd3bfb
JM
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 }
c906108c 350 break;
dfcd3bfb
JM
351 case 24: /* STMIA */
352 case 25: /* LDMIA */
c906108c 353 /* Format 15 */
dfcd3bfb
JM
354 *ainstr = ((tinstr & (1 << 11)) /* base */
355 ? 0xE8B00000 /* LDMIA */
356 : 0xE8A00000) /* STMIA */
357 | ((tinstr & 0x0700) << (16 - 8)) /* Rb */
358 | (tinstr & 0x00FF); /* mask8 */
c906108c 359 break;
dfcd3bfb
JM
360 case 26: /* Bcc */
361 case 27: /* Bcc/SWI */
c906108c 362 if ((tinstr & 0x0F00) == 0x0F00)
dfcd3bfb
JM
363 {
364 /* Format 17 : SWI */
365 *ainstr = 0xEF000000;
c906108c
SS
366 /* Breakpoint must be handled specially. */
367 if ((tinstr & 0x00FF) == 0x18)
368 *ainstr |= ((tinstr & 0x00FF) << 16);
7a292a7a
SS
369 /* New breakpoint value. See gdb/arm-tdep.c */
370 else if ((tinstr & 0x00FF) == 0xFE)
dfcd3bfb 371 *ainstr |= SWI_Breakpoint;
c906108c
SS
372 else
373 *ainstr |= (tinstr & 0x00FF);
dfcd3bfb 374 }
c906108c 375 else if ((tinstr & 0x0F00) != 0x0E00)
dfcd3bfb
JM
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;
c906108c 439 break;
dfcd3bfb 440 case 28: /* B */
c906108c 441 /* Format 18 */
dfcd3bfb
JM
442 state->Reg[15] = (pc + 4
443 + (((tinstr & 0x3FF) << 1)
444 | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
c906108c
SS
445 FLUSHPIPE;
446 valid = t_branch;
447 break;
dfcd3bfb 448 case 29: /* UNDEFINED */
c906108c
SS
449 valid = t_undefined;
450 break;
dfcd3bfb 451 case 30: /* BL instruction 1 */
c906108c
SS
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
dfcd3bfb 457 immediately. */
c906108c 458 state->Reg[14] = state->Reg[15] \
dfcd3bfb
JM
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 */
c906108c 463 if (((tinstr & 0xF800) >> 11) != 31)
dfcd3bfb 464 break; /* exit, since not correct instruction */
c906108c 465 /* else we fall through to process the second half of the BL */
dfcd3bfb
JM
466 pc += 2; /* point the pc at the 2nd half */
467 case 31: /* BL instruction 2 */
c906108c
SS
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
dfcd3bfb 473 r14 is not suitably initialised. */
c906108c 474 {
dfcd3bfb
JM
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;
c906108c
SS
480 }
481 break;
482 }
483
484 return valid;
485}
This page took 0.092231 seconds and 4 git commands to generate.