/* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation
- Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- Written by Stephane Carrez (stcarrez@worldnet.fr)
+ Copyright 1999, 2000, 2001, 2002, 2003, 2007, 2008
+ 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 redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-1, or (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-will be useful, but WITHOUT ANY WARRANTY; without even the implied
-warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-the GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this file; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "sim-main.h"
#include "sim-assert.h"
#include "sim-module.h"
#include "sim-options.h"
-void cpu_free_frame (sim_cpu* cpu, struct cpu_frame *frame);
-
enum {
OPTION_CPU_RESET = OPTION_START,
OPTION_EMUL_OS,
OPTION_CPU_CONFIG,
+ OPTION_CPU_BOOTSTRAP,
OPTION_CPU_MODE
};
'\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 }
};
cpu_option_handler (SIM_DESC sd, sim_cpu *cpu,
int opt, char *arg, int is_command)
{
- sim_cpu *cpu;
int val;
cpu = STATE_CPU (sd, 0);
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;
}
-/* Tentative to keep track of the cpu frame. */
-struct cpu_frame*
-cpu_find_frame (sim_cpu *cpu, uint16 sp)
-{
- struct cpu_frame_list *flist;
-
- flist = cpu->cpu_frames;
- while (flist)
- {
- struct cpu_frame *frame;
-
- frame = flist->frame;
- while (frame)
- {
- if (frame->sp_low <= sp && frame->sp_high >= sp)
- {
- cpu->cpu_current_frame = flist;
- return frame;
- }
-
- frame = frame->up;
- }
- flist = flist->next;
- }
- return 0;
-}
-
-struct cpu_frame_list*
-cpu_create_frame_list (sim_cpu *cpu)
-{
- struct cpu_frame_list *flist;
-
- flist = (struct cpu_frame_list*) malloc (sizeof (struct cpu_frame_list));
- flist->frame = 0;
- flist->next = cpu->cpu_frames;
- flist->prev = 0;
- if (flist->next)
- flist->next->prev = flist;
- cpu->cpu_frames = flist;
- cpu->cpu_current_frame = flist;
- return flist;
-}
-
-void
-cpu_remove_frame_list (sim_cpu *cpu, struct cpu_frame_list *flist)
-{
- struct cpu_frame *frame;
-
- if (flist->prev == 0)
- cpu->cpu_frames = flist->next;
- else
- flist->prev->next = flist->next;
- if (flist->next)
- flist->next->prev = flist->prev;
-
- frame = flist->frame;
- while (frame)
- {
- struct cpu_frame* up = frame->up;
- cpu_free_frame (cpu, frame);
- frame = up;
- }
- free (flist);
-}
-
-struct cpu_frame*
-cpu_create_frame (sim_cpu *cpu, uint16 pc, uint16 sp)
-{
- struct cpu_frame *frame;
-
- frame = (struct cpu_frame*) malloc (sizeof(struct cpu_frame));
- frame->up = 0;
- frame->pc = pc;
- frame->sp_low = sp;
- frame->sp_high = sp;
- return frame;
-}
-
-void
-cpu_free_frame (sim_cpu *cpu, struct cpu_frame *frame)
-{
- free (frame);
-}
-
-uint16
-cpu_frame_reg (sim_cpu *cpu, uint16 rn)
-{
- struct cpu_frame *frame;
-
- if (cpu->cpu_current_frame == 0)
- return 0;
-
- frame = cpu->cpu_current_frame->frame;
- while (frame)
- {
- if (rn == 0)
- return frame->sp_high;
- frame = frame->up;
- rn--;
- }
- return 0;
-}
-
void
cpu_call (sim_cpu *cpu, uint16 addr)
{
-#if HAVE_FRAME
- uint16 pc = cpu->cpu_insn_pc;
- uint16 sp;
- struct cpu_frame_list *flist;
- struct cpu_frame* frame;
- struct cpu_frame* new_frame;
-#endif
cpu_set_pc (cpu, addr);
-#if HAVE_FRAME
- sp = cpu_get_sp (cpu);
-
- cpu->cpu_need_update_frame = 0;
- flist = cpu->cpu_current_frame;
- if (flist == 0)
- flist = cpu_create_frame_list (cpu);
-
- frame = flist->frame;
- if (frame && frame->sp_low > sp)
- frame->sp_low = sp;
-
- new_frame = cpu_create_frame (cpu, pc, sp);
- new_frame->up = frame;
- flist->frame = new_frame;
-#endif
-}
-
-void
-cpu_update_frame (sim_cpu *cpu, int do_create)
-{
-#if HAVE_FRAME
- struct cpu_frame *frame;
-
- frame = cpu_find_frame (cpu, cpu_get_sp (cpu));
- if (frame)
- {
- while (frame != cpu->cpu_current_frame->frame)
- {
- struct cpu_frame* up;
-
- up = cpu->cpu_current_frame->frame->up;
- cpu_free_frame (cpu, cpu->cpu_current_frame->frame);
- cpu->cpu_current_frame->frame = up;
- }
- return;
- }
-
- if (do_create)
- {
- cpu_create_frame_list (cpu);
- frame = cpu_create_frame (cpu, cpu_get_pc (cpu), cpu_get_sp (cpu));
- cpu->cpu_current_frame->frame = frame;
- }
-#endif
}
void
cpu_return (sim_cpu *cpu)
{
-#if HAVE_FRAME
- uint16 sp = cpu_get_sp (cpu);
- struct cpu_frame *frame;
- struct cpu_frame_list *flist;
-
- cpu->cpu_need_update_frame = 0;
- flist = cpu->cpu_current_frame;
- if (flist && flist->frame && flist->frame->up)
- {
- frame = flist->frame->up;
- if (frame->sp_low <= sp && frame->sp_high >= sp)
- {
- cpu_free_frame (cpu, flist->frame);
- flist->frame = frame;
- return;
- }
- }
- cpu_update_frame (cpu, 1);
-#endif
-}
-
-void
-cpu_print_frame (SIM_DESC sd, sim_cpu *cpu)
-{
- struct cpu_frame* frame;
- int level = 0;
-
- if (cpu->cpu_current_frame == 0 || cpu->cpu_current_frame->frame == 0)
- {
- sim_io_printf (sd, "No frame.\n");
- return;
- }
- sim_io_printf (sd, " # PC SP-L SP-H\n");
- frame = cpu->cpu_current_frame->frame;
- while (frame)
- {
- sim_io_printf (sd, "%3d 0x%04x 0x%04x 0x%04x\n",
- level, frame->pc, frame->sp_low, frame->sp_high);
- frame = frame->up;
- level++;
- }
}
/* Set the stack pointer and re-compute the current frame. */
cpu_set_sp (sim_cpu *cpu, uint16 val)
{
cpu->cpu_regs.sp = val;
- cpu_update_frame (cpu, 0);
}
uint16
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);
}
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);
}
cpu->cpu_running = 1;
cpu->cpu_stop_on_interrupt = 0;
cpu->cpu_frequency = 8 * 1000 * 1000;
- cpu->cpu_frames = 0;
- cpu->cpu_current_frame = 0;
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);
int
cpu_reset (sim_cpu *cpu)
{
- cpu->cpu_need_update_frame = 0;
- cpu->cpu_current_frame = 0;
- while (cpu->cpu_frames)
- cpu_remove_frame_list (cpu, cpu->cpu_frames);
-
/* Initialize the config register.
It is only initialized at reset time. */
memset (cpu->ios, 0, sizeof (cpu->ios));
print_io_reg_desc (sd, desc, val, 0);
}
+void
+print_io_word (SIM_DESC sd, const char *name, io_reg_desc *desc,
+ uint16 val, uint16 addr)
+{
+ sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%04x ", name, addr, val);
+ if (desc)
+ print_io_reg_desc (sd, desc, val, 0);
+}
+
void
cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val)
{
}
break;
+ case M6812_CALL:
+ {
+ uint8 page;
+ uint16 addr;
+
+ addr = cpu_fetch16 (cpu);
+ page = cpu_fetch8 (cpu);
+
+ cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
+ cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
+
+ cpu_set_page (cpu, page);
+ cpu_set_pc (cpu, addr);
+ }
+ break;
+
+ case M6812_CALL_INDIRECT:
+ {
+ uint8 code;
+ uint16 addr;
+ uint8 page;
+
+ code = memory_read8 (cpu, cpu_get_pc (cpu));
+ /* Indirect addressing call has the page specified in the
+ memory location pointed to by the address. */
+ if ((code & 0xE3) == 0xE3)
+ {
+ addr = cpu_get_indexed_operand_addr (cpu, 0);
+ page = memory_read8 (cpu, addr + 2);
+ addr = memory_read16 (cpu, addr);
+ }
+ else
+ {
+ /* Otherwise, page is in the opcode. */
+ addr = cpu_get_indexed_operand16 (cpu, 0);
+ page = cpu_fetch8 (cpu);
+ }
+ cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
+ cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
+ cpu_set_page (cpu, page);
+ cpu_set_pc (cpu, addr);
+ }
+ break;
+
+ case M6812_RTC:
+ {
+ uint8 page = cpu_m68hc12_pop_uint8 (cpu);
+ uint16 addr = cpu_m68hc12_pop_uint16 (cpu);
+
+ cpu_set_page (cpu, page);
+ cpu_set_pc (cpu, addr);
+ }
+ break;
+
case M6812_ETBL:
default:
sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
vsprintf (buf, message, args);
va_end (args);
- printf("%s\n", buf);
+ sim_io_printf (CPU_STATE (cpu), "%s\n", buf);
cpu_memory_exception (cpu, excep, addr, buf);
}
{
sim_io_printf (sd, "CPU info:\n");
sim_io_printf (sd, " Absolute cycle: %s\n",
- cycle_to_string (cpu, cpu->cpu_absolute_cycle));
+ cycle_to_string (cpu, cpu->cpu_absolute_cycle,
+ PRINT_TIME | PRINT_CYCLE));
sim_io_printf (sd, " Syscall emulation: %s\n",
cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");