/[gxemul]/upstream/0.3.4/src/cpu_arm.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

Annotation of /upstream/0.3.4/src/cpu_arm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Mon Oct 8 16:18:31 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 19098 byte(s)
0.3.4
1 dpavlin 6 /*
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 dpavlin 10 * $Id: cpu_arm.c,v 1.19 2005/06/27 16:44:54 debug Exp $
29 dpavlin 6 *
30     * ARM CPU emulation.
31     *
32 dpavlin 10 * Whenever there is a reference to "(1)", that means
33     * "http://www.pinknoise.demon.co.uk/ARMinstrs/ARMinstrs.html".
34 dpavlin 6 */
35    
36     #include <stdio.h>
37     #include <stdlib.h>
38     #include <string.h>
39     #include <ctype.h>
40    
41     #include "misc.h"
42    
43    
44     #ifndef ENABLE_ARM
45    
46    
47     #include "cpu_arm.h"
48    
49    
50     /*
51     * arm_cpu_family_init():
52     *
53     * Bogus, when ENABLE_ARM isn't defined.
54     */
55     int arm_cpu_family_init(struct cpu_family *fp)
56     {
57     return 0;
58     }
59    
60    
61     #else /* ENABLE_ARM */
62    
63    
64     #include "cpu.h"
65     #include "cpu_arm.h"
66     #include "machine.h"
67     #include "memory.h"
68     #include "symbol.h"
69    
70    
71 dpavlin 10 /* instr uses the same names as in cpu_arm_instr.c */
72     #define instr(n) arm_instr_ ## n
73    
74     static char *arm_condition_string[16] = {
75     "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
76     "hi", "ls", "ge", "lt", "gt", "le", ""/*Always*/, "(INVALID)" };
77    
78     /* ARM symbolic register names: */
79     static char *arm_regname[N_ARM_REGS] = {
80     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
81     "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" };
82    
83     /* Data processing instructions: */
84     static char *arm_dpiname[16] = {
85     "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
86     "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" };
87     static int arm_dpi_uses_d[16] = {
88     1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 };
89     static int arm_dpi_uses_n[16] = {
90     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0 };
91    
92 dpavlin 6 extern volatile int single_step;
93     extern int old_show_trace_tree;
94     extern int old_instruction_trace;
95     extern int old_quiet_mode;
96     extern int quiet_mode;
97    
98    
99     /*
100     * arm_cpu_new():
101     *
102 dpavlin 10 * Create a new ARM cpu object by filling in the CPU struct.
103     * Return 1 on success, 0 if cpu_type_name isn't a valid ARM processor.
104 dpavlin 6 */
105 dpavlin 10 int arm_cpu_new(struct cpu *cpu, struct memory *mem,
106     struct machine *machine, int cpu_id, char *cpu_type_name)
107 dpavlin 6 {
108 dpavlin 10 if (strcmp(cpu_type_name, "ARM") != 0)
109     return 0;
110 dpavlin 6
111 dpavlin 10 cpu->memory_rw = arm_memory_rw;
112 dpavlin 6
113 dpavlin 10 cpu->cd.arm.flags = ARM_FLAG_I | ARM_FLAG_F | ARM_MODE_USR32;
114 dpavlin 6
115 dpavlin 10 /* Only show name and caches etc for CPU nr 0: */
116 dpavlin 6 if (cpu_id == 0) {
117     debug("%s", cpu->name);
118     }
119    
120 dpavlin 10 return 1;
121 dpavlin 6 }
122    
123    
124     /*
125     * arm_cpu_dumpinfo():
126     */
127     void arm_cpu_dumpinfo(struct cpu *cpu)
128     {
129 dpavlin 10 debug(" (%i MB translation cache)\n",
130     (int)(ARM_TRANSLATION_CACHE_SIZE / 1048576));
131 dpavlin 6 }
132    
133    
134     /*
135     * arm_cpu_list_available_types():
136     *
137     * Print a list of available ARM CPU types.
138     */
139     void arm_cpu_list_available_types(void)
140     {
141     /* TODO */
142    
143     debug("ARM\n");
144     }
145    
146    
147     /*
148     * arm_cpu_register_match():
149     */
150     void arm_cpu_register_match(struct machine *m, char *name,
151     int writeflag, uint64_t *valuep, int *match_register)
152     {
153 dpavlin 10 int i, cpunr = 0;
154 dpavlin 6
155     /* CPU number: */
156    
157     /* TODO */
158    
159 dpavlin 10 /* Register names: */
160     for (i=0; i<N_ARM_REGS; i++) {
161     if (strcasecmp(name, arm_regname[i]) == 0) {
162     if (writeflag) {
163     m->cpus[cpunr]->cd.arm.r[i] = *valuep;
164     if (i == ARM_PC)
165     m->cpus[cpunr]->pc = *valuep;
166     } else
167     *valuep = m->cpus[cpunr]->cd.arm.r[i];
168     *match_register = 1;
169     }
170 dpavlin 6 }
171 dpavlin 10 }
172 dpavlin 6
173 dpavlin 10
174     /*
175     * arm_cpu_register_dump():
176     *
177     * Dump cpu registers in a relatively readable format.
178     *
179     * gprs: set to non-zero to dump GPRs and some special-purpose registers.
180     * coprocs: set bit 0..3 to dump registers in coproc 0..3.
181     */
182     void arm_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
183     {
184     char *symbol;
185     uint64_t offset;
186     int i, x = cpu->cpu_id;
187    
188     if (gprs) {
189     symbol = get_symbol_name(&cpu->machine->symbol_context,
190     cpu->cd.arm.r[ARM_PC], &offset);
191     debug("cpu%i: flags = ", x);
192     debug("%s%s%s%s%s%s",
193     (cpu->cd.arm.flags & ARM_FLAG_N)? "N" : "n",
194     (cpu->cd.arm.flags & ARM_FLAG_Z)? "Z" : "z",
195     (cpu->cd.arm.flags & ARM_FLAG_C)? "C" : "c",
196     (cpu->cd.arm.flags & ARM_FLAG_V)? "V" : "v",
197     (cpu->cd.arm.flags & ARM_FLAG_I)? "I" : "i",
198     (cpu->cd.arm.flags & ARM_FLAG_F)? "F" : "f");
199     debug(" pc = 0x%08x", (int)cpu->cd.arm.r[ARM_PC]);
200    
201     /* TODO: Flags */
202    
203     debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
204    
205     for (i=0; i<N_ARM_REGS; i++) {
206     if ((i % 4) == 0)
207     debug("cpu%i:", x);
208     if (i != ARM_PC)
209     debug(" %s = 0x%08x", arm_regname[i],
210     (int)cpu->cd.arm.r[i]);
211     if ((i % 4) == 3)
212     debug("\n");
213     }
214     }
215 dpavlin 6 }
216    
217    
218     /*
219     * arm_cpu_disassemble_instr():
220     *
221     * Convert an instruction word into human readable format, for instruction
222     * tracing.
223     *
224     * If running is 1, cpu->pc should be the address of the instruction.
225     *
226     * If running is 0, things that depend on the runtime environment (eg.
227     * register contents) will not be shown, and addr will be used instead of
228     * cpu->pc for relative addresses.
229     */
230 dpavlin 10 int arm_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
231 dpavlin 6 int running, uint64_t dumpaddr, int bintrans)
232     {
233 dpavlin 10 uint32_t iw, tmp;
234     int main_opcode, secondary_opcode, s_bit, r16, r12, r8;
235     int p_bit, u_bit, b_bit, w_bit, l_bit;
236     char *symbol, *condition;
237     uint64_t offset;
238 dpavlin 6
239     if (running)
240     dumpaddr = cpu->pc;
241    
242 dpavlin 10 symbol = get_symbol_name(&cpu->machine->symbol_context,
243     dumpaddr, &offset);
244     if (symbol != NULL && offset == 0)
245     debug("<%s>\n", symbol);
246    
247     if (cpu->machine->ncpus > 1 && running)
248     debug("cpu%i:\t", cpu->cpu_id);
249    
250 dpavlin 6 debug("%08x: ", (int)dumpaddr);
251    
252 dpavlin 10 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
253     iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
254     else
255     iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
256 dpavlin 6 debug("%08x\t", (int)iw);
257    
258 dpavlin 10 condition = arm_condition_string[iw >> 28];
259     main_opcode = (iw >> 24) & 15;
260     secondary_opcode = (iw >> 21) & 15;
261     u_bit = (iw >> 23) & 1;
262     b_bit = (iw >> 22) & 1;
263     w_bit = (iw >> 21) & 1;
264     s_bit = l_bit = (iw >> 20) & 1;
265     r16 = (iw >> 16) & 15;
266     r12 = (iw >> 12) & 15;
267     r8 = (iw >> 8) & 15;
268 dpavlin 6
269 dpavlin 10 switch (main_opcode) {
270     case 0x0:
271     case 0x1:
272     case 0x2:
273     case 0x3:
274     /*
275     * See (1):
276     * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form
277     * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form
278     */
279     if (iw & 0x80 && !(main_opcode & 2)) {
280     debug("UNIMPLEMENTED reg (c!=0)\n");
281     break;
282     }
283    
284     debug("%s%s%s\t", arm_dpiname[secondary_opcode],
285     condition, s_bit? "s" : "");
286     if (arm_dpi_uses_d[secondary_opcode])
287     debug("%s,", arm_regname[r12]);
288     if (arm_dpi_uses_n[secondary_opcode])
289     debug("%s,", arm_regname[r16]);
290    
291     if (main_opcode & 2) {
292     /* Immediate form: */
293     int r = (iw >> 7) & 30;
294     uint32_t b = iw & 0xff;
295     while (r-- > 0)
296     b = (b >> 1) | ((b & 1) << 31);
297     if (b < 15)
298     debug("#%i", b);
299     else
300     debug("#0x%x", b);
301     } else {
302     /* Register form: */
303     int t = (iw >> 4) & 7;
304     int c = (iw >> 7) & 31;
305     debug("%s", arm_regname[iw & 15]);
306     switch (t) {
307     case 0: if (c != 0)
308     debug(" LSL #%i", c);
309     break;
310     case 1: debug(" LSL %s", arm_regname[c >> 1]);
311     break;
312     case 2: debug(" LSR #%i", c? c : 32);
313     break;
314     case 3: debug(" LSR %s", arm_regname[c >> 1]);
315     break;
316     case 4: debug(" ASR #%i", c? c : 32);
317     break;
318     case 5: debug(" ASR %s", arm_regname[c >> 1]);
319     break;
320     case 6: if (c != 0)
321     debug(" ROR #%i", c);
322     else
323     debug(" RRX");
324     break;
325     case 7: debug(" ROR %s", arm_regname[c >> 1]);
326     break;
327     }
328     }
329     debug("\n");
330     break;
331     case 0x4: /* Single Data Transfer */
332     case 0x5:
333     case 0x6:
334     case 0x7:
335     /*
336     * See (1):
337     * xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form
338     * xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form
339     */
340     p_bit = main_opcode & 1;
341     if (main_opcode >= 6 && iw & 0x10) {
342     debug("TODO: single data transf. but 0x10\n");
343     break;
344     }
345     debug("%s%s%s", l_bit? "ldr" : "str",
346     condition, b_bit? "b" : "");
347     if (!p_bit && w_bit)
348     debug("t");
349     debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]);
350     if (main_opcode < 6) {
351     /* Immediate form: */
352     uint32_t imm = iw & 0xfff;
353     if (!p_bit)
354     debug("]");
355     if (imm != 0)
356     debug(",#%s%i", u_bit? "" : "-", imm);
357     if (p_bit)
358     debug("]");
359     } else {
360     debug(" TODO: REG-form]");
361     }
362     debug("%s\n", (p_bit && w_bit)? "!" : "");
363     break;
364     case 0x8: /* Block Data Transfer */
365     case 0x9:
366     debug("TODO: block data transfer\n");
367     break;
368     case 0xa: /* B: branch */
369     case 0xb: /* BL: branch and link */
370     debug("b%s%s\t", main_opcode == 0xa? "" : "l", condition);
371     tmp = (iw & 0x00ffffff) << 2;
372     if (tmp & 0x02000000)
373     tmp |= 0xfc000000;
374     tmp = (int32_t)(dumpaddr + tmp + 8);
375     debug("0x%x", (int)tmp);
376     symbol = get_symbol_name(&cpu->machine->symbol_context,
377     tmp, &offset);
378     if (symbol != NULL)
379     debug("\t\t<%s>", symbol);
380     debug("\n");
381     break;
382     case 0xc: /* Coprocessor */
383     case 0xd: /* LDC/STC */
384     /* xxxx110P UNWLnnnn DDDDpppp oooooooo LDC/STC */
385     debug("TODO: coprocessor LDC/STC\n");
386     break;
387     case 0xe: /* CDP (Coprocessor Op) */
388     /* or MRC/MCR!
389     * According to (1):
390     * xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP
391     * xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR
392     */
393     if (iw & 0x10) {
394     debug("%s%s\t",
395     (iw & 0x00100000)? "mrc" : "mcr", condition);
396     debug("%i,%i,r%i,cr%i,cr%i,%i",
397     (int)((iw >> 8) & 15), (int)((iw >>21) & 7),
398     (int)((iw >>12) & 15), (int)((iw >>16) & 15),
399     (int)((iw >> 0) & 15), (int)((iw >> 5) & 7));
400     } else {
401     debug("cdp%s\t", condition);
402     debug("%i,%i,cr%i,cr%i,cr%i",
403     (int)((iw >> 8) & 15),
404     (int)((iw >>20) & 15),
405     (int)((iw >>12) & 15),
406     (int)((iw >>16) & 15),
407     (int)((iw >> 0) & 15));
408     if ((iw >> 5) & 7)
409     debug(",0x%x", (int)((iw >> 5) & 7));
410     }
411     debug("\n");
412     break;
413     case 0xf: /* SWI */
414     debug("swi%s\t", condition);
415     debug("0x%x\n", (int)(iw & 0x00ffffff));
416     break;
417     default:debug("UNIMPLEMENTED\n");
418     }
419    
420 dpavlin 6 return sizeof(uint32_t);
421     }
422    
423    
424 dpavlin 10 /*
425     * arm_create_or_reset_tc():
426     *
427     * Create the translation cache in memory (ie allocate memory for it), if
428     * necessary, and then reset it to an initial state.
429     */
430     static void arm_create_or_reset_tc(struct cpu *cpu)
431     {
432     if (cpu->cd.arm.translation_cache == NULL) {
433     cpu->cd.arm.translation_cache = malloc(
434     ARM_TRANSLATION_CACHE_SIZE + ARM_TRANSLATION_CACHE_MARGIN);
435     if (cpu->cd.arm.translation_cache == NULL) {
436     fprintf(stderr, "arm_create_or_reset_tc(): out of "
437     "memory when allocating the translation cache\n");
438     exit(1);
439     }
440     }
441    
442     /* Create an empty table at the beginning of the translation cache: */
443     memset(cpu->cd.arm.translation_cache, 0, sizeof(uint32_t) *
444     N_BASE_TABLE_ENTRIES);
445    
446     cpu->cd.arm.translation_cache_cur_ofs =
447     N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
448     }
449    
450    
451     /*
452     * arm_tc_allocate_default_page():
453     *
454     * Create a default page (with just pointers to instr(to_be_translated)
455     * at cpu->cd.arm.translation_cache_cur_ofs.
456     */
457     /* forward declaration of to_be_translated and end_of_page: */
458     static void instr(to_be_translated)(struct cpu *,struct arm_instr_call *);
459     static void instr(end_of_page)(struct cpu *,struct arm_instr_call *);
460     static void arm_tc_allocate_default_page(struct cpu *cpu, uint32_t physaddr)
461     {
462     struct arm_tc_physpage *ppp;
463     int i;
464    
465     /* Create the physpage header: */
466     ppp = (struct arm_tc_physpage *)(cpu->cd.arm.translation_cache
467     + cpu->cd.arm.translation_cache_cur_ofs);
468     ppp->next_ofs = 0;
469     ppp->physaddr = physaddr;
470    
471     for (i=0; i<IC_ENTRIES_PER_PAGE; i++)
472     ppp->ics[i].f = instr(to_be_translated);
473    
474     ppp->ics[IC_ENTRIES_PER_PAGE].f = instr(end_of_page);
475    
476     cpu->cd.arm.translation_cache_cur_ofs +=
477     sizeof(struct arm_tc_physpage);
478     }
479    
480    
481 dpavlin 6 #define MEMORY_RW arm_memory_rw
482     #define MEM_ARM
483     #include "memory_rw.c"
484     #undef MEM_ARM
485     #undef MEMORY_RW
486    
487    
488 dpavlin 10 #include "cpu_arm_instr.c"
489    
490    
491 dpavlin 6 /*
492 dpavlin 10 * arm_cpu_run_instr():
493     *
494     * Execute one or more instructions on a specific CPU.
495     *
496     * Return value is the number of instructions executed during this call,
497     * 0 if no instructions were executed.
498     */
499     int arm_cpu_run_instr(struct emul *emul, struct cpu *cpu)
500     {
501     /*
502     * Find the correct translated page in the translation cache,
503     * and start running code on that page.
504     */
505    
506     uint32_t cached_pc, physaddr, physpage_ofs;
507     int pagenr, table_index, n_instrs, low_pc;
508     uint32_t *physpage_entryp;
509     struct arm_tc_physpage *ppp;
510    
511     if (cpu->cd.arm.translation_cache == NULL || cpu->cd.
512     arm.translation_cache_cur_ofs >= ARM_TRANSLATION_CACHE_SIZE)
513     arm_create_or_reset_tc(cpu);
514    
515     cached_pc = cpu->cd.arm.r[ARM_PC];
516    
517     physaddr = cached_pc & ~(((IC_ENTRIES_PER_PAGE-1) << 2) | 3);
518     /* TODO: virtual to physical */
519    
520     pagenr = ADDR_TO_PAGENR(physaddr);
521     table_index = PAGENR_TO_TABLE_INDEX(pagenr);
522    
523     physpage_entryp = &(((uint32_t *)
524     cpu->cd.arm.translation_cache)[table_index]);
525     physpage_ofs = *physpage_entryp;
526     ppp = NULL;
527    
528     /* Traverse the physical page chain: */
529     while (physpage_ofs != 0) {
530     ppp = (struct arm_tc_physpage *)(cpu->cd.arm.translation_cache
531     + physpage_ofs);
532     /* If we found the page in the cache, then we're done: */
533     if (ppp->physaddr == physaddr)
534     break;
535     /* Try the next page in the chain: */
536     physpage_ofs = ppp->next_ofs;
537     }
538    
539     /* If the offset is 0 (or ppp is NULL), then we need to create a
540     new "default" empty translation page. */
541    
542     if (ppp == NULL) {
543     fatal("CREATING page %i (physaddr 0x%08x), table index = %i\n",
544     pagenr, physaddr, table_index);
545     *physpage_entryp = physpage_ofs =
546     cpu->cd.arm.translation_cache_cur_ofs;
547    
548     arm_tc_allocate_default_page(cpu, physaddr);
549    
550     ppp = (struct arm_tc_physpage *)(cpu->cd.arm.translation_cache
551     + physpage_ofs);
552     }
553    
554     cpu->cd.arm.cur_physpage = ppp;
555     cpu->cd.arm.cur_ic_page = &ppp->ics[0];
556     cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
557     PC_TO_IC_ENTRY(cached_pc);
558    
559     /* printf("cached_pc = 0x%08x pagenr = %i table_index = %i, "
560     "physpage_ofs = 0x%08x\n", (int)cached_pc, (int)pagenr,
561     (int)table_index, (int)physpage_ofs); */
562    
563     cpu->cd.arm.n_translated_instrs = 0;
564     cpu->cd.arm.running_translated = 1;
565    
566     if (single_step || cpu->machine->instruction_trace) {
567     /*
568     * Single-step:
569     */
570     struct arm_instr_call *ic = cpu->cd.arm.next_ic ++;
571     if (cpu->machine->instruction_trace) {
572     unsigned char instr[4];
573     if (!cpu->memory_rw(cpu, cpu->mem, cpu->pc, &instr[0],
574     sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) {
575     fatal("arm_cpu_run_instr(): could not read "
576     "the instruction\n");
577     } else
578     arm_cpu_disassemble_instr(cpu, instr, 1, 0, 0);
579     }
580    
581     /* When single-stepping, multiple instruction calls cannot
582     be combined into one. This clears all translations: */
583     if (ppp->flags & ARM_COMBINATIONS) {
584     int i;
585     for (i=0; i<IC_ENTRIES_PER_PAGE; i++)
586     ppp->ics[i].f = instr(to_be_translated);
587     debug("[ Note: The translation of physical page 0x%08x"
588     " contained combinations of instructions; these "
589     "are now flushed because we are single-stepping."
590     " ]\n", ppp->physaddr);
591     ppp->flags &= ~ARM_COMBINATIONS;
592     }
593    
594     /* Execute just one instruction: */
595     ic->f(cpu, ic);
596     n_instrs = 1;
597     } else {
598     /* Execute multiple instructions: */
599     n_instrs = 0;
600     for (;;) {
601     struct arm_instr_call *ic;
602     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
603     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
604     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
605     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
606     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
607     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
608     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
609     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
610    
611     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
612     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
613     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
614     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
615     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
616     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
617     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
618     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
619    
620     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
621     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
622     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
623     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
624     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
625     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
626     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
627     ic = cpu->cd.arm.next_ic ++; ic->f(cpu, ic);
628    
629     n_instrs += 24;
630     if (!cpu->cd.arm.running_translated || single_step ||
631     n_instrs + cpu->cd.arm.n_translated_instrs >= 8192)
632     break;
633     }
634     }
635    
636    
637     /*
638     * Update the program counter and return the correct number of
639     * executed instructions:
640     */
641     low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
642     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
643    
644     if (low_pc >= 0 && low_pc < IC_ENTRIES_PER_PAGE) {
645     cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
646     cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
647     cpu->pc = cpu->cd.arm.r[ARM_PC];
648     } else {
649     fatal("Outside a page (This is actually ok)\n");
650     }
651    
652     return n_instrs + cpu->cd.arm.n_translated_instrs;
653     }
654    
655    
656     #define CPU_RUN arm_cpu_run
657     #define CPU_RINSTR arm_cpu_run_instr
658     #define CPU_RUN_ARM
659     #include "cpu_run.c"
660     #undef CPU_RINSTR
661     #undef CPU_RUN_ARM
662     #undef CPU_RUN
663    
664    
665     /*
666 dpavlin 6 * arm_cpu_family_init():
667     *
668 dpavlin 10 * This function fills the cpu_family struct with valid data.
669 dpavlin 6 */
670     int arm_cpu_family_init(struct cpu_family *fp)
671     {
672     fp->name = "ARM";
673     fp->cpu_new = arm_cpu_new;
674     fp->list_available_types = arm_cpu_list_available_types;
675     fp->register_match = arm_cpu_register_match;
676     fp->disassemble_instr = arm_cpu_disassemble_instr;
677 dpavlin 10 fp->register_dump = arm_cpu_register_dump;
678     fp->run = arm_cpu_run;
679 dpavlin 6 fp->dumpinfo = arm_cpu_dumpinfo;
680     /* fp->show_full_statistics = arm_cpu_show_full_statistics; */
681     /* fp->tlbdump = arm_cpu_tlbdump; */
682     /* fp->interrupt = arm_cpu_interrupt; */
683     /* fp->interrupt_ack = arm_cpu_interrupt_ack; */
684     return 1;
685     }
686    
687     #endif /* ENABLE_ARM */

  ViewVC Help
Powered by ViewVC 1.1.26