/[gxemul]/upstream/0.3.4/src/cpu_arm_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.4/src/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (show annotations)
Mon Oct 8 16:18:31 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 25914 byte(s)
0.3.4
1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_instr.c,v 1.20 2005/06/27 09:20:19 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->cd.arm.n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 */
37
38
39 /*
40 * Helper definitions:
41 *
42 * Each instruction is defined like this:
43 *
44 * X(foo)
45 * {
46 * code for foo;
47 * }
48 * Y(foo)
49 *
50 * The Y macro defines 14 copies of the instruction, one for each possible
51 * condition code. (The NV condition code is not included, and the AL code
52 * uses the main foo function.) Y also defines an array with pointers to
53 * all of these functions.
54 */
55
56 #define X(n) void arm_instr_ ## n(struct cpu *cpu, \
57 struct arm_instr_call *ic)
58
59 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
60 struct arm_instr_call *ic) \
61 { if (cpu->cd.arm.flags & ARM_FLAG_Z) \
62 arm_instr_ ## n (cpu, ic); } \
63 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
64 struct arm_instr_call *ic) \
65 { if (!(cpu->cd.arm.flags & ARM_FLAG_Z)) \
66 arm_instr_ ## n (cpu, ic); } \
67 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
68 struct arm_instr_call *ic) \
69 { if (cpu->cd.arm.flags & ARM_FLAG_C) \
70 arm_instr_ ## n (cpu, ic); } \
71 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
72 struct arm_instr_call *ic) \
73 { if (!(cpu->cd.arm.flags & ARM_FLAG_C)) \
74 arm_instr_ ## n (cpu, ic); } \
75 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
76 struct arm_instr_call *ic) \
77 { if (cpu->cd.arm.flags & ARM_FLAG_N) \
78 arm_instr_ ## n (cpu, ic); } \
79 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
80 struct arm_instr_call *ic) \
81 { if (!(cpu->cd.arm.flags & ARM_FLAG_N)) \
82 arm_instr_ ## n (cpu, ic); } \
83 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
84 struct arm_instr_call *ic) \
85 { if (cpu->cd.arm.flags & ARM_FLAG_V) \
86 arm_instr_ ## n (cpu, ic); } \
87 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
88 struct arm_instr_call *ic) \
89 { if (!(cpu->cd.arm.flags & ARM_FLAG_V)) \
90 arm_instr_ ## n (cpu, ic); } \
91 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
92 struct arm_instr_call *ic) \
93 { if (cpu->cd.arm.flags & ARM_FLAG_C && \
94 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
95 arm_instr_ ## n (cpu, ic); } \
96 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
97 struct arm_instr_call *ic) \
98 { if (cpu->cd.arm.flags & ARM_FLAG_Z && \
99 !(cpu->cd.arm.flags & ARM_FLAG_C)) \
100 arm_instr_ ## n (cpu, ic); } \
101 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
102 struct arm_instr_call *ic) \
103 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
104 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
105 arm_instr_ ## n (cpu, ic); } \
106 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
107 struct arm_instr_call *ic) \
108 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
109 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
110 arm_instr_ ## n (cpu, ic); } \
111 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
112 struct arm_instr_call *ic) \
113 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
114 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) && \
115 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
116 arm_instr_ ## n (cpu, ic); } \
117 void arm_instr_ ## n ## __le(struct cpu *cpu, \
118 struct arm_instr_call *ic) \
119 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
120 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) || \
121 (cpu->cd.arm.flags & ARM_FLAG_Z)) \
122 arm_instr_ ## n (cpu, ic); } \
123 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
124 struct arm_instr_call *) = { \
125 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
126 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
127 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
128 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
129 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
130 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
131 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
132 arm_instr_ ## n , arm_instr_nop };
133
134 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
135
136
137 /* This is for marking a physical page as containing combined instructions: */
138 #define combined (cpu->cd.arm.cur_physpage->flags |= ARM_COMBINATIONS)
139
140
141 void arm_translate_instruction(struct cpu *cpu, struct arm_instr_call *ic);
142
143
144 /*
145 * nothing: Do nothing.
146 *
147 * The difference between this function and the "nop" instruction is that
148 * this function does not increase the program counter or the number of
149 * translated instructions. It is used to "get out" of running in translated
150 * mode.
151 */
152 X(nothing)
153 {
154 cpu->cd.arm.running_translated = 0;
155 cpu->cd.arm.n_translated_instrs --;
156 cpu->cd.arm.next_ic --;
157 }
158
159
160 static struct arm_instr_call nothing_call = { instr(nothing), {0,0,0} };
161
162
163 /*****************************************************************************/
164
165
166 /*
167 * nop: Do nothing.
168 */
169 X(nop)
170 {
171 }
172
173
174 /*
175 * b: Branch (to a different translated page)
176 *
177 * arg[0] = relative offset
178 */
179 X(b)
180 {
181 int low_pc;
182 uint32_t old_pc;
183
184 /* fatal("b: arg[0] = 0x%08x, pc=0x%08x\n", ic->arg[0], cpu->pc); */
185
186 /* Calculate new PC from this instruction + arg[0] */
187 low_pc = ((size_t)ic - (size_t)
188 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
189 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
190 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
191 old_pc = cpu->cd.arm.r[ARM_PC];
192 /* fatal("b: 3: old_pc=0x%08x\n", old_pc); */
193 cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];
194 cpu->pc = cpu->cd.arm.r[ARM_PC];
195 /* fatal("b: 2: pc=0x%08x\n", cpu->pc); */
196
197 fatal("b: different page! TODO\n");
198 exit(1);
199 }
200 Y(b)
201
202
203 /*
204 * b_samepage: Branch (to within the same translated page)
205 *
206 * arg[0] = pointer to new arm_instr_call
207 */
208 X(b_samepage)
209 {
210 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
211 }
212 Y(b_samepage)
213
214
215 /*
216 * bl: Branch and Link (to a different translated page)
217 *
218 * arg[0] = relative address
219 *
220 * TODO: Implement this.
221 * TODO: How about function call trace?
222 */
223 X(bl)
224 {
225 fatal("bl different page: TODO\n");
226 exit(1);
227 }
228 Y(bl)
229
230
231 /*
232 * bl_samepage: A branch + link within the same page
233 *
234 * arg[0] = pointer to new arm_instr_call
235 *
236 * TODO: How about function call trace?
237 */
238 X(bl_samepage)
239 {
240 uint32_t lr, low_pc;
241
242 /* Figure out what the return (link) address will be: */
243 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
244 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
245 lr = cpu->cd.arm.r[ARM_PC];
246 lr &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
247 lr += (low_pc << 2);
248
249 /* Link: */
250 cpu->cd.arm.r[ARM_LR] = lr;
251
252 /* Branch: */
253 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
254 }
255 Y(bl_samepage)
256
257
258 /*
259 * mov: Set a 32-bit register to a 32-bit value.
260 *
261 * arg[0] = pointer to uint32_t in host memory
262 * arg[1] = 32-bit value
263 */
264 X(mov)
265 {
266 *((uint32_t *)ic->arg[0]) = ic->arg[1];
267 }
268 Y(mov)
269
270
271 /*
272 * clear: Set a 32-bit register to 0. (A "mov" to fixed value zero.)
273 *
274 * arg[0] = pointer to uint32_t in host memory
275 */
276 X(clear)
277 {
278 *((uint32_t *)ic->arg[0]) = 0;
279 }
280 Y(clear)
281
282
283 /*
284 * load_byte_imm: Load an 8-bit byte from emulated memory and store it in
285 * a 32-bit word in host memory.
286 *
287 * arg[0] = pointer to uint32_t in host memory of base address
288 * arg[1] = 32-bit offset
289 * arg[2] = pointer to uint32_t in host memory where to store the value
290 */
291 X(load_byte_imm)
292 {
293 unsigned char data[1];
294 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
295 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
296 MEM_READ, CACHE_DATA)) {
297 fatal("load failed: TODO\n");
298 exit(1);
299 }
300 *((uint32_t *)ic->arg[2]) = data[0];
301 }
302 Y(load_byte_imm)
303
304
305 /*
306 * load_byte_w_imm:
307 * Load an 8-bit byte from emulated memory and store it in
308 * a 32-bit word in host memory, with address writeback.
309 *
310 * arg[0] = pointer to uint32_t in host memory of base address
311 * arg[1] = 32-bit offset
312 * arg[2] = pointer to uint32_t in host memory where to store the value
313 */
314 X(load_byte_w_imm)
315 {
316 unsigned char data[1];
317 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
318 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
319 MEM_READ, CACHE_DATA)) {
320 fatal("load failed: TODO\n");
321 exit(1);
322 }
323 *((uint32_t *)ic->arg[2]) = data[0];
324 *((uint32_t *)ic->arg[0]) = addr;
325 }
326 Y(load_byte_w_imm)
327
328
329 /*
330 * load_byte_wpost_imm:
331 * Load an 8-bit byte from emulated memory and store it in
332 * a 32-bit word in host memory, with address writeback AFTER the load.
333 *
334 * arg[0] = pointer to uint32_t in host memory of base address
335 * arg[1] = 32-bit offset
336 * arg[2] = pointer to uint32_t in host memory where to store the value
337 */
338 X(load_byte_wpost_imm)
339 {
340 unsigned char data[1];
341 uint32_t addr = *((uint32_t *)ic->arg[0]);
342 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
343 MEM_READ, CACHE_DATA)) {
344 fatal("load failed: TODO\n");
345 exit(1);
346 }
347 *((uint32_t *)ic->arg[2]) = data[0];
348 *((uint32_t *)ic->arg[0]) = addr + ic->arg[1];
349 }
350 Y(load_byte_wpost_imm)
351
352
353 /*
354 * store_byte_imm: Load a word from a 32-bit word in host memory, and store
355 * the lowest 8 bits of that word at an emulated memory
356 * address.
357 *
358 * arg[0] = pointer to uint32_t in host memory of base address
359 * arg[1] = 32-bit offset
360 * arg[2] = pointer to uint32_t in host memory where to load the value from
361 */
362 X(store_byte_imm)
363 {
364 unsigned char data[1];
365 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
366 data[0] = *((uint32_t *)ic->arg[2]);
367 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
368 MEM_WRITE, CACHE_DATA)) {
369 fatal("store failed: TODO\n");
370 exit(1);
371 }
372 }
373 Y(store_byte_imm)
374
375
376 /*
377 * store_byte_wpost_imm:
378 * Load a word from a 32-bit word in host memory, and store
379 * the lowest 8 bits of that word at an emulated memory address.
380 * Then add the immediate offset to the address, and write back
381 * to the first word.
382 *
383 * arg[0] = pointer to uint32_t in host memory of base address
384 * arg[1] = 32-bit offset
385 * arg[2] = pointer to uint32_t in host memory where to load the value from
386 */
387 X(store_byte_wpost_imm)
388 {
389 unsigned char data[1];
390 uint32_t addr = *((uint32_t *)ic->arg[0]);
391 data[0] = *((uint32_t *)ic->arg[2]);
392 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
393 MEM_WRITE, CACHE_DATA)) {
394 fatal("store failed: TODO\n");
395 exit(1);
396 }
397 *((uint32_t *)ic->arg[0]) = addr + ic->arg[1];
398 }
399 Y(store_byte_wpost_imm)
400
401
402 /*
403 * load_word_imm:
404 * Load a 32-bit word from emulated memory and store it in
405 * a 32-bit word in host memory.
406 *
407 * arg[0] = pointer to uint32_t in host memory of base address
408 * arg[1] = 32-bit offset
409 * arg[2] = pointer to uint32_t in host memory where to store the value
410 */
411 X(load_word_imm)
412 {
413 unsigned char data[sizeof(uint32_t)];
414 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
415 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
416 MEM_READ, CACHE_DATA)) {
417 fatal("load word failed: TODO\n");
418 exit(1);
419 }
420 /* TODO: Big endian */
421 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
422 (data[2] << 16) + (data[3] << 24);
423 }
424 Y(load_word_imm)
425
426
427 /*
428 * load_word_w_imm:
429 * Load a 32-bit word from emulated memory and store it in
430 * a 32-bit word in host memory, with address writeback.
431 *
432 * arg[0] = pointer to uint32_t in host memory of base address
433 * arg[1] = 32-bit offset
434 * arg[2] = pointer to uint32_t in host memory where to store the value
435 */
436 X(load_word_w_imm)
437 {
438 unsigned char data[sizeof(uint32_t)];
439 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
440 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
441 MEM_READ, CACHE_DATA)) {
442 fatal("load word failed: TODO\n");
443 exit(1);
444 }
445 /* TODO: Big endian */
446 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
447 (data[2] << 16) + (data[3] << 24);
448 *((uint32_t *)ic->arg[0]) = addr;
449 }
450 Y(load_word_w_imm)
451
452
453 /*
454 * store_word_imm: Load a 32-bit word from host memory and store it
455 * in emulated memory.
456 *
457 * arg[0] = pointer to uint32_t in host memory of base address
458 * arg[1] = 32-bit offset
459 * arg[2] = pointer to uint32_t in host memory where to load the value from.
460 */
461 X(store_word_imm)
462 {
463 unsigned char data[sizeof(uint32_t)];
464 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
465 uint32_t x = *((uint32_t *)ic->arg[2]);
466 /* TODO: Big endian */
467 data[0] = x; data[1] = x >> 8; data[2] = x >> 16; data[3] = x >> 24;
468 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
469 MEM_WRITE, CACHE_DATA)) {
470 fatal("store word failed: TODO\n");
471 exit(1);
472 }
473 }
474 Y(store_word_imm)
475
476
477 /*
478 * load_byte_imm_pcrel:
479 * Like load_byte_imm, but the source address is the PC register.
480 * Before loading, we have to synchronize the PC register and add 8.
481 *
482 * arg[0] = pointer to ARM_PC (not used here)
483 * arg[1] = 32-bit offset
484 * arg[2] = pointer to uint32_t in host memory where to store the value
485 */
486 X(load_byte_imm_pcrel)
487 {
488 uint32_t low_pc, addr;
489 unsigned char data[1];
490
491 low_pc = ((size_t)ic - (size_t)
492 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
493 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
494 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
495
496 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
497 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
498 MEM_READ, CACHE_DATA)) {
499 fatal("load failed: TODO\n");
500 exit(1);
501 }
502 *((uint32_t *)ic->arg[2]) = data[0];
503 }
504 Y(load_byte_imm_pcrel)
505
506
507 /*
508 * load_word_imm_pcrel:
509 * Like load_word_imm, but the source address is the PC register.
510 * Before loading, we have to synchronize the PC register and add 8.
511 *
512 * arg[0] = pointer to ARM_PC (not used here)
513 * arg[1] = 32-bit offset
514 * arg[2] = pointer to uint32_t in host memory where to store the value
515 */
516 X(load_word_imm_pcrel)
517 {
518 uint32_t low_pc, addr;
519 unsigned char data[sizeof(uint32_t)];
520
521 low_pc = ((size_t)ic - (size_t)
522 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
523 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
524 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
525
526 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
527 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
528 MEM_READ, CACHE_DATA)) {
529 fatal("load failed: TODO\n");
530 exit(1);
531 }
532 /* TODO: Big endian */
533 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
534 (data[2] << 16) + (data[3] << 24);
535 }
536 Y(load_word_imm_pcrel)
537
538
539 /*
540 * cmps: Compare a 32-bit register to a 32-bit value. (Subtraction.)
541 *
542 * arg[0] = pointer to uint32_t in host memory
543 * arg[1] = 32-bit value
544 */
545 X(cmps)
546 {
547 uint32_t a, b, c;
548 int v, n;
549 a = *((uint32_t *)ic->arg[0]);
550 b = ic->arg[1];
551
552 c = a - b;
553 cpu->cd.arm.flags &=
554 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
555 if (c == 0)
556 cpu->cd.arm.flags |= ARM_FLAG_Z;
557 if ((int32_t)c < 0) {
558 cpu->cd.arm.flags |= ARM_FLAG_N;
559 n = 1;
560 } else
561 n = 0;
562 v = !n;
563 if ((int32_t)a >= (int32_t)b)
564 v = n;
565 if (v)
566 cpu->cd.arm.flags |= ARM_FLAG_V;
567 if (a > b)
568 cpu->cd.arm.flags |= ARM_FLAG_C;
569 }
570 Y(cmps)
571
572
573 /*
574 * sub: Subtract an immediate value from a 32-bit word, and store the
575 * result in a 32-bit word.
576 *
577 * arg[0] = pointer to destination uint32_t in host memory
578 * arg[1] = pointer to source uint32_t in host memory
579 * arg[2] = 32-bit value
580 */
581 X(sub)
582 {
583 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) - ic->arg[2];
584 }
585 Y(sub)
586 X(sub_self)
587 {
588 *((uint32_t *)ic->arg[0]) -= ic->arg[2];
589 }
590 Y(sub_self)
591
592
593 /*
594 * add: Add an immediate value to a 32-bit word, and store the
595 * result in a 32-bit word.
596 *
597 * arg[0] = pointer to destination uint32_t in host memory
598 * arg[1] = pointer to source uint32_t in host memory
599 * arg[2] = 32-bit value
600 */
601 X(add)
602 {
603 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) + ic->arg[2];
604 }
605 Y(add)
606 X(add_self)
607 {
608 *((uint32_t *)ic->arg[0]) += ic->arg[2];
609 }
610 Y(add_self)
611
612
613 /*****************************************************************************/
614
615
616 /*
617 * mov_2: Double "mov".
618 *
619 * The current and the next arm_instr_call are treated as "mov"s.
620 */
621 X(mov_2)
622 {
623 *((uint32_t *)ic[0].arg[0]) = ic[0].arg[1];
624 *((uint32_t *)ic[1].arg[0]) = ic[1].arg[1];
625 cpu->cd.arm.next_ic ++;
626 cpu->cd.arm.n_translated_instrs ++;
627 }
628
629
630 /*****************************************************************************/
631
632
633 X(to_be_translated)
634 {
635 /* Translate the instruction... */
636 arm_translate_instruction(cpu, ic);
637
638 /* ... and execute it: */
639 ic->f(cpu, ic);
640 }
641
642
643 X(end_of_page)
644 {
645 printf("end_of_page()! pc=0x%08x\n", cpu->cd.arm.r[ARM_PC]);
646
647 /* Update the PC: Offset 0, but then go to next page: */
648 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
649 cpu->cd.arm.r[ARM_PC] += (IC_ENTRIES_PER_PAGE << 2);
650 cpu->pc = cpu->cd.arm.r[ARM_PC];
651
652 /* Find the new (physical) page: */
653 /* TODO */
654
655 printf("TODO: end_of_page()! new pc=0x%08x\n", cpu->cd.arm.r[ARM_PC]);
656 exit(1);
657 }
658
659
660 /*****************************************************************************/
661
662
663 /*
664 * arm_combine_instructions():
665 *
666 * Combine two or more instructions, if possible, into a single function call.
667 */
668 void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic)
669 {
670 int n_back;
671 n_back = (cpu->pc >> 2) & (IC_ENTRIES_PER_PAGE-1);
672
673 if (n_back >= 1) {
674 /* Double "mov": */
675 if (ic[-1].f == instr(mov) || ic[-1].f == instr(clear)) {
676 if (ic[-1].f == instr(mov) && ic[0].f == instr(mov)) {
677 ic[-1].f = instr(mov_2);
678 combined;
679 }
680 if (ic[-1].f == instr(clear) && ic[0].f == instr(mov)) {
681 ic[-1].f = instr(mov_2);
682 ic[-1].arg[1] = 0;
683 combined;
684 }
685 if (ic[-1].f == instr(mov) && ic[0].f == instr(clear)) {
686 ic[-1].f = instr(mov_2);
687 ic[0].arg[1] = 0;
688 combined;
689 }
690 if (ic[-1].f == instr(clear) && ic[0].f==instr(clear)) {
691 ic[-1].f = instr(mov_2);
692 ic[-1].arg[1] = 0;
693 ic[0].arg[1] = 0;
694 combined;
695 }
696 }
697 }
698 }
699
700
701 /*
702 * arm_translate_instruction():
703 *
704 * Translate an instruction word into an arm_instr_call.
705 */
706 void arm_translate_instruction(struct cpu *cpu, struct arm_instr_call *ic)
707 {
708 uint32_t addr, low_pc, iword, imm;
709 unsigned char ib[4];
710 int condition_code, main_opcode, secondary_opcode, s_bit, r16, r12, r8;
711 int p_bit, u_bit, b_bit, w_bit, l_bit;
712 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
713
714 /* Make sure that PC is in synch: */
715 low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
716 / sizeof(struct arm_instr_call);
717 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
718 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
719 cpu->pc = cpu->cd.arm.r[ARM_PC];
720
721 /* Read the instruction word from memory: */
722 addr = cpu->pc & ~0x3;
723
724 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
725 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
726 fatal("arm_translate_instruction(): read failed: TODO\n");
727 goto bad;
728 }
729
730 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
731 iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
732 else
733 iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
734
735 /* fatal("{ ARM translating pc=0x%08x iword=0x%08x }\n",
736 addr, iword); */
737
738 /* The idea of taking bits 27..24 was found here:
739 http://armphetamine.sourceforge.net/oldinfo.html */
740 condition_code = iword >> 28;
741 main_opcode = (iword >> 24) & 15;
742 secondary_opcode = (iword >> 21) & 15;
743 u_bit = (iword >> 23) & 1;
744 b_bit = (iword >> 22) & 1;
745 w_bit = (iword >> 21) & 1;
746 s_bit = l_bit = (iword >> 20) & 1;
747 r16 = (iword >> 16) & 15;
748 r12 = (iword >> 12) & 15;
749 r8 = (iword >> 8) & 15;
750
751 if (condition_code == 0xf) {
752 fatal("TODO: ARM condition code 0x%x\n",
753 condition_code);
754 goto bad;
755 }
756
757
758 /*
759 * Translate the instruction:
760 */
761
762 switch (main_opcode) {
763
764 case 0x0:
765 case 0x1:
766 case 0x2:
767 case 0x3:
768 if ((main_opcode & 2) == 0) {
769 fatal("REGISTER FORM! TODO\n");
770 goto bad;
771 }
772 imm = iword & 0xff;
773 r8 <<= 1;
774 while (r8-- > 0)
775 imm = (imm >> 1) | ((imm & 1) << 31);
776 switch (secondary_opcode) {
777 case 0x2: /* SUB */
778 case 0x4: /* ADD */
779 if (s_bit) {
780 fatal("sub s_bit: TODO\n");
781 goto bad;
782 }
783 switch (secondary_opcode) {
784 case 0x2:
785 if (r12 == r16)
786 ic->f = cond_instr(sub_self);
787 else
788 ic->f = cond_instr(sub);
789 break;
790 case 0x4:
791 if (r12 == r16)
792 ic->f = cond_instr(add_self);
793 else
794 ic->f = cond_instr(add);
795 break;
796 }
797 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
798 ic->arg[1] = (size_t)(&cpu->cd.arm.r[r16]);
799 ic->arg[2] = imm;
800 break;
801 case 0xa: /* CMP */
802 if (!s_bit) {
803 fatal("cmp !s_bit: TODO\n");
804 goto bad;
805 }
806 ic->f = cond_instr(cmps);
807 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
808 ic->arg[1] = imm;
809 break;
810 case 0xd: /* MOV */
811 if (s_bit) {
812 fatal("mov s_bit: TODO\n");
813 goto bad;
814 }
815 if (r12 == ARM_PC) {
816 fatal("TODO: mov used as branch\n");
817 goto bad;
818 } else {
819 ic->f = cond_instr(mov);
820 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
821 ic->arg[1] = imm;
822 if (imm == 0)
823 ic->f = cond_instr(clear);
824 }
825 break;
826 default:goto bad;
827 }
828 break;
829
830 case 0x4: /* Load and store... */
831 case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
832 case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
833 case 0x7:
834 p_bit = main_opcode & 1;
835 if (main_opcode < 6) {
836 /* Immediate: */
837 imm = iword & 0xfff;
838 if (!u_bit)
839 imm = (int32_t)0-imm;
840 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
841 ic->arg[1] = (size_t)(imm);
842 ic->arg[2] = (size_t)(&cpu->cd.arm.r[r12]);
843 }
844 if (main_opcode == 4 && b_bit) {
845 /* Post-index, immediate: */
846 if (w_bit) {
847 fatal("load/store: T-bit\n");
848 goto bad;
849 }
850 if (r16 == ARM_PC) {
851 fatal("load/store writeback PC: error\n");
852 goto bad;
853 }
854 if (l_bit)
855 ic->f = cond_instr(load_byte_wpost_imm);
856 else
857 ic->f = cond_instr(store_byte_wpost_imm);
858 } else if (main_opcode == 5) {
859 /* Pre-index, immediate: */
860 /* ldr(b) Rd,[Rn,#imm] */
861 if (l_bit) {
862 if (r12 == ARM_PC)
863 fatal("WARNING: ldr to pc register?\n");
864 if (w_bit) {
865 ic->f = b_bit?
866 cond_instr(load_byte_w_imm) :
867 cond_instr(load_word_w_imm);
868 } else {
869 ic->f = b_bit?
870 cond_instr(load_byte_imm) :
871 cond_instr(load_word_imm);
872 }
873 if (r16 == ARM_PC) {
874 if (w_bit) {
875 fatal("w bit load etc\n");
876 goto bad;
877 }
878 ic->f = b_bit?
879 cond_instr(load_byte_imm_pcrel) :
880 cond_instr(load_word_imm_pcrel);
881 }
882 } else {
883 if (w_bit) {
884 fatal("w bit store etc\n");
885 goto bad;
886 }
887 if (r12 == ARM_PC) {
888 fatal("TODO: store pc\n");
889 goto bad;
890 }
891 ic->f = b_bit?
892 cond_instr(store_byte_imm) :
893 cond_instr(store_word_imm);
894 if (r16 == ARM_PC) {
895 fatal("TODO: store pc rel\n");
896 goto bad;
897 }
898 }
899 } else {
900 fatal("Specific Load/store TODO\n");
901 goto bad;
902 }
903 break;
904
905 case 0xa: /* B: branch */
906 case 0xb: /* BL: branch+link */
907 if (main_opcode == 0x0a) {
908 ic->f = cond_instr(b);
909 samepage_function = cond_instr(b_samepage);
910 } else {
911 ic->f = cond_instr(bl);
912 samepage_function = cond_instr(bl_samepage);
913 }
914
915 ic->arg[0] = (iword & 0x00ffffff) << 2;
916 /* Sign-extend: */
917 if (ic->arg[0] & 0x02000000)
918 ic->arg[0] |= 0xfc000000;
919 /* Branches are calculated as PC + 8 + offset: */
920 ic->arg[0] = (int32_t)(ic->arg[0] + 8);
921
922 /* Special case: branch within the same page: */
923 {
924 uint32_t mask_within_page =
925 ((IC_ENTRIES_PER_PAGE-1) << 2) | 3;
926 uint32_t old_pc = addr;
927 uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
928 if ((old_pc & ~mask_within_page) ==
929 (new_pc & ~mask_within_page)) {
930 ic->f = samepage_function;
931 ic->arg[0] = (size_t) (
932 cpu->cd.arm.cur_ic_page +
933 ((new_pc & mask_within_page) >> 2));
934 }
935 }
936 break;
937
938 default:goto bad;
939 }
940
941
942 /*
943 * If we end up here, then an instruction was translated. Now it is
944 * time to check for combinations of instructions that can be
945 * converted into a single function call.
946 */
947
948 /* Single-stepping doesn't work with combinations: */
949 if (single_step || cpu->machine->instruction_trace)
950 return;
951
952 arm_combine_instructions(cpu, ic);
953
954 return;
955
956
957 bad: /*
958 * Nothing was translated. (Unimplemented or illegal instruction.)
959 */
960 quiet_mode = 0;
961 fatal("arm_translate_instruction(): TODO: "
962 "unimplemented ARM instruction:\n");
963 arm_cpu_disassemble_instr(cpu, ib, 1, 0, 0);
964 cpu->running = 0;
965 cpu->dead = 1;
966 cpu->cd.arm.running_translated = 0;
967 *ic = nothing_call;
968 }
969

  ViewVC Help
Powered by ViewVC 1.1.26