/[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

Contents of /trunk/src/cpu_arm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show 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 /*
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.c,v 1.19 2005/06/27 16:44:54 debug Exp $
29 *
30 * ARM CPU emulation.
31 *
32 * Whenever there is a reference to "(1)", that means
33 * "http://www.pinknoise.demon.co.uk/ARMinstrs/ARMinstrs.html".
34 */
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 /* 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 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 * 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 */
105 int arm_cpu_new(struct cpu *cpu, struct memory *mem,
106 struct machine *machine, int cpu_id, char *cpu_type_name)
107 {
108 if (strcmp(cpu_type_name, "ARM") != 0)
109 return 0;
110
111 cpu->memory_rw = arm_memory_rw;
112
113 cpu->cd.arm.flags = ARM_FLAG_I | ARM_FLAG_F | ARM_MODE_USR32;
114
115 /* Only show name and caches etc for CPU nr 0: */
116 if (cpu_id == 0) {
117 debug("%s", cpu->name);
118 }
119
120 return 1;
121 }
122
123
124 /*
125 * arm_cpu_dumpinfo():
126 */
127 void arm_cpu_dumpinfo(struct cpu *cpu)
128 {
129 debug(" (%i MB translation cache)\n",
130 (int)(ARM_TRANSLATION_CACHE_SIZE / 1048576));
131 }
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 int i, cpunr = 0;
154
155 /* CPU number: */
156
157 /* TODO */
158
159 /* 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 }
171 }
172
173
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 }
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 int arm_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
231 int running, uint64_t dumpaddr, int bintrans)
232 {
233 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
239 if (running)
240 dumpaddr = cpu->pc;
241
242 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 debug("%08x: ", (int)dumpaddr);
251
252 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 debug("%08x\t", (int)iw);
257
258 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
269 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 return sizeof(uint32_t);
421 }
422
423
424 /*
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 #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 #include "cpu_arm_instr.c"
489
490
491 /*
492 * 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 * arm_cpu_family_init():
667 *
668 * This function fills the cpu_family struct with valid data.
669 */
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 fp->register_dump = arm_cpu_register_dump;
678 fp->run = arm_cpu_run;
679 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