📄 m68hc11_sim.c
字号:
/* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@nerim.fr)This file is part of GDB, GAS, and the GNU binutils.GDB, GAS, and the GNU binutils are free software; you can redistributethem and/or modify them under the terms of the GNU General PublicLicense as published by the Free Software Foundation; either version1, or (at your option) any later version.GDB, GAS, and the GNU binutils are distributed in the hope that theywill be useful, but WITHOUT ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Seethe GNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this file; see the file COPYING. If not, write to the FreeSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "sim-main.h"#include "sim-assert.h"#include "sim-module.h"#include "sim-options.h"enum { OPTION_CPU_RESET = OPTION_START, OPTION_EMUL_OS, OPTION_CPU_CONFIG, OPTION_CPU_BOOTSTRAP, OPTION_CPU_MODE};static DECLARE_OPTION_HANDLER (cpu_option_handler);static const OPTION cpu_options[] ={ { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET }, '\0', NULL, "Reset the CPU", cpu_option_handler }, { {"emulos", no_argument, NULL, OPTION_EMUL_OS }, '\0', NULL, "Emulate some OS system calls (read, write, ...)", cpu_option_handler }, { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG }, '\0', NULL, "Specify the initial CPU configuration register", cpu_option_handler }, { {"bootstrap", no_argument, NULL, OPTION_CPU_BOOTSTRAP }, '\0', NULL, "Start the processing in bootstrap mode", cpu_option_handler }, { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }};static SIM_RCcpu_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg, int is_command){ int val; cpu = STATE_CPU (sd, 0); switch (opt) { case OPTION_CPU_RESET: sim_board_reset (sd); break; case OPTION_EMUL_OS: cpu->cpu_emul_syscall = 1; break; case OPTION_CPU_CONFIG: if (sscanf(arg, "0x%x", &val) == 1 || sscanf(arg, "%d", &val) == 1) { cpu->cpu_config = val; cpu->cpu_use_local_config = 1; } else cpu->cpu_use_local_config = 0; break; case OPTION_CPU_BOOTSTRAP: cpu->cpu_start_mode = "bootstrap"; break; case OPTION_CPU_MODE: break; } return SIM_RC_OK;} voidcpu_call (sim_cpu *cpu, uint16 addr){ cpu_set_pc (cpu, addr);}voidcpu_return (sim_cpu *cpu){}/* Set the stack pointer and re-compute the current frame. */voidcpu_set_sp (sim_cpu *cpu, uint16 val){ cpu->cpu_regs.sp = val;}uint16cpu_get_reg (sim_cpu* cpu, uint8 reg){ switch (reg) { case 0: return cpu_get_x (cpu); case 1: return cpu_get_y (cpu); case 2: return cpu_get_sp (cpu); case 3: return cpu_get_pc (cpu); default: return 0; }}uint16cpu_get_src_reg (sim_cpu* cpu, uint8 reg){ switch (reg) { case 0: return cpu_get_a (cpu); case 1: return cpu_get_b (cpu); case 2: return cpu_get_ccr (cpu); case 3: return cpu_get_tmp3 (cpu); case 4: return cpu_get_d (cpu); case 5: return cpu_get_x (cpu); case 6: return cpu_get_y (cpu); case 7: return cpu_get_sp (cpu); default: return 0; }}voidcpu_set_dst_reg (sim_cpu* cpu, uint8 reg, uint16 val){ switch (reg) { case 0: cpu_set_a (cpu, val); break; case 1: cpu_set_b (cpu, val); break; case 2: cpu_set_ccr (cpu, val); break; case 3: cpu_set_tmp2 (cpu, val); break; case 4: cpu_set_d (cpu, val); break; case 5: cpu_set_x (cpu, val); break; case 6: cpu_set_y (cpu, val); break; case 7: cpu_set_sp (cpu, val); break; default: break; }}voidcpu_set_reg (sim_cpu* cpu, uint8 reg, uint16 val){ switch (reg) { case 0: cpu_set_x (cpu, val); break; case 1: cpu_set_y (cpu, val); break; case 2: cpu_set_sp (cpu, val); break; case 3: cpu_set_pc (cpu, val); break; default: break; }}/* Returns the address of a 68HC12 indexed operand. Pre and post modifications are handled on the source register. */uint16cpu_get_indexed_operand_addr (sim_cpu* cpu, int restrict){ uint8 reg; uint16 sval; uint16 addr; uint8 code; code = cpu_fetch8 (cpu); /* n,r with 5-bit signed constant. */ if ((code & 0x20) == 0) { reg = (code >> 6) & 3; sval = (code & 0x1f); if (code & 0x10) sval |= 0xfff0; addr = cpu_get_reg (cpu, reg); addr += sval; } /* Auto pre/post increment/decrement. */ else if ((code & 0xc0) != 0xc0) { reg = (code >> 6) & 3; sval = (code & 0x0f); if (sval & 0x8) { sval |= 0xfff0; } else { sval = sval + 1; } addr = cpu_get_reg (cpu, reg); cpu_set_reg (cpu, reg, addr + sval); if ((code & 0x10) == 0) { addr += sval; } } /* [n,r] 16-bits offset indexed indirect. */ else if ((code & 0x07) == 3) { if (restrict) { return 0; } reg = (code >> 3) & 0x03; addr = cpu_get_reg (cpu, reg); addr += cpu_fetch16 (cpu); addr = memory_read16 (cpu, addr); cpu_add_cycles (cpu, 1); } else if ((code & 0x4) == 0) { if (restrict) { return 0; } reg = (code >> 3) & 0x03; addr = cpu_get_reg (cpu, reg); if (code & 0x2) { sval = cpu_fetch16 (cpu); cpu_add_cycles (cpu, 1); } else { sval = cpu_fetch8 (cpu); if (code & 0x1) sval |= 0xff00; cpu_add_cycles (cpu, 1); } addr += sval; } else { reg = (code >> 3) & 0x03; addr = cpu_get_reg (cpu, reg); switch (code & 3) { case 0: addr += cpu_get_a (cpu); break; case 1: addr += cpu_get_b (cpu); break; case 2: addr += cpu_get_d (cpu); break; case 3: default: addr += cpu_get_d (cpu); addr = memory_read16 (cpu, addr); cpu_add_cycles (cpu, 1); break; } } return addr;}uint8cpu_get_indexed_operand8 (sim_cpu* cpu, int restrict){ uint16 addr; addr = cpu_get_indexed_operand_addr (cpu, restrict); return memory_read8 (cpu, addr);}uint16cpu_get_indexed_operand16 (sim_cpu* cpu, int restrict){ uint16 addr; addr = cpu_get_indexed_operand_addr (cpu, restrict); return memory_read16 (cpu, addr);}voidcpu_move8 (sim_cpu *cpu, uint8 code){ uint8 src; uint16 addr; switch (code) { case 0x0b: src = cpu_fetch8 (cpu); addr = cpu_fetch16 (cpu); break; case 0x08: addr = cpu_get_indexed_operand_addr (cpu, 1); src = cpu_fetch8 (cpu); break; case 0x0c: addr = cpu_fetch16 (cpu); src = memory_read8 (cpu, addr); addr = cpu_fetch16 (cpu); break; case 0x09: addr = cpu_get_indexed_operand_addr (cpu, 1); src = memory_read8 (cpu, cpu_fetch16 (cpu)); break; case 0x0d: src = cpu_get_indexed_operand8 (cpu, 1); addr = cpu_fetch16 (cpu); break; case 0x0a: src = cpu_get_indexed_operand8 (cpu, 1); addr = cpu_get_indexed_operand_addr (cpu, 1); break; default: sim_engine_abort (CPU_STATE (cpu), cpu, 0, "Invalid code 0x%0x -- internal error?", code); return; } memory_write8 (cpu, addr, src);}voidcpu_move16 (sim_cpu *cpu, uint8 code){ uint16 src; uint16 addr; switch (code) { case 0x03: src = cpu_fetch16 (cpu); addr = cpu_fetch16 (cpu); break; case 0x00: addr = cpu_get_indexed_operand_addr (cpu, 1); src = cpu_fetch16 (cpu); break; case 0x04: addr = cpu_fetch16 (cpu); src = memory_read16 (cpu, addr); addr = cpu_fetch16 (cpu); break; case 0x01: addr = cpu_get_indexed_operand_addr (cpu, 1); src = memory_read16 (cpu, cpu_fetch16 (cpu)); break; case 0x05: src = cpu_get_indexed_operand16 (cpu, 1); addr = cpu_fetch16 (cpu); break; case 0x02: src = cpu_get_indexed_operand16 (cpu, 1); addr = cpu_get_indexed_operand_addr (cpu, 1); break; default: sim_engine_abort (CPU_STATE (cpu), cpu, 0, "Invalid code 0x%0x -- internal error?", code); return; } memory_write16 (cpu, addr, src);}intcpu_initialize (SIM_DESC sd, sim_cpu *cpu){ sim_add_option_table (sd, 0, cpu_options); memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs)); cpu->cpu_absolute_cycle = 0; cpu->cpu_current_cycle = 0; cpu->cpu_emul_syscall = 1; cpu->cpu_running = 1; cpu->cpu_stop_on_interrupt = 0; cpu->cpu_frequency = 8 * 1000 * 1000; cpu->cpu_use_elf_start = 0; cpu->cpu_elf_start = 0; cpu->cpu_use_local_config = 0; cpu->bank_start = 0; cpu->bank_end = 0; cpu->bank_shift = 0; cpu->cpu_config = M6811_NOSEC | M6811_NOCOP | M6811_ROMON | M6811_EEON; interrupts_initialize (sd, cpu); cpu->cpu_is_initialized = 1; return 0;}/* Reinitialize the processor after a reset. */intcpu_reset (sim_cpu *cpu){ /* Initialize the config register. It is only initialized at reset time. */ memset (cpu->ios, 0, sizeof (cpu->ios)); if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11) cpu->ios[M6811_INIT] = 0x1; else cpu->ios[M6811_INIT] = 0; /* Output compare registers set to 0xFFFF. */ cpu->ios[M6811_TOC1_H] = 0xFF; cpu->ios[M6811_TOC1_L] = 0xFF; cpu->ios[M6811_TOC2_H] = 0xFF; cpu->ios[M6811_TOC2_L] = 0xFF; cpu->ios[M6811_TOC3_H] = 0xFF; cpu->ios[M6811_TOC4_L] = 0xFF; cpu->ios[M6811_TOC5_H] = 0xFF; cpu->ios[M6811_TOC5_L] = 0xFF; /* Setup the processor registers. */ memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs)); cpu->cpu_absolute_cycle = 0; cpu->cpu_current_cycle = 0; cpu->cpu_is_initialized = 0; /* Reset interrupts. */ interrupts_reset (&cpu->cpu_interrupts); /* Reinitialize the CPU operating mode. */ cpu->ios[M6811_HPRIO] = cpu->cpu_mode; return 0;}/* Reinitialize the processor after a reset. */intcpu_restart (sim_cpu *cpu){ uint16 addr; /* Get CPU starting address depending on the CPU mode. */ if (cpu->cpu_use_elf_start == 0) { switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) { /* Single Chip */ default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -