/[gxemul]/upstream/0.3.5/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 /upstream/0.3.5/src/cpu_arm.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: 12486 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.c,v 1.57 2005/08/12 20:20:28 debug Exp $
29 *
30 * ARM CPU emulation.
31 *
32 * Sources of information refered to in cpu_arm*.c:
33 *
34 * (1) http://www.pinknoise.demon.co.uk/ARMinstrs/ARMinstrs.html
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include "misc.h"
43
44
45 #ifndef ENABLE_ARM
46
47
48 #include "cpu_arm.h"
49
50
51 /*
52 * arm_cpu_family_init():
53 *
54 * Bogus, when ENABLE_ARM isn't defined.
55 */
56 int arm_cpu_family_init(struct cpu_family *fp)
57 {
58 return 0;
59 }
60
61
62 #else /* ENABLE_ARM */
63
64
65 #include "cpu.h"
66 #include "cpu_arm.h"
67 #include "machine.h"
68 #include "memory.h"
69 #include "symbol.h"
70
71 #define DYNTRANS_32
72 #include "tmp_arm_head.c"
73
74
75 /* ARM symbolic register names and condition strings: */
76 static char *arm_regname[N_ARM_REGS] = ARM_REG_NAMES;
77 static char *arm_condition_string[16] = ARM_CONDITION_STRINGS;
78
79 /* Data Processing Instructions: */
80 static char *arm_dpiname[16] = ARM_DPI_NAMES;
81 static int arm_dpi_uses_d[16] = { 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1 };
82 static int arm_dpi_uses_n[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0 };
83
84
85 /*
86 * arm_cpu_new():
87 *
88 * Create a new ARM cpu object by filling the CPU struct.
89 * Return 1 on success, 0 if cpu_type_name isn't a valid ARM processor.
90 */
91 int arm_cpu_new(struct cpu *cpu, struct memory *mem,
92 struct machine *machine, int cpu_id, char *cpu_type_name)
93 {
94 if (strcmp(cpu_type_name, "ARM") != 0)
95 return 0;
96
97 cpu->memory_rw = arm_memory_rw;
98 cpu->update_translation_table = arm_update_translation_table;
99 cpu->invalidate_translation_caches_paddr =
100 arm_invalidate_translation_caches_paddr;
101 cpu->invalidate_code_translation_caches =
102 arm_invalidate_code_translation_caches;
103 cpu->is_32bit = 1;
104
105 cpu->cd.arm.flags = ARM_FLAG_I | ARM_FLAG_F | ARM_MODE_USR32;
106
107 /* Only show name and caches etc for CPU nr 0: */
108 if (cpu_id == 0) {
109 debug("%s", cpu->name);
110 }
111
112 return 1;
113 }
114
115
116 /*
117 * arm_cpu_dumpinfo():
118 */
119 void arm_cpu_dumpinfo(struct cpu *cpu)
120 {
121 /* TODO */
122 debug("\n");
123 }
124
125
126 /*
127 * arm_cpu_list_available_types():
128 *
129 * Print a list of available ARM CPU types.
130 */
131 void arm_cpu_list_available_types(void)
132 {
133 /* TODO */
134
135 debug("ARM\n");
136 }
137
138
139 /*
140 * arm_cpu_register_match():
141 */
142 void arm_cpu_register_match(struct machine *m, char *name,
143 int writeflag, uint64_t *valuep, int *match_register)
144 {
145 int i, cpunr = 0;
146
147 /* CPU number: */
148
149 /* TODO */
150
151 /* Register names: */
152 for (i=0; i<N_ARM_REGS; i++) {
153 if (strcasecmp(name, arm_regname[i]) == 0) {
154 if (writeflag) {
155 m->cpus[cpunr]->cd.arm.r[i] = *valuep;
156 if (i == ARM_PC)
157 m->cpus[cpunr]->pc = *valuep;
158 } else
159 *valuep = m->cpus[cpunr]->cd.arm.r[i];
160 *match_register = 1;
161 }
162 }
163 }
164
165
166 /*
167 * arm_cpu_register_dump():
168 *
169 * Dump cpu registers in a relatively readable format.
170 *
171 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
172 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
173 */
174 void arm_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
175 {
176 char *symbol;
177 uint64_t offset;
178 int mode = cpu->cd.arm.flags & ARM_FLAG_MODE;
179 int i, x = cpu->cpu_id;
180
181 if (gprs) {
182 symbol = get_symbol_name(&cpu->machine->symbol_context,
183 cpu->cd.arm.r[ARM_PC], &offset);
184 debug("cpu%i: flags = ", x);
185 debug("%s%s%s%s%s%s",
186 (cpu->cd.arm.flags & ARM_FLAG_N)? "N" : "n",
187 (cpu->cd.arm.flags & ARM_FLAG_Z)? "Z" : "z",
188 (cpu->cd.arm.flags & ARM_FLAG_C)? "C" : "c",
189 (cpu->cd.arm.flags & ARM_FLAG_V)? "V" : "v",
190 (cpu->cd.arm.flags & ARM_FLAG_I)? "I" : "i",
191 (cpu->cd.arm.flags & ARM_FLAG_F)? "F" : "f");
192 if (mode < ARM_MODE_USR32)
193 debug(" pc = 0x%07x",
194 (int)(cpu->cd.arm.r[ARM_PC] & 0x03ffffff));
195 else
196 debug(" pc = 0x%08x", (int)cpu->cd.arm.r[ARM_PC]);
197
198 /* TODO: Flags */
199
200 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
201
202 for (i=0; i<N_ARM_REGS; i++) {
203 if ((i % 4) == 0)
204 debug("cpu%i:", x);
205 if (i != ARM_PC)
206 debug(" %s = 0x%08x", arm_regname[i],
207 (int)cpu->cd.arm.r[i]);
208 if ((i % 4) == 3)
209 debug("\n");
210 }
211 }
212 }
213
214
215 /*
216 * arm_cpu_show_full_statistics():
217 *
218 * Show detailed statistics on opcode usage on each cpu.
219 */
220 void arm_cpu_show_full_statistics(struct machine *m)
221 {
222 fatal("arm_cpu_show_full_statistics(): TODO\n");
223 }
224
225
226 /*
227 * arm_cpu_tlbdump():
228 *
229 * Called from the debugger to dump the TLB in a readable format.
230 * x is the cpu number to dump, or -1 to dump all CPUs.
231 *
232 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
233 * just dumped.
234 */
235 void arm_cpu_tlbdump(struct machine *m, int x, int rawflag)
236 {
237 fatal("arm_cpu_tlbdump(): TODO\n");
238 }
239
240
241 /*
242 * arm_cpu_interrupt():
243 */
244 int arm_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
245 {
246 fatal("arm_cpu_interrupt(): TODO\n");
247 return 0;
248 }
249
250
251 /*
252 * arm_cpu_interrupt_ack():
253 */
254 int arm_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
255 {
256 /* fatal("arm_cpu_interrupt_ack(): TODO\n"); */
257 return 0;
258 }
259
260
261 /*
262 * arm_cpu_disassemble_instr():
263 *
264 * Convert an instruction word into human readable format, for instruction
265 * tracing.
266 *
267 * If running is 1, cpu->pc should be the address of the instruction.
268 *
269 * If running is 0, things that depend on the runtime environment (eg.
270 * register contents) will not be shown, and addr will be used instead of
271 * cpu->pc for relative addresses.
272 */
273 int arm_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
274 int running, uint64_t dumpaddr, int bintrans)
275 {
276 uint32_t iw, tmp;
277 int main_opcode, secondary_opcode, s_bit, r16, r12, r8;
278 int i, n, p_bit, u_bit, b_bit, w_bit, l_bit;
279 char *symbol, *condition;
280 uint64_t offset;
281
282 if (running)
283 dumpaddr = cpu->pc;
284
285 symbol = get_symbol_name(&cpu->machine->symbol_context,
286 dumpaddr, &offset);
287 if (symbol != NULL && offset == 0)
288 debug("<%s>\n", symbol);
289
290 if (cpu->machine->ncpus > 1 && running)
291 debug("cpu%i:\t", cpu->cpu_id);
292
293 debug("%08x: ", (int)dumpaddr);
294
295 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
296 iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
297 else
298 iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
299 debug("%08x\t", (int)iw);
300
301 condition = arm_condition_string[iw >> 28];
302 main_opcode = (iw >> 24) & 15;
303 secondary_opcode = (iw >> 21) & 15;
304 u_bit = (iw >> 23) & 1;
305 b_bit = (iw >> 22) & 1;
306 w_bit = (iw >> 21) & 1;
307 s_bit = l_bit = (iw >> 20) & 1;
308 r16 = (iw >> 16) & 15;
309 r12 = (iw >> 12) & 15;
310 r8 = (iw >> 8) & 15;
311
312 switch (main_opcode) {
313 case 0x0:
314 case 0x1:
315 case 0x2:
316 case 0x3:
317 /*
318 * See (1):
319 * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form
320 * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form
321 */
322 if (iw & 0x80 && !(main_opcode & 2) && iw & 0x10) {
323 debug("UNIMPLEMENTED reg (c!=0), t odd\n");
324 break;
325 }
326
327 debug("%s%s%s\t", arm_dpiname[secondary_opcode],
328 condition, s_bit? "s" : "");
329 if (arm_dpi_uses_d[secondary_opcode])
330 debug("%s,", arm_regname[r12]);
331 if (arm_dpi_uses_n[secondary_opcode])
332 debug("%s,", arm_regname[r16]);
333
334 if (main_opcode & 2) {
335 /* Immediate form: */
336 int r = (iw >> 7) & 30;
337 uint32_t b = iw & 0xff;
338 while (r-- > 0)
339 b = (b >> 1) | ((b & 1) << 31);
340 if (b < 15)
341 debug("#%i", b);
342 else
343 debug("#0x%x", b);
344 } else {
345 /* Register form: */
346 int t = (iw >> 4) & 7;
347 int c = (iw >> 7) & 31;
348 debug("%s", arm_regname[iw & 15]);
349 switch (t) {
350 case 0: if (c != 0)
351 debug(", lsl #%i", c);
352 break;
353 case 1: debug(", lsl %s", arm_regname[c >> 1]);
354 break;
355 case 2: debug(", lsr #%i", c? c : 32);
356 break;
357 case 3: debug(", lsr %s", arm_regname[c >> 1]);
358 break;
359 case 4: debug(", asr #%i", c? c : 32);
360 break;
361 case 5: debug(", asr %s", arm_regname[c >> 1]);
362 break;
363 case 6: if (c != 0)
364 debug(", ror #%i", c);
365 else
366 debug(", rrx");
367 break;
368 case 7: debug(", ror %s", arm_regname[c >> 1]);
369 break;
370 }
371 }
372 debug("\n");
373 break;
374 case 0x4: /* Single Data Transfer */
375 case 0x5:
376 case 0x6:
377 case 0x7:
378 /*
379 * See (1):
380 * xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form
381 * xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form
382 */
383 p_bit = main_opcode & 1;
384 if (main_opcode >= 6 && iw & 0x10) {
385 debug("TODO: single data transf. but 0x10\n");
386 break;
387 }
388 debug("%s%s%s", l_bit? "ldr" : "str",
389 condition, b_bit? "b" : "");
390 if (!p_bit && w_bit)
391 debug("t");
392 debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]);
393 if (main_opcode < 6) {
394 /* Immediate form: */
395 uint32_t imm = iw & 0xfff;
396 if (!p_bit)
397 debug("]");
398 if (imm != 0)
399 debug(",#%s%i", u_bit? "" : "-", imm);
400 if (p_bit)
401 debug("]");
402 } else {
403 debug(" TODO: REG-form]");
404 }
405 debug("%s\n", (p_bit && w_bit)? "!" : "");
406 break;
407 case 0x8: /* Block Data Transfer */
408 case 0x9:
409 /* See (1): xxxx100P USWLnnnn llllllll llllllll */
410 p_bit = main_opcode & 1;
411 s_bit = b_bit;
412 debug("%s%s", l_bit? "ldm" : "stm", condition);
413 switch (u_bit * 2 + p_bit) {
414 case 0: debug("da"); break;
415 case 1: debug("db"); break;
416 case 2: debug("ia"); break;
417 case 3: debug("ib"); break;
418 }
419 debug("\t%s", arm_regname[r16]);
420 if (w_bit)
421 debug("!");
422 debug(",{");
423 n = 0;
424 for (i=0; i<16; i++)
425 if ((iw >> i) & 1) {
426 debug("%s%s", (n > 0)? ",":"", arm_regname[i]);
427 n++;
428 }
429 debug("}");
430 if (s_bit)
431 debug("^");
432 debug("\n");
433 break;
434 case 0xa: /* B: branch */
435 case 0xb: /* BL: branch and link */
436 debug("b%s%s\t", main_opcode == 0xa? "" : "l", condition);
437 tmp = (iw & 0x00ffffff) << 2;
438 if (tmp & 0x02000000)
439 tmp |= 0xfc000000;
440 tmp = (int32_t)(dumpaddr + tmp + 8);
441 debug("0x%x", (int)tmp);
442 symbol = get_symbol_name(&cpu->machine->symbol_context,
443 tmp, &offset);
444 if (symbol != NULL)
445 debug("\t\t<%s>", symbol);
446 debug("\n");
447 break;
448 case 0xc: /* Coprocessor */
449 case 0xd: /* LDC/STC */
450 /* xxxx110P UNWLnnnn DDDDpppp oooooooo LDC/STC */
451 debug("TODO: coprocessor LDC/STC\n");
452 break;
453 case 0xe: /* CDP (Coprocessor Op) */
454 /* or MRC/MCR!
455 * According to (1):
456 * xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP
457 * xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR
458 */
459 if (iw & 0x10) {
460 debug("%s%s\t",
461 (iw & 0x00100000)? "mrc" : "mcr", condition);
462 debug("%i,%i,r%i,cr%i,cr%i,%i",
463 (int)((iw >> 8) & 15), (int)((iw >>21) & 7),
464 (int)((iw >>12) & 15), (int)((iw >>16) & 15),
465 (int)((iw >> 0) & 15), (int)((iw >> 5) & 7));
466 } else {
467 debug("cdp%s\t", condition);
468 debug("%i,%i,cr%i,cr%i,cr%i",
469 (int)((iw >> 8) & 15),
470 (int)((iw >>20) & 15),
471 (int)((iw >>12) & 15),
472 (int)((iw >>16) & 15),
473 (int)((iw >> 0) & 15));
474 if ((iw >> 5) & 7)
475 debug(",0x%x", (int)((iw >> 5) & 7));
476 }
477 debug("\n");
478 break;
479 case 0xf: /* SWI */
480 debug("swi%s\t", condition);
481 debug("0x%x\n", (int)(iw & 0x00ffffff));
482 break;
483 default:debug("UNIMPLEMENTED\n");
484 }
485
486 return sizeof(uint32_t);
487 }
488
489
490 #include "tmp_arm_tail.c"
491
492
493 #endif /* ENABLE_ARM */

  ViewVC Help
Powered by ViewVC 1.1.26