/[gxemul]/upstream/0.4.4/src/cpus/cpu_avr.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.4.4/src/cpus/cpu_avr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (show annotations)
Mon Oct 8 16:21:26 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 14962 byte(s)
0.4.4
1 /*
2 * Copyright (C) 2005-2007 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_avr.c,v 1.22 2006/12/30 13:30:53 debug Exp $
29 *
30 * Atmel AVR (8-bit) CPU emulation.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include "cpu.h"
39 #include "machine.h"
40 #include "memory.h"
41 #include "misc.h"
42 #include "settings.h"
43 #include "symbol.h"
44
45
46 #define DYNTRANS_32
47 #define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH
48 #include "tmp_avr_head.c"
49
50
51 /*
52 * avr_cpu_new():
53 *
54 * Create a new AVR cpu object.
55 *
56 * Returns 1 on success, 0 if there was no matching AVR processor with
57 * this cpu_type_name.
58 */
59 int avr_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
60 int cpu_id, char *cpu_type_name)
61 {
62 int type = 0, i;
63
64 if (strcasecmp(cpu_type_name, "AVR") == 0 ||
65 strcasecmp(cpu_type_name, "AVR16") == 0 ||
66 strcasecmp(cpu_type_name, "AT90S2313") == 0 ||
67 strcasecmp(cpu_type_name, "AT90S8515") == 0)
68 type = 16;
69 if (strcasecmp(cpu_type_name, "AVR22") == 0)
70 type = 22;
71
72 if (type == 0)
73 return 0;
74
75 cpu->run_instr = avr_run_instr;
76 cpu->memory_rw = avr_memory_rw;
77 cpu->update_translation_table = avr_update_translation_table;
78 cpu->invalidate_translation_caches =
79 avr_invalidate_translation_caches;
80 cpu->invalidate_code_translation = avr_invalidate_code_translation;
81 cpu->is_32bit = 1;
82
83 cpu->byte_order = EMUL_LITTLE_ENDIAN;
84
85 cpu->cd.avr.is_22bit = (type == 22);
86 cpu->cd.avr.pc_mask = cpu->cd.avr.is_22bit? 0x3fffff : 0xffff;
87
88 cpu->cd.avr.sram_mask = 0xff; /* 256 bytes ram */
89 cpu->cd.avr.sp = cpu->cd.avr.sram_mask - 2;
90
91 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
92 if (cpu_id == 0) {
93 debug("%s", cpu->name);
94 }
95
96 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
97 CPU_SETTINGS_ADD_REGISTER16("sp", cpu->cd.avr.sp);
98 CPU_SETTINGS_ADD_REGISTER8("sreg", cpu->cd.avr.sreg);
99 for (i=0; i<N_AVR_REGS; i++) {
100 char tmpstr[5];
101 snprintf(tmpstr, sizeof(tmpstr), "r%i", i);
102 CPU_SETTINGS_ADD_REGISTER8(tmpstr, cpu->cd.avr.r[i]);
103 }
104
105 return 1;
106 }
107
108
109 /*
110 * avr_cpu_list_available_types():
111 *
112 * Print a list of available AVR CPU types.
113 */
114 void avr_cpu_list_available_types(void)
115 {
116 debug("AVR\tAVR16\tAVR22\n");
117 }
118
119
120 /*
121 * avr_cpu_dumpinfo():
122 */
123 void avr_cpu_dumpinfo(struct cpu *cpu)
124 {
125 debug(" (%i-bit program counter)\n",
126 cpu->cd.avr.is_22bit? 22 : 16);
127 }
128
129
130 /*
131 * avr_cpu_register_dump():
132 *
133 * Dump cpu registers in a relatively readable format.
134 *
135 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
136 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
137 */
138 void avr_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
139 {
140 char *symbol;
141 uint64_t offset;
142 int i, x = cpu->cpu_id;
143
144 if (gprs) {
145 /* Special registers (pc, ...) first: */
146 symbol = get_symbol_name(&cpu->machine->symbol_context,
147 cpu->pc, &offset);
148
149 debug("cpu%i: sreg = ", x);
150 debug("%c", cpu->cd.avr.sreg & AVR_SREG_I? 'I' : 'i');
151 debug("%c", cpu->cd.avr.sreg & AVR_SREG_T? 'T' : 't');
152 debug("%c", cpu->cd.avr.sreg & AVR_SREG_H? 'H' : 'h');
153 debug("%c", cpu->cd.avr.sreg & AVR_SREG_S? 'S' : 's');
154 debug("%c", cpu->cd.avr.sreg & AVR_SREG_V? 'V' : 'v');
155 debug("%c", cpu->cd.avr.sreg & AVR_SREG_N? 'N' : 'n');
156 debug("%c", cpu->cd.avr.sreg & AVR_SREG_Z? 'Z' : 'z');
157 debug("%c", cpu->cd.avr.sreg & AVR_SREG_C? 'C' : 'c');
158 if (cpu->cd.avr.is_22bit)
159 debug(" pc = 0x%06x", (int)cpu->pc);
160 else
161 debug(" pc = 0x%04x", (int)cpu->pc);
162 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
163
164 for (i=0; i<N_AVR_REGS; i++) {
165 int r = (i >> 3) + ((i & 7) << 2);
166 if ((i % 8) == 0)
167 debug("cpu%i:", x);
168 debug(" r%-2i=0x%02x", r, cpu->cd.avr.r[r]);
169 if ((i % 8) == 7)
170 debug("\n");
171 }
172
173 debug("cpu%i: x=%i, y=%i, z=%i, sp=0x%04x\n", x,
174 (int)(int16_t)(cpu->cd.avr.r[27]*256 + cpu->cd.avr.r[26]),
175 (int)(int16_t)(cpu->cd.avr.r[29]*256 + cpu->cd.avr.r[28]),
176 (int)(int16_t)(cpu->cd.avr.r[31]*256 + cpu->cd.avr.r[30]),
177 cpu->cd.avr.sp);
178 }
179
180 debug("cpu%i: nr of instructions: %lli\n", x,
181 (long long)cpu->machine->ninstrs);
182 debug("cpu%i: nr of cycles: %lli\n", x,
183 (long long)(cpu->machine->ninstrs + cpu->cd.avr.extra_cycles));
184 }
185
186
187 /*
188 * avr_cpu_tlbdump():
189 *
190 * Called from the debugger to dump the TLB in a readable format.
191 * x is the cpu number to dump, or -1 to dump all CPUs.
192 *
193 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
194 * just dumped.
195 */
196 void avr_cpu_tlbdump(struct machine *m, int x, int rawflag)
197 {
198 }
199
200
201 /*
202 * avr_cpu_gdb_stub():
203 *
204 * Execute a "remote GDB" command. Returns a newly allocated response string
205 * on success, NULL on failure.
206 */
207 char *avr_cpu_gdb_stub(struct cpu *cpu, char *cmd)
208 {
209 fatal("avr_cpu_gdb_stub(): TODO\n");
210 return NULL;
211 }
212
213
214 /*
215 * avr_cpu_interrupt():
216 */
217 int avr_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
218 {
219 fatal("avr_cpu_interrupt(): TODO\n");
220 return 0;
221 }
222
223
224 /*
225 * avr_cpu_interrupt_ack():
226 */
227 int avr_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
228 {
229 /* fatal("avr_cpu_interrupt_ack(): TODO\n"); */
230 return 0;
231 }
232
233
234 /* Helper functions: */
235 static void print_two(unsigned char *instr, int *len)
236 { debug(" %02x %02x", instr[*len], instr[*len+1]); (*len) += 2; }
237 static void print_spaces(int len) { int i; debug(" "); for (i=0; i<15-len/2*6;
238 i++) debug(" "); }
239
240
241 /*
242 * avr_cpu_disassemble_instr():
243 *
244 * Convert an instruction word into human readable format, for instruction
245 * tracing and disassembly.
246 *
247 * If running is 1, cpu->pc should be the address of the instruction.
248 *
249 * If running is 0, things that depend on the runtime environment (eg.
250 * register contents) will not be shown, and addr will be used instead of
251 * cpu->pc for relative addresses.
252 */
253 int avr_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
254 int running, uint64_t dumpaddr)
255 {
256 uint64_t offset;
257 int len = 0, addr, iw, rd, rr, imm;
258 char *symbol;
259 char *sreg_names = SREG_NAMES;
260
261 if (running)
262 dumpaddr = cpu->pc;
263
264 symbol = get_symbol_name(&cpu->machine->symbol_context,
265 dumpaddr, &offset);
266 if (symbol != NULL && offset==0)
267 debug("<%s>\n", symbol);
268
269 if (cpu->machine->ncpus > 1 && running)
270 debug("cpu%i: ", cpu->cpu_id);
271
272 /* TODO: 22-bit PC */
273 debug("0x%04x: ", (int)dumpaddr);
274
275 print_two(ib, &len);
276 iw = (ib[1] << 8) + ib[0];
277
278 if ((iw & 0xffff) == 0x0000) {
279 print_spaces(len);
280 debug("nop\n");
281 } else if ((iw & 0xff00) == 0x0100) {
282 print_spaces(len);
283 rd = (iw >> 3) & 30;
284 rr = (iw << 1) & 30;
285 debug("movw\tr%i:r%i,r%i:r%i\n", rd+1, rd, rr+1, rr);
286 } else if ((iw & 0xff00) == 0x0200) {
287 print_spaces(len);
288 rd = ((iw >> 4) & 15) + 16;
289 rr = (iw & 15) + 16;
290 debug("muls\tr%i,r%i\n", rd, rr);
291 } else if ((iw & 0xff88) == 0x0300) {
292 print_spaces(len);
293 rd = ((iw >> 4) & 7) + 16;
294 rr = (iw & 7) + 16;
295 debug("mulsu\tr%i,r%i\n", rd, rr);
296 } else if ((iw & 0xff88) == 0x0308) {
297 print_spaces(len);
298 rd = ((iw >> 4) & 7) + 16;
299 rr = (iw & 7) + 16;
300 debug("fmul\tr%i,r%i\n", rd, rr);
301 } else if ((iw & 0xff88) == 0x0380) {
302 print_spaces(len);
303 rd = ((iw >> 4) & 7) + 16;
304 rr = (iw & 7) + 16;
305 debug("fmuls\tr%i,r%i\n", rd, rr);
306 } else if ((iw & 0xff88) == 0x0388) {
307 print_spaces(len);
308 rd = ((iw >> 4) & 7) + 16;
309 rr = (iw & 7) + 16;
310 debug("fmulsu\tr%i,r%i\n", rd, rr);
311 } else if ((iw & 0xec00) == 0x0400) {
312 print_spaces(len);
313 rd = (iw & 0x1f0) >> 4;
314 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
315 debug("cp%s\tr%i,r%i\n", iw & 0x1000? "" : "c", rd, rr);
316 } else if ((iw & 0xec00) == 0x0800) {
317 print_spaces(len);
318 rd = (iw & 0x1f0) >> 4;
319 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
320 debug("%s\tr%i,r%i\n", iw & 0x1000? "sub" : "sbc", rd, rr);
321 } else if ((iw & 0xec00) == 0x0c00) {
322 print_spaces(len);
323 rd = (iw & 0x1f0) >> 4;
324 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
325 debug("%s\tr%i,r%i\n", iw & 0x1000? "adc" : "add", rd, rr);
326 } else if ((iw & 0xfc00) == 0x1000) {
327 print_spaces(len);
328 rd = (iw & 0x1f0) >> 4;
329 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
330 debug("cpse\tr%i,r%i\n", rd, rr);
331 } else if ((iw & 0xfc00) == 0x2000) {
332 print_spaces(len);
333 rd = (iw & 0x1f0) >> 4;
334 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
335 debug("and\tr%i,r%i\n", rd, rr);
336 } else if ((iw & 0xfc00) == 0x2400) {
337 print_spaces(len);
338 rd = (iw & 0x1f0) >> 4;
339 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
340 debug("eor\tr%i,r%i\n", rd, rr);
341 } else if ((iw & 0xfc00) == 0x2800) {
342 print_spaces(len);
343 rd = (iw & 0x1f0) >> 4;
344 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
345 debug("or\tr%i,r%i\n", rd, rr);
346 } else if ((iw & 0xfc00) == 0x2c00) {
347 print_spaces(len);
348 rd = (iw & 0x1f0) >> 4;
349 rr = ((iw & 0x200) >> 5) | (iw & 0xf);
350 debug("mov\tr%i,r%i\n", rd, rr);
351 } else if ((iw & 0xf000) == 0x3000) {
352 print_spaces(len);
353 rd = ((iw >> 4) & 15) + 16;
354 imm = ((iw >> 4) & 0xf0) + (iw & 15);
355 debug("cpi\tr%i,0x%x\n", rd, imm);
356 } else if ((iw & 0xf000) == 0x4000) {
357 print_spaces(len);
358 rd = ((iw >> 4) & 15) + 16;
359 imm = ((iw >> 4) & 0xf0) + (iw & 15);
360 debug("sbci\tr%i,0x%x\n", rd, imm);
361 } else if ((iw & 0xf000) == 0x5000) {
362 print_spaces(len);
363 rd = ((iw >> 4) & 15) + 16;
364 imm = ((iw >> 4) & 0xf0) + (iw & 15);
365 debug("subi\tr%i,0x%x\n", rd, imm);
366 } else if ((iw & 0xe000) == 0x6000) {
367 print_spaces(len);
368 rd = ((iw >> 4) & 15) + 16;
369 imm = ((iw >> 4) & 0xf0) + (iw & 15);
370 debug("%s\tr%i,0x%x\n", iw & 0x1000? "andi" : "ori", rd, imm);
371 } else if ((iw & 0xfe0f) == 0x8000) {
372 print_spaces(len);
373 rd = (iw >> 4) & 31;
374 debug("ld\tr%i,Z\n", rd);
375 } else if ((iw & 0xfe0f) == 0x8008) {
376 print_spaces(len);
377 rd = (iw >> 4) & 31;
378 debug("ld\tr%i,Y\n", rd);
379 } else if ((iw & 0xfe0f) == 0x8208) {
380 print_spaces(len);
381 rd = (iw >> 4) & 31;
382 debug("st\tY,r%i\n", rd);
383 } else if ((iw & 0xfe0f) == 0x900c) {
384 print_spaces(len);
385 rd = (iw >> 4) & 31;
386 debug("ld\tr%i,X\n", rd);
387 } else if ((iw & 0xfc0f) == 0x900f) {
388 print_spaces(len);
389 rd = (iw >> 4) & 31;
390 debug("%s\tr%i\n", iw & 0x200? "push" : "pop", rd);
391 } else if ((iw & 0xfe0f) == 0x9000) {
392 print_two(ib, &len);
393 addr = (ib[3] << 8) + ib[2];
394 print_spaces(len);
395 if (iw & 0x200)
396 debug("sts\t0x%x,r%i\n", addr, (iw & 0x1f0) >> 4);
397 else
398 debug("lds\tr%i,0x%x\n", (iw & 0x1f0) >> 4, addr);
399 } else if ((iw & 0xfe0f) == 0x9209) {
400 print_spaces(len);
401 rr = (iw >> 4) & 31;
402 debug("st\tY+,r%i\n", rr);
403 } else if ((iw & 0xfe0f) == 0x920a) {
404 print_spaces(len);
405 rr = (iw >> 4) & 31;
406 debug("st\t-Y,r%i\n", rr);
407 } else if ((iw & 0xfe0f) == 0x9401) {
408 print_spaces(len);
409 rd = (iw >> 4) & 31;
410 debug("neg\tr%i\n", rd);
411 } else if ((iw & 0xfe0f) == 0x9402) {
412 print_spaces(len);
413 rd = (iw >> 4) & 31;
414 debug("swap\tr%i\n", rd);
415 } else if ((iw & 0xfe0f) == 0x9403) {
416 print_spaces(len);
417 rd = (iw >> 4) & 31;
418 debug("inc\tr%i\n", rd);
419 } else if ((iw & 0xff0f) == 0x9408) {
420 print_spaces(len);
421 rd = (iw >> 4) & 7;
422 debug("%s%c\n", iw & 0x80? "cl" : "se", sreg_names[rd]);
423 } else if ((iw & 0xfe0f) == 0x940a) {
424 print_spaces(len);
425 rd = (iw >> 4) & 31;
426 debug("dec\tr%i\n", rd);
427 } else if ((iw & 0xff8f) == 0x9408) {
428 print_spaces(len);
429 debug("bset\t%i\n", (iw >> 4) & 7);
430 } else if ((iw & 0xff8f) == 0x9488) {
431 print_spaces(len);
432 debug("bclr\t%i\n", (iw >> 4) & 7);
433 } else if ((iw & 0xffef) == 0x9508) {
434 /* ret and reti */
435 print_spaces(len);
436 debug("ret%s\n", (iw & 0x10)? "i" : "");
437 } else if ((iw & 0xffff) == 0x9588) {
438 print_spaces(len);
439 debug("sleep\n");
440 } else if ((iw & 0xffff) == 0x9598) {
441 print_spaces(len);
442 debug("break\n");
443 } else if ((iw & 0xffff) == 0x95a8) {
444 print_spaces(len);
445 debug("wdr\n");
446 } else if ((iw & 0xffef) == 0x95c8) {
447 print_spaces(len);
448 debug("%slpm\n", iw & 0x0010? "e" : "");
449 } else if ((iw & 0xff00) == 0x9600) {
450 print_spaces(len);
451 imm = ((iw & 0xc0) >> 2) | (iw & 0xf);
452 rd = ((iw >> 4) & 3) * 2 + 24;
453 debug("adiw\tr%i:r%i,0x%x\n", rd, rd+1, imm);
454 } else if ((iw & 0xfd00) == 0x9800) {
455 print_spaces(len);
456 imm = iw & 7;
457 rd = (iw >> 3) & 31; /* A */
458 debug("%sbi\t0x%x,%i\n", iw & 0x0200? "s" : "c", rd, imm);
459 } else if ((iw & 0xfd00) == 0x9900) {
460 print_spaces(len);
461 imm = iw & 7;
462 rd = (iw >> 3) & 31; /* A */
463 debug("sbi%s\t0x%x,%i\n", iw & 0x0200? "s" : "c", rd, imm);
464 } else if ((iw & 0xf000) == 0xb000) {
465 print_spaces(len);
466 imm = ((iw & 0x600) >> 5) | (iw & 0xf);
467 rr = (iw >> 4) & 31;
468 if (iw & 0x800)
469 debug("out\t0x%x,r%i\n", imm, rr);
470 else
471 debug("in\tr%i,0x%x\n", rr, imm);
472 } else if ((iw & 0xe000) == 0xc000) {
473 print_spaces(len);
474 addr = (int16_t)((iw & 0xfff) << 4);
475 addr = (addr >> 3) + dumpaddr + 2;
476 debug("%s\t0x%x\n", iw & 0x1000? "rcall" : "rjmp", addr);
477 } else if ((iw & 0xf000) == 0xe000) {
478 print_spaces(len);
479 rd = ((iw >> 4) & 0xf) + 16;
480 imm = ((iw >> 4) & 0xf0) | (iw & 0xf);
481 debug("ldi\tr%i,0x%x\n", rd, imm);
482 } else if ((iw & 0xfc00) == 0xf000) {
483 print_spaces(len);
484 addr = (iw >> 3) & 0x7f;
485 if (addr >= 64)
486 addr -= 128;
487 addr = (addr + 1) * 2 + dumpaddr;
488 debug("brbs\t%c,0x%x\n", sreg_names[iw & 7], addr);
489 } else if ((iw & 0xfc00) == 0xf400) {
490 print_spaces(len);
491 addr = (iw >> 3) & 0x7f;
492 if (addr >= 64)
493 addr -= 128;
494 addr = (addr + 1) * 2 + dumpaddr;
495 debug("brbc\t%c,0x%x\n", sreg_names[iw & 7], addr);
496 } else if ((iw & 0xfc08) == 0xfc00) {
497 print_spaces(len);
498 rr = (iw >> 4) & 31;
499 imm = iw & 7;
500 debug("sbr%s\tr%i,%i\n", iw & 0x0200 ? "s" : "c", rr, imm);
501 } else {
502 print_spaces(len);
503 debug("UNIMPLEMENTED 0x%04x\n", iw);
504 }
505
506 return len;
507 }
508
509
510 #include "tmp_avr_tail.c"
511

  ViewVC Help
Powered by ViewVC 1.1.26