]>
Commit | Line | Data |
---|---|---|
81e09ed8 | 1 | /* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation |
6aba47ca | 2 | Copyright 1999, 2000, 2001, 2002, 2003, 2007 Free Software Foundation, Inc. |
63f36def | 3 | Written by Stephane Carrez (stcarrez@nerim.fr) |
e0709f50 AC |
4 | |
5 | This file is part of GDB, GAS, and the GNU binutils. | |
6 | ||
7 | GDB, GAS, and the GNU binutils are free software; you can redistribute | |
8 | them and/or modify them under the terms of the GNU General Public | |
9 | License as published by the Free Software Foundation; either version | |
10 | 1, or (at your option) any later version. | |
11 | ||
12 | GDB, GAS, and the GNU binutils are distributed in the hope that they | |
13 | will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
14 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
15 | the GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this file; see the file COPYING. If not, write to the Free | |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #include "sim-main.h" | |
22 | #include "sim-assert.h" | |
23 | #include "sim-module.h" | |
24 | #include "sim-options.h" | |
25 | ||
e0709f50 AC |
26 | enum { |
27 | OPTION_CPU_RESET = OPTION_START, | |
28 | OPTION_EMUL_OS, | |
29 | OPTION_CPU_CONFIG, | |
a685700c | 30 | OPTION_CPU_BOOTSTRAP, |
e0709f50 AC |
31 | OPTION_CPU_MODE |
32 | }; | |
33 | ||
34 | static DECLARE_OPTION_HANDLER (cpu_option_handler); | |
35 | ||
36 | static const OPTION cpu_options[] = | |
37 | { | |
38 | { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET }, | |
39 | '\0', NULL, "Reset the CPU", | |
40 | cpu_option_handler }, | |
41 | ||
42 | { {"emulos", no_argument, NULL, OPTION_EMUL_OS }, | |
43 | '\0', NULL, "Emulate some OS system calls (read, write, ...)", | |
44 | cpu_option_handler }, | |
45 | ||
46 | { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG }, | |
47 | '\0', NULL, "Specify the initial CPU configuration register", | |
48 | cpu_option_handler }, | |
49 | ||
a685700c SC |
50 | { {"bootstrap", no_argument, NULL, OPTION_CPU_BOOTSTRAP }, |
51 | '\0', NULL, "Start the processing in bootstrap mode", | |
52 | cpu_option_handler }, | |
53 | ||
e0709f50 AC |
54 | { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } |
55 | }; | |
56 | ||
57 | ||
58 | static SIM_RC | |
59 | cpu_option_handler (SIM_DESC sd, sim_cpu *cpu, | |
60 | int opt, char *arg, int is_command) | |
61 | { | |
e0709f50 AC |
62 | int val; |
63 | ||
64 | cpu = STATE_CPU (sd, 0); | |
65 | switch (opt) | |
66 | { | |
67 | case OPTION_CPU_RESET: | |
68 | sim_board_reset (sd); | |
69 | break; | |
70 | ||
71 | case OPTION_EMUL_OS: | |
72 | cpu->cpu_emul_syscall = 1; | |
73 | break; | |
74 | ||
75 | case OPTION_CPU_CONFIG: | |
76 | if (sscanf(arg, "0x%x", &val) == 1 | |
77 | || sscanf(arg, "%d", &val) == 1) | |
78 | { | |
79 | cpu->cpu_config = val; | |
80 | cpu->cpu_use_local_config = 1; | |
81 | } | |
82 | else | |
83 | cpu->cpu_use_local_config = 0; | |
84 | break; | |
a685700c SC |
85 | |
86 | case OPTION_CPU_BOOTSTRAP: | |
87 | cpu->cpu_start_mode = "bootstrap"; | |
88 | break; | |
89 | ||
e0709f50 AC |
90 | case OPTION_CPU_MODE: |
91 | break; | |
92 | } | |
93 | ||
94 | return SIM_RC_OK; | |
95 | } | |
96 | ||
e0709f50 | 97 | |
e0709f50 AC |
98 | void |
99 | cpu_call (sim_cpu *cpu, uint16 addr) | |
100 | { | |
e0709f50 AC |
101 | |
102 | cpu_set_pc (cpu, addr); | |
e0709f50 AC |
103 | } |
104 | ||
105 | void | |
106 | cpu_return (sim_cpu *cpu) | |
107 | { | |
e0709f50 AC |
108 | } |
109 | ||
110 | /* Set the stack pointer and re-compute the current frame. */ | |
111 | void | |
112 | cpu_set_sp (sim_cpu *cpu, uint16 val) | |
113 | { | |
114 | cpu->cpu_regs.sp = val; | |
e0709f50 AC |
115 | } |
116 | ||
81e09ed8 SC |
117 | uint16 |
118 | cpu_get_reg (sim_cpu* cpu, uint8 reg) | |
119 | { | |
120 | switch (reg) | |
121 | { | |
122 | case 0: | |
123 | return cpu_get_x (cpu); | |
124 | ||
125 | case 1: | |
126 | return cpu_get_y (cpu); | |
127 | ||
128 | case 2: | |
129 | return cpu_get_sp (cpu); | |
130 | ||
131 | case 3: | |
132 | return cpu_get_pc (cpu); | |
133 | ||
134 | default: | |
135 | return 0; | |
136 | } | |
137 | } | |
138 | ||
139 | uint16 | |
140 | cpu_get_src_reg (sim_cpu* cpu, uint8 reg) | |
141 | { | |
142 | switch (reg) | |
143 | { | |
144 | case 0: | |
145 | return cpu_get_a (cpu); | |
146 | ||
147 | case 1: | |
148 | return cpu_get_b (cpu); | |
149 | ||
150 | case 2: | |
151 | return cpu_get_ccr (cpu); | |
152 | ||
153 | case 3: | |
154 | return cpu_get_tmp3 (cpu); | |
155 | ||
156 | case 4: | |
157 | return cpu_get_d (cpu); | |
158 | ||
159 | case 5: | |
160 | return cpu_get_x (cpu); | |
161 | ||
162 | case 6: | |
163 | return cpu_get_y (cpu); | |
164 | ||
165 | case 7: | |
166 | return cpu_get_sp (cpu); | |
167 | ||
168 | default: | |
169 | return 0; | |
170 | } | |
171 | } | |
172 | ||
173 | void | |
174 | cpu_set_dst_reg (sim_cpu* cpu, uint8 reg, uint16 val) | |
175 | { | |
176 | switch (reg) | |
177 | { | |
178 | case 0: | |
179 | cpu_set_a (cpu, val); | |
180 | break; | |
181 | ||
182 | case 1: | |
183 | cpu_set_b (cpu, val); | |
184 | break; | |
185 | ||
186 | case 2: | |
187 | cpu_set_ccr (cpu, val); | |
188 | break; | |
189 | ||
190 | case 3: | |
191 | cpu_set_tmp2 (cpu, val); | |
192 | break; | |
193 | ||
194 | case 4: | |
195 | cpu_set_d (cpu, val); | |
196 | break; | |
197 | ||
198 | case 5: | |
199 | cpu_set_x (cpu, val); | |
200 | break; | |
201 | ||
202 | case 6: | |
203 | cpu_set_y (cpu, val); | |
204 | break; | |
205 | ||
206 | case 7: | |
207 | cpu_set_sp (cpu, val); | |
208 | break; | |
209 | ||
210 | default: | |
211 | break; | |
212 | } | |
213 | } | |
214 | ||
215 | void | |
216 | cpu_set_reg (sim_cpu* cpu, uint8 reg, uint16 val) | |
217 | { | |
218 | switch (reg) | |
219 | { | |
220 | case 0: | |
221 | cpu_set_x (cpu, val); | |
222 | break; | |
223 | ||
224 | case 1: | |
225 | cpu_set_y (cpu, val); | |
226 | break; | |
227 | ||
228 | case 2: | |
229 | cpu_set_sp (cpu, val); | |
230 | break; | |
231 | ||
232 | case 3: | |
233 | cpu_set_pc (cpu, val); | |
234 | break; | |
235 | ||
236 | default: | |
237 | break; | |
238 | } | |
239 | } | |
240 | ||
241 | /* Returns the address of a 68HC12 indexed operand. | |
242 | Pre and post modifications are handled on the source register. */ | |
243 | uint16 | |
244 | cpu_get_indexed_operand_addr (sim_cpu* cpu, int restrict) | |
245 | { | |
246 | uint8 reg; | |
247 | uint16 sval; | |
248 | uint16 addr; | |
249 | uint8 code; | |
250 | ||
251 | code = cpu_fetch8 (cpu); | |
252 | ||
253 | /* n,r with 5-bit signed constant. */ | |
254 | if ((code & 0x20) == 0) | |
255 | { | |
256 | reg = (code >> 6) & 3; | |
257 | sval = (code & 0x1f); | |
258 | if (code & 0x10) | |
259 | sval |= 0xfff0; | |
260 | ||
261 | addr = cpu_get_reg (cpu, reg); | |
262 | addr += sval; | |
263 | } | |
264 | ||
265 | /* Auto pre/post increment/decrement. */ | |
266 | else if ((code & 0xc0) != 0xc0) | |
267 | { | |
268 | reg = (code >> 6) & 3; | |
269 | sval = (code & 0x0f); | |
270 | if (sval & 0x8) | |
271 | { | |
272 | sval |= 0xfff0; | |
273 | } | |
274 | else | |
275 | { | |
276 | sval = sval + 1; | |
277 | } | |
278 | addr = cpu_get_reg (cpu, reg); | |
279 | cpu_set_reg (cpu, reg, addr + sval); | |
280 | if ((code & 0x10) == 0) | |
281 | { | |
282 | addr += sval; | |
283 | } | |
284 | } | |
285 | ||
286 | /* [n,r] 16-bits offset indexed indirect. */ | |
287 | else if ((code & 0x07) == 3) | |
288 | { | |
289 | if (restrict) | |
290 | { | |
291 | return 0; | |
292 | } | |
293 | reg = (code >> 3) & 0x03; | |
294 | addr = cpu_get_reg (cpu, reg); | |
295 | addr += cpu_fetch16 (cpu); | |
296 | addr = memory_read16 (cpu, addr); | |
297 | cpu_add_cycles (cpu, 1); | |
298 | } | |
299 | else if ((code & 0x4) == 0) | |
300 | { | |
301 | if (restrict) | |
302 | { | |
303 | return 0; | |
304 | } | |
305 | reg = (code >> 3) & 0x03; | |
306 | addr = cpu_get_reg (cpu, reg); | |
307 | if (code & 0x2) | |
308 | { | |
309 | sval = cpu_fetch16 (cpu); | |
310 | cpu_add_cycles (cpu, 1); | |
311 | } | |
312 | else | |
313 | { | |
314 | sval = cpu_fetch8 (cpu); | |
315 | if (code & 0x1) | |
316 | sval |= 0xff00; | |
317 | cpu_add_cycles (cpu, 1); | |
318 | } | |
319 | addr += sval; | |
320 | } | |
321 | else | |
322 | { | |
323 | reg = (code >> 3) & 0x03; | |
324 | addr = cpu_get_reg (cpu, reg); | |
325 | switch (code & 3) | |
326 | { | |
327 | case 0: | |
328 | addr += cpu_get_a (cpu); | |
329 | break; | |
330 | case 1: | |
331 | addr += cpu_get_b (cpu); | |
332 | break; | |
333 | case 2: | |
334 | addr += cpu_get_d (cpu); | |
335 | break; | |
336 | case 3: | |
337 | default: | |
338 | addr += cpu_get_d (cpu); | |
339 | addr = memory_read16 (cpu, addr); | |
340 | cpu_add_cycles (cpu, 1); | |
341 | break; | |
342 | } | |
343 | } | |
344 | ||
345 | return addr; | |
346 | } | |
347 | ||
348 | uint8 | |
349 | cpu_get_indexed_operand8 (sim_cpu* cpu, int restrict) | |
350 | { | |
351 | uint16 addr; | |
352 | ||
353 | addr = cpu_get_indexed_operand_addr (cpu, restrict); | |
354 | return memory_read8 (cpu, addr); | |
355 | } | |
356 | ||
357 | uint16 | |
358 | cpu_get_indexed_operand16 (sim_cpu* cpu, int restrict) | |
359 | { | |
360 | uint16 addr; | |
361 | ||
362 | addr = cpu_get_indexed_operand_addr (cpu, restrict); | |
363 | return memory_read16 (cpu, addr); | |
364 | } | |
365 | ||
366 | void | |
367 | cpu_move8 (sim_cpu *cpu, uint8 code) | |
368 | { | |
369 | uint8 src; | |
370 | uint16 addr; | |
371 | ||
372 | switch (code) | |
373 | { | |
374 | case 0x0b: | |
375 | src = cpu_fetch8 (cpu); | |
376 | addr = cpu_fetch16 (cpu); | |
377 | break; | |
378 | ||
379 | case 0x08: | |
380 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
381 | src = cpu_fetch8 (cpu); | |
382 | break; | |
383 | ||
384 | case 0x0c: | |
385 | addr = cpu_fetch16 (cpu); | |
386 | src = memory_read8 (cpu, addr); | |
387 | addr = cpu_fetch16 (cpu); | |
388 | break; | |
389 | ||
390 | case 0x09: | |
391 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
392 | src = memory_read8 (cpu, cpu_fetch16 (cpu)); | |
393 | break; | |
394 | ||
395 | case 0x0d: | |
396 | src = cpu_get_indexed_operand8 (cpu, 1); | |
397 | addr = cpu_fetch16 (cpu); | |
398 | break; | |
399 | ||
400 | case 0x0a: | |
401 | src = cpu_get_indexed_operand8 (cpu, 1); | |
402 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
403 | break; | |
86596dc8 SC |
404 | |
405 | default: | |
406 | sim_engine_abort (CPU_STATE (cpu), cpu, 0, | |
407 | "Invalid code 0x%0x -- internal error?", code); | |
408 | return; | |
81e09ed8 SC |
409 | } |
410 | memory_write8 (cpu, addr, src); | |
411 | } | |
412 | ||
413 | void | |
414 | cpu_move16 (sim_cpu *cpu, uint8 code) | |
415 | { | |
416 | uint16 src; | |
417 | uint16 addr; | |
418 | ||
419 | switch (code) | |
420 | { | |
421 | case 0x03: | |
422 | src = cpu_fetch16 (cpu); | |
423 | addr = cpu_fetch16 (cpu); | |
424 | break; | |
425 | ||
426 | case 0x00: | |
427 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
428 | src = cpu_fetch16 (cpu); | |
429 | break; | |
430 | ||
431 | case 0x04: | |
432 | addr = cpu_fetch16 (cpu); | |
433 | src = memory_read16 (cpu, addr); | |
434 | addr = cpu_fetch16 (cpu); | |
435 | break; | |
436 | ||
437 | case 0x01: | |
438 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
439 | src = memory_read16 (cpu, cpu_fetch16 (cpu)); | |
440 | break; | |
441 | ||
442 | case 0x05: | |
443 | src = cpu_get_indexed_operand16 (cpu, 1); | |
444 | addr = cpu_fetch16 (cpu); | |
445 | break; | |
446 | ||
447 | case 0x02: | |
448 | src = cpu_get_indexed_operand16 (cpu, 1); | |
449 | addr = cpu_get_indexed_operand_addr (cpu, 1); | |
450 | break; | |
86596dc8 SC |
451 | |
452 | default: | |
453 | sim_engine_abort (CPU_STATE (cpu), cpu, 0, | |
454 | "Invalid code 0x%0x -- internal error?", code); | |
455 | return; | |
81e09ed8 SC |
456 | } |
457 | memory_write16 (cpu, addr, src); | |
458 | } | |
459 | ||
e0709f50 AC |
460 | int |
461 | cpu_initialize (SIM_DESC sd, sim_cpu *cpu) | |
462 | { | |
e0709f50 AC |
463 | sim_add_option_table (sd, 0, cpu_options); |
464 | ||
465 | memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs)); | |
466 | ||
467 | cpu->cpu_absolute_cycle = 0; | |
468 | cpu->cpu_current_cycle = 0; | |
469 | cpu->cpu_emul_syscall = 1; | |
470 | cpu->cpu_running = 1; | |
471 | cpu->cpu_stop_on_interrupt = 0; | |
472 | cpu->cpu_frequency = 8 * 1000 * 1000; | |
e0709f50 AC |
473 | cpu->cpu_use_elf_start = 0; |
474 | cpu->cpu_elf_start = 0; | |
475 | cpu->cpu_use_local_config = 0; | |
77342e5e SC |
476 | cpu->bank_start = 0; |
477 | cpu->bank_end = 0; | |
478 | cpu->bank_shift = 0; | |
e0709f50 AC |
479 | cpu->cpu_config = M6811_NOSEC | M6811_NOCOP | M6811_ROMON | |
480 | M6811_EEON; | |
26128965 | 481 | interrupts_initialize (sd, cpu); |
e0709f50 AC |
482 | |
483 | cpu->cpu_is_initialized = 1; | |
26128965 | 484 | return 0; |
e0709f50 AC |
485 | } |
486 | ||
487 | ||
488 | /* Reinitialize the processor after a reset. */ | |
489 | int | |
490 | cpu_reset (sim_cpu *cpu) | |
491 | { | |
e0709f50 AC |
492 | /* Initialize the config register. |
493 | It is only initialized at reset time. */ | |
494 | memset (cpu->ios, 0, sizeof (cpu->ios)); | |
81e09ed8 SC |
495 | if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11) |
496 | cpu->ios[M6811_INIT] = 0x1; | |
497 | else | |
498 | cpu->ios[M6811_INIT] = 0; | |
e0709f50 AC |
499 | |
500 | /* Output compare registers set to 0xFFFF. */ | |
501 | cpu->ios[M6811_TOC1_H] = 0xFF; | |
502 | cpu->ios[M6811_TOC1_L] = 0xFF; | |
503 | cpu->ios[M6811_TOC2_H] = 0xFF; | |
504 | cpu->ios[M6811_TOC2_L] = 0xFF; | |
505 | cpu->ios[M6811_TOC3_H] = 0xFF; | |
506 | cpu->ios[M6811_TOC4_L] = 0xFF; | |
507 | cpu->ios[M6811_TOC5_H] = 0xFF; | |
508 | cpu->ios[M6811_TOC5_L] = 0xFF; | |
509 | ||
510 | /* Setup the processor registers. */ | |
511 | memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs)); | |
512 | cpu->cpu_absolute_cycle = 0; | |
513 | cpu->cpu_current_cycle = 0; | |
514 | cpu->cpu_is_initialized = 0; | |
515 | ||
26128965 SC |
516 | /* Reset interrupts. */ |
517 | interrupts_reset (&cpu->cpu_interrupts); | |
518 | ||
e0709f50 AC |
519 | /* Reinitialize the CPU operating mode. */ |
520 | cpu->ios[M6811_HPRIO] = cpu->cpu_mode; | |
521 | return 0; | |
522 | } | |
523 | ||
524 | /* Reinitialize the processor after a reset. */ | |
525 | int | |
526 | cpu_restart (sim_cpu *cpu) | |
527 | { | |
528 | uint16 addr; | |
529 | ||
530 | /* Get CPU starting address depending on the CPU mode. */ | |
531 | if (cpu->cpu_use_elf_start == 0) | |
532 | { | |
533 | switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) | |
534 | { | |
535 | /* Single Chip */ | |
536 | default: | |
537 | case 0 : | |
538 | addr = memory_read16 (cpu, 0xFFFE); | |
539 | break; | |
540 | ||
541 | /* Expanded Multiplexed */ | |
542 | case M6811_MDA: | |
543 | addr = memory_read16 (cpu, 0xFFFE); | |
544 | break; | |
545 | ||
546 | /* Special Bootstrap */ | |
547 | case M6811_SMOD: | |
548 | addr = 0; | |
549 | break; | |
550 | ||
551 | /* Factory Test */ | |
552 | case M6811_MDA | M6811_SMOD: | |
553 | addr = memory_read16 (cpu, 0xFFFE); | |
554 | break; | |
555 | } | |
556 | } | |
557 | else | |
558 | { | |
559 | addr = cpu->cpu_elf_start; | |
560 | } | |
561 | ||
562 | /* Setup the processor registers. */ | |
563 | cpu->cpu_insn_pc = addr; | |
564 | cpu->cpu_regs.pc = addr; | |
565 | cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT; | |
566 | cpu->cpu_absolute_cycle = 0; | |
567 | cpu->cpu_is_initialized = 1; | |
568 | cpu->cpu_current_cycle = 0; | |
569 | ||
570 | cpu_call (cpu, addr); | |
571 | ||
572 | return 0; | |
573 | } | |
574 | ||
575 | void | |
576 | print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode) | |
577 | { | |
578 | while (desc->mask) | |
579 | { | |
580 | if (val & desc->mask) | |
581 | sim_io_printf (sd, "%s", | |
582 | mode == 0 ? desc->short_name : desc->long_name); | |
583 | desc++; | |
584 | } | |
585 | } | |
586 | ||
587 | void | |
588 | print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc, | |
589 | uint8 val, uint16 addr) | |
590 | { | |
591 | sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%02x ", name, addr, val); | |
592 | if (desc) | |
593 | print_io_reg_desc (sd, desc, val, 0); | |
594 | } | |
595 | ||
962e9d85 SC |
596 | void |
597 | print_io_word (SIM_DESC sd, const char *name, io_reg_desc *desc, | |
598 | uint16 val, uint16 addr) | |
599 | { | |
600 | sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%04x ", name, addr, val); | |
601 | if (desc) | |
602 | print_io_reg_desc (sd, desc, val, 0); | |
603 | } | |
604 | ||
e0709f50 AC |
605 | void |
606 | cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val) | |
607 | { | |
608 | cpu_set_ccr_V (proc, 0); | |
609 | cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0); | |
610 | cpu_set_ccr_Z (proc, val == 0 ? 1 : 0); | |
611 | } | |
612 | ||
613 | ||
614 | uint16 | |
615 | cpu_fetch_relbranch (sim_cpu *cpu) | |
616 | { | |
617 | uint16 addr = (uint16) cpu_fetch8 (cpu); | |
618 | ||
619 | if (addr & 0x0080) | |
620 | { | |
621 | addr |= 0xFF00; | |
622 | } | |
623 | addr += cpu->cpu_regs.pc; | |
624 | return addr; | |
625 | } | |
626 | ||
81e09ed8 SC |
627 | uint16 |
628 | cpu_fetch_relbranch16 (sim_cpu *cpu) | |
629 | { | |
630 | uint16 addr = cpu_fetch16 (cpu); | |
631 | ||
632 | addr += cpu->cpu_regs.pc; | |
633 | return addr; | |
634 | } | |
e0709f50 AC |
635 | |
636 | /* Push all the CPU registers (when an interruption occurs). */ | |
637 | void | |
638 | cpu_push_all (sim_cpu *cpu) | |
639 | { | |
81e09ed8 SC |
640 | if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11) |
641 | { | |
642 | cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.pc); | |
643 | cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.iy); | |
644 | cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.ix); | |
645 | cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.d); | |
646 | cpu_m68hc11_push_uint8 (cpu, cpu->cpu_regs.ccr); | |
647 | } | |
648 | else | |
649 | { | |
650 | cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.pc); | |
651 | cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.iy); | |
652 | cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.ix); | |
653 | cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.d); | |
654 | cpu_m68hc12_push_uint8 (cpu, cpu->cpu_regs.ccr); | |
655 | } | |
e0709f50 AC |
656 | } |
657 | ||
81e09ed8 SC |
658 | /* Simulation of the dbcc/ibcc/tbcc 68HC12 conditional branch operations. */ |
659 | void | |
660 | cpu_dbcc (sim_cpu* cpu) | |
661 | { | |
662 | uint8 code; | |
663 | uint16 addr; | |
664 | uint16 inc; | |
665 | uint16 reg; | |
666 | ||
667 | code = cpu_fetch8 (cpu); | |
668 | switch (code & 0xc0) | |
669 | { | |
670 | case 0x80: /* ibcc */ | |
671 | inc = 1; | |
672 | break; | |
673 | case 0x40: /* tbcc */ | |
674 | inc = 0; | |
675 | break; | |
676 | case 0: /* dbcc */ | |
677 | inc = -1; | |
678 | break; | |
679 | default: | |
680 | abort (); | |
681 | break; | |
682 | } | |
683 | ||
684 | addr = cpu_fetch8 (cpu); | |
685 | if (code & 0x10) | |
686 | addr |= 0xff00; | |
687 | ||
688 | addr += cpu_get_pc (cpu); | |
689 | reg = cpu_get_src_reg (cpu, code & 0x07); | |
690 | reg += inc; | |
691 | ||
692 | /* Branch according to register value. */ | |
693 | if ((reg != 0 && (code & 0x20)) || (reg == 0 && !(code & 0x20))) | |
694 | { | |
695 | cpu_set_pc (cpu, addr); | |
696 | } | |
697 | cpu_set_dst_reg (cpu, code & 0x07, reg); | |
698 | } | |
699 | ||
700 | void | |
701 | cpu_exg (sim_cpu* cpu, uint8 code) | |
702 | { | |
703 | uint8 r1, r2; | |
704 | uint16 src1; | |
705 | uint16 src2; | |
706 | ||
707 | r1 = (code >> 4) & 0x07; | |
708 | r2 = code & 0x07; | |
709 | if (code & 0x80) | |
710 | { | |
711 | src1 = cpu_get_src_reg (cpu, r1); | |
712 | src2 = cpu_get_src_reg (cpu, r2); | |
713 | if (r2 == 1 || r2 == 2) | |
714 | src2 |= 0xff00; | |
715 | ||
716 | cpu_set_dst_reg (cpu, r2, src1); | |
717 | cpu_set_dst_reg (cpu, r1, src2); | |
718 | } | |
719 | else | |
720 | { | |
721 | src1 = cpu_get_src_reg (cpu, r1); | |
722 | ||
723 | /* Sign extend the 8-bit registers (A, B, CCR). */ | |
724 | if ((r1 == 0 || r1 == 1 || r1 == 2) && (src1 & 0x80)) | |
725 | src1 |= 0xff00; | |
726 | ||
727 | cpu_set_dst_reg (cpu, r2, src1); | |
728 | } | |
729 | } | |
e0709f50 AC |
730 | |
731 | /* Handle special instructions. */ | |
732 | void | |
733 | cpu_special (sim_cpu *cpu, enum M6811_Special special) | |
734 | { | |
735 | switch (special) | |
736 | { | |
737 | case M6811_RTI: | |
738 | { | |
739 | uint8 ccr; | |
740 | ||
81e09ed8 | 741 | ccr = cpu_m68hc11_pop_uint8 (cpu); |
e0709f50 | 742 | cpu_set_ccr (cpu, ccr); |
81e09ed8 SC |
743 | cpu_set_d (cpu, cpu_m68hc11_pop_uint16 (cpu)); |
744 | cpu_set_x (cpu, cpu_m68hc11_pop_uint16 (cpu)); | |
745 | cpu_set_y (cpu, cpu_m68hc11_pop_uint16 (cpu)); | |
746 | cpu_set_pc (cpu, cpu_m68hc11_pop_uint16 (cpu)); | |
747 | cpu_return (cpu); | |
748 | break; | |
749 | } | |
750 | ||
751 | case M6812_RTI: | |
752 | { | |
753 | uint8 ccr; | |
754 | ||
755 | ccr = cpu_m68hc12_pop_uint8 (cpu); | |
756 | cpu_set_ccr (cpu, ccr); | |
757 | cpu_set_d (cpu, cpu_m68hc12_pop_uint16 (cpu)); | |
758 | cpu_set_x (cpu, cpu_m68hc12_pop_uint16 (cpu)); | |
759 | cpu_set_y (cpu, cpu_m68hc12_pop_uint16 (cpu)); | |
760 | cpu_set_pc (cpu, cpu_m68hc12_pop_uint16 (cpu)); | |
e0709f50 AC |
761 | cpu_return (cpu); |
762 | break; | |
763 | } | |
764 | ||
765 | case M6811_WAI: | |
766 | /* In the ELF-start mode, we are in a special mode where | |
767 | the WAI corresponds to an exit. */ | |
768 | if (cpu->cpu_use_elf_start) | |
769 | { | |
770 | cpu_set_pc (cpu, cpu->cpu_insn_pc); | |
771 | sim_engine_halt (CPU_STATE (cpu), cpu, | |
772 | NULL, NULL_CIA, sim_exited, | |
773 | cpu_get_d (cpu)); | |
774 | return; | |
775 | } | |
776 | /* SCz: not correct... */ | |
777 | cpu_push_all (cpu); | |
778 | break; | |
779 | ||
780 | case M6811_SWI: | |
781 | interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI); | |
782 | interrupts_process (&cpu->cpu_interrupts); | |
783 | break; | |
784 | ||
785 | case M6811_EMUL_SYSCALL: | |
786 | case M6811_ILLEGAL: | |
787 | if (cpu->cpu_emul_syscall) | |
788 | { | |
789 | uint8 op = memory_read8 (cpu, | |
790 | cpu_get_pc (cpu) - 1); | |
791 | if (op == 0x41) | |
792 | { | |
793 | cpu_set_pc (cpu, cpu->cpu_insn_pc); | |
794 | sim_engine_halt (CPU_STATE (cpu), cpu, | |
795 | NULL, NULL_CIA, sim_exited, | |
796 | cpu_get_d (cpu)); | |
797 | return; | |
798 | } | |
799 | else | |
800 | { | |
801 | emul_os (op, cpu); | |
802 | } | |
803 | return; | |
804 | } | |
805 | ||
806 | interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL); | |
807 | interrupts_process (&cpu->cpu_interrupts); | |
808 | break; | |
809 | ||
810 | case M6811_TEST: | |
81e09ed8 | 811 | case M6812_BGND: |
e0709f50 AC |
812 | { |
813 | SIM_DESC sd; | |
814 | ||
815 | sd = CPU_STATE (cpu); | |
816 | ||
817 | /* Breakpoint instruction if we are under gdb. */ | |
818 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) | |
819 | { | |
820 | cpu->cpu_regs.pc --; | |
821 | sim_engine_halt (CPU_STATE (cpu), cpu, | |
822 | 0, cpu_get_pc (cpu), sim_stopped, | |
823 | SIM_SIGTRAP); | |
824 | } | |
825 | /* else this is a nop but not in test factory mode. */ | |
826 | break; | |
827 | } | |
81e09ed8 SC |
828 | |
829 | case M6812_IDIVS: | |
830 | { | |
831 | int32 src1 = (int16) cpu_get_d (cpu); | |
832 | int32 src2 = (int16) cpu_get_x (cpu); | |
833 | ||
834 | if (src2 == 0) | |
835 | { | |
836 | cpu_set_ccr_C (cpu, 1); | |
837 | } | |
838 | else | |
839 | { | |
840 | cpu_set_d (cpu, src1 % src2); | |
841 | src1 = src1 / src2; | |
842 | cpu_set_x (cpu, src1); | |
843 | cpu_set_ccr_C (cpu, 0); | |
844 | cpu_set_ccr_Z (cpu, src1 == 0); | |
845 | cpu_set_ccr_N (cpu, src1 & 0x8000); | |
846 | cpu_set_ccr_V (cpu, src1 >= 32768 || src1 < -32768); | |
847 | } | |
848 | } | |
849 | break; | |
850 | ||
851 | case M6812_EDIV: | |
852 | { | |
853 | uint32 src1 = (uint32) cpu_get_x (cpu); | |
854 | uint32 src2 = (uint32) (cpu_get_y (cpu) << 16) | |
855 | | (uint32) (cpu_get_d (cpu)); | |
856 | ||
857 | if (src1 == 0) | |
858 | { | |
859 | cpu_set_ccr_C (cpu, 1); | |
860 | } | |
861 | else | |
862 | { | |
863 | cpu_set_ccr_C (cpu, 0); | |
864 | cpu_set_d (cpu, src2 % src1); | |
865 | src2 = src2 / src1; | |
866 | cpu_set_y (cpu, src2); | |
867 | cpu_set_ccr_Z (cpu, src2 == 0); | |
868 | cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0); | |
869 | cpu_set_ccr_V (cpu, (src2 & 0xffff0000) != 0); | |
870 | } | |
871 | } | |
872 | break; | |
873 | ||
874 | case M6812_EDIVS: | |
875 | { | |
876 | int32 src1 = (int16) cpu_get_x (cpu); | |
877 | int32 src2 = (uint32) (cpu_get_y (cpu) << 16) | |
878 | | (uint32) (cpu_get_d (cpu)); | |
879 | ||
880 | if (src1 == 0) | |
881 | { | |
882 | cpu_set_ccr_C (cpu, 1); | |
883 | } | |
884 | else | |
885 | { | |
886 | cpu_set_ccr_C (cpu, 0); | |
887 | cpu_set_d (cpu, src2 % src1); | |
888 | src2 = src2 / src1; | |
889 | cpu_set_y (cpu, src2); | |
890 | cpu_set_ccr_Z (cpu, src2 == 0); | |
891 | cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0); | |
892 | cpu_set_ccr_V (cpu, src2 > 32767 || src2 < -32768); | |
893 | } | |
894 | } | |
895 | break; | |
896 | ||
897 | case M6812_EMULS: | |
898 | { | |
899 | int32 src1, src2; | |
900 | ||
901 | src1 = (int16) cpu_get_d (cpu); | |
902 | src2 = (int16) cpu_get_y (cpu); | |
903 | src1 = src1 * src2; | |
904 | cpu_set_d (cpu, src1 & 0x0ffff); | |
905 | cpu_set_y (cpu, src1 >> 16); | |
906 | cpu_set_ccr_Z (cpu, src1 == 0); | |
907 | cpu_set_ccr_N (cpu, (src1 & 0x80000000) != 0); | |
908 | cpu_set_ccr_C (cpu, (src1 & 0x00008000) != 0); | |
909 | } | |
910 | break; | |
911 | ||
912 | case M6812_EMACS: | |
913 | { | |
914 | int32 src1, src2; | |
915 | uint16 addr; | |
916 | ||
917 | addr = cpu_fetch16 (cpu); | |
918 | src1 = (int16) memory_read16 (cpu, cpu_get_x (cpu)); | |
919 | src2 = (int16) memory_read16 (cpu, cpu_get_y (cpu)); | |
920 | src1 = src1 * src2; | |
921 | src2 = (((uint32) memory_read16 (cpu, addr)) << 16) | |
922 | | (uint32) memory_read16 (cpu, addr + 2); | |
923 | ||
924 | memory_write16 (cpu, addr, (src1 + src2) >> 16); | |
925 | memory_write16 (cpu, addr + 2, (src1 + src2)); | |
926 | ||
927 | ||
928 | } | |
929 | break; | |
930 | ||
63f36def SC |
931 | case M6812_CALL: |
932 | { | |
933 | uint8 page; | |
934 | uint16 addr; | |
935 | ||
936 | addr = cpu_fetch16 (cpu); | |
937 | page = cpu_fetch8 (cpu); | |
938 | ||
939 | cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu)); | |
940 | cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu)); | |
941 | ||
942 | cpu_set_page (cpu, page); | |
943 | cpu_set_pc (cpu, addr); | |
944 | } | |
945 | break; | |
946 | ||
947 | case M6812_CALL_INDIRECT: | |
948 | { | |
949 | uint8 code; | |
950 | uint16 addr; | |
951 | uint8 page; | |
952 | ||
953 | code = memory_read8 (cpu, cpu_get_pc (cpu)); | |
954 | /* Indirect addressing call has the page specified in the | |
955 | memory location pointed to by the address. */ | |
956 | if ((code & 0xE3) == 0xE3) | |
957 | { | |
958 | addr = cpu_get_indexed_operand_addr (cpu, 0); | |
959 | page = memory_read8 (cpu, addr + 2); | |
960 | addr = memory_read16 (cpu, addr); | |
961 | } | |
962 | else | |
963 | { | |
964 | /* Otherwise, page is in the opcode. */ | |
965 | addr = cpu_get_indexed_operand16 (cpu, 0); | |
966 | page = cpu_fetch8 (cpu); | |
967 | } | |
968 | cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu)); | |
969 | cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu)); | |
970 | cpu_set_page (cpu, page); | |
971 | cpu_set_pc (cpu, addr); | |
972 | } | |
973 | break; | |
974 | ||
975 | case M6812_RTC: | |
976 | { | |
977 | uint8 page = cpu_m68hc12_pop_uint8 (cpu); | |
978 | uint16 addr = cpu_m68hc12_pop_uint16 (cpu); | |
979 | ||
980 | cpu_set_page (cpu, page); | |
981 | cpu_set_pc (cpu, addr); | |
982 | } | |
983 | break; | |
984 | ||
81e09ed8 SC |
985 | case M6812_ETBL: |
986 | default: | |
987 | sim_engine_halt (CPU_STATE (cpu), cpu, NULL, | |
988 | cpu_get_pc (cpu), sim_stopped, | |
989 | SIM_SIGILL); | |
990 | break; | |
e0709f50 AC |
991 | } |
992 | } | |
993 | ||
994 | ||
995 | void | |
996 | cpu_single_step (sim_cpu *cpu) | |
997 | { | |
998 | cpu->cpu_current_cycle = 0; | |
999 | cpu->cpu_insn_pc = cpu_get_pc (cpu); | |
1000 | ||
1001 | /* Handle the pending interrupts. If an interrupt is handled, | |
1002 | treat this as an single step. */ | |
1003 | if (interrupts_process (&cpu->cpu_interrupts)) | |
1004 | { | |
1005 | cpu->cpu_absolute_cycle += cpu->cpu_current_cycle; | |
1006 | return; | |
1007 | } | |
1008 | ||
1009 | /* printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/ | |
81e09ed8 | 1010 | cpu->cpu_interpretor (cpu); |
e0709f50 AC |
1011 | cpu->cpu_absolute_cycle += cpu->cpu_current_cycle; |
1012 | } | |
1013 | ||
1014 | /* VARARGS */ | |
1015 | void | |
1016 | sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep, | |
1017 | uint16 addr, const char *message, ...) | |
1018 | { | |
1019 | char buf[1024]; | |
1020 | va_list args; | |
1021 | ||
1022 | va_start (args, message); | |
1023 | vsprintf (buf, message, args); | |
1024 | va_end (args); | |
1025 | ||
86596dc8 | 1026 | sim_io_printf (CPU_STATE (cpu), "%s\n", buf); |
e0709f50 AC |
1027 | cpu_memory_exception (cpu, excep, addr, buf); |
1028 | } | |
1029 | ||
1030 | ||
1031 | void | |
1032 | cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep, | |
1033 | uint16 addr, const char *message) | |
1034 | { | |
1035 | if (cpu->cpu_running == 0) | |
1036 | return; | |
1037 | ||
1038 | cpu_set_pc (cpu, cpu->cpu_insn_pc); | |
1039 | sim_engine_halt (CPU_STATE (cpu), cpu, NULL, | |
1040 | cpu_get_pc (cpu), sim_stopped, excep); | |
1041 | ||
1042 | #if 0 | |
1043 | cpu->mem_exception = excep; | |
1044 | cpu->fault_addr = addr; | |
1045 | cpu->fault_msg = strdup (message); | |
1046 | ||
1047 | if (cpu->cpu_use_handler) | |
1048 | { | |
1049 | longjmp (&cpu->cpu_exception_handler, 1); | |
1050 | } | |
1051 | (* cpu->callback->printf_filtered) | |
1052 | (cpu->callback, "Fault at 0x%04x: %s\n", addr, message); | |
1053 | #endif | |
1054 | } | |
1055 | ||
1056 | void | |
1057 | cpu_info (SIM_DESC sd, sim_cpu *cpu) | |
1058 | { | |
1059 | sim_io_printf (sd, "CPU info:\n"); | |
2990a9f4 | 1060 | sim_io_printf (sd, " Absolute cycle: %s\n", |
a685700c SC |
1061 | cycle_to_string (cpu, cpu->cpu_absolute_cycle, |
1062 | PRINT_TIME | PRINT_CYCLE)); | |
2990a9f4 | 1063 | |
e0709f50 AC |
1064 | sim_io_printf (sd, " Syscall emulation: %s\n", |
1065 | cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no"); | |
1066 | sim_io_printf (sd, " Memory errors detection: %s\n", | |
1067 | cpu->cpu_check_memory ? "yes" : "no"); | |
1068 | sim_io_printf (sd, " Stop on interrupt: %s\n", | |
1069 | cpu->cpu_stop_on_interrupt ? "yes" : "no"); | |
1070 | } | |
1071 |