2000-07-27 11:23:39 +00:00
|
|
|
/* interp.c -- Simulator for Motorola 68HC11
|
|
|
|
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
|
|
|
Written by Stephane Carrez (stcarrez@worldnet.fr)
|
|
|
|
|
|
|
|
This file is part of GDB, the GNU debugger.
|
|
|
|
|
|
|
|
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 2, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
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 program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
|
|
|
|
#include "sim-main.h"
|
|
|
|
#include "sim-assert.h"
|
|
|
|
#include "sim-hw.h"
|
|
|
|
#include "sim-options.h"
|
|
|
|
#include "hw-tree.h"
|
|
|
|
#include "hw-device.h"
|
|
|
|
#include "hw-ports.h"
|
|
|
|
|
|
|
|
#ifndef MONITOR_BASE
|
|
|
|
# define MONITOR_BASE (0x0C000)
|
|
|
|
# define MONITOR_SIZE (0x04000)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void sim_get_info (SIM_DESC sd, char *cmd);
|
|
|
|
|
|
|
|
|
|
|
|
char *interrupt_names[] = {
|
|
|
|
"reset",
|
|
|
|
"nmi",
|
|
|
|
"int",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef INLINE
|
|
|
|
#if defined(__GNUC__) && defined(__OPTIMIZE__)
|
|
|
|
#define INLINE __inline__
|
|
|
|
#else
|
|
|
|
#define INLINE
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct sim_info_list
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
const char *device;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sim_info_list dev_list[] = {
|
|
|
|
{"cpu", "/m68hc11"},
|
|
|
|
{"timer", "/m68hc11/m68hc11tim"},
|
|
|
|
{"sio", "/m68hc11/m68hc11sio"},
|
|
|
|
{"spi", "/m68hc11/m68hc11spi"},
|
|
|
|
{"eeprom", "/m68hc11/m68hc11eepr"},
|
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Give some information about the simulator. */
|
|
|
|
static void
|
|
|
|
sim_get_info (SIM_DESC sd, char *cmd)
|
|
|
|
{
|
|
|
|
sim_cpu *cpu;
|
|
|
|
|
|
|
|
if (cmd != 0 && (cmd[0] == ' ' || cmd[0] == '-'))
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct hw *hw_dev;
|
|
|
|
cmd++;
|
|
|
|
|
|
|
|
for (i = 0; dev_list[i].name; i++)
|
|
|
|
if (strcmp (cmd, dev_list[i].name) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (dev_list[i].name == 0)
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "Device '%s' not found.\n", cmd);
|
|
|
|
sim_io_eprintf (sd, "Valid devices: cpu timer sio eeprom\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
hw_dev = sim_hw_parse (sd, dev_list[i].device);
|
|
|
|
if (hw_dev == 0)
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "Device '%s' not found\n", dev_list[i].device);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
hw_ioctl (hw_dev, 23, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
cpu_info (sd, cpu);
|
|
|
|
interrupts_info (sd, &cpu->cpu_interrupts);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_board_reset (SIM_DESC sd)
|
|
|
|
{
|
|
|
|
struct hw *hw_cpu;
|
|
|
|
sim_cpu *cpu;
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
/* hw_cpu = sim_hw_parse (sd, "/"); */
|
|
|
|
hw_cpu = sim_hw_parse (sd, "/m68hc11");
|
|
|
|
if (hw_cpu == 0)
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "m68hc11 cpu not found in device tree.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu_reset (cpu);
|
|
|
|
hw_port_event (hw_cpu, 3, 0);
|
|
|
|
cpu_restart (cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIM_DESC
|
|
|
|
sim_open (SIM_OPEN_KIND kind, host_callback *callback,
|
|
|
|
struct _bfd *abfd, char **argv)
|
|
|
|
{
|
|
|
|
char **p;
|
|
|
|
SIM_DESC sd;
|
|
|
|
sim_cpu *cpu;
|
|
|
|
struct hw *device_tree;
|
|
|
|
|
|
|
|
sd = sim_state_alloc (kind, callback);
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
|
|
|
|
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
|
|
|
|
|
|
|
|
/* for compatibility */
|
|
|
|
current_alignment = NONSTRICT_ALIGNMENT;
|
|
|
|
current_target_byte_order = BIG_ENDIAN;
|
|
|
|
|
|
|
|
cpu_initialize (sd, cpu);
|
|
|
|
|
|
|
|
cpu->cpu_use_elf_start = 1;
|
|
|
|
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* getopt will print the error message so we just have to exit if this fails.
|
|
|
|
FIXME: Hmmm... in the case of gdb we need getopt to call
|
|
|
|
print_filtered. */
|
|
|
|
if (sim_parse_args (sd, argv) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
/* Uninstall the modules to avoid memory leaks,
|
|
|
|
file descriptor leaks, etc. */
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
device_tree = sim_hw_parse (sd, "/");
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/reg") == 0)
|
|
|
|
{
|
|
|
|
/* Allocate core managed memory */
|
|
|
|
|
|
|
|
/* the monitor */
|
2000-08-11 18:44:59 +00:00
|
|
|
sim_do_commandf (sd, "memory region 0x%lx@%d,0x%lx",
|
2000-07-27 11:23:39 +00:00
|
|
|
/* MONITOR_BASE, MONITOR_SIZE */
|
2000-08-11 18:44:59 +00:00
|
|
|
0x8000, M6811_RAM_LEVEL, 0x8000);
|
|
|
|
sim_do_commandf (sd, "memory region 0x000@%d,0x8000",
|
|
|
|
M6811_RAM_LEVEL);
|
2000-07-27 11:23:39 +00:00
|
|
|
sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11sio/reg") == 0)
|
|
|
|
{
|
|
|
|
sim_hw_parse (sd, "/m68hc11/m68hc11sio/reg 0x2b 0x5");
|
|
|
|
sim_hw_parse (sd, "/m68hc11/m68hc11sio/backend stdio");
|
|
|
|
sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11sio");
|
|
|
|
}
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11tim/reg") == 0)
|
|
|
|
{
|
|
|
|
/* M68hc11 Timer configuration. */
|
|
|
|
sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5");
|
|
|
|
sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the SPI device. */
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11spi/reg") == 0)
|
|
|
|
{
|
|
|
|
sim_hw_parse (sd, "/m68hc11/m68hc11spi/reg 0x28 0x3");
|
|
|
|
sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11spi");
|
|
|
|
}
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/pram/reg") == 0)
|
|
|
|
{
|
|
|
|
/* M68hc11 persistent ram configuration. */
|
|
|
|
sim_hw_parse (sd, "/m68hc11/nvram/reg 0x0 256");
|
|
|
|
sim_hw_parse (sd, "/m68hc11/nvram/file m68hc11.ram");
|
|
|
|
sim_hw_parse (sd, "/m68hc11/nvram/mode save-modified");
|
|
|
|
/*sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/pram"); */
|
|
|
|
}
|
|
|
|
if (hw_tree_find_property (device_tree, "/m68hc11/m68hc11eepr/reg") == 0)
|
|
|
|
{
|
|
|
|
sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512");
|
|
|
|
/* Connect the CPU reset to all devices. */
|
|
|
|
sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for/establish the a reference program image. */
|
|
|
|
if (sim_analyze_program (sd,
|
|
|
|
(STATE_PROG_ARGV (sd) != NULL
|
|
|
|
? *STATE_PROG_ARGV (sd)
|
|
|
|
: NULL), abfd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Establish any remaining configuration options. */
|
|
|
|
if (sim_config (sd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sim_post_argv_init (sd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
/* Uninstall the modules to avoid memory leaks,
|
|
|
|
file descriptor leaks, etc. */
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (abfd != NULL)
|
|
|
|
{
|
|
|
|
cpu->cpu_elf_start = bfd_get_start_address (abfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
sim_board_reset (sd);
|
|
|
|
|
|
|
|
/* Fudge our descriptor. */
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_close (SIM_DESC sd, int quitting)
|
|
|
|
{
|
|
|
|
/* shut down modules */
|
|
|
|
sim_module_uninstall (sd);
|
|
|
|
|
|
|
|
/* Ensure that any resources allocated through the callback
|
|
|
|
mechanism are released: */
|
|
|
|
sim_io_shutdown (sd);
|
|
|
|
|
|
|
|
/* FIXME - free SD */
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_set_profile (int n)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_set_profile_size (int n)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generic implementation of sim_engine_run that works within the
|
|
|
|
sim_engine setjmp/longjmp framework. */
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_engine_run (SIM_DESC sd,
|
|
|
|
int next_cpu_nr, /* ignore */
|
|
|
|
int nr_cpus, /* ignore */
|
|
|
|
int siggnal) /* ignore */
|
|
|
|
{
|
|
|
|
sim_cpu *cpu;
|
|
|
|
|
|
|
|
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
cpu_single_step (cpu);
|
|
|
|
|
|
|
|
/* process any events */
|
|
|
|
if (sim_events_tickn (sd, cpu->cpu_current_cycle))
|
|
|
|
{
|
|
|
|
sim_events_process (sd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sim_trace (SIM_DESC sd)
|
|
|
|
{
|
|
|
|
sim_resume (sd, 0, 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_info (SIM_DESC sd, int verbose)
|
|
|
|
{
|
|
|
|
sim_io_eprintf (sd, "Simulator info:\n");
|
|
|
|
sim_io_eprintf (sd, " CPU Motorola 68HC11\n");
|
|
|
|
sim_get_info (sd, 0);
|
|
|
|
sim_module_info (sd, verbose || STATE_VERBOSE_P (sd));
|
|
|
|
}
|
|
|
|
|
|
|
|
SIM_RC
|
|
|
|
sim_create_inferior (SIM_DESC sd, struct _bfd *abfd,
|
|
|
|
char **argv, char **env)
|
|
|
|
{
|
|
|
|
sim_cpu *cpu;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
|
|
|
|
if (abfd != NULL)
|
|
|
|
{
|
|
|
|
cpu->cpu_elf_start = bfd_get_start_address (abfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset all state information */
|
|
|
|
sim_board_reset (sd);
|
|
|
|
|
|
|
|
/* Get information about the number of pseudo registers. */
|
|
|
|
for (i = FIRST_SOFT_REGNUM; i <= ZD32_REGNUM; i++)
|
|
|
|
{
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case TMP_REGNUM:
|
|
|
|
cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 0;
|
|
|
|
break;
|
|
|
|
case Z_REGNUM:
|
|
|
|
case ZS_REGNUM:
|
|
|
|
cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 2;
|
|
|
|
break;
|
|
|
|
case XY_REGNUM:
|
|
|
|
cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 4;
|
|
|
|
break;
|
|
|
|
case FP_REGNUM:
|
|
|
|
cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM] = 6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cpu->cpu_page0_reg[i - FIRST_SOFT_REGNUM]
|
|
|
|
= ((i - FIRST_SOFT_REGNUM) * 2) - 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cpu->cpu_nb_pseudo_regs = 8;
|
|
|
|
|
|
|
|
return SIM_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_set_callbacks (host_callback *p)
|
|
|
|
{
|
|
|
|
/* m6811_callback = p; */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
|
|
|
|
{
|
|
|
|
sim_cpu *cpu;
|
|
|
|
uint16 val;
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
switch (rn)
|
|
|
|
{
|
|
|
|
case A_REGNUM:
|
|
|
|
val = cpu_get_a (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_REGNUM:
|
|
|
|
val = cpu_get_b (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D_REGNUM:
|
|
|
|
val = cpu_get_d (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case X_REGNUM:
|
|
|
|
val = cpu_get_x (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Y_REGNUM:
|
|
|
|
val = cpu_get_y (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SP_REGNUM:
|
|
|
|
val = cpu_get_sp (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PC_REGNUM:
|
|
|
|
val = cpu_get_pc (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PSW_REGNUM:
|
|
|
|
val = cpu_get_ccr (cpu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a pseudo register. Pseudo registers are located at
|
|
|
|
beginning of page 0. Each of them is 2 bytes. */
|
|
|
|
default:
|
|
|
|
if (rn < FIRST_SOFT_REGNUM || rn >= ZD32_REGNUM)
|
|
|
|
{
|
|
|
|
val = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint16 addr;
|
|
|
|
|
|
|
|
addr = cpu->cpu_page0_reg[rn - FIRST_SOFT_REGNUM];
|
|
|
|
val = memory_read16 (cpu, addr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
memory[0] = val >> 8;
|
|
|
|
memory[1] = val & 0x0FF;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
|
|
|
|
{
|
|
|
|
uint16 val;
|
|
|
|
sim_cpu *cpu;
|
|
|
|
|
|
|
|
cpu = STATE_CPU (sd, 0);
|
|
|
|
|
|
|
|
val = *memory++;
|
|
|
|
if (length == 2)
|
|
|
|
val = (val << 8) | *memory;
|
|
|
|
|
|
|
|
switch (rn)
|
|
|
|
{
|
|
|
|
case D_REGNUM:
|
|
|
|
cpu_set_d (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_REGNUM:
|
|
|
|
cpu_set_a (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_REGNUM:
|
|
|
|
cpu_set_b (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case X_REGNUM:
|
|
|
|
cpu_set_x (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Y_REGNUM:
|
|
|
|
cpu_set_y (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SP_REGNUM:
|
|
|
|
cpu_set_sp (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PC_REGNUM:
|
|
|
|
cpu_set_pc (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PSW_REGNUM:
|
|
|
|
cpu_set_ccr (cpu, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Write a pseudo register. Pseudo registers are located at
|
|
|
|
beginning of page 0. Each of them is 2 bytes. */
|
|
|
|
default:
|
|
|
|
if (rn >= FIRST_SOFT_REGNUM && rn <= ZD32_REGNUM)
|
|
|
|
{
|
|
|
|
uint16 addr;
|
|
|
|
|
|
|
|
addr = cpu->cpu_page0_reg[rn - FIRST_SOFT_REGNUM];
|
|
|
|
memory_write16 (cpu, addr, val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_size (int s)
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sim_do_command (SIM_DESC sd, char *cmd)
|
|
|
|
{
|
|
|
|
char *mm_cmd = "memory-map";
|
|
|
|
char *int_cmd = "interrupt";
|
|
|
|
|
|
|
|
/* Commands available from GDB: */
|
|
|
|
if (sim_args_command (sd, cmd) != SIM_RC_OK)
|
|
|
|
{
|
|
|
|
if (strncmp (cmd, "info", sizeof ("info") - 1) == 0)
|
|
|
|
sim_get_info (sd, &cmd[4]);
|
|
|
|
else if (strncmp (cmd, "frame", sizeof ("frame") - 1) == 0)
|
|
|
|
cpu_print_frame (sd, STATE_CPU (sd, 0));
|
|
|
|
else if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0))
|
|
|
|
sim_io_eprintf (sd,
|
|
|
|
"`memory-map' command replaced by `sim memory'\n");
|
|
|
|
else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0)
|
|
|
|
sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n");
|
|
|
|
else
|
|
|
|
sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
|
|
|
|
}
|
|
|
|
}
|