/[gxemul]/trunk/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 /trunk/src/cpu_arm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19098 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 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