/[gxemul]/upstream/0.3.5/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.5/src/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (show annotations)
Mon Oct 8 16:18:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 30015 byte(s)
0.3.5
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.51 2005/08/16 05:37:10 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->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 Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
57 struct arm_instr_call *ic) \
58 { if (cpu->cd.arm.flags & ARM_FLAG_Z) \
59 arm_instr_ ## n (cpu, ic); } \
60 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
61 struct arm_instr_call *ic) \
62 { if (!(cpu->cd.arm.flags & ARM_FLAG_Z)) \
63 arm_instr_ ## n (cpu, ic); } \
64 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
65 struct arm_instr_call *ic) \
66 { if (cpu->cd.arm.flags & ARM_FLAG_C) \
67 arm_instr_ ## n (cpu, ic); } \
68 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
69 struct arm_instr_call *ic) \
70 { if (!(cpu->cd.arm.flags & ARM_FLAG_C)) \
71 arm_instr_ ## n (cpu, ic); } \
72 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
73 struct arm_instr_call *ic) \
74 { if (cpu->cd.arm.flags & ARM_FLAG_N) \
75 arm_instr_ ## n (cpu, ic); } \
76 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
77 struct arm_instr_call *ic) \
78 { if (!(cpu->cd.arm.flags & ARM_FLAG_N)) \
79 arm_instr_ ## n (cpu, ic); } \
80 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
81 struct arm_instr_call *ic) \
82 { if (cpu->cd.arm.flags & ARM_FLAG_V) \
83 arm_instr_ ## n (cpu, ic); } \
84 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
85 struct arm_instr_call *ic) \
86 { if (!(cpu->cd.arm.flags & ARM_FLAG_V)) \
87 arm_instr_ ## n (cpu, ic); } \
88 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
89 struct arm_instr_call *ic) \
90 { if (cpu->cd.arm.flags & ARM_FLAG_C && \
91 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
92 arm_instr_ ## n (cpu, ic); } \
93 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
94 struct arm_instr_call *ic) \
95 { if (cpu->cd.arm.flags & ARM_FLAG_Z && \
96 !(cpu->cd.arm.flags & ARM_FLAG_C)) \
97 arm_instr_ ## n (cpu, ic); } \
98 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
99 struct arm_instr_call *ic) \
100 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
101 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
102 arm_instr_ ## n (cpu, ic); } \
103 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
104 struct arm_instr_call *ic) \
105 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
106 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
107 arm_instr_ ## n (cpu, ic); } \
108 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
109 struct arm_instr_call *ic) \
110 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
111 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) && \
112 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
113 arm_instr_ ## n (cpu, ic); } \
114 void arm_instr_ ## n ## __le(struct cpu *cpu, \
115 struct arm_instr_call *ic) \
116 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
117 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) || \
118 (cpu->cd.arm.flags & ARM_FLAG_Z)) \
119 arm_instr_ ## n (cpu, ic); } \
120 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
121 struct arm_instr_call *) = { \
122 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
123 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
124 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
125 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
126 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
127 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
128 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
129 arm_instr_ ## n , arm_instr_nop };
130
131 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
132
133
134 /*****************************************************************************/
135
136
137 /*
138 * nop: Do nothing.
139 */
140 X(nop)
141 {
142 }
143
144
145 /*
146 * b: Branch (to a different translated page)
147 *
148 * arg[0] = relative offset
149 */
150 X(b)
151 {
152 uint32_t low_pc;
153
154 /* Calculate new PC from this instruction + arg[0] */
155 low_pc = ((size_t)ic - (size_t)
156 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
157 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
158 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
159 cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];
160 cpu->pc = cpu->cd.arm.r[ARM_PC];
161
162 /* Find the new physical page and update the translation pointers: */
163 arm_pc_to_pointers(cpu);
164 }
165 Y(b)
166
167
168 /*
169 * b_samepage: Branch (to within the same translated page)
170 *
171 * arg[0] = pointer to new arm_instr_call
172 */
173 X(b_samepage)
174 {
175 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
176 }
177 Y(b_samepage)
178
179
180 /*
181 * bl: Branch and Link (to a different translated page)
182 *
183 * arg[0] = relative address
184 */
185 X(bl)
186 {
187 uint32_t lr, low_pc;
188
189 /* Figure out what the return (link) address will be: */
190 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
191 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
192 lr = cpu->cd.arm.r[ARM_PC];
193 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
194 lr += (low_pc << 2);
195
196 /* Link: */
197 cpu->cd.arm.r[ARM_LR] = lr;
198
199 /* Calculate new PC from this instruction + arg[0] */
200 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
201
202 /* Find the new physical page and update the translation pointers: */
203 arm_pc_to_pointers(cpu);
204 }
205 Y(bl)
206
207
208 /*
209 * bl_trace: Branch and Link (to a different translated page), with trace
210 *
211 * Same as for bl.
212 */
213 X(bl_trace)
214 {
215 uint32_t lr, low_pc;
216
217 /* Figure out what the return (link) address will be: */
218 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
219 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
220 lr = cpu->cd.arm.r[ARM_PC];
221 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
222 lr += (low_pc << 2);
223
224 /* Link: */
225 cpu->cd.arm.r[ARM_LR] = lr;
226
227 /* Calculate new PC from this instruction + arg[0] */
228 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
229
230 cpu_functioncall_trace(cpu, cpu->pc);
231
232 /* Find the new physical page and update the translation pointers: */
233 arm_pc_to_pointers(cpu);
234 }
235 Y(bl_trace)
236
237
238 /*
239 * bl_samepage: A branch + link within the same page
240 *
241 * arg[0] = pointer to new arm_instr_call
242 */
243 X(bl_samepage)
244 {
245 uint32_t lr, low_pc;
246
247 /* Figure out what the return (link) address will be: */
248 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
249 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
250 lr = cpu->cd.arm.r[ARM_PC];
251 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
252 lr += (low_pc << 2);
253
254 /* Link: */
255 cpu->cd.arm.r[ARM_LR] = lr;
256
257 /* Branch: */
258 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
259 }
260 Y(bl_samepage)
261
262
263 /*
264 * bl_samepage_trace: Branch and Link (to the same page), with trace
265 *
266 * Same as for bl_samepage.
267 */
268 X(bl_samepage_trace)
269 {
270 uint32_t tmp_pc, lr, low_pc;
271
272 /* Figure out what the return (link) address will be: */
273 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
274 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
275 lr = cpu->cd.arm.r[ARM_PC];
276 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
277 lr += (low_pc << 2);
278
279 /* Link: */
280 cpu->cd.arm.r[ARM_LR] = lr;
281
282 /* Branch: */
283 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
284
285 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
286 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
287 tmp_pc = cpu->cd.arm.r[ARM_PC];
288 tmp_pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
289 tmp_pc += (low_pc << 2);
290 cpu_functioncall_trace(cpu, tmp_pc);
291 }
292 Y(bl_samepage_trace)
293
294
295 /*
296 * mov_pc: "mov pc,reg"
297 *
298 * arg[0] = pointer to uint32_t in host memory of source register
299 */
300 X(mov_pc)
301 {
302 uint32_t old_pc = cpu->cd.arm.r[ARM_PC];
303 uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1) << 2) | 3;
304
305 /* Update the PC register: */
306 cpu->pc = cpu->cd.arm.r[ARM_PC] = *((uint32_t *)ic->arg[0]);
307
308 /*
309 * Is this a return to code within the same page? Then there is no
310 * need to update all pointers, just next_ic.
311 */
312 if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
313 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
314 ((cpu->pc & mask_within_page) >> 2);
315 } else {
316 /* Find the new physical page and update pointers: */
317 arm_pc_to_pointers(cpu);
318 }
319 }
320 Y(mov_pc)
321
322
323 /*
324 * ret_trace: "mov pc,lr" with trace enabled
325 *
326 * arg[0] = ignored (similar to mov_pc above)
327 */
328 X(ret_trace)
329 {
330 uint32_t old_pc = cpu->cd.arm.r[ARM_PC];
331 uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1) << 2) | 3;
332
333 /* Update the PC register: */
334 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
335
336 cpu_functioncall_trace_return(cpu);
337
338 /*
339 * Is this a return to code within the same page? Then there is no
340 * need to update all pointers, just next_ic.
341 */
342 if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
343 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
344 ((cpu->pc & mask_within_page) >> 2);
345 } else {
346 /* Find the new physical page and update pointers: */
347 arm_pc_to_pointers(cpu);
348 }
349 }
350 Y(ret_trace)
351
352
353 /*
354 * mov_regreg:
355 *
356 * arg[0] = pointer to uint32_t in host memory of destination register
357 * arg[1] = pointer to uint32_t in host memory of source register
358 */
359 X(mov_regreg)
360 {
361 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]);
362 }
363 Y(mov_regreg)
364
365
366 /*
367 * mov: Set a 32-bit register to a 32-bit value.
368 *
369 * arg[0] = pointer to uint32_t in host memory
370 * arg[1] = 32-bit value
371 */
372 X(mov)
373 {
374 *((uint32_t *)ic->arg[0]) = ic->arg[1];
375 }
376 Y(mov)
377
378
379 /*
380 * clear: Set a 32-bit register to 0. (A "mov" to fixed value zero.)
381 *
382 * arg[0] = pointer to uint32_t in host memory
383 */
384 X(clear)
385 {
386 *((uint32_t *)ic->arg[0]) = 0;
387 }
388 Y(clear)
389
390
391 #include "tmp_arm_include.c"
392
393
394 #define A__NAME arm_instr_store_w0_byte_u1_p0_imm_fixinc1
395 #define A__NAME__general arm_instr_store_w0_byte_u1_p0_imm_fixinc1__general
396 #define A__B
397 #define A__U
398 #define A__NOCONDITIONS
399 #define A__FIXINC 1
400 #include "cpu_arm_instr_loadstore.c"
401 #undef A__NOCONDITIONS
402 #undef A__B
403 #undef A__U
404 #undef A__NAME__general
405 #undef A__NAME
406
407
408 /*
409 * load_byte_imm_pcrel:
410 * Like load_byte_imm, but the source address is the PC register.
411 * Before loading, we have to synchronize the PC register and add 8.
412 *
413 * arg[0] = pointer to ARM_PC (not used here)
414 * arg[1] = 32-bit offset
415 * arg[2] = pointer to uint32_t in host memory where to store the value
416 */
417 X(load_byte_imm_pcrel)
418 {
419 uint32_t low_pc, addr;
420 unsigned char data[1];
421
422 low_pc = ((size_t)ic - (size_t)
423 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
424 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
425 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
426
427 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
428 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
429 MEM_READ, CACHE_DATA)) {
430 fatal("load failed: TODO\n");
431 exit(1);
432 }
433 *((uint32_t *)ic->arg[2]) = data[0];
434 }
435 Y(load_byte_imm_pcrel)
436
437
438 /*
439 * load_word_imm_pcrel:
440 * Like load_word_imm, but the source address is the PC register.
441 * Before loading, we have to synchronize the PC register and add 8.
442 *
443 * arg[0] = pointer to ARM_PC (not used here)
444 * arg[1] = 32-bit offset
445 * arg[2] = pointer to uint32_t in host memory where to store the value
446 */
447 X(load_word_imm_pcrel)
448 {
449 uint32_t low_pc, addr;
450 unsigned char data[sizeof(uint32_t)];
451
452 low_pc = ((size_t)ic - (size_t)
453 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
454 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
455 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
456
457 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
458 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
459 MEM_READ, CACHE_DATA)) {
460 fatal("load failed: TODO\n");
461 exit(1);
462 }
463 /* TODO: Big endian */
464 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
465 (data[2] << 16) + (data[3] << 24);
466 }
467 Y(load_word_imm_pcrel)
468
469
470 /*
471 * bdt_load: Block Data Transfer, Load
472 *
473 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
474 * arg[1] = 32-bit instruction word. Most bits are read from this.
475 */
476 X(bdt_load)
477 {
478 unsigned char data[4];
479 uint32_t *np = (uint32_t *)ic->arg[0];
480 uint32_t addr = *np;
481 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
482 int p_bit = iw & 0x01000000;
483 int u_bit = iw & 0x00800000;
484 int s_bit = iw & 0x00400000;
485 int w_bit = iw & 0x00200000;
486 int i;
487
488 if (s_bit) {
489 fatal("bdt: TODO: s-bit\n");
490 exit(1);
491 }
492
493 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1))
494 if ((iw >> i) & 1) {
495 /* Load register i: */
496 if (p_bit) {
497 if (u_bit)
498 addr += sizeof(uint32_t);
499 else
500 addr -= sizeof(uint32_t);
501 }
502 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
503 sizeof(data), MEM_READ, CACHE_DATA)) {
504 fatal("bdt: load failed: TODO\n");
505 exit(1);
506 }
507 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
508 cpu->cd.arm.r[i] = data[0] +
509 (data[1] << 8) + (data[2] << 16)
510 + (data[3] << 24);
511 } else {
512 cpu->cd.arm.r[i] = data[3] +
513 (data[2] << 8) + (data[1] << 16)
514 + (data[0] << 24);
515 }
516 /* NOTE: Special case: */
517 if (i == ARM_PC) {
518 cpu->cd.arm.r[ARM_PC] &= ~3;
519 cpu->pc = cpu->cd.arm.r[ARM_PC];
520 /* TODO: There is no need to update the
521 pointers if this is a return to the
522 same page! */
523 /* Find the new physical page and update the
524 translation pointers: */
525 arm_pc_to_pointers(cpu);
526 }
527 if (!p_bit) {
528 if (u_bit)
529 addr += sizeof(uint32_t);
530 else
531 addr -= sizeof(uint32_t);
532 }
533 }
534
535 if (w_bit)
536 *np = addr;
537 }
538 Y(bdt_load)
539
540
541 /*
542 * bdt_store: Block Data Transfer, Store
543 *
544 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
545 * arg[1] = 32-bit instruction word. Most bits are read from this.
546 */
547 X(bdt_store)
548 {
549 unsigned char data[4];
550 uint32_t *np = (uint32_t *)ic->arg[0];
551 uint32_t addr = *np;
552 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
553 int p_bit = iw & 0x01000000;
554 int u_bit = iw & 0x00800000;
555 int s_bit = iw & 0x00400000;
556 int w_bit = iw & 0x00200000;
557 int i;
558
559 if (s_bit) {
560 fatal("bdt: TODO: s-bit\n");
561 exit(1);
562 }
563
564 if (iw & 0x8000) {
565 /* Synchronize the program counter: */
566 uint32_t low_pc = ((size_t)ic - (size_t)
567 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
568 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
569 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
570 cpu->pc = cpu->cd.arm.r[ARM_PC];
571 }
572
573 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1))
574 if ((iw >> i) & 1) {
575 /* Store register i: */
576 uint32_t value = cpu->cd.arm.r[i];
577 if (i == ARM_PC)
578 value += 12; /* TODO: 8 on some ARMs? */
579 if (p_bit) {
580 if (u_bit)
581 addr += sizeof(uint32_t);
582 else
583 addr -= sizeof(uint32_t);
584 }
585 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
586 data[0] = value;
587 data[1] = value >> 8;
588 data[2] = value >> 16;
589 data[3] = value >> 24;
590 } else {
591 data[0] = value >> 24;
592 data[1] = value >> 16;
593 data[2] = value >> 8;
594 data[3] = value;
595 }
596 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
597 sizeof(data), MEM_WRITE, CACHE_DATA)) {
598 fatal("bdt: store failed: TODO\n");
599 exit(1);
600 }
601 if (!p_bit) {
602 if (u_bit)
603 addr += sizeof(uint32_t);
604 else
605 addr -= sizeof(uint32_t);
606 }
607 }
608
609 if (w_bit)
610 *np = addr;
611 }
612 Y(bdt_store)
613
614
615 /*
616 * cmps: Compare a 32-bit register to a 32-bit value. (Subtraction.)
617 *
618 * arg[0] = pointer to uint32_t in host memory
619 * arg[1] = 32-bit value
620 */
621 X(cmps)
622 {
623 uint32_t a, b, c;
624 int v, n;
625 a = *((uint32_t *)ic->arg[0]);
626 b = ic->arg[1];
627
628 cpu->cd.arm.flags &=
629 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
630 c = a - b;
631 if (a > b)
632 cpu->cd.arm.flags |= ARM_FLAG_C;
633 if (c == 0)
634 cpu->cd.arm.flags |= ARM_FLAG_Z;
635 if ((int32_t)c < 0) {
636 cpu->cd.arm.flags |= ARM_FLAG_N;
637 n = 1;
638 } else
639 n = 0;
640 if ((int32_t)a >= (int32_t)b)
641 v = n;
642 else
643 v = !n;
644 if (v)
645 cpu->cd.arm.flags |= ARM_FLAG_V;
646 }
647 Y(cmps)
648
649
650 #include "cpu_arm_instr_cmps.c"
651
652
653 /*
654 * sub: Subtract an immediate value from a 32-bit word, and store the
655 * result in a 32-bit word.
656 *
657 * arg[0] = pointer to destination uint32_t in host memory
658 * arg[1] = pointer to source uint32_t in host memory
659 * arg[2] = 32-bit value
660 */
661 X(sub)
662 {
663 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) - ic->arg[2];
664 }
665 Y(sub)
666 X(sub_self)
667 {
668 *((uint32_t *)ic->arg[0]) -= ic->arg[2];
669 }
670 Y(sub_self)
671
672
673 /*
674 * add: Add an immediate value to a 32-bit word, and store the
675 * result in a 32-bit word.
676 *
677 * arg[0] = pointer to destination uint32_t in host memory
678 * arg[1] = pointer to source uint32_t in host memory
679 * arg[2] = 32-bit value
680 */
681 X(add)
682 {
683 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) + ic->arg[2];
684 }
685 Y(add)
686 X(add_self)
687 {
688 *((uint32_t *)ic->arg[0]) += ic->arg[2];
689 }
690 Y(add_self)
691
692
693 #include "tmp_arm_include_self.c"
694
695
696 /*****************************************************************************/
697
698
699 /*
700 * mov_2: Double "mov".
701 *
702 * The current and the next arm_instr_call are treated as "mov"s.
703 */
704 X(mov_2)
705 {
706 *((uint32_t *)ic[0].arg[0]) = ic[0].arg[1];
707 *((uint32_t *)ic[1].arg[0]) = ic[1].arg[1];
708 cpu->cd.arm.next_ic ++;
709 cpu->n_translated_instrs ++;
710 }
711
712
713 /*
714 * fill_loop_test:
715 *
716 * A byte-fill loop. Fills at most one page at a time. If the page was not
717 * in the host_store table, then the original sequence (beginning with
718 * cmps r2,#0) is executed instead.
719 *
720 * Z:cmps r2,#0 ic[0]
721 * strb rX,[rY],#1 ic[1]
722 * sub r2,r2,#1 ic[2]
723 * bgt Z ic[3]
724 */
725 X(fill_loop_test)
726 {
727 uint32_t addr, a, n, ofs, maxlen;
728 unsigned char *page;
729
730 addr = *((uint32_t *)ic[1].arg[0]);
731 n = cpu->cd.arm.r[2] + 1;
732 ofs = addr & 0xfff;
733 maxlen = 4096 - ofs;
734 if (n > maxlen)
735 n = maxlen;
736
737 page = cpu->cd.arm.host_store[addr >> 12];
738 if (page == NULL) {
739 arm_cmps_0[2](cpu, ic);
740 return;
741 }
742
743 /* printf("x = %x, n = %i\n", *((uint32_t *)ic[1].arg[2]), n); */
744 memset(page + ofs, *((uint32_t *)ic[1].arg[2]), n);
745
746 *((uint32_t *)ic[1].arg[0]) = addr + n;
747
748 cpu->cd.arm.r[2] -= n;
749 cpu->n_translated_instrs += (4 * n);
750
751 a = cpu->cd.arm.r[2];
752
753 cpu->cd.arm.flags &=
754 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
755 if (a != 0)
756 cpu->cd.arm.flags |= ARM_FLAG_C;
757 else
758 cpu->cd.arm.flags |= ARM_FLAG_Z;
759 if ((int32_t)a < 0)
760 cpu->cd.arm.flags |= ARM_FLAG_N;
761
762 cpu->n_translated_instrs --;
763
764 if ((int32_t)a > 0)
765 cpu->cd.arm.next_ic --;
766 else
767 cpu->cd.arm.next_ic += 3;
768 }
769
770
771 /*****************************************************************************/
772
773
774 X(end_of_page)
775 {
776 /* Update the PC: (offset 0, but on the next page) */
777 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << 2);
778 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE << 2);
779 cpu->pc = cpu->cd.arm.r[ARM_PC];
780
781 /* Find the new physical page and update the translation pointers: */
782 arm_pc_to_pointers(cpu);
783
784 /* end_of_page doesn't count as an executed instruction: */
785 cpu->n_translated_instrs --;
786 }
787
788
789 /*****************************************************************************/
790
791
792 /*
793 * arm_combine_instructions():
794 *
795 * Combine two or more instructions, if possible, into a single function call.
796 */
797 void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic,
798 uint32_t addr)
799 {
800 int n_back;
801 n_back = (addr >> 2) & (ARM_IC_ENTRIES_PER_PAGE-1);
802
803 if (n_back >= 1) {
804 /* Double "mov": */
805 if (ic[-1].f == instr(mov) || ic[-1].f == instr(clear)) {
806 if (ic[-1].f == instr(mov) && ic[0].f == instr(mov)) {
807 ic[-1].f = instr(mov_2);
808 combined;
809 }
810 if (ic[-1].f == instr(clear) && ic[0].f == instr(mov)) {
811 ic[-1].f = instr(mov_2);
812 ic[-1].arg[1] = 0;
813 combined;
814 }
815 if (ic[-1].f == instr(mov) && ic[0].f == instr(clear)) {
816 ic[-1].f = instr(mov_2);
817 ic[0].arg[1] = 0;
818 combined;
819 }
820 if (ic[-1].f == instr(clear) && ic[0].f==instr(clear)) {
821 ic[-1].f = instr(mov_2);
822 ic[-1].arg[1] = 0;
823 ic[0].arg[1] = 0;
824 combined;
825 }
826 }
827 }
828
829 if (n_back >= 3) {
830 if (ic[-3].f == arm_cmps_0[2] &&
831 ic[-2].f == instr(store_w0_byte_u1_p0_imm) &&
832 ic[-2].arg[1] == 1 &&
833 ic[-1].f == arm_sub_self_1[2] &&
834 ic[ 0].f == instr(b_samepage__gt) &&
835 ic[ 0].arg[0] == (size_t)&ic[-3]) {
836 ic[-3].f = instr(fill_loop_test);
837 combined;
838 }
839 }
840
841 /* TODO: Combine forward as well */
842 }
843
844
845 /*****************************************************************************/
846
847
848 /*
849 * arm_instr_to_be_translated():
850 *
851 * Translate an instruction word into an arm_instr_call. ic is filled in with
852 * valid data for the translated instruction, or a "nothing" instruction if
853 * there was a translation failure. The newly translated instruction is then
854 * executed.
855 */
856 X(to_be_translated)
857 {
858 uint32_t addr, low_pc, iword, imm;
859 unsigned char *page;
860 unsigned char ib[4];
861 int condition_code, main_opcode, secondary_opcode, s_bit, r16, r12, r8;
862 int p_bit, u_bit, b_bit, w_bit, l_bit;
863 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
864
865 /* Figure out the (virtual) address of the instruction: */
866 low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
867 / sizeof(struct arm_instr_call);
868 addr = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
869 ARM_INSTR_ALIGNMENT_SHIFT);
870 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
871 cpu->pc = cpu->cd.arm.r[ARM_PC] = addr;
872 addr &= ~0x3;
873
874 /* Read the instruction word from memory: */
875 page = cpu->cd.arm.host_load[addr >> 12];
876
877 if (page != NULL) {
878 /* fatal("TRANSLATION HIT!\n"); */
879 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
880 } else {
881 /* fatal("TRANSLATION MISS!\n"); */
882 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
883 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
884 fatal("to_be_translated(): "
885 "read failed: TODO\n");
886 goto bad;
887 }
888 }
889
890 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
891 iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
892 else
893 iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
894
895 /* fatal("{ ARM translating pc=0x%08x iword=0x%08x }\n",
896 addr, iword); */
897
898
899 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
900 #include "cpu_dyntrans.c"
901 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
902
903
904 /* The idea of taking bits 27..24 was found here:
905 http://armphetamine.sourceforge.net/oldinfo.html */
906 condition_code = iword >> 28;
907 main_opcode = (iword >> 24) & 15;
908 secondary_opcode = (iword >> 21) & 15;
909 u_bit = (iword >> 23) & 1;
910 b_bit = (iword >> 22) & 1;
911 w_bit = (iword >> 21) & 1;
912 s_bit = l_bit = (iword >> 20) & 1;
913 r16 = (iword >> 16) & 15;
914 r12 = (iword >> 12) & 15;
915 r8 = (iword >> 8) & 15;
916
917 if (condition_code == 0xf) {
918 fatal("TODO: ARM condition code 0x%x\n",
919 condition_code);
920 goto bad;
921 }
922
923
924 /*
925 * Translate the instruction:
926 */
927
928 switch (main_opcode) {
929
930 case 0x0:
931 case 0x1:
932 case 0x2:
933 case 0x3:
934 if ((main_opcode & 2) == 0) {
935 if ((iword & 0x0ffffff0) == 0x01a0f000) {
936 /* Hardcoded: mov pc, rX */
937 if ((iword & 15) == ARM_PC) {
938 fatal("mov pc,pc?\n");
939 goto bad;
940 }
941 ic->f = cond_instr(mov_pc);
942 ic->arg[0] = (size_t)
943 (&cpu->cd.arm.r[iword & 15]);
944 if ((iword & 15) == ARM_LR &&
945 cpu->machine->show_trace_tree)
946 ic->f = cond_instr(ret_trace);
947 } else if ((iword & 0x0fff0ff0) == 0x01a00000) {
948 /* Hardcoded: mov reg,reg */
949 if ((iword & 15) == ARM_PC) {
950 fatal("mov reg,pc?\n");
951 goto bad;
952 }
953 ic->f = cond_instr(mov_regreg);
954 ic->arg[0] = (size_t)
955 (&cpu->cd.arm.r[r12]);
956 ic->arg[1] = (size_t)
957 (&cpu->cd.arm.r[iword & 15]);
958 } else {
959 fatal("REGISTER FORM! TODO\n");
960 goto bad;
961 }
962 break;
963 }
964 imm = iword & 0xff;
965 r8 <<= 1;
966 while (r8-- > 0)
967 imm = (imm >> 1) | ((imm & 1) << 31);
968 switch (secondary_opcode) {
969 case 0x2: /* SUB */
970 case 0x4: /* ADD */
971 if (s_bit) {
972 fatal("add/sub s_bit: TODO\n");
973 goto bad;
974 }
975 if (r12 == ARM_PC || r16 == ARM_PC) {
976 fatal("add/sub: PC\n");
977 goto bad;
978 }
979 switch (secondary_opcode) {
980 case 0x2:
981 ic->f = cond_instr(sub);
982 if (r12 == r16) {
983 ic->f = cond_instr(sub_self);
984 if (imm == 1 && r12 != ARM_PC)
985 ic->f = arm_sub_self_1[r12];
986 if (imm == 4 && r12 != ARM_PC)
987 ic->f = arm_sub_self_4[r12];
988 }
989 break;
990 case 0x4:
991 ic->f = cond_instr(add);
992 if (r12 == r16) {
993 ic->f = cond_instr(add_self);
994 if (imm == 1 && r12 != ARM_PC)
995 ic->f = arm_add_self_1[r12];
996 if (imm == 4 && r12 != ARM_PC)
997 ic->f = arm_add_self_4[r12];
998 }
999 break;
1000 }
1001 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
1002 ic->arg[1] = (size_t)(&cpu->cd.arm.r[r16]);
1003 ic->arg[2] = imm;
1004 break;
1005 case 0xa: /* CMP */
1006 if (!s_bit) {
1007 fatal("cmp !s_bit: TODO\n");
1008 goto bad;
1009 }
1010 ic->f = cond_instr(cmps);
1011 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
1012 ic->arg[1] = imm;
1013 if (imm == 0 && r16 != ARM_PC)
1014 ic->f = arm_cmps_0[r16];
1015 break;
1016 case 0xd: /* MOV */
1017 if (s_bit) {
1018 fatal("mov s_bit: TODO\n");
1019 goto bad;
1020 }
1021 if (r12 == ARM_PC) {
1022 fatal("TODO: mov used as branch\n");
1023 goto bad;
1024 } else {
1025 ic->f = cond_instr(mov);
1026 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
1027 ic->arg[1] = imm;
1028 if (imm == 0)
1029 ic->f = cond_instr(clear);
1030 }
1031 break;
1032 default:goto bad;
1033 }
1034 break;
1035
1036 case 0x4: /* Load and store... */
1037 case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
1038 case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
1039 case 0x7:
1040 p_bit = main_opcode & 1;
1041 ic->f = load_store_instr[((iword >> 16) & 0x3f0)
1042 + condition_code];
1043 imm = iword & 0xfff;
1044 if (!u_bit)
1045 imm = (int32_t)0-imm;
1046 if (main_opcode < 6) {
1047 /* Immediate: */
1048 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
1049 ic->arg[1] = (size_t)(imm);
1050 ic->arg[2] = (size_t)(&cpu->cd.arm.r[r12]);
1051 }
1052 if (main_opcode == 4 && b_bit) {
1053 /* Post-index, immediate: */
1054 if (imm == 1 && !w_bit && l_bit)
1055 ic->f = instr(store_w0_byte_u1_p0_imm_fixinc1);
1056 if (w_bit) {
1057 fatal("load/store: T-bit\n");
1058 goto bad;
1059 }
1060 if (r16 == ARM_PC) {
1061 fatal("load/store writeback PC: error\n");
1062 goto bad;
1063 }
1064 } else if (main_opcode == 5) {
1065 /* Pre-index, immediate: */
1066 /* ldr(b) Rd,[Rn,#imm] */
1067 if (l_bit) {
1068 if (r12 == ARM_PC) {
1069 fatal("WARNING: ldr to pc register?\n");
1070 goto bad;
1071 }
1072 if (r16 == ARM_PC) {
1073 if (w_bit) {
1074 fatal("w bit load etc\n");
1075 goto bad;
1076 }
1077 ic->f = b_bit?
1078 cond_instr(load_byte_imm_pcrel) :
1079 cond_instr(load_word_imm_pcrel);
1080 }
1081 } else {
1082 if (r12 == ARM_PC) {
1083 fatal("TODO: store pc\n");
1084 goto bad;
1085 }
1086 if (r16 == ARM_PC) {
1087 fatal("TODO: store pc rel\n");
1088 goto bad;
1089 }
1090 }
1091 } else {
1092 fatal("Specific Load/store TODO\n");
1093 goto bad;
1094 }
1095 break;
1096
1097 case 0x8: /* Multiple load/store... (Block data transfer) */
1098 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
1099 if (l_bit)
1100 ic->f = cond_instr(bdt_load);
1101 else
1102 ic->f = cond_instr(bdt_store);
1103 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
1104 ic->arg[1] = (size_t)iword;
1105 if (r16 == ARM_PC) {
1106 fatal("TODO: bdt with PC as base\n");
1107 goto bad;
1108 }
1109 break;
1110
1111 case 0xa: /* B: branch */
1112 case 0xb: /* BL: branch+link */
1113 if (main_opcode == 0x0a) {
1114 ic->f = cond_instr(b);
1115 samepage_function = cond_instr(b_samepage);
1116 } else {
1117 if (cpu->machine->show_trace_tree) {
1118 ic->f = cond_instr(bl_trace);
1119 samepage_function =
1120 cond_instr(bl_samepage_trace);
1121 } else {
1122 ic->f = cond_instr(bl);
1123 samepage_function = cond_instr(bl_samepage);
1124 }
1125 }
1126
1127 ic->arg[0] = (iword & 0x00ffffff) << 2;
1128 /* Sign-extend: */
1129 if (ic->arg[0] & 0x02000000)
1130 ic->arg[0] |= 0xfc000000;
1131 /*
1132 * Branches are calculated as PC + 8 + offset.
1133 */
1134 ic->arg[0] = (int32_t)(ic->arg[0] + 8);
1135
1136 /* Special case: branch within the same page: */
1137 {
1138 uint32_t mask_within_page =
1139 ((ARM_IC_ENTRIES_PER_PAGE-1) << 2) | 3;
1140 uint32_t old_pc = addr;
1141 uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
1142 if ((old_pc & ~mask_within_page) ==
1143 (new_pc & ~mask_within_page)) {
1144 ic->f = samepage_function;
1145 ic->arg[0] = (size_t) (
1146 cpu->cd.arm.cur_ic_page +
1147 ((new_pc & mask_within_page) >> 2));
1148 }
1149 }
1150 break;
1151
1152 default:goto bad;
1153 }
1154
1155
1156 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
1157 #include "cpu_dyntrans.c"
1158 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
1159 }
1160

  ViewVC Help
Powered by ViewVC 1.1.26