OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/tags/gdb/gdb-6.8/gdb-6.8.openrisc-2.1/sim/m68hc11
    from Rev 24 to Rev 33
    Reverse comparison

Rev 24 → Rev 33

/dv-m68hc11.c
0,0 → 1,1131
/* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2007, 2008
Free Software Foundation, Inc.
Written by Stephane Carrez (stcarrez@nerim.fr)
(From a driver model Contributed by Cygnus Solutions.)
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.
 
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, see <http://www.gnu.org/licenses/>.
*/
 
 
#include "sim-main.h"
#include "sim-hw.h"
#include "hw-main.h"
#include "sim-options.h"
#include "hw-base.h"
#include <limits.h>
 
/* DEVICE
 
m68hc11cpu - m68hc11 cpu virtual device
m68hc12cpu - m68hc12 cpu virtual device
DESCRIPTION
 
Implements the external m68hc11/68hc12 functionality. This includes
the delivery of of interrupts generated from other devices and the
handling of device specific registers.
 
 
PROPERTIES
 
reg <base> <size>
 
Register base (should be 0x1000 0x03f for C11, 0x0000 0x3ff for HC12).
 
clock <hz>
 
Frequency of the quartz used by the processor.
 
mode [single | expanded | bootstrap | test]
 
Cpu operating mode (the MODA and MODB external pins).
 
 
PORTS
 
reset (input)
 
Reset the cpu and generates a cpu-reset event (used to reset
other devices).
 
nmi (input)
 
Deliver a non-maskable interrupt to the processor.
 
 
set-port-a (input)
set-port-c (input)
set-pord-d (input)
 
Allow an external device to set the value of port A, C or D inputs.
 
 
cpu-reset (output)
 
Event generated after the CPU performs a reset.
 
 
port-a (output)
port-b (output)
port-c (output)
port-d (output)
 
Event generated when the value of the output port A, B, C or D
changes.
 
 
BUGS
 
When delivering an interrupt, this code assumes that there is only
one processor (number 0).
 
*/
 
enum
{
OPTION_OSC_SET = OPTION_START,
OPTION_OSC_CLEAR,
OPTION_OSC_INFO
};
 
static DECLARE_OPTION_HANDLER (m68hc11_option_handler);
 
static const OPTION m68hc11_options[] =
{
{ {"osc-set", required_argument, NULL, OPTION_OSC_SET },
'\0', "BIT,FREQ", "Set the oscillator on input port BIT",
m68hc11_option_handler },
{ {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR },
'\0', "BIT", "Clear oscillator on input port BIT",
m68hc11_option_handler },
{ {"osc-info", no_argument, NULL, OPTION_OSC_INFO },
'\0', NULL, "Print information about current input oscillators",
m68hc11_option_handler },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
 
struct input_osc
{
signed64 on_time;
signed64 off_time;
signed64 repeat;
struct hw_event *event;
const char *name;
uint8 mask;
uint8 value;
uint16 addr;
};
 
#define NR_PORT_A_OSC (4)
#define NR_PORT_B_OSC (0)
#define NR_PORT_C_OSC (8)
#define NR_PORT_D_OSC (6)
#define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC)
struct m68hc11cpu {
/* Pending interrupts for delivery by event handler. */
int pending_reset;
int pending_nmi;
int pending_level;
struct hw_event *event;
unsigned_word attach_address;
int attach_size;
int attach_space;
int last_oscillator;
struct input_osc oscillators[NR_OSC];
};
 
 
 
/* input port ID's */
 
enum {
RESET_PORT,
NMI_PORT,
IRQ_PORT,
CPU_RESET_PORT,
SET_PORT_A,
SET_PORT_C,
SET_PORT_D,
CPU_WRITE_PORT,
PORT_A,
PORT_B,
PORT_C,
PORT_D,
CAPTURE
};
 
 
static const struct hw_port_descriptor m68hc11cpu_ports[] = {
 
/* Interrupt inputs. */
{ "reset", RESET_PORT, 0, input_port, },
{ "nmi", NMI_PORT, 0, input_port, },
{ "irq", IRQ_PORT, 0, input_port, },
 
{ "set-port-a", SET_PORT_A, 0, input_port, },
{ "set-port-c", SET_PORT_C, 0, input_port, },
{ "set-port-d", SET_PORT_D, 0, input_port, },
 
{ "cpu-write-port", CPU_WRITE_PORT, 0, input_port, },
 
/* Events generated for connection to other devices. */
{ "cpu-reset", CPU_RESET_PORT, 0, output_port, },
 
/* Events generated when the corresponding port is
changed by the program. */
{ "port-a", PORT_A, 0, output_port, },
{ "port-b", PORT_B, 0, output_port, },
{ "port-c", PORT_C, 0, output_port, },
{ "port-d", PORT_D, 0, output_port, },
 
{ "capture", CAPTURE, 0, output_port, },
 
{ NULL, },
};
 
static hw_io_read_buffer_method m68hc11cpu_io_read_buffer;
static hw_io_write_buffer_method m68hc11cpu_io_write_buffer;
static hw_ioctl_method m68hc11_ioctl;
 
/* Finish off the partially created hw device. Attach our local
callbacks. Wire up our port names etc. */
 
static hw_port_event_method m68hc11cpu_port_event;
 
static void make_oscillator (struct m68hc11cpu *controller,
const char *id, uint16 addr, uint8 mask);
static struct input_osc *find_oscillator (struct m68hc11cpu *controller,
const char *id);
static void reset_oscillators (struct hw *me);
 
static void
dv_m6811_attach_address_callback (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, sz=%ld, client=%s",
level, space, (unsigned long) addr, (unsigned long) nr_bytes,
hw_path (client)));
 
if (space != io_map)
{
sim_core_attach (hw_system (me),
NULL, /*cpu*/
level,
access_read_write_exec,
space, addr,
nr_bytes,
0, /* modulo */
client,
NULL);
}
else
{
/*printf("Attach from sub device: %d\n", (long) addr);*/
sim_core_attach (hw_system (me),
NULL, /*cpu*/
level,
access_io,
space, addr,
nr_bytes,
0, /* modulo */
client,
NULL);
}
}
 
static void
dv_m6811_detach_address_callback (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
sim_core_detach (hw_system (me), NULL, /*cpu*/
level, space, addr);
}
 
static void
m68hc11_delete (struct hw* me)
{
struct m68hc11cpu *controller;
controller = hw_data (me);
 
reset_oscillators (me);
hw_detach_address (me, M6811_IO_LEVEL,
controller->attach_space,
controller->attach_address,
controller->attach_size, me);
}
 
 
static void
attach_m68hc11_regs (struct hw *me,
struct m68hc11cpu *controller)
{
SIM_DESC sd;
sim_cpu *cpu;
reg_property_spec reg;
const char *cpu_mode;
if (hw_find_property (me, "reg") == NULL)
hw_abort (me, "Missing \"reg\" property");
 
if (!hw_find_reg_array_property (me, "reg", 0, &reg))
hw_abort (me, "\"reg\" property must contain one addr/size entry");
 
hw_unit_address_to_attach_address (hw_parent (me),
&reg.address,
&controller->attach_space,
&controller->attach_address,
me);
hw_unit_size_to_attach_size (hw_parent (me),
&reg.size,
&controller->attach_size, me);
 
hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
controller->attach_space,
controller->attach_address,
controller->attach_size,
me);
set_hw_delete (me, m68hc11_delete);
 
/* Get cpu frequency. */
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
if (hw_find_property (me, "clock") != NULL)
{
cpu->cpu_frequency = hw_find_integer_property (me, "clock");
}
else
{
cpu->cpu_frequency = 8*1000*1000;
}
 
if (hw_find_property (me, "use_bank") != NULL)
hw_attach_address (hw_parent (me), 0,
exec_map,
cpu->bank_start,
cpu->bank_end - cpu->bank_start,
me);
 
cpu_mode = "expanded";
if (hw_find_property (me, "mode") != NULL)
cpu_mode = hw_find_string_property (me, "mode");
 
if (strcmp (cpu_mode, "test") == 0)
cpu->cpu_mode = M6811_MDA | M6811_SMOD;
else if (strcmp (cpu_mode, "bootstrap") == 0)
cpu->cpu_mode = M6811_SMOD;
else if (strcmp (cpu_mode, "single") == 0)
cpu->cpu_mode = 0;
else
cpu->cpu_mode = M6811_MDA;
 
controller->last_oscillator = 0;
 
/* Create oscillators for input port A. */
make_oscillator (controller, "A7", M6811_PORTA, 0x80);
make_oscillator (controller, "A2", M6811_PORTA, 0x04);
make_oscillator (controller, "A1", M6811_PORTA, 0x02);
make_oscillator (controller, "A0", M6811_PORTA, 0x01);
 
/* port B is output only. */
 
/* Create oscillators for input port C. */
make_oscillator (controller, "C0", M6811_PORTC, 0x01);
make_oscillator (controller, "C1", M6811_PORTC, 0x02);
make_oscillator (controller, "C2", M6811_PORTC, 0x04);
make_oscillator (controller, "C3", M6811_PORTC, 0x08);
make_oscillator (controller, "C4", M6811_PORTC, 0x10);
make_oscillator (controller, "C5", M6811_PORTC, 0x20);
make_oscillator (controller, "C6", M6811_PORTC, 0x40);
make_oscillator (controller, "C7", M6811_PORTC, 0x80);
 
/* Create oscillators for input port D. */
make_oscillator (controller, "D0", M6811_PORTD, 0x01);
make_oscillator (controller, "D1", M6811_PORTD, 0x02);
make_oscillator (controller, "D2", M6811_PORTD, 0x04);
make_oscillator (controller, "D3", M6811_PORTD, 0x08);
make_oscillator (controller, "D4", M6811_PORTD, 0x10);
make_oscillator (controller, "D5", M6811_PORTD, 0x20);
 
/* Add oscillator commands. */
sim_add_option_table (sd, 0, m68hc11_options);
}
 
static void
m68hc11cpu_finish (struct hw *me)
{
struct m68hc11cpu *controller;
 
controller = HW_ZALLOC (me, struct m68hc11cpu);
set_hw_data (me, controller);
set_hw_io_read_buffer (me, m68hc11cpu_io_read_buffer);
set_hw_io_write_buffer (me, m68hc11cpu_io_write_buffer);
set_hw_ports (me, m68hc11cpu_ports);
set_hw_port_event (me, m68hc11cpu_port_event);
set_hw_attach_address (me, dv_m6811_attach_address_callback);
set_hw_detach_address (me, dv_m6811_detach_address_callback);
#ifdef set_hw_ioctl
set_hw_ioctl (me, m68hc11_ioctl);
#else
me->to_ioctl = m68hc11_ioctl;
#endif
 
/* Initialize the pending interrupt flags. */
controller->pending_level = 0;
controller->pending_reset = 0;
controller->pending_nmi = 0;
controller->event = NULL;
 
attach_m68hc11_regs (me, controller);
}
 
/* An event arrives on an interrupt port. */
 
static void
deliver_m68hc11cpu_interrupt (struct hw *me, void *data)
{
}
 
static void
make_oscillator (struct m68hc11cpu *controller, const char *name,
uint16 addr, uint8 mask)
{
struct input_osc *osc;
 
if (controller->last_oscillator >= NR_OSC)
hw_abort (0, "Too many oscillators");
 
osc = &controller->oscillators[controller->last_oscillator];
osc->name = name;
osc->addr = addr;
osc->mask = mask;
controller->last_oscillator++;
}
 
/* Find the oscillator given the input port name. */
static struct input_osc *
find_oscillator (struct m68hc11cpu *controller, const char *name)
{
int i;
 
for (i = 0; i < controller->last_oscillator; i++)
if (strcasecmp (controller->oscillators[i].name, name) == 0)
return &controller->oscillators[i];
 
return 0;
}
 
static void
oscillator_handler (struct hw *me, void *data)
{
struct input_osc *osc = (struct input_osc*) data;
SIM_DESC sd;
sim_cpu *cpu;
signed64 dt;
uint8 val;
 
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
 
/* Change the input bit. */
osc->value ^= osc->mask;
val = cpu->ios[osc->addr] & ~osc->mask;
val |= osc->value;
m68hc11cpu_set_port (me, cpu, osc->addr, val);
 
/* Setup event to toggle the bit. */
if (osc->value)
dt = osc->on_time;
else
dt = osc->off_time;
 
if (dt && --osc->repeat >= 0)
{
sim_events *events = STATE_EVENTS (sd);
 
dt += events->nr_ticks_to_process;
osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc);
}
else
osc->event = 0;
}
 
static void
reset_oscillators (struct hw *me)
{
struct m68hc11cpu *controller = hw_data (me);
int i;
 
for (i = 0; i < controller->last_oscillator; i++)
{
if (controller->oscillators[i].event)
{
hw_event_queue_deschedule (me, controller->oscillators[i].event);
controller->oscillators[i].event = 0;
}
}
}
static void
m68hc11cpu_port_event (struct hw *me,
int my_port,
struct hw *source,
int source_port,
int level)
{
struct m68hc11cpu *controller = hw_data (me);
SIM_DESC sd;
sim_cpu* cpu;
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
switch (my_port)
{
case RESET_PORT:
HW_TRACE ((me, "port-in reset"));
 
/* The reset is made in 3 steps:
- First, cleanup the current sim_cpu struct.
- Reset the devices.
- Restart the cpu for the reset (get the CPU mode from the
CONFIG register that gets initialized by EEPROM device). */
cpu_reset (cpu);
reset_oscillators (me);
hw_port_event (me, CPU_RESET_PORT, 1);
cpu_restart (cpu);
break;
case NMI_PORT:
controller->pending_nmi = 1;
HW_TRACE ((me, "port-in nmi"));
break;
case IRQ_PORT:
/* level == 0 means that the interrupt was cleared. */
if(level == 0)
controller->pending_level = -1; /* signal end of interrupt */
else
controller->pending_level = level;
HW_TRACE ((me, "port-in level=%d", level));
break;
 
case SET_PORT_A:
m68hc11cpu_set_port (me, cpu, M6811_PORTA, level);
break;
case SET_PORT_C:
m68hc11cpu_set_port (me, cpu, M6811_PORTC, level);
break;
 
case SET_PORT_D:
m68hc11cpu_set_port (me, cpu, M6811_PORTD, level);
break;
 
case CPU_WRITE_PORT:
break;
 
default:
hw_abort (me, "bad switch");
break;
}
 
/* Schedule an event to be delivered immediately after current
instruction. */
if(controller->event != NULL)
hw_event_queue_deschedule(me, controller->event);
controller->event =
hw_event_queue_schedule (me, 0, deliver_m68hc11cpu_interrupt, NULL);
}
 
 
io_reg_desc config_desc[] = {
{ M6811_NOSEC, "NOSEC ", "Security Mode Disable" },
{ M6811_NOCOP, "NOCOP ", "COP System Disable" },
{ M6811_ROMON, "ROMON ", "Enable On-chip Rom" },
{ M6811_EEON, "EEON ", "Enable On-chip EEprom" },
{ 0, 0, 0 }
};
 
io_reg_desc hprio_desc[] = {
{ M6811_RBOOT, "RBOOT ", "Read Bootstrap ROM" },
{ M6811_SMOD, "SMOD ", "Special Mode" },
{ M6811_MDA, "MDA ", "Mode Select A" },
{ M6811_IRV, "IRV ", "Internal Read Visibility" },
{ 0, 0, 0 }
};
 
io_reg_desc option_desc[] = {
{ M6811_ADPU, "ADPU ", "A/D Powerup" },
{ M6811_CSEL, "CSEL ", "A/D/EE Charge pump clock source select" },
{ M6811_IRQE, "IRQE ", "IRQ Edge/Level sensitive" },
{ M6811_DLY, "DLY ", "Stop exit turn on delay" },
{ M6811_CME, "CME ", "Clock Monitor Enable" },
{ M6811_CR1, "CR1 ", "COP timer rate select (CR1)" },
{ M6811_CR0, "CR0 ", "COP timer rate select (CR0)" },
{ 0, 0, 0 }
};
 
static void
m68hc11_info (struct hw *me)
{
SIM_DESC sd;
uint16 base = 0;
sim_cpu *cpu;
struct m68hc11sio *controller;
uint8 val;
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
controller = hw_data (me);
 
base = cpu_get_io_base (cpu);
sim_io_printf (sd, "M68HC11:\n");
 
val = cpu->ios[M6811_HPRIO];
print_io_byte (sd, "HPRIO ", hprio_desc, val, base + M6811_HPRIO);
switch (cpu->cpu_mode)
{
case M6811_MDA | M6811_SMOD:
sim_io_printf (sd, "[test]\n");
break;
case M6811_SMOD:
sim_io_printf (sd, "[bootstrap]\n");
break;
case M6811_MDA:
sim_io_printf (sd, "[extended]\n");
break;
default:
sim_io_printf (sd, "[single]\n");
break;
}
 
val = cpu->ios[M6811_CONFIG];
print_io_byte (sd, "CONFIG", config_desc, val, base + M6811_CONFIG);
sim_io_printf (sd, "\n");
 
val = cpu->ios[M6811_OPTION];
print_io_byte (sd, "OPTION", option_desc, val, base + M6811_OPTION);
sim_io_printf (sd, "\n");
 
val = cpu->ios[M6811_INIT];
print_io_byte (sd, "INIT ", 0, val, base + M6811_INIT);
sim_io_printf (sd, "Ram = 0x%04x IO = 0x%04x\n",
(((uint16) (val & 0xF0)) << 8),
(((uint16) (val & 0x0F)) << 12));
 
 
cpu_info (sd, cpu);
interrupts_info (sd, &cpu->cpu_interrupts);
}
 
static int
m68hc11_ioctl (struct hw *me,
hw_ioctl_request request,
va_list ap)
{
m68hc11_info (me);
return 0;
}
 
/* Setup an oscillator on an input port.
 
TON represents the time in seconds that the input port should be set to 1.
TOFF is the time in seconds for the input port to be set to 0.
 
The oscillator frequency is therefore 1 / (ton + toff).
 
REPEAT indicates the number of 1 <-> 0 transitions until the oscillator
stops. */
int
m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port,
double ton, double toff, signed64 repeat)
{
sim_cpu *cpu;
struct input_osc *osc;
double f;
 
cpu = STATE_CPU (sd, 0);
 
/* Find oscillator that corresponds to the input port. */
osc = find_oscillator (hw_data (cpu->hw_cpu), port);
if (osc == 0)
return -1;
 
/* Compute the ON time in cpu cycles. */
f = (double) (cpu->cpu_frequency) * ton;
osc->on_time = (signed64) (f / 4.0);
if (osc->on_time < 1)
osc->on_time = 1;
 
/* Compute the OFF time in cpu cycles. */
f = (double) (cpu->cpu_frequency) * toff;
osc->off_time = (signed64) (f / 4.0);
if (osc->off_time < 1)
osc->off_time = 1;
 
osc->repeat = repeat;
if (osc->event)
hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
 
osc->event = hw_event_queue_schedule (cpu->hw_cpu,
osc->value ? osc->on_time
: osc->off_time,
oscillator_handler, osc);
return 0;
}
 
/* Clear the oscillator. */
int
m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port)
{
sim_cpu *cpu;
struct input_osc *osc;
 
cpu = STATE_CPU (sd, 0);
osc = find_oscillator (hw_data (cpu->hw_cpu), port);
if (osc == 0)
return -1;
 
if (osc->event)
hw_event_queue_deschedule (cpu->hw_cpu, osc->event);
osc->event = 0;
osc->repeat = 0;
return 0;
}
 
static int
get_frequency (const char *s, double *f)
{
char *p;
*f = strtod (s, &p);
if (s == p)
return -1;
 
if (*p)
{
if (strcasecmp (p, "khz") == 0)
*f = *f * 1000.0;
else if (strcasecmp (p, "mhz") == 0)
*f = *f * 1000000.0;
else if (strcasecmp (p, "hz") != 0)
return -1;
}
return 0;
}
 
static SIM_RC
m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu,
int opt, char *arg, int is_command)
{
struct m68hc11cpu *controller;
double f;
char *p;
int i;
int title_printed = 0;
if (cpu == 0)
cpu = STATE_CPU (sd, 0);
 
controller = hw_data (cpu->hw_cpu);
switch (opt)
{
case OPTION_OSC_SET:
p = strchr (arg, ',');
if (p)
*p++ = 0;
 
if (p == 0)
sim_io_eprintf (sd, "No frequency specified\n");
else if (get_frequency (p, &f) < 0 || f < 1.0e-8)
sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p);
else if (m68hc11cpu_set_oscillator (sd, arg,
1.0 / (f * 2.0),
1.0 / (f * 2.0), LONG_MAX))
sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
break;
 
case OPTION_OSC_CLEAR:
if (m68hc11cpu_clear_oscillator (sd, arg) != 0)
sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg);
break;
 
case OPTION_OSC_INFO:
for (i = 0; i < controller->last_oscillator; i++)
{
signed64 t;
struct input_osc *osc;
 
osc = &controller->oscillators[i];
if (osc->event)
{
double f;
int cur_value;
int next_value;
char freq[32];
 
if (title_printed == 0)
{
title_printed = 1;
sim_io_printf (sd, " PORT Frequency Current"
" Next Transition time\n");
}
 
f = (double) (osc->on_time + osc->off_time);
f = (double) (cpu->cpu_frequency / 4) / f;
t = hw_event_remain_time (cpu->hw_cpu, osc->event);
 
if (f > 10000.0)
sprintf (freq, "%6.2f", f / 1000.0);
else
sprintf (freq, "%6.2f", f);
cur_value = osc->value ? 1 : 0;
next_value = osc->value ? 0 : 1;
if (f > 10000.0)
sim_io_printf (sd, " %4.4s %8.8s khz"
" %d %d %35.35s\n",
osc->name, freq,
cur_value, next_value,
cycle_to_string (cpu, t,
PRINT_TIME | PRINT_CYCLE));
else
sim_io_printf (sd, " %4.4s %8.8s hz "
" %d %d %35.35s\n",
osc->name, freq,
cur_value, next_value,
cycle_to_string (cpu, t,
PRINT_TIME | PRINT_CYCLE));
}
}
break;
}
 
return SIM_RC_OK;
}
 
/* generic read/write */
 
static unsigned
m68hc11cpu_io_read_buffer (struct hw *me,
void *dest,
int space,
unsigned_word base,
unsigned nr_bytes)
{
SIM_DESC sd;
struct m68hc11cpu *controller = hw_data (me);
sim_cpu *cpu;
unsigned byte = 0;
int result;
HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
 
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
 
if (base >= cpu->bank_start && base < cpu->bank_end)
{
address_word virt_addr = phys_to_virt (cpu, base);
if (virt_addr != base)
return sim_core_read_buffer (sd, cpu, space, dest,
virt_addr, nr_bytes);
}
 
/* Handle reads for the sub-devices. */
base -= controller->attach_address;
result = sim_core_read_buffer (sd, cpu,
io_map, dest, base, nr_bytes);
if (result > 0)
return result;
while (nr_bytes)
{
if (base >= controller->attach_size)
break;
 
memcpy (dest, &cpu->ios[base], 1);
dest = (char*) dest + 1;
base++;
byte++;
nr_bytes--;
}
return byte;
}
 
void
m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu,
unsigned addr, uint8 val)
{
uint8 mask;
uint8 delta;
int check_interrupts = 0;
int i;
switch (addr)
{
case M6811_PORTA:
if (cpu->ios[M6811_PACTL] & M6811_DDRA7)
mask = 3;
else
mask = 0x83;
 
val = val & mask;
val |= cpu->ios[M6811_PORTA] & ~mask;
delta = val ^ cpu->ios[M6811_PORTA];
cpu->ios[M6811_PORTA] = val;
if (delta & 0x80)
{
/* Pulse accumulator is enabled. */
if ((cpu->ios[M6811_PACTL] & M6811_PAEN)
&& !(cpu->ios[M6811_PACTL] & M6811_PAMOD))
{
int inc;
 
/* Increment event counter according to rising/falling edge. */
if (cpu->ios[M6811_PACTL] & M6811_PEDGE)
inc = (val & 0x80) ? 1 : 0;
else
inc = (val & 0x80) ? 0 : 1;
 
cpu->ios[M6811_PACNT] += inc;
 
/* Event counter overflowed. */
if (inc && cpu->ios[M6811_PACNT] == 0)
{
cpu->ios[M6811_TFLG2] |= M6811_PAOVI;
check_interrupts = 1;
}
}
}
 
/* Scan IC3, IC2 and IC1. Bit number is 3 - i. */
for (i = 0; i < 3; i++)
{
uint8 mask = (1 << i);
if (delta & mask)
{
uint8 edge;
int captured;
 
edge = cpu->ios[M6811_TCTL2];
edge = (edge >> (2 * i)) & 0x3;
switch (edge)
{
case 0:
captured = 0;
break;
case 1:
captured = (val & mask) != 0;
break;
case 2:
captured = (val & mask) == 0;
break;
default:
captured = 1;
break;
}
if (captured)
{
cpu->ios[M6811_TFLG1] |= (1 << i);
hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i);
check_interrupts = 1;
}
}
}
break;
 
case M6811_PORTC:
mask = cpu->ios[M6811_DDRC];
val = val & mask;
val |= cpu->ios[M6811_PORTC] & ~mask;
cpu->ios[M6811_PORTC] = val;
break;
 
case M6811_PORTD:
mask = cpu->ios[M6811_DDRD];
val = val & mask;
val |= cpu->ios[M6811_PORTD] & ~mask;
cpu->ios[M6811_PORTD] = val;
break;
 
default:
break;
}
 
if (check_interrupts)
interrupts_update_pending (&cpu->cpu_interrupts);
}
 
static void
m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu,
unsigned_word addr, uint8 val)
{
switch (addr)
{
case M6811_PORTA:
hw_port_event (me, PORT_A, val);
break;
 
case M6811_PIOC:
break;
 
case M6811_PORTC:
hw_port_event (me, PORT_C, val);
break;
 
case M6811_PORTB:
hw_port_event (me, PORT_B, val);
break;
 
case M6811_PORTCL:
break;
 
case M6811_DDRC:
break;
 
case M6811_PORTD:
hw_port_event (me, PORT_D, val);
break;
 
case M6811_DDRD:
break;
 
case M6811_TMSK2:
break;
/* Change the RAM and I/O mapping. */
case M6811_INIT:
{
uint8 old_bank = cpu->ios[M6811_INIT];
cpu->ios[M6811_INIT] = val;
 
/* Update IO mapping. Detach from the old address
and attach to the new one. */
if ((old_bank & 0x0F) != (val & 0x0F))
{
struct m68hc11cpu *controller = hw_data (me);
 
hw_detach_address (hw_parent (me), M6811_IO_LEVEL,
controller->attach_space,
controller->attach_address,
controller->attach_size,
me);
controller->attach_address = (val & 0x0F0) << 12;
hw_attach_address (hw_parent (me), M6811_IO_LEVEL,
controller->attach_space,
controller->attach_address,
controller->attach_size,
me);
}
if ((old_bank & 0xF0) != (val & 0xF0))
{
;
}
return;
}
 
/* Writing the config is similar to programing the eeprom.
The config register value is the last byte of the EEPROM.
This last byte is not mapped in memory (that's why we have
to add '1' to 'end_addr'). */
case M6811_CONFIG:
{
return;
}
 
/* COP reset. */
case M6811_COPRST:
if (val == 0xAA && cpu->ios[addr] == 0x55)
{
val = 0;
/* COP reset here. */
}
break;
default:
break;
 
}
cpu->ios[addr] = val;
}
 
static unsigned
m68hc11cpu_io_write_buffer (struct hw *me,
const void *source,
int space,
unsigned_word base,
unsigned nr_bytes)
{
SIM_DESC sd;
struct m68hc11cpu *controller = hw_data (me);
unsigned byte;
sim_cpu *cpu;
int result;
 
HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
 
sd = hw_system (me);
cpu = STATE_CPU (sd, 0);
 
if (base >= cpu->bank_start && base < cpu->bank_end)
{
address_word virt_addr = phys_to_virt (cpu, base);
if (virt_addr != base)
return sim_core_write_buffer (sd, cpu, space, source,
virt_addr, nr_bytes);
}
base -= controller->attach_address;
result = sim_core_write_buffer (sd, cpu,
io_map, source, base, nr_bytes);
if (result > 0)
return result;
 
byte = 0;
while (nr_bytes)
{
uint8 val;
if (base >= controller->attach_size)
break;
 
val = *((uint8*) source);
m68hc11cpu_io_write (me, cpu, base, val);
source = (char*) source + 1;
base++;
byte++;
nr_bytes--;
}
return byte;
}
 
const struct hw_descriptor dv_m68hc11_descriptor[] = {
{ "m68hc11", m68hc11cpu_finish },
{ "m68hc12", m68hc11cpu_finish },
{ NULL },
};
 
dv-m68hc11.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: m68hc11_sim.c =================================================================== --- m68hc11_sim.c (nonexistent) +++ m68hc11_sim.c (revision 33) @@ -0,0 +1,1071 @@ +/* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation + 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. + +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. + +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, see . */ + +#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_RC +cpu_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; +} + + +void +cpu_call (sim_cpu *cpu, uint16 addr) +{ + + cpu_set_pc (cpu, addr); +} + +void +cpu_return (sim_cpu *cpu) +{ +} + +/* Set the stack pointer and re-compute the current frame. */ +void +cpu_set_sp (sim_cpu *cpu, uint16 val) +{ + cpu->cpu_regs.sp = val; +} + +uint16 +cpu_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; + } +} + +uint16 +cpu_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; + } +} + +void +cpu_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; + } +} + +void +cpu_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. */ +uint16 +cpu_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; +} + +uint8 +cpu_get_indexed_operand8 (sim_cpu* cpu, int restrict) +{ + uint16 addr; + + addr = cpu_get_indexed_operand_addr (cpu, restrict); + return memory_read8 (cpu, addr); +} + +uint16 +cpu_get_indexed_operand16 (sim_cpu* cpu, int restrict) +{ + uint16 addr; + + addr = cpu_get_indexed_operand_addr (cpu, restrict); + return memory_read16 (cpu, addr); +} + +void +cpu_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); +} + +void +cpu_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); +} + +int +cpu_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. */ +int +cpu_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. */ +int +cpu_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: + case 0 : + addr = memory_read16 (cpu, 0xFFFE); + break; + + /* Expanded Multiplexed */ + case M6811_MDA: + addr = memory_read16 (cpu, 0xFFFE); + break; + + /* Special Bootstrap */ + case M6811_SMOD: + addr = 0; + break; + + /* Factory Test */ + case M6811_MDA | M6811_SMOD: + addr = memory_read16 (cpu, 0xFFFE); + break; + } + } + else + { + addr = cpu->cpu_elf_start; + } + + /* Setup the processor registers. */ + cpu->cpu_insn_pc = addr; + cpu->cpu_regs.pc = addr; + cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT; + cpu->cpu_absolute_cycle = 0; + cpu->cpu_is_initialized = 1; + cpu->cpu_current_cycle = 0; + + cpu_call (cpu, addr); + + return 0; +} + +void +print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode) +{ + while (desc->mask) + { + if (val & desc->mask) + sim_io_printf (sd, "%s", + mode == 0 ? desc->short_name : desc->long_name); + desc++; + } +} + +void +print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc, + uint8 val, uint16 addr) +{ + sim_io_printf (sd, " %-9.9s @ 0x%04x 0x%02x ", name, addr, val); + if (desc) + 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) +{ + cpu_set_ccr_V (proc, 0); + cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0); + cpu_set_ccr_Z (proc, val == 0 ? 1 : 0); +} + + +uint16 +cpu_fetch_relbranch (sim_cpu *cpu) +{ + uint16 addr = (uint16) cpu_fetch8 (cpu); + + if (addr & 0x0080) + { + addr |= 0xFF00; + } + addr += cpu->cpu_regs.pc; + return addr; +} + +uint16 +cpu_fetch_relbranch16 (sim_cpu *cpu) +{ + uint16 addr = cpu_fetch16 (cpu); + + addr += cpu->cpu_regs.pc; + return addr; +} + +/* Push all the CPU registers (when an interruption occurs). */ +void +cpu_push_all (sim_cpu *cpu) +{ + if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11) + { + cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.pc); + cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.iy); + cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.ix); + cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.d); + cpu_m68hc11_push_uint8 (cpu, cpu->cpu_regs.ccr); + } + else + { + cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.pc); + cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.iy); + cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.ix); + cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.d); + cpu_m68hc12_push_uint8 (cpu, cpu->cpu_regs.ccr); + } +} + +/* Simulation of the dbcc/ibcc/tbcc 68HC12 conditional branch operations. */ +void +cpu_dbcc (sim_cpu* cpu) +{ + uint8 code; + uint16 addr; + uint16 inc; + uint16 reg; + + code = cpu_fetch8 (cpu); + switch (code & 0xc0) + { + case 0x80: /* ibcc */ + inc = 1; + break; + case 0x40: /* tbcc */ + inc = 0; + break; + case 0: /* dbcc */ + inc = -1; + break; + default: + abort (); + break; + } + + addr = cpu_fetch8 (cpu); + if (code & 0x10) + addr |= 0xff00; + + addr += cpu_get_pc (cpu); + reg = cpu_get_src_reg (cpu, code & 0x07); + reg += inc; + + /* Branch according to register value. */ + if ((reg != 0 && (code & 0x20)) || (reg == 0 && !(code & 0x20))) + { + cpu_set_pc (cpu, addr); + } + cpu_set_dst_reg (cpu, code & 0x07, reg); +} + +void +cpu_exg (sim_cpu* cpu, uint8 code) +{ + uint8 r1, r2; + uint16 src1; + uint16 src2; + + r1 = (code >> 4) & 0x07; + r2 = code & 0x07; + if (code & 0x80) + { + src1 = cpu_get_src_reg (cpu, r1); + src2 = cpu_get_src_reg (cpu, r2); + if (r2 == 1 || r2 == 2) + src2 |= 0xff00; + + cpu_set_dst_reg (cpu, r2, src1); + cpu_set_dst_reg (cpu, r1, src2); + } + else + { + src1 = cpu_get_src_reg (cpu, r1); + + /* Sign extend the 8-bit registers (A, B, CCR). */ + if ((r1 == 0 || r1 == 1 || r1 == 2) && (src1 & 0x80)) + src1 |= 0xff00; + + cpu_set_dst_reg (cpu, r2, src1); + } +} + +/* Handle special instructions. */ +void +cpu_special (sim_cpu *cpu, enum M6811_Special special) +{ + switch (special) + { + case M6811_RTI: + { + uint8 ccr; + + ccr = cpu_m68hc11_pop_uint8 (cpu); + cpu_set_ccr (cpu, ccr); + cpu_set_d (cpu, cpu_m68hc11_pop_uint16 (cpu)); + cpu_set_x (cpu, cpu_m68hc11_pop_uint16 (cpu)); + cpu_set_y (cpu, cpu_m68hc11_pop_uint16 (cpu)); + cpu_set_pc (cpu, cpu_m68hc11_pop_uint16 (cpu)); + cpu_return (cpu); + break; + } + + case M6812_RTI: + { + uint8 ccr; + + ccr = cpu_m68hc12_pop_uint8 (cpu); + cpu_set_ccr (cpu, ccr); + cpu_set_d (cpu, cpu_m68hc12_pop_uint16 (cpu)); + cpu_set_x (cpu, cpu_m68hc12_pop_uint16 (cpu)); + cpu_set_y (cpu, cpu_m68hc12_pop_uint16 (cpu)); + cpu_set_pc (cpu, cpu_m68hc12_pop_uint16 (cpu)); + cpu_return (cpu); + break; + } + + case M6811_WAI: + /* In the ELF-start mode, we are in a special mode where + the WAI corresponds to an exit. */ + if (cpu->cpu_use_elf_start) + { + cpu_set_pc (cpu, cpu->cpu_insn_pc); + sim_engine_halt (CPU_STATE (cpu), cpu, + NULL, NULL_CIA, sim_exited, + cpu_get_d (cpu)); + return; + } + /* SCz: not correct... */ + cpu_push_all (cpu); + break; + + case M6811_SWI: + interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI); + interrupts_process (&cpu->cpu_interrupts); + break; + + case M6811_EMUL_SYSCALL: + case M6811_ILLEGAL: + if (cpu->cpu_emul_syscall) + { + uint8 op = memory_read8 (cpu, + cpu_get_pc (cpu) - 1); + if (op == 0x41) + { + cpu_set_pc (cpu, cpu->cpu_insn_pc); + sim_engine_halt (CPU_STATE (cpu), cpu, + NULL, NULL_CIA, sim_exited, + cpu_get_d (cpu)); + return; + } + else + { + emul_os (op, cpu); + } + return; + } + + interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL); + interrupts_process (&cpu->cpu_interrupts); + break; + + case M6811_TEST: + case M6812_BGND: + { + SIM_DESC sd; + + sd = CPU_STATE (cpu); + + /* Breakpoint instruction if we are under gdb. */ + if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) + { + cpu->cpu_regs.pc --; + sim_engine_halt (CPU_STATE (cpu), cpu, + 0, cpu_get_pc (cpu), sim_stopped, + SIM_SIGTRAP); + } + /* else this is a nop but not in test factory mode. */ + break; + } + + case M6812_IDIVS: + { + int32 src1 = (int16) cpu_get_d (cpu); + int32 src2 = (int16) cpu_get_x (cpu); + + if (src2 == 0) + { + cpu_set_ccr_C (cpu, 1); + } + else + { + cpu_set_d (cpu, src1 % src2); + src1 = src1 / src2; + cpu_set_x (cpu, src1); + cpu_set_ccr_C (cpu, 0); + cpu_set_ccr_Z (cpu, src1 == 0); + cpu_set_ccr_N (cpu, src1 & 0x8000); + cpu_set_ccr_V (cpu, src1 >= 32768 || src1 < -32768); + } + } + break; + + case M6812_EDIV: + { + uint32 src1 = (uint32) cpu_get_x (cpu); + uint32 src2 = (uint32) (cpu_get_y (cpu) << 16) + | (uint32) (cpu_get_d (cpu)); + + if (src1 == 0) + { + cpu_set_ccr_C (cpu, 1); + } + else + { + cpu_set_ccr_C (cpu, 0); + cpu_set_d (cpu, src2 % src1); + src2 = src2 / src1; + cpu_set_y (cpu, src2); + cpu_set_ccr_Z (cpu, src2 == 0); + cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0); + cpu_set_ccr_V (cpu, (src2 & 0xffff0000) != 0); + } + } + break; + + case M6812_EDIVS: + { + int32 src1 = (int16) cpu_get_x (cpu); + int32 src2 = (uint32) (cpu_get_y (cpu) << 16) + | (uint32) (cpu_get_d (cpu)); + + if (src1 == 0) + { + cpu_set_ccr_C (cpu, 1); + } + else + { + cpu_set_ccr_C (cpu, 0); + cpu_set_d (cpu, src2 % src1); + src2 = src2 / src1; + cpu_set_y (cpu, src2); + cpu_set_ccr_Z (cpu, src2 == 0); + cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0); + cpu_set_ccr_V (cpu, src2 > 32767 || src2 < -32768); + } + } + break; + + case M6812_EMULS: + { + int32 src1, src2; + + src1 = (int16) cpu_get_d (cpu); + src2 = (int16) cpu_get_y (cpu); + src1 = src1 * src2; + cpu_set_d (cpu, src1 & 0x0ffff); + cpu_set_y (cpu, src1 >> 16); + cpu_set_ccr_Z (cpu, src1 == 0); + cpu_set_ccr_N (cpu, (src1 & 0x80000000) != 0); + cpu_set_ccr_C (cpu, (src1 & 0x00008000) != 0); + } + break; + + case M6812_EMACS: + { + int32 src1, src2; + uint16 addr; + + addr = cpu_fetch16 (cpu); + src1 = (int16) memory_read16 (cpu, cpu_get_x (cpu)); + src2 = (int16) memory_read16 (cpu, cpu_get_y (cpu)); + src1 = src1 * src2; + src2 = (((uint32) memory_read16 (cpu, addr)) << 16) + | (uint32) memory_read16 (cpu, addr + 2); + + memory_write16 (cpu, addr, (src1 + src2) >> 16); + memory_write16 (cpu, addr + 2, (src1 + src2)); + + + } + 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, + cpu_get_pc (cpu), sim_stopped, + SIM_SIGILL); + break; + } +} + + +void +cpu_single_step (sim_cpu *cpu) +{ + cpu->cpu_current_cycle = 0; + cpu->cpu_insn_pc = cpu_get_pc (cpu); + + /* Handle the pending interrupts. If an interrupt is handled, + treat this as an single step. */ + if (interrupts_process (&cpu->cpu_interrupts)) + { + cpu->cpu_absolute_cycle += cpu->cpu_current_cycle; + return; + } + + /* printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/ + cpu->cpu_interpretor (cpu); + cpu->cpu_absolute_cycle += cpu->cpu_current_cycle; +} + +/* VARARGS */ +void +sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep, + uint16 addr, const char *message, ...) +{ + char buf[1024]; + va_list args; + + va_start (args, message); + vsprintf (buf, message, args); + va_end (args); + + sim_io_printf (CPU_STATE (cpu), "%s\n", buf); + cpu_memory_exception (cpu, excep, addr, buf); +} + + +void +cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep, + uint16 addr, const char *message) +{ + if (cpu->cpu_running == 0) + return; + + cpu_set_pc (cpu, cpu->cpu_insn_pc); + sim_engine_halt (CPU_STATE (cpu), cpu, NULL, + cpu_get_pc (cpu), sim_stopped, excep); + +#if 0 + cpu->mem_exception = excep; + cpu->fault_addr = addr; + cpu->fault_msg = strdup (message); + + if (cpu->cpu_use_handler) + { + longjmp (&cpu->cpu_exception_handler, 1); + } + (* cpu->callback->printf_filtered) + (cpu->callback, "Fault at 0x%04x: %s\n", addr, message); +#endif +} + +void +cpu_info (SIM_DESC sd, sim_cpu *cpu) +{ + sim_io_printf (sd, "CPU info:\n"); + sim_io_printf (sd, " Absolute cycle: %s\n", + 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 " : "no"); + sim_io_printf (sd, " Memory errors detection: %s\n", + cpu->cpu_check_memory ? "yes" : "no"); + sim_io_printf (sd, " Stop on interrupt: %s\n", + cpu->cpu_stop_on_interrupt ? "yes" : "no"); +} +
m68hc11_sim.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: interp.c =================================================================== --- interp.c (nonexistent) +++ interp.c (revision 33) @@ -0,0 +1,815 @@ +/* interp.c -- Simulator for Motorola 68HC11/68HC12 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008 + Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.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 3 of the License, 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, see . */ + +#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" +#include "elf32-m68hc1x.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_68hc11[] = { + {"cpu", "/m68hc11"}, + {"timer", "/m68hc11/m68hc11tim"}, + {"sio", "/m68hc11/m68hc11sio"}, + {"spi", "/m68hc11/m68hc11spi"}, + {"eeprom", "/m68hc11/m68hc11eepr"}, + {0, 0} +}; + +struct sim_info_list dev_list_68hc12[] = { + {"cpu", "/m68hc12"}, + {"timer", "/m68hc12/m68hc12tim"}, + {"sio", "/m68hc12/m68hc12sio"}, + {"spi", "/m68hc12/m68hc12spi"}, + {"eeprom", "/m68hc12/m68hc12eepr"}, + {0, 0} +}; + +/* Cover function of sim_state_free to free the cpu buffers as well. */ + +static void +free_state (SIM_DESC sd) +{ + if (STATE_MODULES (sd) != NULL) + sim_module_uninstall (sd); + + sim_state_free (sd); +} + +/* Give some information about the simulator. */ +static void +sim_get_info (SIM_DESC sd, char *cmd) +{ + sim_cpu *cpu; + + cpu = STATE_CPU (sd, 0); + if (cmd != 0 && (cmd[0] == ' ' || cmd[0] == '-')) + { + int i; + struct hw *hw_dev; + struct sim_info_list *dev_list; + const struct bfd_arch_info *arch; + + arch = STATE_ARCHITECTURE (sd); + cmd++; + + if (arch->arch == bfd_arch_m68hc11) + dev_list = dev_list_68hc11; + else + dev_list = dev_list_68hc12; + + 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_info (sd, cpu); + interrupts_info (sd, &cpu->cpu_interrupts); +} + + +void +sim_board_reset (SIM_DESC sd) +{ + struct hw *hw_cpu; + sim_cpu *cpu; + const struct bfd_arch_info *arch; + const char *cpu_type; + + cpu = STATE_CPU (sd, 0); + arch = STATE_ARCHITECTURE (sd); + + /* hw_cpu = sim_hw_parse (sd, "/"); */ + if (arch->arch == bfd_arch_m68hc11) + { + cpu->cpu_type = CPU_M6811; + cpu_type = "/m68hc11"; + } + else + { + cpu->cpu_type = CPU_M6812; + cpu_type = "/m68hc12"; + } + + hw_cpu = sim_hw_parse (sd, cpu_type); + if (hw_cpu == 0) + { + sim_io_eprintf (sd, "%s cpu not found in device tree.", cpu_type); + return; + } + + cpu_reset (cpu); + hw_port_event (hw_cpu, 3, 0); + cpu_restart (cpu); +} + +static int +sim_hw_configure (SIM_DESC sd) +{ + const struct bfd_arch_info *arch; + struct hw *device_tree; + sim_cpu *cpu; + + arch = STATE_ARCHITECTURE (sd); + if (arch == 0) + return 0; + + cpu = STATE_CPU (sd, 0); + cpu->cpu_configured_arch = arch; + device_tree = sim_hw_parse (sd, "/"); + if (arch->arch == bfd_arch_m68hc11) + { + cpu->cpu_interpretor = cpu_interp_m6811; + if (hw_tree_find_property (device_tree, "/m68hc11/reg") == 0) + { + /* Allocate core managed memory */ + + /* the monitor */ + sim_do_commandf (sd, "memory region 0x%lx@%d,0x%lx", + /* MONITOR_BASE, MONITOR_SIZE */ + 0x8000, M6811_RAM_LEVEL, 0x8000); + sim_do_commandf (sd, "memory region 0x000@%d,0x8000", + M6811_RAM_LEVEL); + sim_hw_parse (sd, "/m68hc11/reg 0x1000 0x03F"); + if (cpu->bank_start < cpu->bank_end) + { + sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000", + cpu->bank_virtual, M6811_RAM_LEVEL); + sim_hw_parse (sd, "/m68hc11/use_bank 1"); + } + } + if (cpu->cpu_start_mode) + { + sim_hw_parse (sd, "/m68hc11/mode %s", cpu->cpu_start_mode); + } + 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"); + sim_hw_parse (sd, "/m68hc11 > capture capture /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/nvram/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"); + sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr"); + } + sim_hw_parse (sd, "/m68hc11 > port-a cpu-write-port /m68hc11"); + sim_hw_parse (sd, "/m68hc11 > port-b cpu-write-port /m68hc11"); + sim_hw_parse (sd, "/m68hc11 > port-c cpu-write-port /m68hc11"); + sim_hw_parse (sd, "/m68hc11 > port-d cpu-write-port /m68hc11"); + cpu->hw_cpu = sim_hw_parse (sd, "/m68hc11"); + } + else + { + cpu->cpu_interpretor = cpu_interp_m6812; + if (hw_tree_find_property (device_tree, "/m68hc12/reg") == 0) + { + /* Allocate core external memory. */ + sim_do_commandf (sd, "memory region 0x%lx@%d,0x%lx", + 0x8000, M6811_RAM_LEVEL, 0x8000); + sim_do_commandf (sd, "memory region 0x000@%d,0x8000", + M6811_RAM_LEVEL); + if (cpu->bank_start < cpu->bank_end) + { + sim_do_commandf (sd, "memory region 0x%lx@%d,0x100000", + cpu->bank_virtual, M6811_RAM_LEVEL); + sim_hw_parse (sd, "/m68hc12/use_bank 1"); + } + sim_hw_parse (sd, "/m68hc12/reg 0x0 0x3FF"); + } + + if (!hw_tree_find_property (device_tree, "/m68hc12/m68hc12sio@1/reg")) + { + sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/reg 0xC0 0x8"); + sim_hw_parse (sd, "/m68hc12/m68hc12sio@1/backend stdio"); + sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12sio@1"); + } + if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12tim/reg") == 0) + { + /* M68hc11 Timer configuration. */ + sim_hw_parse (sd, "/m68hc12/m68hc12tim/reg 0x1b 0x5"); + sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12tim"); + sim_hw_parse (sd, "/m68hc12 > capture capture /m68hc12/m68hc12tim"); + } + + /* Create the SPI device. */ + if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12spi/reg") == 0) + { + sim_hw_parse (sd, "/m68hc12/m68hc12spi/reg 0x28 0x3"); + sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12spi"); + } + if (hw_tree_find_property (device_tree, "/m68hc12/nvram/reg") == 0) + { + /* M68hc11 persistent ram configuration. */ + sim_hw_parse (sd, "/m68hc12/nvram/reg 0x2000 8192"); + sim_hw_parse (sd, "/m68hc12/nvram/file m68hc12.ram"); + sim_hw_parse (sd, "/m68hc12/nvram/mode save-modified"); + } + if (hw_tree_find_property (device_tree, "/m68hc12/m68hc12eepr/reg") == 0) + { + sim_hw_parse (sd, "/m68hc12/m68hc12eepr/reg 0x0800 2048"); + sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12eepr"); + } + + sim_hw_parse (sd, "/m68hc12 > port-a cpu-write-port /m68hc12"); + sim_hw_parse (sd, "/m68hc12 > port-b cpu-write-port /m68hc12"); + sim_hw_parse (sd, "/m68hc12 > port-c cpu-write-port /m68hc12"); + sim_hw_parse (sd, "/m68hc12 > port-d cpu-write-port /m68hc12"); + cpu->hw_cpu = sim_hw_parse (sd, "/m68hc12"); + } + return 1; +} + +/* Get the memory bank parameters by looking at the global symbols + defined by the linker. */ +static int +sim_get_bank_parameters (SIM_DESC sd, bfd* abfd) +{ + sim_cpu *cpu; + long symsize; + long symbol_count, i; + unsigned size; + asymbol** asymbols; + asymbol** current; + + cpu = STATE_CPU (sd, 0); + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + { + sim_io_eprintf (sd, "Cannot read symbols of program"); + return 0; + } + asymbols = (asymbol **) xmalloc (symsize); + symbol_count = bfd_canonicalize_symtab (abfd, asymbols); + if (symbol_count < 0) + { + sim_io_eprintf (sd, "Cannot read symbols of program"); + return 0; + } + + size = 0; + for (i = 0, current = asymbols; i < symbol_count; i++, current++) + { + const char* name = bfd_asymbol_name (*current); + + if (strcmp (name, BFD_M68HC11_BANK_START_NAME) == 0) + { + cpu->bank_start = bfd_asymbol_value (*current); + } + else if (strcmp (name, BFD_M68HC11_BANK_SIZE_NAME) == 0) + { + size = bfd_asymbol_value (*current); + } + else if (strcmp (name, BFD_M68HC11_BANK_VIRTUAL_NAME) == 0) + { + cpu->bank_virtual = bfd_asymbol_value (*current); + } + } + free (asymbols); + + cpu->bank_end = cpu->bank_start + size; + cpu->bank_shift = 0; + for (; size > 1; size >>= 1) + cpu->bank_shift++; + + return 0; +} + +static int +sim_prepare_for_program (SIM_DESC sd, bfd* abfd) +{ + sim_cpu *cpu; + int elf_flags = 0; + + cpu = STATE_CPU (sd, 0); + + if (abfd != NULL) + { + asection *s; + + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + elf_flags = elf_elfheader (abfd)->e_flags; + + cpu->cpu_elf_start = bfd_get_start_address (abfd); + /* See if any section sets the reset address */ + cpu->cpu_use_elf_start = 1; + for (s = abfd->sections; s && cpu->cpu_use_elf_start; s = s->next) + { + if (s->flags & SEC_LOAD) + { + bfd_size_type size; + + size = bfd_get_section_size (s); + if (size > 0) + { + bfd_vma lma; + + if (STATE_LOAD_AT_LMA_P (sd)) + lma = bfd_section_lma (abfd, s); + else + lma = bfd_section_vma (abfd, s); + + if (lma <= 0xFFFE && lma+size >= 0x10000) + cpu->cpu_use_elf_start = 0; + } + } + } + + if (elf_flags & E_M68HC12_BANKS) + { + if (sim_get_bank_parameters (sd, abfd) != 0) + sim_io_eprintf (sd, "Memory bank parameters are not initialized\n"); + } + } + + if (!sim_hw_configure (sd)) + return SIM_RC_FAIL; + + /* reset all state information */ + sim_board_reset (sd); + + return SIM_RC_OK; +} + +SIM_DESC +sim_open (SIM_OPEN_KIND kind, host_callback *callback, + bfd *abfd, char **argv) +{ + SIM_DESC sd; + sim_cpu *cpu; + + 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); + + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) + { + free_state (sd); + 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. */ + free_state (sd); + return 0; + } + + /* 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) + { + free_state (sd); + return 0; + } + + /* Establish any remaining configuration options. */ + if (sim_config (sd) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + if (sim_post_argv_init (sd) != SIM_RC_OK) + { + /* Uninstall the modules to avoid memory leaks, + file descriptor leaks, etc. */ + free_state (sd); + return 0; + } + if (sim_prepare_for_program (sd, abfd) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* 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 */ + sim_state_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) +{ + const char *cpu_type; + const struct bfd_arch_info *arch; + + /* Nothing to do if there is no verbose flag set. */ + if (verbose == 0 && STATE_VERBOSE_P (sd) == 0) + return; + + arch = STATE_ARCHITECTURE (sd); + if (arch->arch == bfd_arch_m68hc11) + cpu_type = "68HC11"; + else + cpu_type = "68HC12"; + + sim_io_eprintf (sd, "Simulator info:\n"); + sim_io_eprintf (sd, " CPU Motorola %s\n", cpu_type); + 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) +{ + return sim_prepare_for_program (sd, abfd); +} + + +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; + int size = 2; + + cpu = STATE_CPU (sd, 0); + switch (rn) + { + case A_REGNUM: + val = cpu_get_a (cpu); + size = 1; + break; + + case B_REGNUM: + val = cpu_get_b (cpu); + size = 1; + 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); + size = 1; + break; + + case PAGE_REGNUM: + val = cpu_get_page (cpu); + size = 1; + break; + + default: + val = 0; + break; + } + if (size == 1) + { + memory[0] = val; + } + else + { + memory[0] = val >> 8; + memory[1] = val & 0x0FF; + } + return size; +} + +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); + return 1; + + case B_REGNUM: + cpu_set_b (cpu, val); + return 1; + + 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); + return 1; + + case PAGE_REGNUM: + cpu_set_page (cpu, val); + return 1; + + default: + 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"; + sim_cpu *cpu; + + cpu = STATE_CPU (sd, 0); + /* 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, 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); + } + + /* If the architecture changed, re-configure. */ + if (STATE_ARCHITECTURE (sd) != cpu->cpu_configured_arch) + sim_hw_configure (sd); +} + +/* Halt the simulator after just one instruction */ + +static void +has_stepped (SIM_DESC sd, + void *data) +{ + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); +} + + +/* Generic resume - assumes the existance of sim_engine_run */ + +void +sim_resume (SIM_DESC sd, + int step, + int siggnal) +{ + sim_engine *engine = STATE_ENGINE (sd); + jmp_buf buf; + int jmpval; + + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* we only want to be single stepping the simulator once */ + if (engine->stepper != NULL) + { + sim_events_deschedule (sd, engine->stepper); + engine->stepper = NULL; + } + sim_module_resume (sd); + + /* run/resume the simulator */ + engine->jmpbuf = &buf; + jmpval = setjmp (buf); + if (jmpval == sim_engine_start_jmpval + || jmpval == sim_engine_restart_jmpval) + { + int last_cpu_nr = sim_engine_last_cpu_nr (sd); + int next_cpu_nr = sim_engine_next_cpu_nr (sd); + int nr_cpus = sim_engine_nr_cpus (sd); + + sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); + if (next_cpu_nr >= nr_cpus) + next_cpu_nr = 0; + + /* Only deliver the siggnal ]sic] the first time through - don't + re-deliver any siggnal during a restart. */ + if (jmpval == sim_engine_restart_jmpval) + siggnal = 0; + + /* Install the stepping event after having processed some + pending events. This is necessary for HC11/HC12 simulator + because the tick counter is incremented by the number of cycles + the instruction took. Some pending ticks to process can still + be recorded internally by the simulator and sim_events_preprocess + will handle them. If the stepping event is inserted before, + these pending ticks will raise the event and the simulator will + stop without having executed any instruction. */ + if (step) + engine->stepper = sim_events_schedule (sd, 0, has_stepped, sd); + +#ifdef SIM_CPU_EXCEPTION_RESUME + { + sim_cpu* cpu = STATE_CPU (sd, next_cpu_nr); + SIM_CPU_EXCEPTION_RESUME(sd, cpu, siggnal); + } +#endif + + sim_engine_run (sd, next_cpu_nr, nr_cpus, siggnal); + } + engine->jmpbuf = NULL; + + sim_module_suspend (sd); +}
interp.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: emulos.c =================================================================== --- emulos.c (nonexistent) +++ emulos.c (revision 33) @@ -0,0 +1,160 @@ +/* emulos.c -- Small OS emulation + Copyright 1999, 2000, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@worldnet.fr) + +This file is part of GDB, GAS, and the GNU binutils. + +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. + +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, see . */ + +#include "sim-main.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef WIN32 +#include +#include + +/* This file emulates some OS system calls. + It's basically used to give access to the host OS facilities + like: stdin, stdout, files, time of day. */ +static int bench_mode = -1; +static struct timeval bench_start; +static struct timeval bench_stop; + +void +emul_bench (struct _sim_cpu* cpu) +{ + int op; + + op = cpu_get_d (cpu); + switch (op) + { + case 0: + bench_mode = 0; + gettimeofday (&bench_start, 0); + break; + + case 1: + gettimeofday (&bench_stop, 0); + if (bench_mode != 0) + printf ("bench start not called...\n"); + bench_mode = 1; + break; + + case 2: + { + int sz = 0; + int addr = cpu_get_x (cpu); + double t_start, t_stop, t; + char buf[1024]; + + op = cpu_get_y (cpu); + t_start = (double) (bench_start.tv_sec) * 1.0e6; + t_start += (double) (bench_start.tv_usec); + t_stop = (double) (bench_stop.tv_sec) * 1.0e6; + t_stop += (double) (bench_stop.tv_usec); + + while (sz < 1024) + { + buf[sz] = memory_read8 (cpu, addr); + if (buf[sz] == 0) + break; + + sz ++; + addr++; + } + buf[1023] = 0; + + if (bench_mode != 1) + printf ("bench_stop not called"); + + bench_mode = -1; + t = t_stop - t_start; + printf ("%-40.40s [%6d] %3.3f us\n", buf, + op, t / (double) (op)); + break; + } + } +} +#endif + +void +emul_write(struct _sim_cpu* state) +{ + int addr = cpu_get_x (state) & 0x0FFFF; + int size = cpu_get_d (state) & 0x0FFFF; + + if (addr + size > 0x0FFFF) { + size = 0x0FFFF - addr; + } + state->cpu_running = 0; + while (size) + { + uint8 val = memory_read8 (state, addr); + + write(0, &val, 1); + addr ++; + size--; + } +} + +/* emul_exit () is used by the default startup code of GCC to implement + the exit (). For a real target, this will create an ILLEGAL fault. + But doing an exit () on a real target is really a non-sense. + exit () is important for the validation of GCC. The exit status + is passed in 'D' register. */ +void +emul_exit (sim_cpu *cpu) +{ + sim_engine_halt (CPU_STATE (cpu), cpu, + NULL, NULL_CIA, sim_exited, + cpu_get_d (cpu)); +} + +void +emul_os (int code, sim_cpu *proc) +{ + proc->cpu_current_cycle = 8; + switch (code) + { + case 0x0: + break; + + /* 0xCD 0x01 */ + case 0x01: + emul_write (proc); + break; + + /* 0xCD 0x02 */ + case 0x02: + break; + + /* 0xCD 0x03 */ + case 0x03: + emul_exit (proc); + break; + + /* 0xCD 0x04 */ + case 0x04: +#ifndef WIN32 + emul_bench (proc); +#endif + break; + + default: + break; + } +} +
emulos.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: gencode.c =================================================================== --- gencode.c (nonexistent) +++ gencode.c (revision 33) @@ -0,0 +1,2151 @@ +/* gencode.c -- Motorola 68HC11 & 68HC12 Emulator Generator + Copyright 1999, 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.fr) + +This file is part of GDB, GAS, and the GNU binutils. + +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. + +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, see . */ + +#include +#include +#include +#include + +#include "ansidecl.h" +#include "opcode/m68hc11.h" + +#define TABLE_SIZE(X) (sizeof(X) / sizeof(X[0])) + +/* Combination of CCR flags. */ +#define M6811_ZC_BIT M6811_Z_BIT|M6811_C_BIT +#define M6811_NZ_BIT M6811_N_BIT|M6811_Z_BIT +#define M6811_NZV_BIT M6811_N_BIT|M6811_Z_BIT|M6811_V_BIT +#define M6811_NZC_BIT M6811_N_BIT|M6811_Z_BIT|M6811_C_BIT +#define M6811_NVC_BIT M6811_N_BIT|M6811_V_BIT|M6811_C_BIT +#define M6811_ZVC_BIT M6811_Z_BIT|M6811_V_BIT|M6811_C_BIT +#define M6811_NZVC_BIT M6811_ZVC_BIT|M6811_N_BIT +#define M6811_HNZVC_BIT M6811_NZVC_BIT|M6811_H_BIT +#define M6811_HNVC_BIT M6811_NVC_BIT|M6811_H_BIT +#define M6811_VC_BIT M6811_V_BIT|M6811_C_BIT + +/* Flags when the insn only changes some CCR flags. */ +#define CHG_NONE 0,0,0 +#define CHG_Z 0,0,M6811_Z_BIT +#define CHG_C 0,0,M6811_C_BIT +#define CHG_ZVC 0,0,M6811_ZVC_BIT +#define CHG_NZC 0,0,M6811_NZC_BIT +#define CHG_NZV 0,0,M6811_NZV_BIT +#define CHG_NZVC 0,0,M6811_NZVC_BIT +#define CHG_HNZVC 0,0,M6811_HNZVC_BIT +#define CHG_ALL 0,0,0xff + +/* The insn clears and changes some flags. */ +#define CLR_I 0,M6811_I_BIT,0 +#define CLR_C 0,M6811_C_BIT,0 +#define CLR_V 0,M6811_V_BIT,0 +#define CLR_V_CHG_ZC 0,M6811_V_BIT,M6811_ZC_BIT +#define CLR_V_CHG_NZ 0,M6811_V_BIT,M6811_NZ_BIT +#define CLR_V_CHG_ZVC 0,M6811_V_BIT,M6811_ZVC_BIT +#define CLR_N_CHG_ZVC 0,M6811_N_BIT,M6811_ZVC_BIT /* Used by lsr */ +#define CLR_VC_CHG_NZ 0,M6811_VC_BIT,M6811_NZ_BIT + +/* The insn sets some flags. */ +#define SET_I M6811_I_BIT,0,0 +#define SET_C M6811_C_BIT,0,0 +#define SET_V M6811_V_BIT,0,0 +#define SET_Z_CLR_NVC M6811_Z_BIT,M6811_NVC_BIT,0 +#define SET_C_CLR_V_CHG_NZ M6811_C_BIT,M6811_V_BIT,M6811_NZ_BIT +#define SET_Z_CHG_HNVC M6811_Z_BIT,0,M6811_HNVC_BIT + +#define _M 0xff + +static int cpu_type; + +struct m6811_opcode_pattern +{ + const char *name; + const char *pattern; + const char *ccr_update; +}; + +/* + * { "test", M6811_OP_NONE, 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +---- Insn CCR changes + * Format ------+ +---------- Max # cycles + * Size -----------------+ +--------------- Min # cycles + * +-------------------- Opcode + */ +struct m6811_opcode_pattern m6811_opcode_patterns[] = { + /* Move 8 and 16 bits. We need two implementations: one that sets the + flags and one that preserve them. */ + { "movtst8", "dst8 = src8", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "movtst16", "dst16 = src16", "cpu_ccr_update_tst16 (proc, dst16)" }, + { "mov8", "dst8 = src8" }, + { "mov16", "dst16 = src16" }, + { "lea16", "dst16 = addr" }, + + /* Conditional branches. 'addr' is the address of the branch. */ + { "bra", "cpu_set_pc (proc, addr)" }, + { "bhi", + "if ((cpu_get_ccr (proc) & (M6811_C_BIT|M6811_Z_BIT)) == 0)\n@ \ + cpu_set_pc (proc, addr)" }, + { "bls", + "if ((cpu_get_ccr (proc) & (M6811_C_BIT|M6811_Z_BIT)))\n@ \ + cpu_set_pc (proc, addr)" }, + { "bcc", "if (!cpu_get_ccr_C (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bcs", "if (cpu_get_ccr_C (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bne", "if (!cpu_get_ccr_Z (proc))\n@ cpu_set_pc (proc, addr)" }, + { "beq", "if (cpu_get_ccr_Z (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bvc", "if (!cpu_get_ccr_V (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bvs", "if (cpu_get_ccr_V (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bpl", "if (!cpu_get_ccr_N (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bmi", "if (cpu_get_ccr_N (proc))\n@ cpu_set_pc (proc, addr)" }, + { "bge", "if ((cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc)) == 0)\n@ cpu_set_pc (proc, addr)" }, + { "blt", "if ((cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc)))\n@ cpu_set_pc (proc, addr)" }, + { "bgt", + "if ((cpu_get_ccr_Z (proc) | (cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc))) == 0)\n@ \ + cpu_set_pc (proc, addr)" }, + { "ble", + "if ((cpu_get_ccr_Z (proc) | (cpu_get_ccr_N (proc) ^ cpu_get_ccr_V (proc))))\n@ \ + cpu_set_pc (proc, addr)" }, + + /* brclr and brset perform a test and a conditional jump at the same + time. Flags are not changed. */ + { "brclr8", + "if ((src8 & dst8) == 0)\n@ cpu_set_pc (proc, addr)" }, + { "brset8", + "if (((~src8) & dst8) == 0)\n@ cpu_set_pc (proc, addr)" }, + + + { "rts11", "addr = cpu_m68hc11_pop_uint16 (proc); cpu_set_pc (proc, addr); cpu_return(proc)" }, + { "rts12", "addr = cpu_m68hc12_pop_uint16 (proc); cpu_set_pc (proc, addr); cpu_return(proc)" }, + + { "mul16", "dst16 = ((uint16) src8 & 0x0FF) * ((uint16) dst8 & 0x0FF)", + "cpu_set_ccr_C (proc, src8 & 0x80)" }, + { "neg8", "dst8 = - src8", + "cpu_set_ccr_C (proc, src8 == 0); cpu_ccr_update_tst8 (proc, dst8)" }, + { "com8", "dst8 = ~src8", + "cpu_set_ccr_C (proc, 1); cpu_ccr_update_tst8 (proc, dst8);" }, + { "clr8", "dst8 = 0", + "cpu_set_ccr (proc, (cpu_get_ccr (proc) & (M6811_S_BIT|M6811_X_BIT|M6811_H_BIT| \ +M6811_I_BIT)) | M6811_Z_BIT)"}, + { "clr16","dst16 = 0", + "cpu_set_ccr (proc, (cpu_get_ccr (proc) & (M6811_S_BIT|M6811_X_BIT|M6811_H_BIT| \ +M6811_I_BIR)) | M6811_Z_BIT)"}, + + /* 8-bits shift and rotation. */ + { "lsr8", "dst8 = src8 >> 1", + "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" }, + { "lsl8", "dst8 = src8 << 1", + "cpu_set_ccr_C (proc, (src8 & 0x80) >> 7); cpu_ccr_update_shift8 (proc, dst8)" }, + { "asr8", "dst8 = (src8 >> 1) | (src8 & 0x80)", + "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" }, + { "ror8", "dst8 = (src8 >> 1) | (cpu_get_ccr_C (proc) << 7)", + "cpu_set_ccr_C (proc, src8 & 1); cpu_ccr_update_shift8 (proc, dst8)" }, + { "rol8", "dst8 = (src8 << 1) | (cpu_get_ccr_C (proc))", + "cpu_set_ccr_C (proc, (src8 & 0x80) >> 7); cpu_ccr_update_shift8 (proc, dst8)" }, + + /* 16-bits shift instructions. */ + { "lsl16", "dst16 = src16 << 1", + "cpu_set_ccr_C (proc, (src16&0x8000) >> 15); cpu_ccr_update_shift16 (proc, dst16)"}, + { "lsr16", "dst16 = src16 >> 1", + "cpu_set_ccr_C (proc, src16 & 1); cpu_ccr_update_shift16 (proc, dst16)"}, + + { "dec8", "dst8 = src8 - 1", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "inc8", "dst8 = src8 + 1", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "tst8", 0, "cpu_set_ccr_C (proc, 0); cpu_ccr_update_tst8 (proc, src8)" }, + + { "sub8", "cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\ +dst8 = dst8 - src8", 0 }, + { "add8", "cpu_ccr_update_add8 (proc, dst8 + src8, dst8, src8);\ +dst8 = dst8 + src8", 0 }, + { "sbc8", "if (cpu_get_ccr_C (proc))\n@ \ +{\n\ + cpu_ccr_update_sub8 (proc, dst8 - src8 - 1, dst8, src8);\n\ + dst8 = dst8 - src8 - 1;\n\ +}\n\ +else\n\ +{\n\ + cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\n\ + dst8 = dst8 - src8;\n\ +}", 0 }, + { "adc8", "if (cpu_get_ccr_C (proc))\n@ \ +{\n\ + cpu_ccr_update_add8 (proc, dst8 + src8 + 1, dst8, src8);\n\ + dst8 = dst8 + src8 + 1;\n\ +}\n\ +else\n\ +{\n\ + cpu_ccr_update_add8 (proc, dst8 + src8, dst8, src8);\n\ + dst8 = dst8 + src8;\n\ +}", + 0 }, + + /* 8-bits logical operations. */ + { "and8", "dst8 = dst8 & src8", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "eor8", "dst8 = dst8 ^ src8", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "or8", "dst8 = dst8 | src8", "cpu_ccr_update_tst8 (proc, dst8)" }, + { "bclr8","dst8 = (~dst8) & src8", "cpu_ccr_update_tst8 (proc, dst8)" }, + + /* 16-bits add and subtract instructions. */ + { "sub16", "cpu_ccr_update_sub16 (proc, dst16 - src16, dst16, src16);\ +dst16 = dst16 - src16", 0 }, + { "add16", "cpu_ccr_update_add16 (proc, dst16 + src16, dst16, src16);\ +dst16 = dst16 + src16", 0 }, + { "inc16", "dst16 = src16 + 1", "cpu_set_ccr_Z (proc, dst16 == 0)" }, + { "dec16", "dst16 = src16 - 1", "cpu_set_ccr_Z (proc, dst16 == 0)" }, + + /* Special increment/decrement for the stack pointer: + flags are not changed. */ + { "ins16", "dst16 = src16 + 1" }, + { "des16", "dst16 = src16 - 1" }, + + { "jsr_11_16", "cpu_m68hc11_push_uint16 (proc, cpu_get_pc (proc)); cpu_call (proc, addr)"}, + { "jsr_12_16", "cpu_m68hc12_push_uint16 (proc, cpu_get_pc (proc)); cpu_call (proc, addr)"}, + + /* xgdx and xgdx patterns. Flags are not changed. */ + { "xgdxy16", "dst16 = cpu_get_d (proc); cpu_set_d (proc, src16)"}, + { "stop", "cpu_special (proc, M6811_STOP)"}, + + /* tsx, tsy, txs, tys don't affect the flags. Sp value is corrected + by +/- 1. */ + { "tsxy16", "dst16 = src16 + 1;"}, + { "txys16", "dst16 = src16 - 1;"}, + + /* Add b to X or Y with an unsigned extension 8->16. Flags not changed. */ + { "abxy16","dst16 = dst16 + (uint16) src8"}, + + /* After 'daa', the Z flag is undefined. Mark it as changed. */ + { "daa8", "cpu_special (proc, M6811_DAA)" }, + { "nop", 0 }, + + + /* Integer divide: + (parallel (set IX (div D IX)) + (set D (mod D IX))) */ + { "idiv16", "if (src16 == 0)\n{\n\ +dst16 = 0xffff;\ +}\nelse\n{\n\ +cpu_set_d (proc, dst16 % src16);\ +dst16 = dst16 / src16;\ +}", + "cpu_set_ccr_Z (proc, dst16 == 0); cpu_set_ccr_V (proc, 0);\ +cpu_set_ccr_C (proc, src16 == 0)" }, + + /* Fractional divide: + (parallel (set IX (div (mul D 65536) IX) + (set D (mod (mul D 65536) IX)))) */ + { "fdiv16", "if (src16 <= dst16 )\n{\n\ +dst16 = 0xffff;\n\ +cpu_set_ccr_Z (proc, 0);\n\ +cpu_set_ccr_V (proc, 1);\n\ +cpu_set_ccr_C (proc, dst16 == 0);\n\ +}\nelse\n{\n\ +unsigned long l = (unsigned long) (dst16) << 16;\n\ +cpu_set_d (proc, (uint16) (l % (unsigned long) (src16)));\n\ +dst16 = (uint16) (l / (unsigned long) (src16));\n\ +cpu_set_ccr_V (proc, 0);\n\ +cpu_set_ccr_C (proc, 0);\n\ +cpu_set_ccr_Z (proc, dst16 == 0);\n\ +}", 0 }, + + /* Operations to get/set the CCR. */ + { "clv", 0, "cpu_set_ccr_V (proc, 0)" }, + { "sev", 0, "cpu_set_ccr_V (proc, 1)" }, + { "clc", 0, "cpu_set_ccr_C (proc, 0)" }, + { "sec", 0, "cpu_set_ccr_C (proc, 1)" }, + { "cli", 0, "cpu_set_ccr_I (proc, 0)" }, + { "sei", 0, "cpu_set_ccr_I (proc, 1)" }, + + /* Some special instructions are implemented by 'cpu_special'. */ + { "rti11", "cpu_special (proc, M6811_RTI)" }, + { "rti12", "cpu_special (proc, M6812_RTI)" }, + { "wai", "cpu_special (proc, M6811_WAI)" }, + { "test", "cpu_special (proc, M6811_TEST)" }, + { "swi", "cpu_special (proc, M6811_SWI)" }, + { "syscall","cpu_special (proc, M6811_EMUL_SYSCALL)" }, + + { "page2", "cpu_page2_interp (proc)", 0 }, + { "page3", "cpu_page3_interp (proc)", 0 }, + { "page4", "cpu_page4_interp (proc)", 0 }, + + /* 68HC12 special instructions. */ + { "bgnd", "cpu_special (proc, M6812_BGND)" }, + { "call8", "cpu_special (proc, M6812_CALL)" }, + { "call_ind", "cpu_special (proc, M6812_CALL_INDIRECT)" }, + { "dbcc8", "cpu_dbcc (proc)" }, + { "ediv", "cpu_special (proc, M6812_EDIV)" }, + { "emul", "{ uint32 src1 = (uint32) cpu_get_d (proc);\ + uint32 src2 = (uint32) cpu_get_y (proc);\ + src1 *= src2;\ + cpu_set_d (proc, src1);\ + cpu_set_y (proc, src1 >> 16);\ + cpu_set_ccr_Z (proc, src1 == 0);\ + cpu_set_ccr_C (proc, src1 & 0x08000);\ + cpu_set_ccr_N (proc, src1 & 0x80000000);}" }, + { "emuls", "cpu_special (proc, M6812_EMULS)" }, + { "mem", "cpu_special (proc, M6812_MEM)" }, + { "rtc", "cpu_special (proc, M6812_RTC)" }, + { "emacs", "cpu_special (proc, M6812_EMACS)" }, + { "idivs", "cpu_special (proc, M6812_IDIVS)" }, + { "edivs", "cpu_special (proc, M6812_EDIVS)" }, + { "exg8", "cpu_exg (proc, src8)" }, + { "move8", "cpu_move8 (proc, op)" }, + { "move16","cpu_move16 (proc, op)" }, + + { "max8", "cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\ + if (dst8 < src8) dst8 = src8" }, + { "min8", "cpu_ccr_update_sub8 (proc, dst8 - src8, dst8, src8);\ + if (dst8 > src8) dst8 = src8" }, + { "max16", "cpu_ccr_update_sub16 (proc, dst16 - src16, dst16, src16);\ + if (dst16 < src16) dst16 = src16" }, + { "min16", "cpu_ccr_update_sub16 (proc, dst16 - src16, dst16, src16);\ + if (dst16 > src16) dst16 = src16" }, + + { "rev", "cpu_special (proc, M6812_REV);" }, + { "revw", "cpu_special (proc, M6812_REVW);" }, + { "wav", "cpu_special (proc, M6812_WAV);" }, + { "tbl8", "cpu_special (proc, M6812_ETBL);" }, + { "tbl16", "cpu_special (proc, M6812_ETBL);" } +}; + +/* Definition of an opcode of the 68HC11. */ +struct m6811_opcode_def +{ + const char *name; + const char *operands; + const char *insn_pattern; + unsigned char insn_size; + unsigned char insn_code; + unsigned char insn_min_cycles; + unsigned char insn_max_cycles; + unsigned char set_flags_mask; + unsigned char clr_flags_mask; + unsigned char chg_flags_mask; +}; + + +/* + * { "dex", "x->x", "dec16", 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +----- Insn CCR changes + * Operands ---+ +------------ Max # cycles + * Pattern -----------+ +--------------- Min # cycles + * Size -----------------+ +-------------------- Opcode + * + * Operands Fetch operand Save result + * ------- -------------- ------------ + * x->x src16 = x x = dst16 + * d->d src16 = d d = dst16 + * b,a->a src8 = b dst8 = a a = dst8 + * sp->x src16 = sp x = dst16 + * (sp)->a src8 = pop8 a = dst8 + * a->(sp) src8 = a push8 dst8 + * (x)->(x) src8 = (IND, X) (IND, X) = dst8 + * (y)->a src8 = (IND, Y) a = dst8 + * ()->b src8 = (EXT) b = dst8 + */ +struct m6811_opcode_def m6811_page1_opcodes[] = { + { "test", 0, 0, 1, 0x00, 5, _M, CHG_NONE }, + { "nop", 0, 0, 1, 0x01, 2, 2, CHG_NONE }, + { "idiv", "x,d->x", "idiv16", 1, 0x02, 3, 41, CLR_V_CHG_ZC}, + { "fdiv", "x,d->x", "fdiv16", 1, 0x03, 3, 41, CHG_ZVC}, + { "lsrd", "d->d", "lsr16", 1, 0x04, 3, 3, CLR_N_CHG_ZVC }, + { "asld", "d->d", "lsl16", 1, 0x05, 3, 3, CHG_NZVC }, + { "tap", "a->ccr", "mov8", 1, 0x06, 2, 2, CHG_ALL}, + { "tpa", "ccr->a", "mov8", 1, 0x07, 2, 2, CHG_NONE }, + { "inx", "x->x", "inc16", 1, 0x08, 3, 3, CHG_Z }, + { "dex", "x->x", "dec16", 1, 0x09, 3, 3, CHG_Z }, + { "clv", 0, 0, 1, 0x0a, 2, 2, CLR_V }, + { "sev", 0, 0, 1, 0x0b, 2, 2, SET_V }, + { "clc", 0, 0, 1, 0x0c, 2, 2, CLR_C }, + { "sec", 0, 0, 1, 0x0d, 2, 2, SET_C }, + { "cli", 0, 0, 1, 0x0e, 2, 2, CLR_I }, + { "sei", 0, 0, 1, 0x0f, 2, 2, SET_I }, + { "sba", "b,a->a", "sub8", 1, 0x10, 2, 2, CHG_NZVC }, + { "cba", "b,a", "sub8", 1, 0x11, 2, 2, CHG_NZVC }, + { "brset","*,#,r", "brset8", 4, 0x12, 6, 6, CHG_NONE }, + { "brclr","*,#,r", "brclr8", 4, 0x13, 6, 6, CHG_NONE }, + { "bset", "*,#->*", "or8", 3, 0x14, 6, 6, CLR_V_CHG_NZ }, + { "bclr", "*,#->*", "bclr8", 3, 0x15, 6, 6, CLR_V_CHG_NZ }, + { "tab", "a->b", "movtst8", 1, 0x16, 2, 2, CLR_V_CHG_NZ }, + { "tba", "b->a", "movtst8", 1, 0x17, 2, 2, CLR_V_CHG_NZ }, + { "page2", 0, "page2", 1, 0x18, 0, 0, CHG_NONE }, + { "page3", 0, "page3", 1, 0x1a, 0, 0, CHG_NONE }, + + /* After 'daa', the Z flag is undefined. Mark it as changed. */ + { "daa", "", "daa8", 1, 0x19, 2, 2, CHG_NZVC }, + { "aba", "b,a->a", "add8", 1, 0x1b, 2, 2, CHG_HNZVC}, + { "bset", "(x),#->(x)","or8", 3, 0x1c, 7, 7, CLR_V_CHG_NZ }, + { "bclr", "(x),#->(x)","bclr8", 3, 0x1d, 7, 7, CLR_V_CHG_NZ }, + { "brset","(x),#,r", "brset8", 4, 0x1e, 7, 7, CHG_NONE }, + { "brclr","(x),#,r", "brclr8", 4, 0x1f, 7, 7, CHG_NONE }, + + /* Relative branch. All of them take 3 bytes. Flags not changed. */ + { "bra", "r", 0, 2, 0x20, 3, 3, CHG_NONE }, + { "brn", "r", "nop", 2, 0x21, 3, 3, CHG_NONE }, + { "bhi", "r", 0, 2, 0x22, 3, 3, CHG_NONE }, + { "bls", "r", 0, 2, 0x23, 3, 3, CHG_NONE }, + { "bcc", "r", 0, 2, 0x24, 3, 3, CHG_NONE }, + { "bcs", "r", 0, 2, 0x25, 3, 3, CHG_NONE }, + { "bne", "r", 0, 2, 0x26, 3, 3, CHG_NONE }, + { "beq", "r", 0, 2, 0x27, 3, 3, CHG_NONE }, + { "bvc", "r", 0, 2, 0x28, 3, 3, CHG_NONE }, + { "bvs", "r", 0, 2, 0x29, 3, 3, CHG_NONE }, + { "bpl", "r", 0, 2, 0x2a, 3, 3, CHG_NONE }, + { "bmi", "r", 0, 2, 0x2b, 3, 3, CHG_NONE }, + { "bge", "r", 0, 2, 0x2c, 3, 3, CHG_NONE }, + { "blt", "r", 0, 2, 0x2d, 3, 3, CHG_NONE }, + { "bgt", "r", 0, 2, 0x2e, 3, 3, CHG_NONE }, + { "ble", "r", 0, 2, 0x2f, 3, 3, CHG_NONE }, + + { "tsx", "sp->x", "tsxy16", 1, 0x30, 3, 3, CHG_NONE }, + { "ins", "sp->sp", "ins16", 1, 0x31, 3, 3, CHG_NONE }, + { "pula", "(sp)->a", "mov8", 1, 0x32, 4, 4, CHG_NONE }, + { "pulb", "(sp)->b", "mov8", 1, 0x33, 4, 4, CHG_NONE }, + { "des", "sp->sp", "des16", 1, 0x34, 3, 3, CHG_NONE }, + { "txs", "x->sp", "txys16", 1, 0x35, 3, 3, CHG_NONE }, + { "psha", "a->(sp)", "mov8", 1, 0x36, 3, 3, CHG_NONE }, + { "pshb", "b->(sp)", "mov8", 1, 0x37, 3, 3, CHG_NONE }, + { "pulx", "(sp)->x", "mov16", 1, 0x38, 5, 5, CHG_NONE }, + { "rts", 0, "rts11", 1, 0x39, 5, 5, CHG_NONE }, + { "abx", "b,x->x", "abxy16", 1, 0x3a, 3, 3, CHG_NONE }, + { "rti", 0, "rti11", 1, 0x3b, 12, 12, CHG_ALL}, + { "pshx", "x->(sp)", "mov16", 1, 0x3c, 4, 4, CHG_NONE }, + { "mul", "b,a->d", "mul16", 1, 0x3d, 3, 10, CHG_C }, + { "wai", 0, 0, 1, 0x3e, 14, _M, CHG_NONE }, + { "swi", 0, 0, 1, 0x3f, 14, _M, CHG_NONE }, + { "nega", "a->a", "neg8", 1, 0x40, 2, 2, CHG_NZVC }, + { "syscall", "", "syscall", 1, 0x41, 2, 2, CHG_NONE }, + { "coma", "a->a", "com8", 1, 0x43, 2, 2, SET_C_CLR_V_CHG_NZ }, + { "lsra", "a->a", "lsr8", 1, 0x44, 2, 2, CLR_N_CHG_ZVC}, + { "rora", "a->a", "ror8", 1, 0x46, 2, 2, CHG_NZVC }, + { "asra", "a->a", "asr8", 1, 0x47, 2, 2, CHG_NZVC }, + { "asla", "a->a", "lsl8", 1, 0x48, 2, 2, CHG_NZVC }, + { "rola", "a->a", "rol8", 1, 0x49, 2, 2, CHG_NZVC }, + { "deca", "a->a", "dec8", 1, 0x4a, 2, 2, CHG_NZV }, + { "inca", "a->a", "inc8", 1, 0x4c, 2, 2, CHG_NZV }, + { "tsta", "a", "tst8", 1, 0x4d, 2, 2, CLR_V_CHG_NZ }, + { "clra", "->a", "clr8", 1, 0x4f, 2, 2, SET_Z_CLR_NVC }, + { "negb", "b->b", "neg8", 1, 0x50, 2, 2, CHG_NZVC }, + { "comb", "b->b", "com8", 1, 0x53, 2, 2, SET_C_CLR_V_CHG_NZ }, + { "lsrb", "b->b", "lsr8", 1, 0x54, 2, 2, CLR_N_CHG_ZVC }, + { "rorb", "b->b", "ror8", 1, 0x56, 2, 2, CHG_NZVC }, + { "asrb", "b->b", "asr8", 1, 0x57, 2, 2, CHG_NZVC }, + { "aslb", "b->b", "lsl8", 1, 0x58, 2, 2, CHG_NZVC }, + { "rolb", "b->b", "rol8", 1, 0x59, 2, 2, CHG_NZVC }, + { "decb", "b->b", "dec8", 1, 0x5a, 2, 2, CHG_NZV }, + { "incb", "b->b", "inc8", 1, 0x5c, 2, 2, CHG_NZV }, + { "tstb", "b", "tst8", 1, 0x5d, 2, 2, CLR_V_CHG_NZ }, + { "clrb", "->b", "clr8", 1, 0x5f, 2, 2, SET_Z_CLR_NVC }, + { "neg", "(x)->(x)", "neg8", 2, 0x60, 6, 6, CHG_NZVC }, + { "com", "(x)->(x)", "com8", 2, 0x63, 6, 6, SET_C_CLR_V_CHG_NZ }, + { "lsr", "(x)->(x)", "lsr8", 2, 0x64, 6, 6, CLR_N_CHG_ZVC }, + { "ror", "(x)->(x)", "ror8", 2, 0x66, 6, 6, CHG_NZVC }, + { "asr", "(x)->(x)", "asr8", 2, 0x67, 6, 6, CHG_NZVC }, + { "asl", "(x)->(x)", "lsl8", 2, 0x68, 6, 6, CHG_NZVC }, + { "rol", "(x)->(x)", "rol8", 2, 0x69, 6, 6, CHG_NZVC }, + { "dec", "(x)->(x)", "dec8", 2, 0x6a, 6, 6, CHG_NZV }, + { "inc", "(x)->(x)", "inc8", 2, 0x6c, 6, 6, CHG_NZV }, + { "tst", "(x)", "tst8", 2, 0x6d, 6, 6, CLR_V_CHG_NZ }, + { "jmp", "&(x)", "bra", 2, 0x6e, 3, 3, CHG_NONE }, + { "clr", "->(x)", "clr8", 2, 0x6f, 6, 6, SET_Z_CLR_NVC }, + { "neg", "()->()", "neg8", 3, 0x70, 6, 6, CHG_NZVC }, + { "com", "()->()", "com8", 3, 0x73, 6, 6, SET_C_CLR_V_CHG_NZ }, + { "lsr", "()->()", "lsr8", 3, 0x74, 6, 6, CLR_V_CHG_ZVC }, + { "ror", "()->()", "ror8", 3, 0x76, 6, 6, CHG_NZVC }, + { "asr", "()->()", "asr8", 3, 0x77, 6, 6, CHG_NZVC }, + { "asl", "()->()", "lsl8", 3, 0x78, 6, 6, CHG_NZVC }, + { "rol", "()->()", "rol8", 3, 0x79, 6, 6, CHG_NZVC }, + { "dec", "()->()", "dec8", 3, 0x7a, 6, 6, CHG_NZV }, + { "inc", "()->()", "inc8", 3, 0x7c, 6, 6, CHG_NZV }, + { "tst", "()", "tst8", 3, 0x7d, 6, 6, CLR_V_CHG_NZ }, + { "jmp", "&()", "bra", 3, 0x7e, 3, 3, CHG_NONE }, + { "clr", "->()", "clr8", 3, 0x7f, 6, 6, SET_Z_CLR_NVC }, + { "suba", "#,a->a", "sub8", 2, 0x80, 2, 2, CHG_NZVC }, + { "cmpa", "#,a", "sub8", 2, 0x81, 2, 2, CHG_NZVC }, + { "sbca", "#,a->a", "sbc8", 2, 0x82, 2, 2, CHG_NZVC }, + { "subd", "#,d->d", "sub16", 3, 0x83, 4, 4, CHG_NZVC }, + { "anda", "#,a->a", "and8", 2, 0x84, 2, 2, CLR_V_CHG_NZ }, + { "bita", "#,a", "and8", 2, 0x85, 2, 2, CLR_V_CHG_NZ }, + { "ldaa", "#->a", "movtst8", 2, 0x86, 2, 2, CLR_V_CHG_NZ }, + { "eora", "#,a->a", "eor8", 2, 0x88, 2, 2, CLR_V_CHG_NZ }, + { "adca", "#,a->a", "adc8", 2, 0x89, 2, 2, CHG_HNZVC }, + { "oraa", "#,a->a", "or8", 2, 0x8a, 2, 2, CLR_V_CHG_NZ }, + { "adda", "#,a->a", "add8", 2, 0x8b, 2, 2, CHG_HNZVC }, + { "cmpx", "#,x", "sub16", 3, 0x8c, 4, 4, CHG_NZVC }, + { "bsr", "r", "jsr_11_16", 2, 0x8d, 6, 6, CHG_NONE }, + { "lds", "#->sp", "movtst16", 3, 0x8e, 3, 3, CLR_V_CHG_NZ }, + { "xgdx", "x->x", "xgdxy16", 1, 0x8f, 3, 3, CHG_NONE }, + { "suba", "*,a->a", "sub8", 2, 0x90, 3, 3, CHG_NZVC }, + { "cmpa", "*,a", "sub8", 2, 0x91, 3, 3, CHG_NZVC }, + { "sbca", "*,a->a", "sbc8", 2, 0x92, 3, 3, CHG_NZVC }, + { "subd", "*,d->d", "sub16", 2, 0x93, 5, 5, CHG_NZVC }, + { "anda", "*,a->a", "and8", 2, 0x94, 3, 3, CLR_V_CHG_NZ }, + { "bita", "*,a", "and8", 2, 0x95, 3, 3, CLR_V_CHG_NZ }, + { "ldaa", "*->a", "movtst8", 2, 0x96, 3, 3, CLR_V_CHG_NZ }, + { "staa", "a->*", "movtst8", 2, 0x97, 3, 3, CLR_V_CHG_NZ }, + { "eora", "*,a->a", "eor8", 2, 0x98, 3, 3, CLR_V_CHG_NZ }, + { "adca", "*,a->a", "adc8", 2, 0x99, 3, 3, CHG_HNZVC }, + { "oraa", "*,a->a", "or8", 2, 0x9a, 3, 3, CLR_V_CHG_NZ }, + { "adda", "*,a->a", "add8", 2, 0x9b, 3, 3, CHG_HNZVC }, + { "cmpx", "*,x", "sub16", 2, 0x9c, 5, 5, CHG_NZVC }, + { "jsr", "*", "jsr_11_16", 2, 0x9d, 5, 5, CHG_NONE }, + { "lds", "*->sp", "movtst16", 2, 0x9e, 4, 4, CLR_V_CHG_NZ }, + { "sts", "sp->*", "movtst16", 2, 0x9f, 4, 4, CLR_V_CHG_NZ }, + { "suba", "(x),a->a", "sub8", 2, 0xa0, 4, 4, CHG_NZVC }, + { "cmpa", "(x),a", "sub8", 2, 0xa1, 4, 4, CHG_NZVC }, + { "sbca", "(x),a->a", "sbc8", 2, 0xa2, 4, 4, CHG_NZVC }, + { "subd", "(x),d->d", "sub16", 2, 0xa3, 6, 6, CHG_NZVC }, + { "anda", "(x),a->a", "and8", 2, 0xa4, 4, 4, CLR_V_CHG_NZ }, + { "bita", "(x),a", "and8", 2, 0xa5, 4, 4, CLR_V_CHG_NZ }, + { "ldaa", "(x)->a", "movtst8", 2, 0xa6, 4, 4, CLR_V_CHG_NZ }, + { "staa", "a->(x)", "movtst8", 2, 0xa7, 4, 4, CLR_V_CHG_NZ }, + { "eora", "(x),a->a", "eor8", 2, 0xa8, 4, 4, CLR_V_CHG_NZ }, + { "adca", "(x),a->a", "adc8", 2, 0xa9, 4, 4, CHG_HNZVC }, + { "oraa", "(x),a->a", "or8", 2, 0xaa, 4, 4, CLR_V_CHG_NZ }, + { "adda", "(x),a->a", "add8", 2, 0xab, 4, 4, CHG_HNZVC }, + { "cmpx", "(x),x", "sub16", 2, 0xac, 6, 6, CHG_NZVC }, + { "jsr", "&(x)", "jsr_11_16", 2, 0xad, 6, 6, CHG_NONE }, + { "lds", "(x)->sp", "movtst16", 2, 0xae, 5, 5, CLR_V_CHG_NZ }, + { "sts", "sp->(x)", "movtst16", 2, 0xaf, 5, 5, CLR_V_CHG_NZ }, + { "suba", "(),a->a", "sub8", 3, 0xb0, 4, 4, CHG_NZVC }, + { "cmpa", "(),a", "sub8", 3, 0xb1, 4, 4, CHG_NZVC }, + { "sbca", "(),a->a", "sbc8", 3, 0xb2, 4, 4, CHG_NZVC }, + { "subd", "(),d->d", "sub16", 3, 0xb3, 6, 6, CHG_NZVC }, + { "anda", "(),a->a", "and8", 3, 0xb4, 4, 4, CLR_V_CHG_NZ }, + { "bita", "(),a", "and8", 3, 0xb5, 4, 4, CLR_V_CHG_NZ }, + { "ldaa", "()->a", "movtst8", 3, 0xb6, 4, 4, CLR_V_CHG_NZ }, + { "staa", "a->()", "movtst8", 3, 0xb7, 4, 4, CLR_V_CHG_NZ }, + { "eora", "(),a->a", "eor8", 3, 0xb8, 4, 4, CLR_V_CHG_NZ }, + { "adca", "(),a->a", "adc8", 3, 0xb9, 4, 4, CHG_HNZVC }, + { "oraa", "(),a->a", "or8", 3, 0xba, 4, 4, CLR_V_CHG_NZ }, + { "adda", "(),a->a", "add8", 3, 0xbb, 4, 4, CHG_HNZVC }, + { "cmpx", "(),x", "sub16", 3, 0xbc, 5, 5, CHG_NZVC }, + { "jsr", "&()", "jsr_11_16", 3, 0xbd, 6, 6, CHG_NONE }, + { "lds", "()->sp", "movtst16", 3, 0xbe, 5, 5, CLR_V_CHG_NZ }, + { "sts", "sp->()", "movtst16", 3, 0xbf, 5, 5, CLR_V_CHG_NZ }, + { "subb", "#,b->b", "sub8", 2, 0xc0, 2, 2, CHG_NZVC }, + { "cmpb", "#,b", "sub8", 2, 0xc1, 2, 2, CHG_NZVC }, + { "sbcb", "#,b->b", "sbc8", 2, 0xc2, 2, 2, CHG_NZVC }, + { "addd", "#,d->d", "add16", 3, 0xc3, 4, 4, CHG_NZVC }, + { "andb", "#,b->b", "and8", 2, 0xc4, 2, 2, CLR_V_CHG_NZ }, + { "bitb", "#,b", "and8", 2, 0xc5, 2, 2, CLR_V_CHG_NZ }, + { "ldab", "#->b", "movtst8", 2, 0xc6, 2, 2, CLR_V_CHG_NZ }, + { "eorb", "#,b->b", "eor8", 2, 0xc8, 2, 2, CLR_V_CHG_NZ }, + { "adcb", "#,b->b", "adc8", 2, 0xc9, 2, 2, CHG_HNZVC }, + { "orab", "#,b->b", "or8", 2, 0xca, 2, 2, CLR_V_CHG_NZ }, + { "addb", "#,b->b", "add8", 2, 0xcb, 2, 2, CHG_HNZVC }, + { "ldd", "#->d", "movtst16", 3, 0xcc, 3, 3, CLR_V_CHG_NZ }, + { "page4",0, "page4", 1, 0xcd, 0, 0, CHG_NONE }, + { "ldx", "#->x", "movtst16", 3, 0xce, 3, 3, CLR_V_CHG_NZ }, + { "stop", 0, 0, 1, 0xcf, 2, 2, CHG_NONE }, + { "subb", "*,b->b", "sub8", 2, 0xd0, 3, 3, CHG_NZVC }, + { "cmpb", "*,b", "sub8", 2, 0xd1, 3, 3, CHG_NZVC }, + { "sbcb", "*,b->b", "sbc8", 2, 0xd2, 3, 3, CHG_NZVC }, + { "addd", "*,d->d", "add16", 2, 0xd3, 5, 5, CHG_NZVC }, + { "andb", "*,b->b", "and8", 2, 0xd4, 3, 3, CLR_V_CHG_NZ }, + { "bitb", "*,b", "and8", 2, 0xd5, 3, 3, CLR_V_CHG_NZ }, + { "ldab", "*->b", "movtst8", 2, 0xd6, 3, 3, CLR_V_CHG_NZ }, + { "stab", "b->*", "movtst8", 2, 0xd7, 3, 3, CLR_V_CHG_NZ }, + { "eorb", "*,b->b", "eor8", 2, 0xd8, 3, 3, CLR_V_CHG_NZ }, + { "adcb", "*,b->b", "adc8", 2, 0xd9, 3, 3, CHG_HNZVC }, + { "orab", "*,b->b", "or8", 2, 0xda, 3, 3, CLR_V_CHG_NZ }, + { "addb", "*,b->b", "add8", 2, 0xdb, 3, 3, CHG_HNZVC }, + { "ldd", "*->d", "movtst16", 2, 0xdc, 4, 4, CLR_V_CHG_NZ }, + { "std", "d->*", "movtst16", 2, 0xdd, 4, 4, CLR_V_CHG_NZ }, + { "ldx", "*->x", "movtst16", 2, 0xde, 4, 4, CLR_V_CHG_NZ }, + { "stx", "x->*", "movtst16", 2, 0xdf, 4, 4, CLR_V_CHG_NZ }, + { "subb", "(x),b->b", "sub8", 2, 0xe0, 4, 4, CHG_NZVC }, + { "cmpb", "(x),b", "sub8", 2, 0xe1, 4, 4, CHG_NZVC }, + { "sbcb", "(x),b->b", "sbc8", 2, 0xe2, 4, 4, CHG_NZVC }, + { "addd", "(x),d->d", "add16", 2, 0xe3, 6, 6, CHG_NZVC }, + { "andb", "(x),b->b", "and8", 2, 0xe4, 4, 4, CLR_V_CHG_NZ }, + { "bitb", "(x),b", "and8", 2, 0xe5, 4, 4, CLR_V_CHG_NZ }, + { "ldab", "(x)->b", "movtst8", 2, 0xe6, 4, 4, CLR_V_CHG_NZ }, + { "stab", "b->(x)", "movtst8", 2, 0xe7, 4, 4, CLR_V_CHG_NZ }, + { "eorb", "(x),b->b", "eor8", 2, 0xe8, 4, 4, CLR_V_CHG_NZ }, + { "adcb", "(x),b->b", "adc8", 2, 0xe9, 4, 4, CHG_HNZVC }, + { "orab", "(x),b->b", "or8", 2, 0xea, 4, 4, CLR_V_CHG_NZ }, + { "addb", "(x),b->b", "add8", 2, 0xeb, 4, 4, CHG_HNZVC }, + { "ldd", "(x)->d", "movtst16", 2, 0xec, 5, 5, CLR_V_CHG_NZ }, + { "std", "d->(x)", "movtst16", 2, 0xed, 5, 5, CLR_V_CHG_NZ }, + { "ldx", "(x)->x", "movtst16", 2, 0xee, 5, 5, CLR_V_CHG_NZ }, + { "stx", "x->(x)", "movtst16", 2, 0xef, 5, 5, CLR_V_CHG_NZ }, + { "subb", "(),b->b", "sub8", 3, 0xf0, 4, 4, CHG_NZVC }, + { "cmpb", "(),b", "sub8", 3, 0xf1, 4, 4, CHG_NZVC }, + { "sbcb", "(),b->b", "sbc8", 3, 0xf2, 4, 4, CHG_NZVC }, + { "addd", "(),d->d", "add16", 3, 0xf3, 6, 6, CHG_NZVC }, + { "andb", "(),b->b", "and8", 3, 0xf4, 4, 4, CLR_V_CHG_NZ }, + { "bitb", "(),b", "and8", 3, 0xf5, 4, 4, CLR_V_CHG_NZ }, + { "ldab", "()->b", "movtst8", 3, 0xf6, 4, 4, CLR_V_CHG_NZ }, + { "stab", "b->()", "movtst8", 3, 0xf7, 4, 4, CLR_V_CHG_NZ }, + { "eorb", "(),b->b", "eor8", 3, 0xf8, 4, 4, CLR_V_CHG_NZ }, + { "adcb", "(),b->b", "eor8", 3, 0xf9, 4, 4, CHG_HNZVC }, + { "orab", "(),b->b", "or8", 3, 0xfa, 4, 4, CLR_V_CHG_NZ }, + { "addb", "(),b->b", "add8", 3, 0xfb, 4, 4, CHG_HNZVC }, + { "ldd", "()->d", "movtst16", 3, 0xfc, 5, 5, CLR_V_CHG_NZ }, + { "std", "d->()", "movtst16", 3, 0xfd, 5, 5, CLR_V_CHG_NZ }, + { "ldx", "()->x", "movtst16", 3, 0xfe, 5, 5, CLR_V_CHG_NZ }, + { "stx", "x->()", "movtst16", 3, 0xff, 5, 5, CLR_V_CHG_NZ } +}; + + +/* Page 2 opcodes */ +/* + * { "dex", "x->x", "dec16", 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +----- Insn CCR changes + * Operands ---+ +------------ Max # cycles + * Pattern -----------+ +--------------- Min # cycles + * Size -----------------+ +-------------------- Opcode + */ +struct m6811_opcode_def m6811_page2_opcodes[] = { + { "iny", "y->y", "inc16", 2, 0x08, 4, 4, CHG_Z }, + { "dey", "y->y", "dec16", 2, 0x09, 4, 4, CHG_Z }, + { "bset", "(y),#->(y)","or8", 4, 0x1c, 8, 8, CLR_V_CHG_NZ }, + { "bclr", "(y),#->(y)","bclr8", 4, 0x1d, 8, 8, CLR_V_CHG_NZ }, + { "brset","(y),#,r", "brset8", 5, 0x1e, 8, 8, CHG_NONE }, + { "brclr","(y),#,r", "brclr8", 5, 0x1f, 8, 8, CHG_NONE }, + { "tsy", "sp->y", "tsxy16", 2, 0x30, 4, 4, CHG_NONE }, + { "tys", "y->sp", "txys16", 2, 0x35, 4, 4, CHG_NONE }, + { "puly", "(sp)->y", "mov16", 2, 0x38, 6, 6, CHG_NONE }, + { "aby", "b,y->y", "abxy16", 2, 0x3a, 4, 4, CHG_NONE }, + { "pshy", "y->(sp)", "mov16", 2, 0x3c, 5, 5, CHG_NONE }, + { "neg", "(y)->(y)", "neg8", 3, 0x60, 7, 7, CHG_NZVC }, + { "com", "(y)->(y)", "com8", 3, 0x63, 7, 7, SET_C_CLR_V_CHG_NZ}, + { "lsr", "(y)->(y)", "lsr8", 3, 0x64, 7, 7, CLR_V_CHG_ZVC }, + { "ror", "(y)->(y)", "ror8", 3, 0x66, 7, 7, CHG_NZVC }, + { "asr", "(y)->(y)", "asr8", 3, 0x67, 7, 7, CHG_NZVC }, + { "asl", "(y)->(y)", "lsl8", 3, 0x68, 7, 7, CHG_NZVC }, + { "rol", "(y)->(y)", "rol8", 3, 0x69, 7, 7, CHG_NZVC }, + { "dec", "(y)->(y)", "dec8", 3, 0x6a, 7, 7, CHG_NZV }, + { "inc", "(y)->(y)", "inc8", 3, 0x6c, 7, 7, CHG_NZV }, + { "tst", "(y)", "tst8", 3, 0x6d, 7, 7, CLR_V_CHG_NZ }, + { "jmp", "&(y)", "bra", 3, 0x6e, 4, 4, CHG_NONE }, + { "clr", "->(y)", "clr8", 3, 0x6f, 7, 7, SET_Z_CLR_NVC }, + { "cmpy", "#,y", "sub16", 4, 0x8c, 5, 5, CHG_NZVC }, + { "xgdy", "y->y", "xgdxy16", 2, 0x8f, 4, 4, CHG_NONE }, + { "cmpy", "*,y", "sub16", 3, 0x9c, 6, 6, CHG_NZVC }, + { "suba", "(y),a->a", "sub8", 3, 0xa0, 5, 5, CHG_NZVC }, + { "cmpa", "(y),a", "sub8", 3, 0xa1, 5, 5, CHG_NZVC }, + { "sbca", "(y),a->a", "sbc8", 3, 0xa2, 5, 5, CHG_NZVC }, + { "subd", "(y),d->d", "sub16", 3, 0xa3, 7, 7, CHG_NZVC }, + { "anda", "(y),a->a", "and8", 3, 0xa4, 5, 5, CLR_V_CHG_NZ }, + { "bita", "(y),a", "and8", 3, 0xa5, 5, 5, CLR_V_CHG_NZ }, + { "ldaa", "(y)->a", "movtst8", 3, 0xa6, 5, 5, CLR_V_CHG_NZ }, + { "staa", "a->(y)", "movtst8", 3, 0xa7, 5, 5, CLR_V_CHG_NZ }, + { "eora", "(y),a->a", "eor8", 3, 0xa8, 5, 5, CLR_V_CHG_NZ }, + { "adca", "(y),a->a", "adc8", 3, 0xa9, 5, 5, CHG_HNZVC }, + { "oraa", "(y),a->a", "or8", 3, 0xaa, 5, 5, CLR_V_CHG_NZ }, + { "adda", "(y),a->a", "add8", 3, 0xab, 5, 5, CHG_HNZVC }, + { "cmpy", "(y),y", "sub16", 3, 0xac, 7, 7, CHG_NZVC }, + { "jsr", "&(y)", "jsr_11_16", 3, 0xad, 6, 6, CHG_NONE }, + { "lds", "(y)->sp", "movtst16", 3, 0xae, 6, 6, CLR_V_CHG_NZ }, + { "sts", "sp->(y)", "movtst16", 3, 0xaf, 6, 6, CLR_V_CHG_NZ }, + { "cmpy", "(),y", "sub16", 4, 0xbc, 7, 7, CHG_NZVC }, + { "ldy", "#->y", "movtst16", 4, 0xce, 4, 4, CLR_V_CHG_NZ }, + { "ldy", "*->y", "movtst16", 3, 0xde, 5, 5, CLR_V_CHG_NZ }, + { "sty", "y->*", "movtst16", 3, 0xdf, 5, 5, CLR_V_CHG_NZ }, + { "subb", "(y),b->b", "sub8", 3, 0xe0, 5, 5, CHG_NZVC }, + { "cmpb", "(y),b", "sub8", 3, 0xe1, 5, 5, CHG_NZVC }, + { "sbcb", "(y),b->b", "sbc8", 3, 0xe2, 5, 5, CHG_NZVC }, + { "addd", "(y),d->d", "add16", 3, 0xe3, 7, 7, CHG_NZVC }, + { "andb", "(y),b->b", "and8", 3, 0xe4, 5, 5, CLR_V_CHG_NZ }, + { "bitb", "(y),b", "and8", 3, 0xe5, 5, 5, CLR_V_CHG_NZ }, + { "ldab", "(y)->b", "movtst8", 3, 0xe6, 5, 5, CLR_V_CHG_NZ }, + { "stab", "b->(y)", "movtst8", 3, 0xe7, 5, 5, CLR_V_CHG_NZ }, + { "eorb", "(y),b->b", "eor8", 3, 0xe8, 5, 5, CLR_V_CHG_NZ }, + { "adcb", "(y),b->b", "adc8", 3, 0xe9, 5, 5, CHG_HNZVC }, + { "orab", "(y),b->b", "or8", 3, 0xea, 5, 5, CLR_V_CHG_NZ }, + { "addb", "(y),b->b", "add8", 3, 0xeb, 5, 5, CHG_HNZVC }, + { "ldd", "(y)->d", "movtst16", 3, 0xec, 6, 6, CLR_V_CHG_NZ }, + { "std", "d->(y)", "movtst16", 3, 0xed, 6, 6, CLR_V_CHG_NZ }, + { "ldy", "(y)->y", "movtst16", 3, 0xee, 6, 6, CLR_V_CHG_NZ }, + { "sty", "y->(y)", "movtst16", 3, 0xef, 6, 6, CLR_V_CHG_NZ }, + { "ldy", "()->y", "movtst16", 4, 0xfe, 6, 6, CLR_V_CHG_NZ }, + { "sty", "y->()", "movtst16", 4, 0xff, 6, 6, CLR_V_CHG_NZ } +}; + +/* Page 3 opcodes */ +/* + * { "dex", "x->x", "dec16", 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +----- Insn CCR changes + * Operands ---+ +------------ Max # cycles + * Pattern -----------+ +--------------- Min # cycles + * Size -----------------+ +-------------------- Opcode + */ +struct m6811_opcode_def m6811_page3_opcodes[] = { + { "cmpd", "#,d", "sub16", 4, 0x83, 5, 5, CHG_NZVC }, + { "cmpd", "*,d", "sub16", 3, 0x93, 6, 6, CHG_NZVC }, + { "cmpd", "(x),d", "sub16", 3, 0xa3, 7, 7, CHG_NZVC }, + { "cmpy", "(x),y", "sub16", 3, 0xac, 7, 7, CHG_NZVC }, + { "cmpd", "(),d", "sub16", 4, 0xb3, 7, 7, CHG_NZVC }, + { "ldy", "(x)->y", "movtst16", 3, 0xee, 6, 6, CLR_V_CHG_NZ }, + { "sty", "y->(x)", "movtst16", 3, 0xef, 6, 6, CLR_V_CHG_NZ } +}; + +/* Page 4 opcodes */ +/* + * { "dex", "x->x", "dec16", 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +----- Insn CCR changes + * Operands ---+ +------------ Max # cycles + * Pattern -----------+ +--------------- Min # cycles + * Size -----------------+ +-------------------- Opcode + */ +struct m6811_opcode_def m6811_page4_opcodes[] = { + { "syscall", "", "syscall", 2, 0x03, 6, 6, CHG_NONE }, + { "cmpd", "(y),d", "sub16", 3, 0xa3, 7, 7, CHG_NZVC }, + { "cmpx", "(y),x", "sub16", 3, 0xac, 7, 7, CHG_NZVC }, + { "ldx", "(y)->x", "movtst16", 3, 0xee, 6, 6, CLR_V_CHG_NZ }, + { "stx", "x->(y)", "movtst16", 3, 0xef, 6, 6, CLR_V_CHG_NZ } +}; + +/* 68HC12 opcodes */ +/* + * { "dex", "x->x", "dec16", 1, 0x00, 5, _M, CHG_NONE }, + * Name -+ +----- Insn CCR changes + * Operands ---+ +------------ Max # cycles + * Pattern -----------+ +--------------- Min # cycles + * Size -----------------+ +-------------------- Opcode + */ +struct m6811_opcode_def m6812_page1_opcodes[] = { + { "adca", "#,a->a", "adc8", 2, 0x89, 1, 1, CHG_HNZVC }, + { "adca", "*,a->a", "adc8", 2, 0x99, 3, 3, CHG_HNZVC }, + { "adca", "(),a->a", "adc8", 3, 0xb9, 3, 3, CHG_HNZVC }, + { "adca", "[],a->a", "adc8", 2, 0xa9, 3, 3, CHG_HNZVC }, + + { "adcb", "#,b->b", "adc8", 2, 0xc9, 1, 1, CHG_HNZVC }, + { "adcb", "*,b->b", "adc8", 3, 0xd9, 3, 3, CHG_HNZVC }, + { "adcb", "(),b->b", "adc8", 3, 0xf9, 3, 3, CHG_HNZVC }, + { "adcb", "[],b->b", "adc8", 2, 0xe9, 3, 3, CHG_HNZVC }, + + { "adda", "#,a->a", "add8", 2, 0x8b, 1, 1, CHG_HNZVC }, + { "adda", "*,a->a", "add8", 3, 0x9b, 3, 3, CHG_HNZVC }, + { "adda", "(),a->a", "add8", 3, 0xbb, 3, 3, CHG_HNZVC }, + { "adda", "[],a->a", "add8", 2, 0xab, 3, 3, CHG_HNZVC }, + + { "addb", "#,b->b", "add8", 2, 0xcb, 1, 1, CHG_HNZVC }, + { "addb", "*,b->b", "add8", 3, 0xdb, 3, 3, CHG_HNZVC }, + { "addb", "(),b->b", "add8", 3, 0xfb, 3, 3, CHG_HNZVC }, + { "addb", "[],b->b", "add8", 2, 0xeb, 3, 3, CHG_HNZVC }, + + { "addd", "#,d->d", "add16", 3, 0xc3, 2, 2, CHG_NZVC }, + { "addd", "*,d->d", "add16", 2, 0xd3, 3, 3, CHG_NZVC }, + { "addd", "(),d->d", "add16", 3, 0xf3, 3, 3, CHG_NZVC }, + { "addd", "[],d->d", "add16", 2, 0xe3, 3, 3, CHG_NZVC }, + + { "anda", "#,a->a", "and8", 2, 0x84, 1, 1, CLR_V_CHG_NZ }, + { "anda", "*,a->a", "and8", 2, 0x94, 3, 3, CLR_V_CHG_NZ }, + { "anda", "(),a->a", "and8", 3, 0xb4, 3, 3, CLR_V_CHG_NZ }, + { "anda", "[],a->a", "and8", 2, 0xa4, 3, 3, CLR_V_CHG_NZ }, + + { "andb", "#,b->b", "and8", 2, 0xc4, 1, 1, CLR_V_CHG_NZ }, + { "andb", "*,b->b", "and8", 2, 0xd4, 3, 3, CLR_V_CHG_NZ }, + { "andb", "(),b->b", "and8", 3, 0xf4, 3, 3, CLR_V_CHG_NZ }, + { "andb", "[],b->b", "and8", 2, 0xe4, 3, 3, CLR_V_CHG_NZ }, + + { "andcc", "#,ccr->ccr", "and8", 2, 0x10, 1, 1, CHG_ALL }, + + { "asl", "()->()", "lsl8", 3, 0x78, 4, 4, CHG_NZVC }, + { "asl", "[]->[]", "lsl8", 2, 0x68, 3, 3, CHG_NZVC }, + + { "asla", "a->a", "lsl8", 1, 0x48, 1, 1, CHG_NZVC }, + { "aslb", "b->b", "lsl8", 1, 0x58, 1, 1, CHG_NZVC }, + { "asld", "d->d", "lsl16", 1, 0x59, 1, 1, CHG_NZVC }, + + { "asr", "()->()", "asr8", 3, 0x77, 4, 4, CHG_NZVC }, + { "asr", "[]->[]", "asr8", 2, 0x67, 3, 3, CHG_NZVC }, + + { "asra", "a->a", "asr8", 1, 0x47, 1, 1, CHG_NZVC }, + { "asrb", "b->b", "asr8", 1, 0x57, 1, 1, CHG_NZVC }, + + { "bcc", "r", 0, 2, 0x24, 1, 3, CHG_NONE }, + + { "bclr", "*,#->*", "bclr8", 3, 0x4d, 4, 4, CLR_V_CHG_NZ }, + { "bclr", "(),#->()", "bclr8", 4, 0x1d, 4, 4, CLR_V_CHG_NZ }, + { "bclr", "[],#->[]", "bclr8", 3, 0x0d, 4, 4, CLR_V_CHG_NZ }, + + { "bcs", "r", 0, 2, 0x25, 1, 3, CHG_NONE }, + { "beq", "r", 0, 2, 0x27, 1, 3, CHG_NONE }, + { "bge", "r", 0, 2, 0x2c, 1, 3, CHG_NONE }, + + { "bgnd", 0, 0, 1, 0x00, 5, 5, CHG_NONE }, + + { "bgt", "r", 0, 2, 0x2e, 1, 3, CHG_NONE }, + { "bhi", "r", 0, 2, 0x22, 1, 3, CHG_NONE }, + + { "bita", "#,a", "and8", 2, 0x85, 1, 1, CLR_V_CHG_NZ }, + { "bita", "*,a", "and8", 2, 0x95, 3, 3, CLR_V_CHG_NZ }, + { "bita", "(),a", "and8", 3, 0xb5, 3, 3, CLR_V_CHG_NZ }, + { "bita", "[],a", "and8", 2, 0xa5, 3, 3, CLR_V_CHG_NZ }, + + { "bitb", "#,b", "and8", 2, 0xc5, 1, 1, CLR_V_CHG_NZ }, + { "bitb", "*,b", "and8", 2, 0xd5, 3, 3, CLR_V_CHG_NZ }, + { "bitb", "(),b", "and8", 3, 0xf5, 3, 3, CLR_V_CHG_NZ }, + { "bitb", "[],b", "and8", 2, 0xe5, 3, 3, CLR_V_CHG_NZ }, + + { "ble", "r", 0, 2, 0x2f, 1, 3, CHG_NONE }, + { "bls", "r", 0, 2, 0x23, 1, 3, CHG_NONE }, + { "blt", "r", 0, 2, 0x2d, 1, 3, CHG_NONE }, + { "bmi", "r", 0, 2, 0x2b, 1, 3, CHG_NONE }, + { "bne", "r", 0, 2, 0x26, 1, 3, CHG_NONE }, + { "bpl", "r", 0, 2, 0x2a, 1, 3, CHG_NONE }, + { "bra", "r", 0, 2, 0x20, 1, 3, CHG_NONE }, + + { "brclr", "*,#,r", "brclr8", 4, 0x4f, 4, 4, CHG_NONE }, + { "brclr", "(),#,r", "brclr8", 5, 0x1f, 5, 5, CHG_NONE }, + { "brclr", "[],#,r", "brclr8", 4, 0x0f, 4, 4, CHG_NONE }, + + { "brn", "r", "nop", 2, 0x21, 1, 3, CHG_NONE }, + + { "brset", "*,#,r", "brset8", 4, 0x4e, 4, 4, CHG_NONE }, + { "brset", "(),#,r", "brset8", 5, 0x1e, 5, 5, CHG_NONE }, + { "brset", "[],#,r", "brset8", 4, 0x0e, 4, 4, CHG_NONE }, + + { "bset", "*,#->*", "or8", 3, 0x4c, 4, 4, CLR_V_CHG_NZ }, + { "bset", "(),#->()", "or8", 4, 0x1c, 4, 4, CLR_V_CHG_NZ }, + { "bset", "[],#->[]", "or8", 3, 0x0c, 4, 4, CLR_V_CHG_NZ }, + + { "bsr", "r", "jsr_12_16", 2, 0x07, 4, 4, CHG_NONE }, + + { "bvc", "r", 0, 2, 0x28, 1, 3, CHG_NONE }, + { "bvs", "r", 0, 2, 0x29, 1, 3, CHG_NONE }, + + { "call", "", "call8", 4, 0x4a, 8, 8, CHG_NONE }, + { "call", "", "call_ind",2, 0x4b, 8, 8, CHG_NONE }, + + { "clr", "->()", "clr8", 3, 0x79, 3, 3, SET_Z_CLR_NVC }, + { "clr", "->[]", "clr8", 2, 0x69, 2, 2, SET_Z_CLR_NVC }, + + { "clra", "->a", "clr8", 1, 0x87, 1, 1, SET_Z_CLR_NVC }, + { "clrb", "->b", "clr8", 1, 0xc7, 1, 1, SET_Z_CLR_NVC }, + + { "cpa", "#,a", "sub8", 2, 0x81, 1, 1, CHG_NZVC }, + { "cpa", "*,a", "sub8", 2, 0x91, 3, 3, CHG_NZVC }, + { "cpa", "(),a", "sub8", 3, 0xb1, 3, 3, CHG_NZVC }, + { "cpa", "[],a", "sub8", 2, 0xa1, 3, 3, CHG_NZVC }, + + { "cpb", "#,b", "sub8", 2, 0xc1, 1, 1, CHG_NZVC }, + { "cpb", "*,b", "sub8", 2, 0xd1, 3, 3, CHG_NZVC }, + { "cpb", "(),b", "sub8", 3, 0xf1, 3, 3, CHG_NZVC }, + { "cpb", "[],b", "sub8", 2, 0xe1, 3, 3, CHG_NZVC }, + + { "com", "()->()", "com8", 3, 0x71, 4, 4, SET_C_CLR_V_CHG_NZ }, + { "com", "[]->[]", "com8", 2, 0x61, 3, 3, SET_C_CLR_V_CHG_NZ }, + + { "coma", "a->a", "com8", 1, 0x41, 1, 1, SET_C_CLR_V_CHG_NZ }, + { "comb", "b->b", "com8", 1, 0x51, 1, 1, SET_C_CLR_V_CHG_NZ }, + + { "cpd", "#,d", "sub16", 3, 0x8c, 2, 2, CHG_NZVC }, + { "cpd", "*,d", "sub16", 2, 0x9c, 3, 3, CHG_NZVC }, + { "cpd", "(),d", "sub16", 3, 0xbc, 3, 3, CHG_NZVC }, + { "cpd", "[],d", "sub16", 2, 0xac, 3, 3, CHG_NZVC }, + + { "cps", "#,sp", "sub16", 3, 0x8f, 2, 2, CHG_NZVC }, + { "cps", "*,sp", "sub16", 2, 0x9f, 3, 3, CHG_NZVC }, + { "cps", "(),sp", "sub16", 3, 0xbf, 3, 3, CHG_NZVC }, + { "cps", "[],sp", "sub16", 2, 0xaf, 3, 3, CHG_NZVC }, + + { "cpx", "#,x", "sub16", 3, 0x8e, 2, 2, CHG_NZVC }, + { "cpx", "*,x", "sub16", 2, 0x9e, 3, 3, CHG_NZVC }, + { "cpx", "(),x", "sub16", 3, 0xbe, 3, 3, CHG_NZVC }, + { "cpx", "[],x", "sub16", 2, 0xae, 3, 3, CHG_NZVC }, + + { "cpy", "#,y", "sub16", 3, 0x8d, 2, 2, CHG_NZVC }, + { "cpy", "*,y", "sub16", 2, 0x9d, 3, 3, CHG_NZVC }, + { "cpy", "(),y", "sub16", 3, 0xbd, 3, 3, CHG_NZVC }, + { "cpy", "[],y", "sub16", 2, 0xad, 3, 3, CHG_NZVC }, + + /* dbeq, dbne, ibeq, ibne, tbeq, tbne */ + { "dbeq", 0, "dbcc8", 3, 0x04, 3, 3, CHG_NONE }, + + { "dec", "()->()", "dec8", 3, 0x73, 4, 4, CHG_NZV }, + { "dec", "[]->[]", "dec8", 2, 0x63, 3, 3, CHG_NZV }, + + { "deca", "a->a", "dec8", 1, 0x43, 1, 1, CHG_NZV }, + { "decb", "b->b", "dec8", 1, 0x53, 1, 1, CHG_NZV }, + + { "dex", "x->x", "dec16", 1, 0x09, 1, 1, CHG_Z }, + { "dey", "y->y", "dec16", 1, 0x03, 1, 1, CHG_Z }, + + { "ediv", 0, 0, 1, 0x11, 11, 11, CHG_NZVC }, + { "emul", 0, 0, 1, 0x13, 3, 3, CHG_NZC }, + + { "eora", "#,a->a", "eor8", 2, 0x88, 1, 1, CLR_V_CHG_NZ }, + { "eora", "*,a->a", "eor8", 2, 0x98, 3, 3, CLR_V_CHG_NZ }, + { "eora", "(),a->a", "eor8", 3, 0xb8, 3, 3, CLR_V_CHG_NZ }, + { "eora", "[],a->a", "eor8", 2, 0xa8, 3, 3, CLR_V_CHG_NZ }, + + { "eorb", "#,b->b", "eor8", 2, 0xc8, 1, 1, CLR_V_CHG_NZ }, + { "eorb", "*,b->b", "eor8", 2, 0xd8, 3, 3, CLR_V_CHG_NZ }, + { "eorb", "(),b->b", "eor8", 3, 0xf8, 3, 3, CLR_V_CHG_NZ }, + { "eorb", "[],b->b", "eor8", 2, 0xe8, 3, 3, CLR_V_CHG_NZ }, + + /* exg, sex, tfr */ + { "exg", "#", "exg8", 2, 0xb7, 1, 1, CHG_NONE }, + + { "inc", "()->()", "inc8", 3, 0x72, 4, 4, CHG_NZV }, + { "inc", "[]->[]", "inc8", 2, 0x62, 3, 3, CHG_NZV }, + + { "inca", "a->a", "inc8", 1, 0x42, 1, 1, CHG_NZV }, + { "incb", "b->b", "inc8", 1, 0x52, 1, 1, CHG_NZV }, + + { "inx", "x->x", "inc16", 1, 0x08, 1, 1, CHG_Z }, + { "iny", "y->y", "inc16", 1, 0x02, 1, 1, CHG_Z }, + + { "jmp", "&()", "bra", 3, 0x06, 3, 3, CHG_NONE }, + { "jmp", "&[]", "bra", 2, 0x05, 3, 3, CHG_NONE }, + + { "jsr", "*", "jsr_12_16", 2, 0x17, 4, 4, CHG_NONE }, + { "jsr", "&()", "jsr_12_16", 3, 0x16, 4, 4, CHG_NONE }, + { "jsr", "&[]", "jsr_12_16", 2, 0x15, 4, 4, CHG_NONE }, + + { "ldaa", "#->a", "movtst8", 2, 0x86, 1, 1, CLR_V_CHG_NZ }, + { "ldaa", "*->a", "movtst8", 2, 0x96, 3, 3, CLR_V_CHG_NZ }, + { "ldaa", "()->a", "movtst8", 3, 0xb6, 3, 3, CLR_V_CHG_NZ }, + { "ldaa", "[]->a", "movtst8", 2, 0xa6, 3, 3, CLR_V_CHG_NZ }, + + { "ldab", "#->b", "movtst8", 2, 0xc6, 1, 1, CLR_V_CHG_NZ }, + { "ldab", "*->b", "movtst8", 2, 0xd6, 3, 3, CLR_V_CHG_NZ }, + { "ldab", "()->b", "movtst8", 3, 0xf6, 3, 3, CLR_V_CHG_NZ }, + { "ldab", "[]->b", "movtst8", 2, 0xe6, 3, 3, CLR_V_CHG_NZ }, + + { "ldd", "#->d", "movtst16", 3, 0xcc, 2, 2, CLR_V_CHG_NZ }, + { "ldd", "*->d", "movtst16", 2, 0xdc, 3, 3, CLR_V_CHG_NZ }, + { "ldd", "()->d", "movtst16", 3, 0xfc, 3, 3, CLR_V_CHG_NZ }, + { "ldd", "[]->d", "movtst16", 2, 0xec, 3, 3, CLR_V_CHG_NZ }, + + { "lds", "#->sp", "movtst16", 3, 0xcf, 2, 2, CLR_V_CHG_NZ }, + { "lds", "*->sp", "movtst16", 2, 0xdf, 3, 3, CLR_V_CHG_NZ }, + { "lds", "()->sp", "movtst16", 3, 0xff, 3, 3, CLR_V_CHG_NZ }, + { "lds", "[]->sp", "movtst16", 2, 0xef, 3, 3, CLR_V_CHG_NZ }, + + { "ldx", "#->x", "movtst16", 3, 0xce, 2, 2, CLR_V_CHG_NZ }, + { "ldx", "*->x", "movtst16", 2, 0xde, 3, 3, CLR_V_CHG_NZ }, + { "ldx", "()->x", "movtst16", 3, 0xfe, 3, 3, CLR_V_CHG_NZ }, + { "ldx", "[]->x", "movtst16", 2, 0xee, 3, 3, CLR_V_CHG_NZ }, + + { "ldy", "#->y", "movtst16", 3, 0xcd, 2, 2, CLR_V_CHG_NZ }, + { "ldy", "*->y", "movtst16", 2, 0xdd, 3, 3, CLR_V_CHG_NZ }, + { "ldy", "()->y", "movtst16", 3, 0xfd, 3, 3, CLR_V_CHG_NZ }, + { "ldy", "[]->y", "movtst16", 2, 0xed, 3, 3, CLR_V_CHG_NZ }, + + { "leas", "&[]->sp", "lea16", 2, 0x1b, 2, 2, CHG_NONE }, + { "leax", "&[]->x", "lea16", 2, 0x1a, 2, 2, CHG_NONE }, + { "leay", "&[]->y", "lea16", 2, 0x19, 2, 2, CHG_NONE }, + + { "lsr", "()->()", "lsr8", 3, 0x74, 4, 4, CLR_N_CHG_ZVC }, + { "lsr", "[]->[]", "lsr8", 2, 0x64, 3, 3, CLR_N_CHG_ZVC }, + + { "lsra", "a->a", "lsr8", 1, 0x44, 1, 1, CLR_N_CHG_ZVC }, + { "lsrb", "b->b", "lsr8", 1, 0x54, 1, 1, CLR_N_CHG_ZVC }, + { "lsrd", "d->d", "lsr16", 1, 0x49, 1, 1, CLR_N_CHG_ZVC }, + + { "mem", 0, 0, 1, 0x01, 5, 5, CHG_HNZVC }, + + { "mul", "b,a->d", "mul16", 1, 0x12, 3, 3, CHG_C }, + + { "neg", "()->()", "neg8", 3, 0x70, 4, 4, CHG_NZVC }, + { "neg", "[]->[]", "neg8", 2, 0x60, 3, 3, CHG_NZVC }, + + { "nega", "a->a", "neg8", 1, 0x40, 1, 1, CHG_NZVC }, + { "negb", "b->b", "neg8", 1, 0x50, 1, 1, CHG_NZVC }, + + { "nop", "", "nop", 1, 0xa7, 1, 1, CHG_NONE }, + + { "oraa", "#,a->a", "or8", 2, 0x8a, 1, 1, CLR_V_CHG_NZ }, + { "oraa", "*,a->a", "or8", 2, 0x9a, 3, 3, CLR_V_CHG_NZ }, + { "oraa", "(),a->a", "or8", 3, 0xba, 3, 3, CLR_V_CHG_NZ }, + { "oraa", "[],a->a", "or8", 2, 0xaa, 3, 3, CLR_V_CHG_NZ }, + + { "orab", "#,b->b", "or8", 2, 0xca, 1, 1, CLR_V_CHG_NZ }, + { "orab", "*,b->b", "or8", 2, 0xda, 3, 3, CLR_V_CHG_NZ }, + { "orab", "(),b->b", "or8", 3, 0xfa, 3, 3, CLR_V_CHG_NZ }, + { "orab", "[],b->b", "or8", 2, 0xea, 3, 3, CLR_V_CHG_NZ }, + + { "orcc", "#,ccr->ccr", "or8", 2, 0x14, 1, 1, CHG_ALL }, + + { "page2", 0, "page2", 1, 0x18, 0, 0, CHG_NONE }, + + { "psha", "a->(sp)", "mov8", 1, 0x36, 2, 2, CHG_NONE }, + { "pshb", "b->(sp)", "mov8", 1, 0x37, 2, 2, CHG_NONE }, + { "pshc", "ccr->(sp)", "mov8", 1, 0x39, 2, 2, CHG_NONE }, + { "pshd", "d->(sp)", "mov16", 1, 0x3b, 2, 2, CHG_NONE }, + { "pshx", "x->(sp)", "mov16", 1, 0x34, 2, 2, CHG_NONE }, + { "pshy", "y->(sp)", "mov16", 1, 0x35, 2, 2, CHG_NONE }, + + { "pula", "(sp)->a", "mov8", 1, 0x32, 3, 3, CHG_NONE }, + { "pulb", "(sp)->b", "mov8", 1, 0x33, 3, 3, CHG_NONE }, + { "pulc", "(sp)->ccr", "mov8", 1, 0x38, 3, 3, CHG_ALL }, + { "puld", "(sp)->d", "mov16", 1, 0x3a, 3, 3, CHG_NONE }, + { "pulx", "(sp)->x", "mov16", 1, 0x30, 3, 3, CHG_NONE }, + { "puly", "(sp)->y", "mov16", 1, 0x31, 3, 3, CHG_NONE }, + + { "rol", "()->()", "rol8", 3, 0x75, 4, 4, CHG_NZVC }, + { "rol", "[]->[]", "rol8", 2, 0x65, 3, 3, CHG_NZVC }, + + { "rola", "a->a", "rol8", 1, 0x45, 1, 1, CHG_NZVC }, + { "rolb", "b->b", "rol8", 1, 0x55, 1, 1, CHG_NZVC }, + + { "ror", "()->()", "ror8", 3, 0x76, 4, 4, CHG_NZVC }, + { "ror", "[]->[]", "ror8", 2, 0x66, 3, 3, CHG_NZVC }, + + { "rora", "a->a", "ror8", 1, 0x46, 1, 1, CHG_NZVC }, + { "rorb", "b->b", "ror8", 1, 0x56, 1, 1, CHG_NZVC }, + + { "rtc", 0, 0, 1, 0x0a, 6, 6, CHG_NONE }, + { "rti", 0, "rti12", 1, 0x0b, 8, 10, CHG_ALL}, + { "rts", 0, "rts12", 1, 0x3d, 5, 5, CHG_NONE }, + + { "sbca", "#,a->a", "sbc8", 2, 0x82, 1, 1, CHG_NZVC }, + { "sbca", "*,a->a", "sbc8", 2, 0x92, 3, 3, CHG_NZVC }, + { "sbca", "(),a->a", "sbc8", 3, 0xb2, 3, 3, CHG_NZVC }, + { "sbca", "[],a->a", "sbc8", 2, 0xa2, 3, 3, CHG_NZVC }, + + { "sbcb", "#,b->b", "sbc8", 2, 0xc2, 1, 1, CHG_NZVC }, + { "sbcb", "*,b->b", "sbc8", 2, 0xd2, 3, 3, CHG_NZVC }, + { "sbcb", "(),b->b", "sbc8", 3, 0xf2, 3, 3, CHG_NZVC }, + { "sbcb", "[],b->b", "sbc8", 2, 0xe2, 3, 3, CHG_NZVC }, + + { "staa", "a->*", "movtst8", 2, 0x5a, 2, 2, CLR_V_CHG_NZ }, + { "staa", "a->()", "movtst8", 3, 0x7a, 3, 3, CLR_V_CHG_NZ }, + { "staa", "a->[]", "movtst8", 2, 0x6a, 2, 2, CLR_V_CHG_NZ }, + + { "stab", "b->*", "movtst8", 2, 0x5b, 2, 2, CLR_V_CHG_NZ }, + { "stab", "b->()", "movtst8", 3, 0x7b, 3, 3, CLR_V_CHG_NZ }, + { "stab", "b->[]", "movtst8", 2, 0x6b, 2, 2, CLR_V_CHG_NZ }, + + { "std", "d->*", "movtst16", 2, 0x5c, 2, 2, CLR_V_CHG_NZ }, + { "std", "d->()", "movtst16", 3, 0x7c, 3, 3, CLR_V_CHG_NZ }, + { "std", "d->[]", "movtst16", 2, 0x6c, 2, 2, CLR_V_CHG_NZ }, + + { "sts", "sp->*", "movtst16", 2, 0x5f, 2, 2, CLR_V_CHG_NZ }, + { "sts", "sp->()", "movtst16", 3, 0x7f, 3, 3, CLR_V_CHG_NZ }, + { "sts", "sp->[]", "movtst16", 2, 0x6f, 2, 2, CLR_V_CHG_NZ }, + + { "stx", "x->*", "movtst16", 2, 0x5e, 2, 2, CLR_V_CHG_NZ }, + { "stx", "x->()", "movtst16", 3, 0x7e, 3, 3, CLR_V_CHG_NZ }, + { "stx", "x->[]", "movtst16", 2, 0x6e, 2, 2, CLR_V_CHG_NZ }, + + { "sty", "y->*", "movtst16", 2, 0x5d, 2, 2, CLR_V_CHG_NZ }, + { "sty", "y->()", "movtst16", 3, 0x7d, 3, 3, CLR_V_CHG_NZ }, + { "sty", "y->[]", "movtst16", 2, 0x6d, 2, 2, CLR_V_CHG_NZ }, + + { "suba", "#,a->a", "sub8", 2, 0x80, 1, 1, CHG_NZVC }, + { "suba", "*,a->a", "sub8", 2, 0x90, 3, 3, CHG_NZVC }, + { "suba", "(),a->a", "sub8", 3, 0xb0, 3, 3, CHG_NZVC }, + { "suba", "[],a->a", "sub8", 2, 0xa0, 3, 3, CHG_NZVC }, + + { "subb", "#,b->b", "sub8", 2, 0xc0, 1, 1, CHG_NZVC }, + { "subb", "*,b->b", "sub8", 2, 0xd0, 3, 3, CHG_NZVC }, + { "subb", "(),b->b", "sub8", 3, 0xf0, 3, 3, CHG_NZVC }, + { "subb", "[],b->b", "sub8", 2, 0xe0, 3, 3, CHG_NZVC }, + + { "subd", "#,d->d", "sub16", 3, 0x83, 2, 2, CHG_NZVC }, + { "subd", "*,d->d", "sub16", 2, 0x93, 3, 3, CHG_NZVC }, + { "subd", "(),d->d", "sub16", 3, 0xb3, 3, 3, CHG_NZVC }, + { "subd", "[],d->d", "sub16", 2, 0xa3, 3, 3, CHG_NZVC }, + + { "swi", 0, 0, 1, 0x3f, 9, 9, CHG_NONE }, + + { "tst", "()", "tst8", 3, 0xf7, 3, 3, CLR_VC_CHG_NZ }, + { "tst", "[]", "tst8", 2, 0xe7, 3, 3, CLR_VC_CHG_NZ }, + + { "tsta", "a", "tst8", 1, 0x97, 1, 1, CLR_VC_CHG_NZ }, + { "tstb", "b", "tst8", 1, 0xd7, 1, 1, CLR_VC_CHG_NZ }, + + { "wai", 0, 0, 1, 0x3e, 8, _M, CHG_NONE } +}; + +struct m6811_opcode_def m6812_page2_opcodes[] = { + { "cba", "b,a", "sub8", 2, 0x17, 2, 2, CHG_NZVC }, + + /* After 'daa', the Z flag is undefined. Mark it as changed. */ + { "daa", 0, "daa8", 2, 0x07, 3, 3, CHG_NZVC }, + + { "edivs", 0, 0, 2, 0x14, 12, 12, CHG_NZVC }, + { "emacs", 0, 0, 2, 0x12, 13, 13, CHG_NZVC }, + + { "emaxd", "[],d->d", "max16", 3, 0x1a, 4, 4, CHG_NZVC }, + { "emaxm", "[],d->[]", "max16", 3, 0x1e, 4, 4, CHG_NZVC }, + { "emind", "[],d->d", "min16", 3, 0x1b, 4, 4, CHG_NZVC }, + { "eminm", "[],d->[]", "min16", 3, 0x1f, 4, 4, CHG_NZVC }, + + { "emuls", 0, 0, 2, 0x13, 3, 3, CHG_NZC }, + { "etbl", "[]", "tbl16", 3, 0x3f, 10, 10, CHG_NZC }, + { "fdiv", "x,d->x", "fdiv16", 2, 0x11, 12, 12, CHG_ZVC }, + { "idiv", "x,d->x", "idiv16", 2, 0x10, 12, 12, CLR_V_CHG_ZC }, + { "idivs", 0, 0, 2, 0x15, 12, 12, CHG_NZVC }, + + { "lbcc", "R", "bcc", 4, 0x24, 3, 4, CHG_NONE }, + { "lbcs", "R", "bcs", 4, 0x25, 3, 4, CHG_NONE }, + { "lbeq", "R", "beq", 4, 0x27, 3, 4, CHG_NONE }, + { "lbge", "R", "bge", 4, 0x2c, 3, 4, CHG_NONE }, + { "lbgt", "R", "bgt", 4, 0x2e, 3, 4, CHG_NONE }, + { "lbhi", "R", "bhi", 4, 0x22, 3, 4, CHG_NONE }, + { "lble", "R", "ble", 4, 0x2f, 3, 4, CHG_NONE }, + { "lbls", "R", "bls", 4, 0x23, 3, 4, CHG_NONE }, + { "lblt", "R", "blt", 4, 0x2d, 3, 4, CHG_NONE }, + { "lbmi", "R", "bmi", 4, 0x2b, 3, 4, CHG_NONE }, + { "lbne", "R", "bne", 4, 0x26, 3, 4, CHG_NONE }, + { "lbpl", "R", "bpl", 4, 0x2a, 3, 4, CHG_NONE }, + { "lbra", "R", "bra", 4, 0x20, 4, 4, CHG_NONE }, + { "lbrn", "R", "nop", 4, 0x21, 3, 3, CHG_NONE }, + { "lbvc", "R", "bvc", 4, 0x28, 3, 4, CHG_NONE }, + { "lbvs", "R", "bvs", 4, 0x29, 3, 4, CHG_NONE }, + + { "maxa", "[],a->a", "max8", 3, 0x18, 4, 4, CHG_NZVC }, + { "maxm", "[],a->[]", "max8", 3, 0x1c, 4, 4, CHG_NZVC }, + { "mina", "[],a->a", "min8", 3, 0x19, 4, 4, CHG_NZVC }, + { "minm", "[],a->[]", "min8", 3, 0x1d, 4, 4, CHG_NZVC }, + + { "movb", 0, "move8", 5, 0x0b, 4, 4, CHG_NONE }, + { "movb", 0, "move8", 4, 0x08, 4, 4, CHG_NONE }, + { "movb", 0, "move8", 6, 0x0c, 6, 6, CHG_NONE }, + { "movb", 0, "move8", 5, 0x09, 5, 5, CHG_NONE }, + { "movb", 0, "move8", 5, 0x0d, 5, 5, CHG_NONE }, + { "movb", 0, "move8", 4, 0x0a, 5, 5, CHG_NONE }, + + { "movw", 0, "move16", 6, 0x03, 5, 5, CHG_NONE }, + { "movw", 0, "move16", 5, 0x00, 4, 4, CHG_NONE }, + { "movw", 0, "move16", 6, 0x04, 6, 6, CHG_NONE }, + { "movw", 0, "move16", 5, 0x01, 5, 5, CHG_NONE }, + { "movw", 0, "move16", 5, 0x05, 5, 5, CHG_NONE }, + { "movw", 0, "move16", 4, 0x02, 5, 5, CHG_NONE }, + + { "rev", 0, 0, 2, 0x3a, _M, _M, CHG_HNZVC }, + { "revw", 0, 0, 2, 0x3b, _M, _M, CHG_HNZVC }, + { "sba", "b,a->a", "sub8", 2, 0x16, 2, 2, CHG_NZVC }, + + { "stop", 0, 0, 2, 0x3e, 2, 9, CHG_NONE }, + + { "tab", "a->b", "movtst8", 2, 0x0e, 2, 2, CLR_V_CHG_NZ }, + { "tba", "b->a", "movtst8", 2, 0x0f, 2, 2, CLR_V_CHG_NZ }, + + { "wav", 0, 0, 2, 0x3c, 8, _M, SET_Z_CHG_HNVC } +}; + +void fatal_error (const struct m6811_opcode_def*, const char*, ...); +void print (FILE*, int, const char*,...); +int gen_fetch_operands (FILE*, int, const struct m6811_opcode_def*, + const char*); +void gen_save_result (FILE*, int, const struct m6811_opcode_def*, + int, const char*); +const struct m6811_opcode_pattern* +find_opcode_pattern (const struct m6811_opcode_def*); +void gen_interp (FILE*, int, const struct m6811_opcode_def*); +void gen_interpreter_for_table (FILE*, int, + const struct m6811_opcode_def*, + int, const char*); +void gen_interpreter (FILE*); + + +static int indent_level = 2; +static int current_insn_size = 0; + +/* Fatal error message and exit. This method is called when an inconsistency + is detected in the generation table. */ +void +fatal_error (const struct m6811_opcode_def *opcode, const char *msg, ...) +{ + va_list argp; + + fprintf (stderr, "Fatal error: "); + va_start (argp, msg); + vfprintf (stderr, msg, argp); + va_end (argp); + fprintf (stderr, "\n"); + if (opcode) + { + fprintf (stderr, "Opcode: 0x%02x %s %s\n", + opcode->insn_code, + opcode->name ? opcode->name : "(null)", + opcode->operands ? opcode->operands : "(null)"); + } + exit (1); +} + + +/* Format and pretty print for the code generation. (printf like format). */ +void +print (FILE *fp, int col, const char *msg, ...) +{ + va_list argp; + char buf[1024]; + int cur_col = -1; + int i; + + /* Format in a buffer. */ + va_start (argp, msg); + vsprintf (buf, msg, argp); + va_end (argp); + + /* Basic pretty print: + - Every line is indented at column 'col', + - Indentation is updated when '{' and '}' are found, + - Indentation is incremented by the special character '@' (not displayed). + - New lines inserted automatically after ';' */ + for (i = 0; buf[i]; i++) + { + if (buf[i] == '{') + col += indent_level; + else if (buf[i] == '}') + col -= indent_level; + else if (buf[i] == '@') + { + col += indent_level; + continue; + } + if (cur_col == -1 && buf[i] != ' ' && buf[i] != '\t' && buf[i] != '\n') + { + cur_col = 0; + while (cur_col < col) + { + fputc (' ', fp); + cur_col++; + } + } + if (buf[i] == '}') + col -= indent_level; + else if (buf[i] == '{') + col += indent_level; + else if (buf[i] == '\n') + cur_col = -1; + + if (cur_col != -1 || buf[i] == '\n') + fputc (buf[i], fp); + + if (buf[i] == ';') + { + fputc ('\n', fp); + cur_col = -1; + } + } +} + + +/* Generate the code to obtain the operands before execution of the + instruction. Operands are copied in local variables. This allows to + have the same instruction pattern and different operand formats. + There is a maximum of 3 variables: + + 8-bits 16-bits + 1st operand: src8 src16 + 2nd operand: dst8 dst16 + alt operand: addr addr + + The operand string is interpreted as follows: + + a Copy A register in the local 8-bits variable. + b " B " + ccr " ccr " + d " D " " " 16-bits variable. + x " X " + y " Y " + sp " SP " + pc " PC " + * 68HC11 page0 memory pointer. + Get 8-bits page0 offset from program, set up 'addr' local + variable to refer to the location in page0. + Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable. + (x) 68HC11 indirect access with X register. + Get 8-bits unsigned offset from program, set up 'addr' = X + offset. + Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable. + (y) Same as (x) with Y register. + () 68HC11 extended address mode (global variable). + Get 16-bits address from program and set 'addr'. + Copy the 8/16-bits value pointed to by 'addr' in a 8/16-bits variable. + [] 68HC12 indexed addressing mode + (sp) Pop + Pop a 8/16-bits value from stack and set in a 8/16-bits variable. + r Relative branch + Get 8-bits relative branch, compute absolute address and set 'addr' + # 68HC11 immediate value + Get a 8/16-bits value from program and set a 8/16-bits variable. + &(x) + &(y) + &() Similar to (x), (y) and () except that we don't read the + value pointed to by 'addr' (ie, only 'addr' is setup). Used by jmp/jsr. + &[] Similar to [] but don't read the value pointed to by the address. + , Operand separator. + - End of input operands. + + Example: + (x),a->a addr = x + (uint16) (fetch8 (proc)); + src8 = a + *,#,r addr = (uint16) (fetch8 (proc)) <- Temporary 'addr' + src8 = read_mem8 (proc, addr) + dst8 = fetch8 (proc) + addr = fetch_relbranch (proc) <- Final 'addr' + + Returns 1 if the 'addr' operand is set, 0 otherwise. */ +int +gen_fetch_operands (FILE *fp, int col, + const struct m6811_opcode_def *opcode, + const char *operand_size) +{ + static char *vars[2] = { + "src", + "dst" + }; + char c; + int addr_set = 0; + int cur_var = 0; + const char *operands = opcode->operands; + + if (operands == 0) + operands = ""; + + while ((c = *operands++) != 0) + { + switch (c) + { + case 'a': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + print (fp, col, "%s8 = cpu_get_a (proc);", vars[cur_var]); + break; + + case 'b': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + print (fp, col, "%s8 = cpu_get_b (proc);", vars[cur_var]); + break; + + case 'd': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + print (fp, col, "%s16 = cpu_get_d (proc);", vars[cur_var]); + break; + + case 'x': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + print (fp, col, "%s16 = cpu_get_x (proc);", vars[cur_var]); + break; + + case 'y': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + print (fp, col, "%s16 = cpu_get_y (proc);", vars[cur_var]); + break; + + case '*': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + if (addr_set) + fatal_error (opcode, "Wrong use of '*', 'addr' already used"); + + addr_set = 1; + current_insn_size += 1; + print (fp, col, "addr = (uint16) cpu_fetch8 (proc);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + break; + + case '&': + if (addr_set) + fatal_error (opcode, "Wrong use of '&', 'addr' already used"); + + addr_set = 1; + if (strncmp (operands, "(x)", 3) == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_x (proc) + (uint16) cpu_fetch8 (proc);"); + operands += 3; + } + else if (strncmp (operands, "(y)", 3) == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_y (proc) + (uint16) cpu_fetch8 (proc);"); + operands += 3; + } + else if (strncmp (operands, "()", 2) == 0) + { + current_insn_size += 2; + print (fp, col, "addr = cpu_fetch16 (proc);"); + operands += 2; + } + else if (strncmp (operands, "[]", 2) == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_indexed_operand_addr (proc, 0);"); + operands += 2; + } + else + { + fatal_error (opcode, "Unknown operand"); + } + break; + + case '(': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + if (addr_set) + fatal_error (opcode, "Wrong use of '(', 'addr' already used"); + + if (strncmp (operands, "x)", 2) == 0) + { + addr_set = 1; + current_insn_size += 1; + print (fp, col, "addr = cpu_get_x (proc) + (uint16) cpu_fetch8 (proc);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + operands += 2; + } + else if (strncmp (operands, "y)", 2) == 0) + { + addr_set = 1; + current_insn_size += 1; + print (fp, col, "addr = cpu_get_y (proc) + (uint16) cpu_fetch8 (proc);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + operands += 2; + } + else if (strncmp (operands, ")", 1) == 0) + { + addr_set = 1; + current_insn_size += 2; + print (fp, col, "addr = cpu_fetch16 (proc);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + operands++; + } + else if (strncmp (operands, "@)", 2) == 0) + { + current_insn_size += 2; + print (fp, col, "addr = cpu_fetch16 (proc);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + operands += 2; + } + else if (strncmp (operands, "sp)", 3) == 0) + { + print (fp, col, "%s%s = cpu_%s_pop_uint%s (proc);", + vars[cur_var], operand_size, + cpu_type == cpu6811 ? "m68hc11" : "m68hc12", + operand_size); + operands += 3; + } + else + { + fatal_error (opcode, "Unknown operand"); + } + break; + + case '[': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + if (addr_set) + fatal_error (opcode, "Wrong use of '[', 'addr' already used"); + + if (strncmp (operands, "]", 1) == 0) + { + addr_set = 1; + current_insn_size += 1; + print (fp, col, "addr = cpu_get_indexed_operand_addr (proc,0);"); + print (fp, col, "%s%s = memory_read%s (proc, addr);", + vars[cur_var], operand_size, operand_size); + operands += 1; + } + else if (strncmp (operands, "]", 1) == 0) + { + current_insn_size += 1; + print (fp, col, "%s%s = cpu_get_indexed_operand%s (proc,0);", + vars[cur_var], operand_size, operand_size); + operands += 1; + } + else + { + fatal_error (opcode, "Unknown operand"); + } + break; + + case '{': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + if (addr_set) + fatal_error (opcode, "Wrong use of '{', 'addr' already used"); + + if (strncmp (operands, "}", 1) == 0) + { + current_insn_size += 1; + print (fp, col, "%s%s = cpu_get_indexed_operand%s (proc, 1);", + vars[cur_var], operand_size, operand_size); + operands += 1; + } + else + { + fatal_error (opcode, "Unknown operand"); + } + break; + + case 's': + if (cur_var >= 2) + fatal_error (opcode, "Too many locals"); + + if (strncmp (operands, "p", 1) == 0) + { + print (fp, col, "%s16 = cpu_get_sp (proc);", vars[cur_var]); + operands++; + } + else + { + fatal_error (opcode, "Unknown operands"); + } + break; + + case 'c': + if (strncmp (operands, "cr", 2) == 0) + { + print (fp, col, "%s8 = cpu_get_ccr (proc);", vars[cur_var]); + operands += 2; + } + else + { + fatal_error (opcode, "Unknown operands"); + } + break; + + case 'r': + if (addr_set && cur_var != 2) + fatal_error (opcode, "Wrong use of 'r'"); + + addr_set = 1; + current_insn_size += 1; + print (fp, col, "addr = cpu_fetch_relbranch (proc);"); + break; + + case 'R': + if (addr_set && cur_var != 2) + fatal_error (opcode, "Wrong use of 'R'"); + + addr_set = 1; + current_insn_size += 2; + print (fp, col, "addr = cpu_fetch_relbranch16 (proc);"); + break; + + case '#': + if (strcmp (operand_size, "8") == 0) + { + current_insn_size += 1; + } + else + { + current_insn_size += 2; + } + print (fp, col, "%s%s = cpu_fetch%s (proc);", vars[cur_var], + operand_size, operand_size); + break; + + case ',': + cur_var ++; + break; + + case '-': + return addr_set; + + default: + fatal_error (opcode, "Invalid operands"); + break; + } + } + return addr_set; +} + + +/* Generate the code to save the instruction result. The result is in + a local variable: either 'dst8' or 'dst16'. + There may be only one result. Instructions with 2 results (ie idiv + and fdiv), take care of saving the first value. + + The operand string is the same as for 'gen_fetch_operands'. + Everything before '->' is ignored. If the '->' is not found, it + is assumed that there is nothing to save. After '->', the operand + string is interpreted as follows: + + a Save 'dst8' in A register + b " B " + ccr " CCR " + d " 'dst16' D " + x " X " + y " Y " + sp " SP " + * 68HC11 page0 memory pointer. + (x) 68HC11 indirect access with X register. + (y) Same as (x) with Y register. + () 68HC11 extended address mode (global variable). + For these modes, if they were used as an input operand, + the 'addr' variable contains the address of memory where + the result must be saved. + If they were not used an input operand, 'addr' is computed + (as in gen_fetch_operands()), and the result is saved. + [] 68HC12 indexed indirect + (sp) Push + Push the 8/16-bits result on the stack. */ +void +gen_save_result (FILE *fp, int col, + const struct m6811_opcode_def *opcode, + int addr_set, + const char *operand_size) +{ + char c; + const char *operands = opcode->operands; + + /* When the result is saved, 'result_size' is a string which + indicates the size of the saved result ("8" or "16"). This + is a sanity check with 'operand_size' to detect inconsistencies + in the different tables. */ + const char *result_size = 0; + + if (operands == 0) + operands = ""; + + operands = strchr (operands, '-'); + if (operands == 0) + return; + + operands++; + if (*operands++ != '>') + { + fatal_error (opcode, "Invalid operand"); + } + + c = *operands++; + switch (c) + { + case 'a': + result_size = "8"; + print (fp, col, "cpu_set_a (proc, dst8);"); + break; + + case 'b': + result_size = "8"; + print (fp, col, "cpu_set_b (proc, dst8);"); + break; + + case 'd': + result_size = "16"; + print (fp, col, "cpu_set_d (proc, dst16);"); + break; + + case 'x': + result_size = "16"; + print (fp, col, "cpu_set_x (proc, dst16);"); + break; + + case 'y': + result_size = "16"; + print (fp, col, "cpu_set_y (proc, dst16);"); + break; + + case '*': + if (addr_set == 0) + { + current_insn_size += 1; + print (fp, col, "addr = (uint16) cpu_fetch8 (proc);"); + } + result_size = operand_size; + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + break; + + case '(': + if (strncmp (operands, "x)", 2) == 0) + { + if (addr_set == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_x (proc) + cpu_fetch8 (proc);"); + } + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + operands += 2; + result_size = operand_size; + } + else if (strncmp (operands, "y)", 2) == 0) + { + if (addr_set == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_y (proc) + cpu_fetch8 (proc);"); + } + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + operands += 2; + result_size = operand_size; + } + else if (strncmp (operands, ")", 1) == 0) + { + if (addr_set == 0) + { + current_insn_size += 2; + print (fp, col, "addr = cpu_fetch16 (proc);"); + } + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + operands++; + result_size = operand_size; + } + else if (strncmp (operands, "sp)", 3) == 0) + { + print (fp, col, "cpu_%s_push_uint%s (proc, dst%s);", + cpu_type == cpu6811 ? "m68hc11" : "m68hc12", + operand_size, operand_size); + operands += 3; + result_size = operand_size; + } + else + { + fatal_error (opcode, "Invalid operand"); + } + break; + + case '[': + if (strncmp (operands, "]", 1) == 0) + { + if (addr_set == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_indexed_operand_addr (proc,0);"); + } + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + operands++; + result_size = operand_size; + } + else + { + fatal_error (opcode, "Invalid operand"); + } + break; + + case '{': + if (strncmp (operands, "}", 1) == 0) + { + current_insn_size += 1; + print (fp, col, "addr = cpu_get_indexed_operand_addr (proc, 1);"); + print (fp, col, "memory_write%s (proc, addr, dst%s);", + operand_size, operand_size); + operands++; + result_size = operand_size; + } + else + { + fatal_error (opcode, "Invalid operand"); + } + break; + + case 's': + if (strncmp (operands, "p", 1) == 0) + { + print (fp, col, "cpu_set_sp (proc, dst16);"); + operands++; + result_size = "16"; + } + else + { + fatal_error (opcode, "Invalid operand"); + } + break; + + case 'c': + if (strncmp (operands, "cr", 2) == 0) + { + print (fp, col, "cpu_set_ccr (proc, dst8);"); + operands += 2; + result_size = "8"; + } + else + { + fatal_error (opcode, "Invalid operand"); + } + break; + + default: + fatal_error (opcode, "Invalid operand"); + break; + } + + if (*operands != 0) + fatal_error (opcode, "Garbage at end of operand"); + + if (result_size == 0) + fatal_error (opcode, "? No result seems to be saved"); + + if (strcmp (result_size, operand_size) != 0) + fatal_error (opcode, "Result saved different than pattern size"); +} + + +/* Find the instruction pattern for a given instruction. */ +const struct m6811_opcode_pattern* +find_opcode_pattern (const struct m6811_opcode_def *opcode) +{ + int i; + const char *pattern = opcode->insn_pattern; + + if (pattern == 0) + { + pattern = opcode->name; + } + for (i = 0; i < TABLE_SIZE(m6811_opcode_patterns); i++) + { + if (strcmp (m6811_opcode_patterns[i].name, pattern) == 0) + { + return &m6811_opcode_patterns[i]; + } + } + fatal_error (opcode, "Unknown instruction pattern"); + return 0; +} + +/* Generate the code for interpretation of instruction 'opcode'. */ +void +gen_interp (FILE *fp, int col, const struct m6811_opcode_def *opcode) +{ + const char *operands = opcode->operands; + int addr_set; + const char *pattern = opcode->insn_pattern; + const struct m6811_opcode_pattern *op; + const char *operand_size; + + if (pattern == 0) + { + pattern = opcode->name; + } + + /* Find out the size of the operands: 8 or 16-bits. */ + if (strcmp(&pattern[strlen(pattern) - 1], "8") == 0) + { + operand_size = "8"; + } + else if (strcmp (&pattern[strlen(pattern) - 2], "16") == 0) + { + operand_size = "16"; + } + else + { + operand_size = ""; + } + + if (operands == 0) + operands = ""; + + /* Generate entry point for the instruction. */ + print (fp, col, "case 0x%02x: /* %s %s */\n", opcode->insn_code, + opcode->name, operands); + col += indent_level; + + /* Generate the code to get the instruction operands. */ + addr_set = gen_fetch_operands (fp, col, opcode, operand_size); + + /* Generate instruction interpretation. */ + op = find_opcode_pattern (opcode); + if (op->pattern) + { + print (fp, col, "%s;", op->pattern); + } + + /* Generate the code to save the result. */ + gen_save_result (fp, col, opcode, addr_set, operand_size); + + /* For some instructions, generate the code to update the flags. */ + if (op && op->ccr_update) + { + print (fp, col, "%s;", op->ccr_update); + } + print (fp, col, "break;"); +} + + +/* Generate the interpretor for a given 68HC11 page set. */ +void +gen_interpreter_for_table (FILE *fp, int col, + const struct m6811_opcode_def *table, + int size, + const char *cycles_table_name) +{ + int i; + int init_size; + + init_size = table == m6811_page1_opcodes + || table == m6812_page1_opcodes? 1 : 2; + + /* Get the opcode and dispatch directly. */ + print (fp, col, "op = cpu_fetch8 (proc);"); + print (fp, col, "cpu_add_cycles (proc, %s[op]);", cycles_table_name); + + print (fp, col, "switch (op)\n"); + col += indent_level; + print (fp, col, "{\n"); + + for (i = 0; i < size; i++) + { + /* The table contains duplicate entries (ie, instruction aliases). */ + if (i > 0 && table[i].insn_code == table[i - 1].insn_code) + continue; + + current_insn_size = init_size; + gen_interp (fp, col, &table[i]); +#if 0 + if (current_insn_size != table[i].insn_size) + { + fatal_error (&table[i], "Insn size %ld inconsistent with %ld", + current_insn_size, table[i].insn_size); + } +#endif + } + + print (fp, col, "default:\n"); + print (fp, col + indent_level, "cpu_special (proc, M6811_ILLEGAL);"); + print (fp, col + indent_level, "break;"); + print (fp, col, "}\n"); +} + +/* Generate the table of instruction cycle. These tables are indexed + by the opcode number to allow a fast cycle time computation. */ +void +gen_cycle_table (FILE *fp, const char *name, + const struct m6811_opcode_def *table, + int size) +{ + int i; + char cycles[256]; + int page1; + + page1 = table == m6811_page1_opcodes; + + /* Build the cycles table. The table is indexed by the opcode. */ + memset (cycles, 0, sizeof (cycles)); + while (--size >= 0) + { + if (table->insn_min_cycles > table->insn_max_cycles) + fatal_error (table, "Wrong insn cycles"); + + if (table->insn_max_cycles == _M) + cycles[table->insn_code] = table->insn_min_cycles; + else + cycles[table->insn_code] = table->insn_max_cycles; + + table++; + } + + /* Some check: for the page1 opcode, the cycle type of the page2/3/4 + opcode must be 0. */ + if (page1 && (cycles[M6811_OPCODE_PAGE2] != 0 + || cycles[M6811_OPCODE_PAGE3] != 0 + || cycles[M6811_OPCODE_PAGE4] != 0)) + fatal_error (0, "Invalid cycle table"); + + /* Generates the cycles table. */ + print (fp, 0, "static const unsigned char %s[256] = {\n", name); + for (i = 0; i < 256; i++) + { + if ((i % 16) == 0) + { + print (fp, indent_level, "/* %3d */ ", i); + } + fprintf (fp, "%2d", cycles[i]); + if (i != 255) + fprintf (fp, ","); + + if ((i % 16) != 15) + fprintf (fp, " "); + else + fprintf (fp, "\n"); + } + print (fp, 0, "};\n\n"); +} + +#define USE_SRC8 1 +#define USE_DST8 2 + +void +gen_function_entry (FILE *fp, const char *name, int locals) +{ + /* Generate interpretor entry point. */ + print (fp, 0, "%s (proc)\n", name); + print (fp, indent_level, "struct _sim_cpu* proc;"); + print (fp, indent_level, "{\n"); + + /* Interpretor local variables. */ + print (fp, indent_level, "unsigned char op;"); + print (fp, indent_level, "uint16 addr, src16, dst16;"); + if (locals & USE_SRC8) + print (fp, indent_level, "uint8 src8;\n"); + if (locals & USE_DST8) + print (fp, indent_level, "uint8 dst8;\n"); +} + +void +gen_function_close (FILE *fp) +{ + print (fp, 0, "}\n"); +} + +int +cmp_opcode (void* e1, void* e2) +{ + struct m6811_opcode_def* op1 = (struct m6811_opcode_def*) e1; + struct m6811_opcode_def* op2 = (struct m6811_opcode_def*) e2; + + return (int) (op1->insn_code) - (int) (op2->insn_code); +} + +void +prepare_table (struct m6811_opcode_def* table, int size) +{ + int i; + + qsort (table, size, sizeof (table[0]), cmp_opcode); + for (i = 1; i < size; i++) + { + if (table[i].insn_code == table[i-1].insn_code) + { + fprintf (stderr, "Two insns with code 0x%02x\n", + table[i].insn_code); + } + } +} + +void +gen_interpreter (FILE *fp) +{ + int col = 0; + + prepare_table (m6811_page1_opcodes, TABLE_SIZE (m6811_page1_opcodes)); + prepare_table (m6811_page2_opcodes, TABLE_SIZE (m6811_page2_opcodes)); + prepare_table (m6811_page3_opcodes, TABLE_SIZE (m6811_page3_opcodes)); + prepare_table (m6811_page4_opcodes, TABLE_SIZE (m6811_page4_opcodes)); + + prepare_table (m6812_page1_opcodes, TABLE_SIZE (m6812_page1_opcodes)); + prepare_table (m6812_page2_opcodes, TABLE_SIZE (m6812_page2_opcodes)); + + /* Generate header of interpretor. */ + print (fp, col, "/* File generated automatically by gencode. */\n"); + print (fp, col, "#include \"sim-main.h\"\n\n"); + + if (cpu_type & cpu6811) + { + gen_cycle_table (fp, "cycles_page1", m6811_page1_opcodes, + TABLE_SIZE (m6811_page1_opcodes)); + gen_cycle_table (fp, "cycles_page2", m6811_page2_opcodes, + TABLE_SIZE (m6811_page2_opcodes)); + gen_cycle_table (fp, "cycles_page3", m6811_page3_opcodes, + TABLE_SIZE (m6811_page3_opcodes)); + gen_cycle_table (fp, "cycles_page4", m6811_page4_opcodes, + TABLE_SIZE (m6811_page4_opcodes)); + + gen_function_entry (fp, "static void\ncpu_page3_interp", 0); + gen_interpreter_for_table (fp, indent_level, + m6811_page3_opcodes, + TABLE_SIZE(m6811_page3_opcodes), + "cycles_page3"); + gen_function_close (fp); + + gen_function_entry (fp, "static void\ncpu_page4_interp", 0); + gen_interpreter_for_table (fp, indent_level, + m6811_page4_opcodes, + TABLE_SIZE(m6811_page4_opcodes), + "cycles_page4"); + gen_function_close (fp); + + /* Generate the page 2, 3 and 4 handlers. */ + gen_function_entry (fp, "static void\ncpu_page2_interp", + USE_SRC8 | USE_DST8); + gen_interpreter_for_table (fp, indent_level, + m6811_page2_opcodes, + TABLE_SIZE(m6811_page2_opcodes), + "cycles_page2"); + gen_function_close (fp); + + /* Generate the interpretor entry point. */ + gen_function_entry (fp, "void\ncpu_interp_m6811", + USE_SRC8 | USE_DST8); + + gen_interpreter_for_table (fp, indent_level, m6811_page1_opcodes, + TABLE_SIZE(m6811_page1_opcodes), + "cycles_page1"); + gen_function_close (fp); + } + else + { + gen_cycle_table (fp, "cycles_page1", m6812_page1_opcodes, + TABLE_SIZE (m6812_page1_opcodes)); + gen_cycle_table (fp, "cycles_page2", m6812_page2_opcodes, + TABLE_SIZE (m6812_page2_opcodes)); + + gen_function_entry (fp, "static void\ncpu_page2_interp", + USE_SRC8 | USE_DST8); + gen_interpreter_for_table (fp, indent_level, + m6812_page2_opcodes, + TABLE_SIZE(m6812_page2_opcodes), + "cycles_page2"); + gen_function_close (fp); + + /* Generate the interpretor entry point. */ + gen_function_entry (fp, "void\ncpu_interp_m6812", + USE_SRC8 | USE_DST8); + + gen_interpreter_for_table (fp, indent_level, m6812_page1_opcodes, + TABLE_SIZE(m6812_page1_opcodes), + "cycles_page1"); + gen_function_close (fp); + } +} + +void +usage (char* prog) +{ + fprintf (stderr, "Usage: %s {-m6811|-m6812}\n", prog); + exit (2); +} + +int +main (int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-m6811") == 0) + cpu_type = cpu6811; + else if (strcmp (argv[i], "-m6812") == 0) + cpu_type = cpu6812; + else + { + usage (argv[0]); + } + } + if (cpu_type == 0) + usage (argv[0]); + + gen_interpreter (stdout); + if (fclose (stdout) != 0) + { + fprintf (stderr, "Error while generating the interpreter: %d\n", + errno); + return 1; + } + return 0; +}
gencode.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: ChangeLog =================================================================== --- ChangeLog (nonexistent) +++ ChangeLog (revision 33) @@ -0,0 +1,631 @@ +2006-12-21 Hans-Peter Nilsson + + * config.in: Regenerate. + +2006-06-13 Richard Earnshaw + + * configure: Regenerated. + +2006-06-05 Daniel Jacobowitz + + * configure: Regenerated. + +2006-05-31 Daniel Jacobowitz + + * configure: Regenerated. + +2006-03-29 Hans-Peter Nilsson + + * configure: Regenerate. + +2005-03-23 Mark Kettenis + + * configure: Regenerate. + +2005-01-14 Andrew Cagney + + * configure.ac: Sinclude aclocal.m4 before common.m4. Add + explicit call to AC_CONFIG_HEADER. + * configure: Regenerate. + +2005-01-11 Andrew Cagney + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +2005-01-07 Andrew Cagney + + * configure.ac: Rename configure.in, require autoconf 2.59. + * configure: Re-generate. + +2004-12-08 Hans-Peter Nilsson + + * configure: Regenerate for ../common/aclocal.m4 update. + +2004-06-15 Alan Modra + + * interp.c (sim_prepare_for_program): Use bfd_get_section_size + instead of bfd_get_section_size_before_reloc. + +2003-08-08 Stephane Carrez + + * dv-m68hc11tim.c (cycle_to_string): Add flags parameter to better + control the translation. + (m68hc11tim_print_timer): Update cycle_to_string conversion. + (m68hc11tim_timer_event): Fix handling of output + compare register with its interrupts. + (m68hc11tim_io_write_buffer): Check output compare + after setting M6811_TMSK1. + (m68hc11tim_io_read_buffer): Fix compilation warning. + * dv-m68hc11.c (m68hc11_option_handler): Likewise. + * dv-m68hc11spi.c (m68hc11spi_info): Likewise. + * dv-m68hc11sio.c (m68hc11sio_info): Likewise. + * interrupts.c (interrupts_info): Likewise. + (interrupts_reset): Recognize bootstrap mode. + * sim-main.h (PRINT_CYCLE, PRINT_TIME): New defines. + (_sim_cpu): Add cpu_start_mode. + (cycle_to_string): Add flags member. + * m68hc11_sim.c (OPTION_CPU_BOOTSTRAP): New option. + (cpu_options): Declare new option bootstrap. + (cpu_option_handler): Handle it. + (cpu_info): Update call to cycle_to_string. + +2003-08-08 Stephane Carrez + + * sim-main.h (phys_to_virt): Use memory bank parameters to translate + the physical address in virtual address. + (struct _sim_cpu): Add memory bank members. + * m68hc11_sim.c (cpu_initialize): Clear memory bank parameters. + * interp.c (sim_hw_configure): Create memory bank according to memory + bank parameters. + (sim_get_bank_parameters): New function to obtain memory bank config + from the symbol table. + (sim_prepare_for_program): Call it to obtain the memory bank parameters. + (sim_open): Call sim_prepare_for_program. + * dv-m68hc11.c (m68hc11cpu_io_write_buffer): Use memory bank parameters + to check if address is within bank window. + (m68hc11cpu_io_read_buffer): Likewise. + (attach_m68hc11_regs): Map the memory bank according to memory bank + parameters. + +2003-08-08 Stephane Carrez , + + * sim-main.h (PAGE_REGNUM, Z_REGNUM): Use same numbering as gdb. + +2003-08-08 Stephane Carrez , + Gary Piercey + + * m68hc11_sim.c (print_io_word): New function to print 16-bit value. + * sim-main.h (print_io_word): Declare. + * dv-m68hc11tim.c (tmsk1_desc): New description table for TMSK1. + (tflg1_desc): Likewise for TFLG1. + (m68hc11tim_info): Print input and output compare registers + +2003-03-02 Stephane Carrez + + * Makefile.in (SIM_EXTRA_CFLAGS): Set WITH_TARGET_ADDRESS_BITSIZE + to 32 to support memory bank switching; temporarily use 32-bit for + WORD_BITSIZE to avoid a bug in sim-common. + +2003-03-01 Stephane Carrez + + * interp.c (sim_fetch_register): Only store a single byte for + 1 byte registers. + +2003-02-27 Andrew Cagney + + * interp.c (sim_prepare_for_program, sim_open) + (sim_create_inferior): Rename _bfd to bfd. + +2002-08-13 Stephane Carrez + + * dv-m68hc11eepr.c (struct m68hc11eepr ): Use const char* for filename. + +2002-08-13 Marko Kohtala + + * interp.c (sim_prepare_for_program): Look up the image for the + reset vector and set cpu_use_elf_start to 1 if not found. + (sim_open): Do not set cpu_use_elf_start. + +2002-08-13 Marko Kohtala + + * interp.c (sim_hw_configure): Return 1 for success. + (sim_prepare_for_program): Use the sim_hw_configure exit code to + return SIM_RC_FAIL. + +2002-08-13 Stephane Carrez + + * dv-m68hc11.c (m68hc11cpu_io_read_buffer): Translate memory + bank window to some virtual address to read from extended memory. + (m68hc11cpu_io_write_buffer): Likewise for writing. + (attach_m68hc11_regs): When use_bank property is defined, attach + to the 68HC12 16K memory bank window. + * interp.c (sim_hw_configure): Create memory region for banked + memory. + +2002-08-13 Stephane Carrez + + * interp.c (sim_hw_configure): Connect port-X to cpu-write-port. + * dv-m68hc11.c (m68hc11cpu_ports): Add cpu-write-port input. + (m68hc11cpu_port_event): Handle CPU_WRITE_PORT event. + +2002-08-13 Marko Kohtala + + * dv-m68hc11.c (m68hc11cpu_io_write): Fix to update IO mapping + when IO mapping changed, not when internal RAM mapping is changed. + +2002-08-13 Stephane Carrez + + * m68hc11_sim.c (cpu_special): Handle call and rtc instructions. + * sim-main.h (M6812_CALL_INDIRECT): Add to enum. + (m6811_regs): Add page register. + (cpu_set_page, cpu_get_page): New macros. + (phys_to_virt): New function. + (cpu_get_indexed_operand_addr, cpu_return): Declare. + * gencode.c: Identify indirect addressing mode for call and fix daa. + (gen_function_entry): New param to tell if src8/dst8 locals are + necessary. + (gen_interpreter): Use it to avoid generation of unused variables. + * interp.c (sim_fetch_register): Allow to read page register; page + register, A, B and CCR are only 1 byte wide. + (sim_store_register): Likewise for writing. + +2002-06-16 Andrew Cagney + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +2002-06-09 Andrew Cagney + + * Makefile.in (INCLUDE): Update path to callback.h. + * sim-main.h: Include "gdb/callback.h" and "gdb/remote-sim.h". + +2002-03-07 Stephane Carrez + + * m68hc11_sim.c (cpu_move8): Call sim_engine_abort in default case. + (cpu_move16): Likewise. + (sim_memory_error): Use sim_io_printf. + (cpu_option_handler): Fix compilation warning. + * interp.c (sim_hw_configure): Fix compilation warning; + remove m68hc12sio@2 device. + (sim_open): Likewise. + * dv-m68hc11tim.c (m68hc11tim_port_event): Fix clear of TFLG2 + flags when reset. + (cycle_to_string): Improve convertion of cpu cycle number. + (m68hc11tim_info): Print info about PACNT. + (m68hc11tim_io_write_buffer): Fix clearing of TFLG2; handle + TCTL1 and TCTL2 registers. + * dv-m68hc11.c (m68hc11_info): Print 6811 current running mode. + +2002-03-07 Stephane Carrez + + * interp.c (sim_hw_configure): Save the HW cpu pointer in the + cpu struct. + (sim_hw_configure): Connect the capture input/output events. + * sim-main.h (_sim_cpu): New member hw_cpu. + (m68hc11cpu_set_oscillator): Declare. + (m68hc11cpu_clear_oscillator): Declare. + (m68hc11cpu_set_port): Declare. + * dv-m68hc11.c (m68hc11_options): New for oscillator commands. + (m68hc11cpu_ports): New input ports and output ports to reflect + the HC11 IOs. + (m68hc11_delete): Cleanup any running oscillator. + (attach_m68hc11_regs): Create the input oscillators. + (make_oscillator): New function. + (find_oscillator): New function. + (oscillator_handler): New function. + (reset_oscillators): New function. + (m68hc11cpu_port_event): Handle the new input ports. + (m68hc11cpu_set_oscillator): New function. + (m68hc11cpu_clear_oscillator): New function. + (get_frequency): New function. + (m68hc11_option_handler): New function. + (m68hc11cpu_set_port): New function. + (m68hc11cpu_io_write): Post the port output events. + * dv-m68hc11spi.c (set_bit_port): Use m68hc11cpu_set_port to set + the output port value. + * dv-m68hc11tim.c (m68hc11tim_port_event): Handle CAPTURE event + by latching the TCNT value in the register. + +2002-03-07 Stephane Carrez + + * sim-main.h (cpu_frame, cpu_frame_list): Remove. + (cpu_frame_reg, cpu_print_frame): Remove. + (cpu_m68hc11_push_uint8, cpu_m68hc11_pop_uint8): Cleanup. + (cpu_m68hc11_push_uint16, cpu_m68hc11_pop_uint16): Likewise. + (cpu_m68hc12_push_uint8, cpu_m68hc12_push_uint16): Likewise. + (cpu_m68hc12_pop_uint8, cpu_m68hc12_pop_uint16): Likewise. + * m68hc11_sim.c (cpu_find_frame): Remove. + (cpu_create_frame_list): Remove. + (cpu_remove_frame_list, cpu_create_frame, cpu_free_frame): Remove. + (cpu_frame_reg, cpu_print_frame, cpu_update_frame): Remove. + (cpu_call): Cleanup to remove #if HAVE_FRAME and calls to the above. + (cpu_update_frame): Likewise. + (cpu_return): Likewise. + (cpu_reset): Likewise. + (cpu_initialize): Likewise. + * interp.c (sim_do_command): Remove call to cpu_print_frame. + +2002-03-07 Stephane Carrez + + * interrupts.c (interrupts_reset): New function, setup interrupt + vector address according to cpu mode. + (interrupts_initialize): Move reset portion to the above. + (interrupt_names): New table to give a name to interrupts. + (idefs): Handle pulse accumulator interrupts. + (interrupts_info): Print the interrupt history. + (interrupt_option_handler): New function. + (interrupt_options): New table of options. + (interrupts_update_pending): Keep track of when interrupts are + raised and implement breakpoint-on-raise-interrupt. + (interrupts_process): Keep track of when interrupts are taken + and implement breakpoint-on-interrupt. + * interrupts.h (struct interrupt_history): Define. + (struct interrupt): Keep track of the interrupt history. + (interrupts_reset): Declare. + (interrupts_initialize): Update prototype. + * m68hc11_sim.c (cpu_reset): Reset interrupts. + (cpu_initialize): Cleanup. + +2001-07-28 Stephane Carrez + + * dv-m68hc11eepr.c (m68hc11eepr_info): Fix print of current write + address. + (m68hc11eepr_port_event): Fix detach/attach logic. + +2001-07-22 Stephane Carrez + + * Makefile.in (SIM_OBJS): Remove sim-resume.o + * interp.c (sim_resume): New function from sim-resume.c, install + the stepping event after having processed the pending ticks. + (has_stepped): Likewise. + (sim_info): Produce an output only if verbose or STATE_VERBOSE_P. + +2001-07-10 Andrew Cagney + + * Makefile.in (gencode): Provide explicit path to gencode.c. + +2001-05-20 Stephane Carrez + + * Makefile.in (M68HC11_OBJS): Add m68hc12int.o. + (m68hc12int.c): Generate using gencode -m6812. + (m68hc11int.c): Likewise with -m6811. + + * gencode.c (m6811_opcode_patterns): New patterns for 68HC12. + (m6811_page1_opcodes): Remove duplicate entries. + (m6811_page2_opcodes): Likewise. + (m6811_page3_opcodes): Likewise. + (m6811_page4_opcodes): Likewise. + (m6812_page1_opcodes): New table for 68HC12 instructions. + (m6812_page2_opcodes): Likewise. + (gen_fetch_operands): New modes [] and &[] for 68HC12 operands. + (gen_save_result): Likewise. + (gen_interpreter_for_table): Handle 68HC11 and 68HC12 opcodes. + (cmp_opcode): New function for opcode comparision. + (prepare_table): Sort the opcodes. + (gen_interpreter): Prepare all the tables and generate either + a 68HC11 or a 68HC12 simulator. + (main): New options -m6811 and -m6812. + + * m68hc11_sim.c (cpu_single_step): Use pointer to cpu interpretor. + (cpu_special): Simulation of some 68HC12 instructions. + (cpu_exg): New function. + (cpu_dbcc): Likewise. + (cpu_fetch_relbranch16): Likewise. + (cpu_push_all): Push according to 68HC11 or 68HC12. + (cpu_move16): Likewise. + (cpu_move8): Likewise. + (cpu_get_indexed_operand16): Likewise. + (cpu_get_indexed_operand8): Likewise. + (cpu_get_indexed_operand_addr): Likewise. + (cpu_set_reg, cpu_set_dst_reg, cpu_get_src_reg, cpu_get_reg): Likewise. + (cpu_reset): Setup INIT register according to architecture. + + * sim-main.h (M6811_Special): Add 68HC12 specific instructions. + (_sim_cpu): Keep track of the cpu being simulated. + (cpu_get_tmp3, cpu_get_tmp2, cpu_set_tmp3, cpu_set_tmp2): New. + (cpu_m68hc11_push_uintxx): Rename of cpu_push_uintxx. + (cpu_m68hc11_pop_uint8): Likewise. + (cpu_m68hc12_push_uintxx): New functions for 68HC12. + (cpu_m68hc12_pop_uintxx): Likewise. + (cpu_exg, cpu_dbcc, cpu_move8, cpu_move16): Likewise, + (cpu_fetch_relbranch16): Likewise. + (cpu_interp_m6811): Rename of cpu_interp. + (cpu_interp_m6812): New function. + * interp.c (free_state): New function. + (dev_list_68hc12): New table. + (sim_board_reset): Reset depending on the cpu (HC11 or HC12). + (sim_hw_configure): New function. + (sim_prepare_for_program): New function. + (sim_open): Use above new functions. + (sim_close): Call free_state(). + (sim_info): Print info according to cpu. + (sim_create_inferior): Use sim_prepare_for_program. + (sim_do_command): Configure the hardware after a change of the + architecture. + +2001-05-20 Stephane Carrez + + * dv-m68hc11sio.c (m68hc11sio_tx_poll): Always check for + pending interrupts. + * interrupts.c (interrupts_process): Keep track of the last number + of masked insn cycles. + (interrupts_initialize): Clear last number of masked insn cycles. + (interrupts_info): Report them. + (interrupts_update_pending): Compute clear and set masks of + interrupts and clear the interrupt bits before setting them + (due to SCI interrupt sharing). + * interrupts.h (struct interrupts): New members last_mask_cycles + and xirq_last_mask_cycles. + +2000-11-26 Stephane Carrez + + * dv-m68hc11.c (m68hc11cpu_io_read_buffer): Use attach_size + instead of a hard-coded value. + (m68hc11cpu_io_write_buffer): Likewise. + (dv_m68hc11_descriptor): Define a 68hc12 device. + * dv-m68hc11eepr.c (dv_m68hc11eepr_descriptor): Likewise. + * dv-m68hc11tim.c (dv_m68hc11tim_descriptor): Likewise. + * dv-m68hc11spi.c (dv_m68hc11spi_descriptor): Likewise. + * dv-m68hc11sio.c (dv_m68hc11sio_descriptor): Likewise. + +2000-11-22 Stephane Carrez + + * dv-m68hc11.c (attach_m68hc11_regs): Register a delete handler. + (m68hc11cpu_delete): Delete handler to detach the address space. + +2000-11-24 Stephane Carrez + + * dv-m68hc11eepr.c (attach_m68hc11eepr_regs): Use hw_malloc. + * dv-nvram.c (attach_nvram_regs): Use hw_free and hw_malloc + instead of free and malloc. + +2000-09-11 Stephane Carrez + + * Makefile.in: Was missing from initial patch. + +2000-09-10 Stephane Carrez + + * interp.c (sim_store_register): Remove soft register hack. + (sim_fetch_register): Likewise. + (sim_create_inferior): Likewise. + * sim-main.h: Likewise. + +2000-09-10 Stephane Carrez + + * interrupts.c (interrupts_update_pending): Clear the mask of + pending interrupts here. + (interrupts_get_current): Don't clear the mask of pending interrupts. + +2000-09-10 Stephane Carrez + + * sim-main.h: Define cycle_to_string. + * dv-m68hc11tim.c (cycle_to_string): New function to translate + the cpu cycle into some formatted time string. + (m68hc11tim_print_timer): Use it. + * dv-m68hc11sio.c (m68hc11sio_info): Use cycle_to_string. + * dv-m68hc11spi.c (m68hc11spi_info): Likewise. + * interrupts.c (interrupts_info): Likewise. + * m68hc11_sim.c (cpu_info): Likewise. + +2000-09-06 Stephane Carrez + + * dv-m68hc11tim.c (m68hc11tim_timer_event): Compute the overflow + interrupt and compare events accurately. Take into account the + pending ticks not processed by the simulator yet (introduced a shift). + (m68hc11_port_event): Reset the timer interrupt delays. + (m68hc11tim_io_read_buffer): Be able to read several bytes. + (m68hc11tim_io_write_buffer): Likewise for write. + (m68hc11tim_io_write_buffer): Recompute the timer overflow interrupt. + +2000-09-06 Stephane Carrez + + * dv-m68hc11spi.c (m68hc11spi_io_read_buffer): Clear the interrupts. + (m68hc11spi_io_write_buffer): Likewise and fix the spi frame. + (m68hc11spi_info): Clarify the status report + of the SPI when a byte is being sent. + (m68hc11spi_clock): Fix the spi send frame. + +2000-08-11 Stephane Carrez + + * sim-main.h (m68hc11_map_level): Define level of address mappings. + * dv-m68hc11eepr.c (struct m68hc11eepr ): New flag to indicate + whether the eeprom is currently mapped or not. + (m68hc11eepr_port_event): Use the flag to see if we must unmap + or map the eeprom. Update the flag to reflect the current state. + Use M6811_EEPROM_LEVEL when mapping the eeprom. + (m68hc11eepr_finish): Remove overlap hack. + (attach_m68hc11eepr_regs): Use M6811_IO_LEVEL when mapping the + config and control registers. + * dv-m68hc11.c (m68hc11cpu_finish): Remove overlap hack. + (attach_m68hc11_regs): Use M6811_IO_LEVEL. + (m68hc11cpu_io_write): Likewise when unmapping and re-mapping. + * dv-m68hc11spi.c (m68hc11spi_finish): Likewise. + (attach_m68hc11spi_regs): Likewise. + * dv-m68hc11tim.c (m68hc11tim_finish): Likewise. + (attach_m68hc11tim_regs): Likewise. + * dv-m68hc11sio.c (m68hc11sio_finish): Likewise. + (attach_m68hc11sio_regs): Likewise. + * interp.c (sim_open): Likewise. + * dv-nvram.c (attach_nvram_regs): Likewise. + +Thu Jul 27 21:27:25 2000 Andrew Cagney + + * configure, config.in: Regenerate. + +2000-06-25 Stephane Carrez + + * Makefile.in (SIM_RUN_OBJS): Define to use nrun.c + * dv-m68hc11.c (m68hc11cpu_finish): Register detach address callback. + (dv_m6811_detach_address_callback): New function to detach a + device from an address space. + * dv-m68hc11eepr.c (m68hc11eepr_port_event): Initialize + config register according to --cpu-config option. + * sim-main.h (_sim_cpu): Add cpu_config member. + * interp.c (sim_open): Delete specific simulator options. + * m68hc11_sim.c (cpu_option_handler): New options + --emulos and -cpu-config to configure the simulator. + (cpu_initialize): Initialize cpu_config member. + +2000-06-24 Stephane Carrez + + * emulos.c: Fix indentation and comments. + * gencode.c: Likewise. + * dv-m68hc11tim.c (m68hc11tim_timer_event): Handle COMPARE_EVENT. + (m68hc11tim_io_write_buffer): Write compare registers and + setup compare event. + * interp.c: Remove unused global variables. + * interrupts.c (idefs): New compare interrupts. + Fix indentation and comments. + * interrupts.h: Likewise. + +2000-06-18 Stephane Carrez + + * dv-m68hc11sio.c: Fix indentation and comments. + Remove INT_PORT. + * dv-m68hc11.c: Fix indentation and comments. + (m68hc11cpu_port_event): Move initialization of M6811_HPRIO from here. + * m68hc11_sim.c (cpu_reset): To here. + * dv-m68hc11eepr.c: Fix indentation and comments. + +2000-06-17 Stephane Carrez + + * dv-nvram.c: New file, rename from dv-pram.c. + * dv-pram.c: Delete file. + * sim-main.h: Incorporate m68hc11_sim.h. + * m68hc11_sim.h: Delete file. + * configure.in: Rename pram into nvram. + * interp.c (sim_open): Likewise in creation of device tree. + +2000-05-31 Stephane Carrez + + * interp.c (sim_open): Create the SPI device. + * dv-m68hc11spi.c: New file for SPI device simulation. + * configure.in (hw_extra_devices): Add SPI device. + +2000-05-28 Stephane Carrez + + * interrupts.c (interrupts_initialize): Clear XIRQ accounting. + (interrupts_process): Separate IRQ and XIRQ accounting. + (interrupts_info): Report XIRQ accounting. + * interrupts.h (struct interrupts): Added accounting for XIRQ. + +2000-04-16 Stephane Carrez + + * dv-pram.c (attach_pram_regs): Fix the 'save-modified' mode. + * m68hc11_sim.h (_sim_cpu): Allow configuration of cpu mode. + * dv-m68hc11.c (attach_m68hc11_regs): Get the cpu MODA,MODB + configuration from the 'mode' device tree property. + (m68hc11cpu_port_event): Reset M6811_HPRIO to the cpu MODA, MODB + configuration. + +2000-02-24 Stephane Carrez + + * sim-main.h: Remove WITH_TARGET_* defines. + * Makefile.in (SIM_EXTRA_CFLAGS): Specify the WITH_TARGET_* flags. + +2000-02-08 Stephane Carrez + + * dv-m68hc11sio.c (m68hc11sio_port_event): Setup the SCI to + 1200 baud when cpu is in bootstrap mode. + + * dv-m68hc11tim.c (m68hc11tim_io_write_buffer): Be able to + write in the TCTN timer register. + + * dv-m68hc11sio.c (m68hc11sio_io_write_buffer): Divide cpu clock + by 4 to obtain the E clock frequency. + (sccr2_desc): Use M6811_TIE for TIE bit. + (m68hc11sio_info): Fix baud rate report. + + * dv-m68hc11tim.c (to_realtime): Likewise. + + * interp.c (sim_open): When building device tree, only provide + devices that do not exist yet. + + * emulos.c: Fix compilation pb under Windows. + + * dv-m68hc11.c (attach_m68hc11_regs): Get the clock frequency + from the 'clock' property. + +2000-01-02 Stephane Carrez + + * m68hc11_sim.h (*_REGNUM): Define. + (_sim_cpu): New member cpu_page0_reg table. + * interp.c (sim_create_inferior): Fill the cpu_page0_reg table with + addresses of soft registers in .page0. + (sim_fetch_register, sim_store_register): Use cpu_page0_reg table + to get/set soft registers. + +1999-12-31 Stephane Carrez + + * dv-m68hc11.c (m68hc11cpu_io_write_buffer): Clear byte to avoid + returning random values. + +1999-12-17 Stephane Carrez + + * gencode.c: Fix "subb N,x" that used a instead of b. + +1999-09-09 Stephane Carrez + + * gencode.c: Fixed sbc8 and adc8 when there was a initial carry. + +1999-09-01 Stephane Carrez + + * sim-main.h (SIM_HANDLES_LMA): Define to enable loading using lma. + +1999-08-14 Stephane Carrez + + * dv-m68hc11.c (attach_m68hc11_regs): Save the size of the + register region in the m68hc11cpu struct. + (m68hc11cpu_io_write): When the IO mapping addres changes, + detach the register region and re-attach it at the new address. + (m68hc11cpu_io_read_buffer): Renamed base_address into + attach_address. + (m68hc11cpu_io_write_buffer): Likewise. Pass the hw pointer + to m68hc11cpu_io_write. + +1999-08-13 Stephane Carrez + + * gencode.c: For sbc8, check the carry and increment the source + before trying to set the carry for the result. + +1999-05-24 John S. Kallal + + * interp.c (sim_get_info): Don't crash if the command line is 0. + Define prototype for sim_get_info() and init_system(). + (sim_info): Correct call to sim_get_info(). + +1999-05-16 Stephane Carrez + + * configure.in: Recognize m6811-*-*. + * configure: Regenerate. + * m68hc11_sim.h (cpu_ccr_update_add8, cpu_ccr_update_add16, + cpu_ccr_update_sub8, cpu_ccr_update_sub16): + Correct the computation of carry of 8 and 16-bits add and subtract. + * gencode.c: Use cpu_ccr_update_sub8 for subtraction (carry and + overflow set in a different manner than add). + +1999-05-14 Stephane Carrez + + * dv-m68hc11.c (dv_m6811_attach_address_callback): Removed a + trace message. + * interp.c (sim_open, sim_create_inferior): Initialize the + cpu_elf_start from the ELF header. + * m68hc11_sim.c (cpu_initialize): Clear the new data members. + (cpu_restart): Use cpu_elf_start as the starting address when + the flag is set. + (cpu_special): When cpu_use_elf_start is set, the WAI instruction + exits the simulator (exit status is in D). + * m68hc11_sim.h (_sim_cpu): Added members cpu_use_elf_start and + cpu_elf_star to start execution at address specified in ELF file. + +1999-05-02 Stephane Carrez + + * Makefile.in, config.in, configure, configure.in: New files. + * gencode.c: New file, generation of 68HC11 interpreter. + * m68hc11_sim.h, m68hc11_sim.c: New files, specific operations + for interpreter. + * interrupts.c, interrupts.h: New files, management of interrupts. + * interp.c, sim-main.h, + * dv-m68hc11.c, dv-m68hc11eepr.c, dv-m68hc11sio.c, + dv-m68hc11tim.c, dv-pram.c: New files representing devices for + 68HC11 (dv-pram.c is generic and could probably migrate to common). + * emulos.c: New file, basic emulation of some os.
ChangeLog Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dv-m68hc11tim.c =================================================================== --- dv-m68hc11tim.c (nonexistent) +++ dv-m68hc11tim.c (revision 33) @@ -0,0 +1,841 @@ +/* dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices. + Copyright (C) 1999, 2000, 2002, 2003, 2007, 2008 + Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.fr) + (From a driver model Contributed by Cygnus Solutions.) + + This file is part of the program 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 3 of the License, 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, see . + + */ + + +#include "sim-main.h" +#include "hw-main.h" +#include "sim-assert.h" +#include + +/* DEVICE + + m68hc11tim - m68hc11 timer devices + + + DESCRIPTION + + Implements the m68hc11 timer as described in Chapter 10 + of the pink book. + + + PROPERTIES + + none + + + PORTS + + reset (input) + + Reset the timer device. This port must be connected to + the cpu-reset output port. + + capture (input) + + Input capture. This port must be connected to the input + captures. It latches the current TCNT free running counter + into one of the three input capture registers. + + */ + + + +/* port ID's */ + +enum +{ + RESET_PORT, + CAPTURE +}; + + +static const struct hw_port_descriptor m68hc11tim_ports[] = +{ + { "reset", RESET_PORT, 0, input_port, }, + { "capture", CAPTURE, 0, input_port, }, + { NULL, }, +}; + + +/* Timer Controller information. */ +struct m68hc11tim +{ + unsigned long cop_delay; + unsigned long rti_delay; + unsigned long ovf_delay; + signed64 clock_prescaler; + signed64 tcnt_adjust; + signed64 cop_prev_interrupt; + signed64 rti_prev_interrupt; + + /* Periodic timers. */ + struct hw_event *rti_timer_event; + struct hw_event *cop_timer_event; + struct hw_event *tof_timer_event; + struct hw_event *cmp_timer_event; +}; + + + +/* Finish off the partially created hw device. Attach our local + callbacks. Wire up our port names etc. */ + +static hw_io_read_buffer_method m68hc11tim_io_read_buffer; +static hw_io_write_buffer_method m68hc11tim_io_write_buffer; +static hw_port_event_method m68hc11tim_port_event; +static hw_ioctl_method m68hc11tim_ioctl; + +#define M6811_TIMER_FIRST_REG (M6811_TCTN) +#define M6811_TIMER_LAST_REG (M6811_PACNT) + + +static void +attach_m68hc11tim_regs (struct hw *me, + struct m68hc11tim *controller) +{ + hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, + M6811_TIMER_FIRST_REG, + M6811_TIMER_LAST_REG - M6811_TIMER_FIRST_REG + 1, + me); +} + +static void +m68hc11tim_finish (struct hw *me) +{ + struct m68hc11tim *controller; + + controller = HW_ZALLOC (me, struct m68hc11tim); + set_hw_data (me, controller); + set_hw_io_read_buffer (me, m68hc11tim_io_read_buffer); + set_hw_io_write_buffer (me, m68hc11tim_io_write_buffer); + set_hw_ports (me, m68hc11tim_ports); + set_hw_port_event (me, m68hc11tim_port_event); +#ifdef set_hw_ioctl + set_hw_ioctl (me, m68hc11tim_ioctl); +#else + me->to_ioctl = m68hc11tim_ioctl; +#endif + + /* Preset defaults. */ + controller->clock_prescaler = 1; + controller->tcnt_adjust = 0; + + /* Attach ourself to our parent bus. */ + attach_m68hc11tim_regs (me, controller); +} + + +/* An event arrives on an interrupt port. */ + +static void +m68hc11tim_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + SIM_DESC sd; + struct m68hc11tim *controller; + sim_cpu *cpu; + unsigned8 val; + unsigned16 tcnt; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + switch (my_port) + { + case RESET_PORT: + { + HW_TRACE ((me, "Timer reset")); + + /* Cancel all timer events. */ + if (controller->rti_timer_event) + { + hw_event_queue_deschedule (me, controller->rti_timer_event); + controller->rti_timer_event = 0; + controller->rti_prev_interrupt = 0; + } + if (controller->cop_timer_event) + { + hw_event_queue_deschedule (me, controller->cop_timer_event); + controller->cop_timer_event = 0; + controller->cop_prev_interrupt = 0; + } + if (controller->tof_timer_event) + { + hw_event_queue_deschedule (me, controller->tof_timer_event); + controller->tof_timer_event = 0; + } + if (controller->cmp_timer_event) + { + hw_event_queue_deschedule (me, controller->cmp_timer_event); + controller->cmp_timer_event = 0; + } + + /* Reset the state of Timer registers. This also restarts + the timer events (overflow and RTI clock). The pending + flags (TFLG2) must be cleared explicitly here. */ + val = 0; + cpu->ios[M6811_TFLG2] = 0; + m68hc11tim_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_TMSK2, 1); + m68hc11tim_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_PACTL, 1); + break; + } + + case CAPTURE: + tcnt = (uint16) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler); + switch (level) + { + case M6811_TIC1: + case M6811_TIC2: + case M6811_TIC3: + cpu->ios[level] = tcnt >> 8; + cpu->ios[level + 1] = tcnt; + break; + + default: + hw_abort (me, "Invalid event parameter %d", level); + break; + } + break; + + default: + hw_abort (me, "Event on unknown port %d", my_port); + break; + } +} + +enum event_type +{ + COP_EVENT, + RTI_EVENT, + OVERFLOW_EVENT, + COMPARE_EVENT +}; + +void +m68hc11tim_timer_event (struct hw *me, void *data) +{ + SIM_DESC sd; + struct m68hc11tim *controller; + sim_cpu *cpu; + enum event_type type; + unsigned long delay; + struct hw_event **eventp; + int check_interrupt = 0; + unsigned mask; + unsigned flags; + unsigned long tcnt_internal; + unsigned long tcnt, tcnt_prev; + signed64 tcnt_insn_end; + signed64 tcnt_insn_start; + int i; + sim_events *events; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + type = (enum event_type) ((long) data) & 0x0FF; + events = STATE_EVENTS (sd); + + delay = 0; + switch (type) + { + case COP_EVENT: + eventp = &controller->cop_timer_event; + delay = controller->cop_delay; + delay = controller->cop_prev_interrupt + controller->cop_delay; + controller->cop_prev_interrupt = delay; + delay = delay - cpu->cpu_absolute_cycle; + check_interrupt = 1; + delay += events->nr_ticks_to_process; + break; + + case RTI_EVENT: + eventp = &controller->rti_timer_event; + delay = controller->rti_prev_interrupt + controller->rti_delay; + + if (((long) (data) & 0x0100) == 0) + { + cpu->ios[M6811_TFLG2] |= M6811_RTIF; + check_interrupt = 1; + controller->rti_prev_interrupt = delay; + delay += controller->rti_delay; + } + delay = delay - cpu->cpu_absolute_cycle; + delay += events->nr_ticks_to_process; + break; + + case OVERFLOW_EVENT: + /* Compute the 68HC11 internal free running counter. */ + tcnt_internal = (cpu->cpu_absolute_cycle - controller->tcnt_adjust); + + /* We must take into account the prescaler that comes + before the counter (it's a power of 2). */ + tcnt_internal &= 0x0ffff * controller->clock_prescaler; + + /* Compute the time when the overflow will occur. It occurs when + the counter increments from 0x0ffff to 0x10000 (and thus resets). */ + delay = (0x10000 * controller->clock_prescaler) - tcnt_internal; + + /* The 'nr_ticks_to_process' will be subtracted when the event + is scheduled. */ + delay += events->nr_ticks_to_process; + + eventp = &controller->tof_timer_event; + if (((long) (data) & 0x100) == 0) + { + cpu->ios[M6811_TFLG2] |= M6811_TOF; + check_interrupt = 1; + } + break; + + case COMPARE_EVENT: + /* Compute value of TCNT register (64-bit precision) at beginning + and end of instruction. */ + tcnt_insn_end = (cpu->cpu_absolute_cycle - controller->tcnt_adjust); + tcnt_insn_start = (tcnt_insn_end - cpu->cpu_current_cycle); + + /* TCNT value at beginning of current instruction. */ + tcnt_prev = (tcnt_insn_start / controller->clock_prescaler) & 0x0ffff; + + /* TCNT value at end of current instruction. */ + tcnt = (tcnt_insn_end / controller->clock_prescaler) & 0x0ffff; + + /* We must take into account the prescaler that comes + before the counter (it's a power of 2). */ + tcnt_internal = tcnt_insn_end; + tcnt_internal &= 0x0ffff * controller->clock_prescaler; + + flags = cpu->ios[M6811_TMSK1]; + mask = 0x80; + delay = 65536 * controller->clock_prescaler; + + /* Scan each output compare register to see if one matches + the free running counter. Set the corresponding OCi flag + if the output compare is enabled. */ + for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1) + { + unsigned long compare; + + compare = (cpu->ios[i] << 8) + cpu->ios[i + 1]; + + /* See if compare is reached; handle wrap arround. */ + if ((compare >= tcnt_prev && compare <= tcnt && tcnt_prev < tcnt) + || (compare >= tcnt_prev && tcnt_prev > tcnt) + || (compare < tcnt && tcnt_prev > tcnt)) + { + unsigned dt; + + if (compare > tcnt) + dt = 0x10000 - compare - tcnt; + else + dt = tcnt - compare; + + cpu->ios[M6811_TFLG1] |= mask; + + /* Raise interrupt now at the correct CPU cycle so that + we can find the interrupt latency. */ + cpu->cpu_absolute_cycle -= dt; + interrupts_update_pending (&cpu->cpu_interrupts); + cpu->cpu_absolute_cycle += dt; + } + + /* Compute how many times for the next match. + Use the internal counter value to take into account the + prescaler accurately. */ + compare = compare * controller->clock_prescaler; + if (compare > tcnt_internal) + compare = compare - tcnt_internal; + else + compare = compare - tcnt_internal + + 65536 * controller->clock_prescaler; + + if (compare < delay) + delay = compare; + } + + /* Deactivate the compare timer if no output compare is enabled. */ + if ((flags & 0xF8) == 0) + delay = 0; + else + delay += events->nr_ticks_to_process; + + eventp = &controller->cmp_timer_event; + break; + + default: + eventp = 0; + break; + } + + if (*eventp) + { + hw_event_queue_deschedule (me, *eventp); + *eventp = 0; + } + + if (delay != 0) + { + *eventp = hw_event_queue_schedule (me, delay, + m68hc11tim_timer_event, + (void*) type); + } + + if (check_interrupt) + interrupts_update_pending (&cpu->cpu_interrupts); +} + + +/* Descriptions of the Timer I/O ports. These descriptions are only used to + give information of the Timer device under GDB. */ +io_reg_desc tmsk1_desc[] = { + { M6811_OC1I, "OC1I ", "Timer Output Compare 1 Interrupt Enable" }, + { M6811_OC2I, "OC2I ", "Timer Output Compare 2 Interrupt Enable" }, + { M6811_OC3I, "OC3I ", "Timer Output Compare 3 Interrupt Enable" }, + { M6811_OC4I, "OC4I ", "Timer Output Compare 4 Interrupt Enable" }, + { M6811_OC5I, "OC5I ", "Timer Input Capture 4 / Output Compare 5 Enable" }, + { M6811_IC1I, "IC1I ", "Timer Input Capture 1 Interrupt Enable" }, + { M6811_IC2I, "IC2I ", "Timer Input Capture 2 Interrupt Enable" }, + { M6811_IC3I, "IC3I ", "Timer Input Capture 3 Interrupt Enable" }, + { 0, 0, 0 } +}; + +io_reg_desc tflg1_desc[] = { + { M6811_OC1F, "OC1F ", "Timer Output Compare 1 Interrupt Flag" }, + { M6811_OC2F, "OC2F ", "Timer Output Compare 2 Interrupt Flag" }, + { M6811_OC3F, "OC3F ", "Timer Output Compare 3 Interrupt Flag" }, + { M6811_OC4F, "OC4F ", "Timer Output Compare 4 Interrupt Flag" }, + { M6811_OC5F, "OC5F ", "Timer Input Capture 4 / Output Compare 5 Flag" }, + { M6811_IC1F, "IC1F ", "Timer Input Capture 1 Interrupt Flag" }, + { M6811_IC2F, "IC2F ", "Timer Input Capture 2 Interrupt Flag" }, + { M6811_IC3F, "IC3F ", "Timer Input Capture 3 Interrupt Flag" }, + { 0, 0, 0 } +}; + +io_reg_desc tmsk2_desc[] = { + { M6811_TOI, "TOI ", "Timer Overflow Interrupt Enable" }, + { M6811_RTII, "RTII ", "RTI Interrupt Enable" }, + { M6811_PAOVI, "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" }, + { M6811_PAII, "PAII ", "Pulse Accumulator Interrupt Enable" }, + { M6811_PR1, "PR1 ", "Timer prescaler (PR1)" }, + { M6811_PR0, "PR0 ", "Timer prescaler (PR0)" }, + { M6811_TPR_1, "TPR_1 ", "Timer prescaler div 1" }, + { M6811_TPR_4, "TPR_4 ", "Timer prescaler div 4" }, + { M6811_TPR_8, "TPR_8 ", "Timer prescaler div 8" }, + { M6811_TPR_16, "TPR_16", "Timer prescaler div 16" }, + { 0, 0, 0 } +}; + +io_reg_desc tflg2_desc[] = { + { M6811_TOF, "TOF ", "Timer Overflow Bit" }, + { M6811_RTIF, "RTIF ", "Read Time Interrupt Flag" }, + { M6811_PAOVF, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" }, + { M6811_PAIF, "PAIF ", "Pulse Accumulator Input Edge" }, + { 0, 0, 0 } +}; + +io_reg_desc pactl_desc[] = { + { M6811_DDRA7, "DDRA7 ", "Data Direction for Port A bit-7" }, + { M6811_PAEN, "PAEN ", "Pulse Accumulator System Enable" }, + { M6811_PAMOD, "PAMOD ", "Pulse Accumulator Mode" }, + { M6811_PEDGE, "PEDGE ", "Pulse Accumulator Edge Control" }, + { M6811_RTR1, "RTR1 ", "RTI Interrupt rate select (RTR1)" }, + { M6811_RTR0, "RTR0 ", "RTI Interrupt rate select (RTR0)" }, + { 0, 0, 0 } +}; + +static double +to_realtime (sim_cpu *cpu, signed64 t) +{ + return (double) (t) / (double) (cpu->cpu_frequency / 4); +} + +const char* +cycle_to_string (sim_cpu *cpu, signed64 t, int flags) +{ + char time_buf[32]; + char cycle_buf[32]; + static char buf[64]; + + time_buf[0] = 0; + cycle_buf[0] = 0; + if (flags & PRINT_TIME) + { + double dt; + + dt = to_realtime (cpu, t); + if (dt < 0.001) + sprintf (time_buf, " (%3.1f us)", dt * 1000000.0); + else if (dt < 1.0) + sprintf (time_buf, " (%3.1f ms)", dt * 1000.0); + else + sprintf (time_buf, " (%3.1f s)", dt); + } + + if (flags & PRINT_CYCLE) + sprintf (cycle_buf, " cycle%s", + (t > 1 ? "s" : "")); + + if (t < LONG_MAX) + sprintf (buf, "%9lu%s%s", (unsigned long) t, cycle_buf, time_buf); + else + sprintf (buf, "%llu%s%s", t, cycle_buf, time_buf); + return buf; +} + +static void +m68hc11tim_print_timer (struct hw *me, const char *name, + struct hw_event *event) +{ + SIM_DESC sd; + + sd = hw_system (me); + if (event == 0) + { + sim_io_printf (sd, " No %s interrupt will be raised.\n", name); + } + else + { + signed64 t; + sim_cpu* cpu; + + cpu = STATE_CPU (sd, 0); + + t = hw_event_remain_time (me, event); + sim_io_printf (sd, " Next %s interrupt in %s\n", + name, cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE)); + } +} + +static void +m68hc11tim_info (struct hw *me) +{ + SIM_DESC sd; + uint16 base = 0; + sim_cpu *cpu; + struct m68hc11tim *controller; + uint8 val; + uint16 val16; + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + sim_io_printf (sd, "M68HC11 Timer:\n"); + + base = cpu_get_io_base (cpu); + + /* Info for TIC1 */ + val16 = (cpu->ios[M6811_TIC1_H] << 8) + cpu->ios[M6811_TIC1_L]; + print_io_word (sd, "TIC1 ", 0, val16, base + M6811_TIC1); + sim_io_printf (sd, "\n"); + + /* Info for TIC2 */ + val16 = (cpu->ios[M6811_TIC2_H] << 8) + cpu->ios[M6811_TIC2_L]; + print_io_word (sd, "TIC2 ", 0, val16, base + M6811_TIC2); + sim_io_printf (sd, "\n"); + + /* Info for TIC3 */ + val16 = (cpu->ios[M6811_TIC3_H] << 8) + cpu->ios[M6811_TIC3_L]; + print_io_word (sd, "TIC3 ", 0, val16, base + M6811_TIC3); + sim_io_printf (sd, "\n"); + + /* Info for TOC1 */ + val16 = (cpu->ios[M6811_TOC1_H] << 8) + cpu->ios[M6811_TOC1_L]; + print_io_word (sd, "TOC1 ", 0, val16, base + M6811_TOC1); + sim_io_printf (sd, "\n"); + + /* Info for TOC2 */ + val16 = (cpu->ios[M6811_TOC2_H] << 8) + cpu->ios[M6811_TOC2_L]; + print_io_word (sd, "TOC2 ", 0, val16, base + M6811_TOC2); + sim_io_printf (sd, "\n"); + + /* Info for TOC3 */ + val16 = (cpu->ios[M6811_TOC3_H] << 8) + cpu->ios[M6811_TOC3_L]; + print_io_word (sd, "TOC3 ", 0, val16, base + M6811_TOC3); + sim_io_printf (sd, "\n"); + + /* Info for TOC4 */ + val16 = (cpu->ios[M6811_TOC4_H] << 8) + cpu->ios[M6811_TOC4_L]; + print_io_word (sd, "TOC4 ", 0, val16, base + M6811_TOC4); + sim_io_printf (sd, "\n"); + + /* Info for TOC5 */ + val16 = (cpu->ios[M6811_TOC5_H] << 8) + cpu->ios[M6811_TOC5_L]; + print_io_word (sd, "TOC5 ", 0, val16, base + M6811_TOC5); + sim_io_printf (sd, "\n"); + + /* Info for TMSK1 */ + val = cpu->ios[M6811_TMSK1]; + print_io_byte (sd, "TMSK1 ", tmsk1_desc, val, base + M6811_TMSK1); + sim_io_printf (sd, "\n"); + + /* Info for TFLG1 */ + val = cpu->ios[M6811_TFLG1]; + print_io_byte (sd, "TFLG1", tflg1_desc, val, base + M6811_TFLG1); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_TMSK2]; + print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_TFLG2]; + print_io_byte (sd, "TFLG2", tflg2_desc, val, base + M6811_TFLG2); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_PACTL]; + print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_PACNT]; + print_io_byte (sd, "PACNT", 0, val, base + M6811_PACNT); + sim_io_printf (sd, "\n"); + + /* Give info about the next timer interrupts. */ + m68hc11tim_print_timer (me, "RTI", controller->rti_timer_event); + m68hc11tim_print_timer (me, "COP", controller->cop_timer_event); + m68hc11tim_print_timer (me, "OVERFLOW", controller->tof_timer_event); + m68hc11tim_print_timer (me, "COMPARE", controller->cmp_timer_event); +} + +static int +m68hc11tim_ioctl (struct hw *me, + hw_ioctl_request request, + va_list ap) +{ + m68hc11tim_info (me); + return 0; +} + +/* generic read/write */ + +static unsigned +m68hc11tim_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11tim *controller; + sim_cpu *cpu; + unsigned8 val; + unsigned cnt = 0; + + HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + while (nr_bytes) + { + switch (base) + { + /* The cpu_absolute_cycle is updated after each instruction. + Reading in a 16-bit register will be split in two accesses + but this will be atomic within the simulator. */ + case M6811_TCTN_H: + val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / (controller->clock_prescaler * 256)); + break; + + case M6811_TCTN_L: + val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler); + break; + + default: + val = cpu->ios[base]; + break; + } + *((unsigned8*) dest) = val; + dest = (char*) dest + 1; + base++; + nr_bytes--; + cnt++; + } + return cnt; +} + +static unsigned +m68hc11tim_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11tim *controller; + sim_cpu *cpu; + unsigned8 val, n; + signed64 adj; + int reset_compare = 0; + int reset_overflow = 0; + int cnt = 0; + + HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + while (nr_bytes) + { + val = *((const unsigned8*) source); + switch (base) + { + /* Set the timer counter low part, trying to preserve the low part. + We compute the absolute cycle adjustment that we have to apply + to obtain the timer current value. Computation must be made + in 64-bit to avoid overflow problems. */ + case M6811_TCTN_L: + adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / (controller->clock_prescaler * (signed64) 256)) & 0x0FF; + adj = cpu->cpu_absolute_cycle + - (adj * controller->clock_prescaler * (signed64) 256) + - ((signed64) adj * controller->clock_prescaler); + controller->tcnt_adjust = adj; + reset_compare = 1; + reset_overflow = 1; + break; + + case M6811_TCTN_H: + adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler) & 0x0ff; + adj = cpu->cpu_absolute_cycle + - ((signed64) val * controller->clock_prescaler * (signed64) 256) + - (adj * controller->clock_prescaler); + controller->tcnt_adjust = adj; + reset_compare = 1; + reset_overflow = 1; + break; + + case M6811_TMSK2: + + /* Timer prescaler cannot be changed after 64 bus cycles. */ + if (cpu->cpu_absolute_cycle >= 64) + { + val &= ~(M6811_PR1 | M6811_PR0); + val |= cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0); + } + switch (val & (M6811_PR1 | M6811_PR0)) + { + case 0: + n = 1; + break; + case M6811_PR0: + n = 4; + break; + case M6811_PR1: + n = 8; + break; + default: + case M6811_PR1 | M6811_PR0: + n = 16; + break; + } + if (cpu->cpu_absolute_cycle < 64) + { + reset_overflow = 1; + controller->clock_prescaler = n; + } + cpu->ios[base] = val; + interrupts_update_pending (&cpu->cpu_interrupts); + break; + + case M6811_PACTL: + n = (1 << ((val & (M6811_RTR1 | M6811_RTR0)))); + cpu->ios[base] = val; + + controller->rti_delay = (long) (n) * 8192; + m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100)); + break; + + case M6811_TFLG2: + val &= cpu->ios[M6811_TFLG2]; + cpu->ios[M6811_TFLG2] &= ~val; + interrupts_update_pending (&cpu->cpu_interrupts); + break; + + case M6811_TMSK1: + cpu->ios[M6811_TMSK1] = val; + interrupts_update_pending (&cpu->cpu_interrupts); + reset_compare = 1; + break; + + case M6811_TFLG1: + val &= cpu->ios[M6811_TFLG1]; + cpu->ios[M6811_TFLG1] &= ~val; + interrupts_update_pending (&cpu->cpu_interrupts); + break; + + case M6811_TOC1: + case M6811_TOC2: + case M6811_TOC3: + case M6811_TOC4: + case M6811_TOC5: + cpu->ios[base] = val; + reset_compare = 1; + break; + + case M6811_TCTL1: + case M6811_TCTL2: + cpu->ios[base] = val; + break; + + default: + cpu->ios[base] = val; + break; + } + + base++; + nr_bytes--; + cnt++; + source = (char*) source + 1; + } + + /* Re-compute the next timer compare event. */ + if (reset_compare) + { + m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT)); + } + if (reset_overflow) + { + m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100)); + } + return cnt; +} + + +const struct hw_descriptor dv_m68hc11tim_descriptor[] = { + { "m68hc11tim", m68hc11tim_finish }, + { "m68hc12tim", m68hc11tim_finish }, + { NULL }, +}; +
dv-m68hc11tim.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dv-m68hc11sio.c =================================================================== --- dv-m68hc11sio.c (nonexistent) +++ dv-m68hc11sio.c (revision 33) @@ -0,0 +1,661 @@ +/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device. + Copyright (C) 1999, 2000, 2001, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@worldnet.fr) + (From a driver model Contributed by Cygnus Solutions.) + + This file is part of the program 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 3 of the License, 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, see . + + */ + + +#include "sim-main.h" +#include "hw-main.h" +#include "dv-sockser.h" +#include "sim-assert.h" + + +/* DEVICE + + m68hc11sio - m68hc11 serial I/O + + + DESCRIPTION + + Implements the m68hc11 serial I/O controller described in the m68hc11 + user guide. The serial I/O controller is directly connected to the CPU + interrupt. The simulator implements: + + - baud rate emulation + - 8-bits transfers + + PROPERTIES + + backend {tcp | stdio} + + Use dv-sockser TCP-port backend or stdio for backend. Default: stdio. + + + PORTS + + reset (input) + + Reset port. This port is only used to simulate a reset of the serial + I/O controller. It should be connected to the RESET output of the cpu. + + */ + + + +/* port ID's */ + +enum +{ + RESET_PORT +}; + + +static const struct hw_port_descriptor m68hc11sio_ports[] = +{ + { "reset", RESET_PORT, 0, input_port, }, + { NULL, }, +}; + + +/* Serial Controller information. */ +struct m68hc11sio +{ + enum {sio_tcp, sio_stdio} backend; /* backend */ + + /* Number of cpu cycles to send a bit on the wire. */ + unsigned long baud_cycle; + + /* Length in bits of characters sent, this includes the + start/stop and parity bits. Together with baud_cycle, this + is used to find the number of cpu cycles to send/receive a data. */ + unsigned int data_length; + + /* Information about next character to be transmited. */ + unsigned char tx_has_char; + unsigned char tx_char; + + unsigned char rx_char; + unsigned char rx_clear_scsr; + + /* Periodic I/O polling. */ + struct hw_event* tx_poll_event; + struct hw_event* rx_poll_event; +}; + + + +/* Finish off the partially created hw device. Attach our local + callbacks. Wire up our port names etc. */ + +static hw_io_read_buffer_method m68hc11sio_io_read_buffer; +static hw_io_write_buffer_method m68hc11sio_io_write_buffer; +static hw_port_event_method m68hc11sio_port_event; +static hw_ioctl_method m68hc11sio_ioctl; + +#define M6811_SCI_FIRST_REG (M6811_BAUD) +#define M6811_SCI_LAST_REG (M6811_SCDR) + + +static void +attach_m68hc11sio_regs (struct hw *me, + struct m68hc11sio *controller) +{ + hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, + M6811_SCI_FIRST_REG, + M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1, + me); + + if (hw_find_property(me, "backend") != NULL) + { + const char *value = hw_find_string_property(me, "backend"); + if(! strcmp(value, "tcp")) + controller->backend = sio_tcp; + else if(! strcmp(value, "stdio")) + controller->backend = sio_stdio; + else + hw_abort (me, "illegal value for backend parameter `%s':" + "use tcp or stdio", value); + } +} + + +static void +m68hc11sio_finish (struct hw *me) +{ + struct m68hc11sio *controller; + + controller = HW_ZALLOC (me, struct m68hc11sio); + set_hw_data (me, controller); + set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer); + set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer); + set_hw_ports (me, m68hc11sio_ports); + set_hw_port_event (me, m68hc11sio_port_event); +#ifdef set_hw_ioctl + set_hw_ioctl (me, m68hc11sio_ioctl); +#else + me->to_ioctl = m68hc11sio_ioctl; +#endif + + /* Preset defaults. */ + controller->backend = sio_stdio; + + /* Attach ourself to our parent bus. */ + attach_m68hc11sio_regs (me, controller); + + /* Initialize to reset state. */ + controller->tx_poll_event = NULL; + controller->rx_poll_event = NULL; + controller->tx_char = 0; + controller->tx_has_char = 0; + controller->rx_clear_scsr = 0; + controller->rx_char = 0; +} + + + +/* An event arrives on an interrupt port. */ + +static void +m68hc11sio_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + SIM_DESC sd; + struct m68hc11sio *controller; + sim_cpu *cpu; + unsigned8 val; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + switch (my_port) + { + case RESET_PORT: + { + HW_TRACE ((me, "SCI reset")); + + /* Reset the state of SCI registers. */ + val = 0; + m68hc11sio_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_BAUD, 1); + m68hc11sio_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_SCCR1, 1); + m68hc11sio_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_SCCR2, 1); + + cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE; + controller->rx_char = 0; + controller->tx_char = 0; + controller->tx_has_char = 0; + controller->rx_clear_scsr = 0; + if (controller->rx_poll_event) + { + hw_event_queue_deschedule (me, controller->rx_poll_event); + controller->rx_poll_event = 0; + } + if (controller->tx_poll_event) + { + hw_event_queue_deschedule (me, controller->tx_poll_event); + controller->tx_poll_event = 0; + } + + /* In bootstrap mode, initialize the SCI to 1200 bauds to + simulate some initial setup by the internal rom. */ + if (((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD) + { + unsigned char val = 0x33; + + m68hc11sio_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_BAUD, 1); + val = 0x12; + m68hc11sio_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_SCCR2, 1); + } + break; + } + + default: + hw_abort (me, "Event on unknown port %d", my_port); + break; + } +} + + +void +m68hc11sio_rx_poll (struct hw *me, void *data) +{ + SIM_DESC sd; + struct m68hc11sio *controller; + sim_cpu *cpu; + char cc; + int cnt; + int check_interrupt = 0; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + switch (controller->backend) + { + case sio_tcp: + cnt = dv_sockser_read (sd); + if (cnt != -1) + { + cc = (char) cnt; + cnt = 1; + } + break; + + case sio_stdio: + cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1); + break; + + default: + cnt = 0; + break; + } + + if (cnt == 1) + { + /* Raise the overrun flag if the previous character was not read. */ + if (cpu->ios[M6811_SCSR] & M6811_RDRF) + cpu->ios[M6811_SCSR] |= M6811_OR; + + cpu->ios[M6811_SCSR] |= M6811_RDRF; + controller->rx_char = cc; + controller->rx_clear_scsr = 0; + check_interrupt = 1; + } + else + { + /* handle idle line detect here. */ + ; + } + + if (controller->rx_poll_event) + { + hw_event_queue_deschedule (me, controller->rx_poll_event); + controller->rx_poll_event = 0; + } + + if (cpu->ios[M6811_SCCR2] & M6811_RE) + { + unsigned long clock_cycle; + + /* Compute CPU clock cycles to wait for the next character. */ + clock_cycle = controller->data_length * controller->baud_cycle; + + controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle, + m68hc11sio_rx_poll, + NULL); + } + + if (check_interrupt) + interrupts_update_pending (&cpu->cpu_interrupts); +} + + +void +m68hc11sio_tx_poll (struct hw *me, void *data) +{ + SIM_DESC sd; + struct m68hc11sio *controller; + sim_cpu *cpu; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + + cpu->ios[M6811_SCSR] |= M6811_TDRE; + cpu->ios[M6811_SCSR] |= M6811_TC; + + /* Transmitter is enabled and we have something to send. */ + if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char) + { + cpu->ios[M6811_SCSR] &= ~M6811_TDRE; + cpu->ios[M6811_SCSR] &= ~M6811_TC; + controller->tx_has_char = 0; + switch (controller->backend) + { + case sio_tcp: + dv_sockser_write (sd, controller->tx_char); + break; + + case sio_stdio: + sim_io_write_stdout (sd, &controller->tx_char, 1); + sim_io_flush_stdout (sd); + break; + + default: + break; + } + } + + if (controller->tx_poll_event) + { + hw_event_queue_deschedule (me, controller->tx_poll_event); + controller->tx_poll_event = 0; + } + + if ((cpu->ios[M6811_SCCR2] & M6811_TE) + && ((cpu->ios[M6811_SCSR] & M6811_TC) == 0)) + { + unsigned long clock_cycle; + + /* Compute CPU clock cycles to wait for the next character. */ + clock_cycle = controller->data_length * controller->baud_cycle; + + controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle, + m68hc11sio_tx_poll, + NULL); + } + + interrupts_update_pending (&cpu->cpu_interrupts); +} + +/* Descriptions of the SIO I/O ports. These descriptions are only used to + give information of the SIO device under GDB. */ +io_reg_desc sccr2_desc[] = { + { M6811_TIE, "TIE ", "Transmit Interrupt Enable" }, + { M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" }, + { M6811_RIE, "RIE ", "Receive Interrupt Enable" }, + { M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" }, + { M6811_TE, "TE ", "Transmit Enable" }, + { M6811_RE, "RE ", "Receive Enable" }, + { M6811_RWU, "RWU ", "Receiver Wake Up" }, + { M6811_SBK, "SBRK ", "Send Break" }, + { 0, 0, 0 } +}; + +io_reg_desc sccr1_desc[] = { + { M6811_R8, "R8 ", "Receive Data bit 8" }, + { M6811_T8, "T8 ", "Transmit Data bit 8" }, + { M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" }, + { M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" }, + { 0, 0, 0 } +}; + +io_reg_desc scsr_desc[] = { + { M6811_TDRE, "TDRE ", "Transmit Data Register Empty" }, + { M6811_TC, "TC ", "Transmit Complete" }, + { M6811_RDRF, "RDRF ", "Receive Data Register Full" }, + { M6811_IDLE, "IDLE ", "Idle Line Detect" }, + { M6811_OR, "OR ", "Overrun Error" }, + { M6811_NF, "NF ", "Noise Flag" }, + { M6811_FE, "FE ", "Framing Error" }, + { 0, 0, 0 } +}; + +io_reg_desc baud_desc[] = { + { M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" }, + { M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" }, + { M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" }, + { M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" }, + { M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" }, + { M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" }, + { M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" }, + { 0, 0, 0 } +}; + +static void +m68hc11sio_info (struct hw *me) +{ + SIM_DESC sd; + uint16 base = 0; + sim_cpu *cpu; + struct m68hc11sio *controller; + uint8 val; + long clock_cycle; + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + sim_io_printf (sd, "M68HC11 SIO:\n"); + + base = cpu_get_io_base (cpu); + + val = cpu->ios[M6811_BAUD]; + print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD); + sim_io_printf (sd, " (%ld baud)\n", + (cpu->cpu_frequency / 4) / controller->baud_cycle); + + val = cpu->ios[M6811_SCCR1]; + print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1); + sim_io_printf (sd, " (%d bits) (%dN1)\n", + controller->data_length, controller->data_length - 2); + + val = cpu->ios[M6811_SCCR2]; + print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_SCSR]; + print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR); + sim_io_printf (sd, "\n"); + + clock_cycle = controller->data_length * controller->baud_cycle; + + if (controller->tx_poll_event) + { + signed64 t; + int n; + + t = hw_event_remain_time (me, controller->tx_poll_event); + n = (clock_cycle - t) / controller->baud_cycle; + n = controller->data_length - n; + sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n", + cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE), + n, (n > 1 ? "s" : "")); + } + if (controller->rx_poll_event) + { + signed64 t; + + t = hw_event_remain_time (me, controller->rx_poll_event); + sim_io_printf (sd, " Receive finished in %s\n", + cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE)); + } + +} + +static int +m68hc11sio_ioctl (struct hw *me, + hw_ioctl_request request, + va_list ap) +{ + m68hc11sio_info (me); + return 0; +} + +/* generic read/write */ + +static unsigned +m68hc11sio_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11sio *controller; + sim_cpu *cpu; + unsigned8 val; + + HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + switch (base) + { + case M6811_SCSR: + controller->rx_clear_scsr = cpu->ios[M6811_SCSR] + & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE); + + case M6811_BAUD: + case M6811_SCCR1: + case M6811_SCCR2: + val = cpu->ios[base]; + break; + + case M6811_SCDR: + if (controller->rx_clear_scsr) + { + cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr; + } + val = controller->rx_char; + break; + + default: + return 0; + } + *((unsigned8*) dest) = val; + return 1; +} + +static unsigned +m68hc11sio_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11sio *controller; + sim_cpu *cpu; + unsigned8 val; + + HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + val = *((const unsigned8*) source); + switch (base) + { + case M6811_BAUD: + { + long divisor; + long baud; + + cpu->ios[M6811_BAUD] = val; + switch (val & (M6811_SCP1|M6811_SCP0)) + { + case M6811_BAUD_DIV_1: + divisor = 1 * 16; + break; + + case M6811_BAUD_DIV_3: + divisor = 3 * 16; + break; + + case M6811_BAUD_DIV_4: + divisor = 4 * 16; + break; + + default: + case M6811_BAUD_DIV_13: + divisor = 13 * 16; + break; + } + val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0); + divisor *= (1 << val); + + baud = (cpu->cpu_frequency / 4) / divisor; + + HW_TRACE ((me, "divide rate %ld, baud rate %ld", + divisor, baud)); + + controller->baud_cycle = divisor; + } + break; + + case M6811_SCCR1: + { + if (val & M6811_M) + controller->data_length = 11; + else + controller->data_length = 10; + + cpu->ios[M6811_SCCR1] = val; + } + break; + + case M6811_SCCR2: + if ((val & M6811_RE) == 0) + { + val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF); + val |= (cpu->ios[M6811_SCCR2] + & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF)); + cpu->ios[M6811_SCCR2] = val; + break; + } + + /* Activate reception. */ + if (controller->rx_poll_event == 0) + { + long clock_cycle; + + /* Compute CPU clock cycles to wait for the next character. */ + clock_cycle = controller->data_length * controller->baud_cycle; + + controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle, + m68hc11sio_rx_poll, + NULL); + } + cpu->ios[M6811_SCCR2] = val; + interrupts_update_pending (&cpu->cpu_interrupts); + break; + + /* No effect. */ + case M6811_SCSR: + return 1; + + case M6811_SCDR: + if (!(cpu->ios[M6811_SCSR] & M6811_TDRE)) + { + return 0; + } + + controller->tx_char = val; + controller->tx_has_char = 1; + if ((cpu->ios[M6811_SCCR2] & M6811_TE) + && controller->tx_poll_event == 0) + { + m68hc11sio_tx_poll (me, NULL); + } + return 1; + + default: + return 0; + } + return nr_bytes; +} + + +const struct hw_descriptor dv_m68hc11sio_descriptor[] = { + { "m68hc11sio", m68hc11sio_finish }, + { "m68hc12sio", m68hc11sio_finish }, + { NULL }, +}; +
dv-m68hc11sio.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dv-m68hc11eepr.c =================================================================== --- dv-m68hc11eepr.c (nonexistent) +++ dv-m68hc11eepr.c (revision 33) @@ -0,0 +1,628 @@ +/* dv-m68hc11eepr.c -- Simulation of the 68HC11 Internal EEPROM. + Copyright (C) 1999, 2000, 2001, 2002, 2007, 2008 + Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.fr) + (From a driver model Contributed by Cygnus Solutions.) + + 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. + + 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, see . + + */ + + +#include "sim-main.h" +#include "hw-main.h" +#include "sim-assert.h" +#include "sim-events.h" + +#include +#include +#include + + + +/* DEVICE + + m68hc11eepr - m68hc11 EEPROM + + + DESCRIPTION + + Implements the 68HC11 eeprom device described in the m68hc11 + user guide (Chapter 4 in the pink book). + + + PROPERTIES + + reg + + Base of eeprom and its length. + + file + + Path of the EEPROM file. The default is 'm6811.eeprom'. + + + PORTS + + None + + */ + + + +/* static functions */ + + +/* port ID's */ + +enum +{ + RESET_PORT +}; + + +static const struct hw_port_descriptor m68hc11eepr_ports[] = +{ + { "reset", RESET_PORT, 0, input_port, }, + { NULL, }, +}; + + + +/* The timer/counter register internal state. Note that we store + state using the control register images, in host endian order. */ + +struct m68hc11eepr +{ + address_word base_address; /* control register base */ + int attach_space; + unsigned size; + int mapped; + + /* Current state of the eeprom programing: + - eeprom_wmode indicates whether the EEPROM address and byte have + been latched. + - eeprom_waddr indicates the EEPROM address that was latched + and eeprom_wbyte is the byte that was latched. + - eeprom_wcycle indicates the CPU absolute cycle type when + the high voltage was applied (successfully) on the EEPROM. + + These data members are setup only when we detect good EEPROM programing + conditions (see Motorola EEPROM Programming and PPROG register usage). + When the high voltage is switched off, we look at the CPU absolute + cycle time to see if the EEPROM command must succeeds or not. + The EEPROM content is updated and saved only at that time. + (EEPROM command is: byte zero bits program, byte erase, row erase + and bulk erase). + + The CONFIG register is programmed in the same way. It is physically + located at the end of the EEPROM (eeprom size + 1). It is not mapped + in memory but it's saved in the EEPROM file. */ + unsigned long eeprom_wcycle; + uint16 eeprom_waddr; + uint8 eeprom_wbyte; + uint8 eeprom_wmode; + + uint8* eeprom; + + /* Minimum time in CPU cycles for programming the EEPROM. */ + unsigned long eeprom_min_cycles; + + const char* file_name; +}; + + + +/* Finish off the partially created hw device. Attach our local + callbacks. Wire up our port names etc. */ + +static hw_io_read_buffer_method m68hc11eepr_io_read_buffer; +static hw_io_write_buffer_method m68hc11eepr_io_write_buffer; +static hw_ioctl_method m68hc11eepr_ioctl; + +/* Read or write the memory bank content from/to a file. + Returns 0 if the operation succeeded and -1 if it failed. */ +static int +m6811eepr_memory_rw (struct m68hc11eepr *controller, int mode) +{ + const char *name = controller->file_name; + int fd; + size_t size; + + size = controller->size; + fd = open (name, mode, 0644); + if (fd < 0) + { + if (mode == O_RDONLY) + { + memset (controller->eeprom, 0xFF, size); + /* Default value for CONFIG register (0xFF should be ok): + controller->eeprom[size - 1] = M6811_NOSEC | M6811_NOCOP + | M6811_ROMON | M6811_EEON; */ + return 0; + } + return -1; + } + + if (mode == O_RDONLY) + { + if (read (fd, controller->eeprom, size) != size) + { + close (fd); + return -1; + } + } + else + { + if (write (fd, controller->eeprom, size) != size) + { + close (fd); + return -1; + } + } + close (fd); + + return 0; +} + + + + +static void +attach_m68hc11eepr_regs (struct hw *me, + struct m68hc11eepr *controller) +{ + unsigned_word attach_address; + int attach_space; + unsigned attach_size; + reg_property_spec reg; + + if (hw_find_property (me, "reg") == NULL) + hw_abort (me, "Missing \"reg\" property"); + + if (!hw_find_reg_array_property (me, "reg", 0, ®)) + hw_abort (me, "\"reg\" property must contain one addr/size entry"); + + hw_unit_address_to_attach_address (hw_parent (me), + ®.address, + &attach_space, + &attach_address, + me); + hw_unit_size_to_attach_size (hw_parent (me), + ®.size, + &attach_size, me); + + /* Attach the two IO registers that control the EEPROM. + The EEPROM is only attached at reset time because it may + be enabled/disabled by the EEON bit in the CONFIG register. */ + hw_attach_address (hw_parent (me), M6811_IO_LEVEL, + io_map, M6811_PPROG, 1, me); + hw_attach_address (hw_parent (me), M6811_IO_LEVEL, + io_map, M6811_CONFIG, 1, me); + + if (hw_find_property (me, "file") == NULL) + controller->file_name = "m6811.eeprom"; + else + controller->file_name = hw_find_string_property (me, "file"); + + controller->attach_space = attach_space; + controller->base_address = attach_address; + controller->eeprom = (char*) hw_malloc (me, attach_size + 1); + controller->eeprom_min_cycles = 10000; + controller->size = attach_size + 1; + controller->mapped = 0; + + m6811eepr_memory_rw (controller, O_RDONLY); +} + + +/* An event arrives on an interrupt port. */ + +static void +m68hc11eepr_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + SIM_DESC sd; + struct m68hc11eepr *controller; + sim_cpu *cpu; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + switch (my_port) + { + case RESET_PORT: + { + HW_TRACE ((me, "EEPROM reset")); + + /* Re-read the EEPROM from the file. This gives the chance + to users to erase this file before doing a reset and have + a fresh EEPROM taken into account. */ + m6811eepr_memory_rw (controller, O_RDONLY); + + /* Reset the state of EEPROM programmer. The CONFIG register + is also initialized from the EEPROM/file content. */ + cpu->ios[M6811_PPROG] = 0; + if (cpu->cpu_use_local_config) + cpu->ios[M6811_CONFIG] = cpu->cpu_config; + else + cpu->ios[M6811_CONFIG] = controller->eeprom[controller->size-1]; + controller->eeprom_wmode = 0; + controller->eeprom_waddr = 0; + controller->eeprom_wbyte = 0; + + /* Attach or detach to the bus depending on the EEPROM enable bit. + The EEPROM CONFIG register is still enabled and can be programmed + for a next configuration (taken into account only after a reset, + see Motorola spec). */ + if (!(cpu->ios[M6811_CONFIG] & M6811_EEON)) + { + if (controller->mapped) + hw_detach_address (hw_parent (me), M6811_EEPROM_LEVEL, + controller->attach_space, + controller->base_address, + controller->size - 1, + me); + controller->mapped = 0; + } + else + { + if (!controller->mapped) + hw_attach_address (hw_parent (me), M6811_EEPROM_LEVEL, + controller->attach_space, + controller->base_address, + controller->size - 1, + me); + controller->mapped = 1; + } + break; + } + + default: + hw_abort (me, "Event on unknown port %d", my_port); + break; + } +} + + +static void +m68hc11eepr_finish (struct hw *me) +{ + struct m68hc11eepr *controller; + + controller = HW_ZALLOC (me, struct m68hc11eepr); + set_hw_data (me, controller); + set_hw_io_read_buffer (me, m68hc11eepr_io_read_buffer); + set_hw_io_write_buffer (me, m68hc11eepr_io_write_buffer); + set_hw_ports (me, m68hc11eepr_ports); + set_hw_port_event (me, m68hc11eepr_port_event); +#ifdef set_hw_ioctl + set_hw_ioctl (me, m68hc11eepr_ioctl); +#else + me->to_ioctl = m68hc11eepr_ioctl; +#endif + + attach_m68hc11eepr_regs (me, controller); +} + + + +static io_reg_desc pprog_desc[] = { + { M6811_BYTE, "BYTE ", "Byte Program Mode" }, + { M6811_ROW, "ROW ", "Row Program Mode" }, + { M6811_ERASE, "ERASE ", "Erase Mode" }, + { M6811_EELAT, "EELAT ", "EEProm Latch Control" }, + { M6811_EEPGM, "EEPGM ", "EEProm Programming Voltable Enable" }, + { 0, 0, 0 } +}; +extern io_reg_desc config_desc[]; + + +/* Describe the state of the EEPROM device. */ +static void +m68hc11eepr_info (struct hw *me) +{ + SIM_DESC sd; + uint16 base = 0; + sim_cpu *cpu; + struct m68hc11eepr *controller; + uint8 val; + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + base = cpu_get_io_base (cpu); + + sim_io_printf (sd, "M68HC11 EEprom:\n"); + + val = cpu->ios[M6811_PPROG]; + print_io_byte (sd, "PPROG ", pprog_desc, val, base + M6811_PPROG); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_CONFIG]; + print_io_byte (sd, "CONFIG ", config_desc, val, base + M6811_CONFIG); + sim_io_printf (sd, "\n"); + + val = controller->eeprom[controller->size - 1]; + print_io_byte (sd, "(*NEXT*) ", config_desc, val, base + M6811_CONFIG); + sim_io_printf (sd, "\n"); + + /* Describe internal state of EEPROM. */ + if (controller->eeprom_wmode) + { + if (controller->eeprom_waddr == controller->size - 1) + sim_io_printf (sd, " Programming CONFIG register "); + else + sim_io_printf (sd, " Programming: 0x%04x ", + controller->eeprom_waddr + controller->base_address); + + sim_io_printf (sd, "with 0x%02x\n", + controller->eeprom_wbyte); + } + + sim_io_printf (sd, " EEProm file: %s\n", + controller->file_name); +} + +static int +m68hc11eepr_ioctl (struct hw *me, + hw_ioctl_request request, + va_list ap) +{ + m68hc11eepr_info (me); + return 0; +} + +/* generic read/write */ + +static unsigned +m68hc11eepr_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11eepr *controller; + sim_cpu *cpu; + + HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + controller = hw_data (me); + cpu = STATE_CPU (sd, 0); + + if (space == io_map) + { + unsigned cnt = 0; + + while (nr_bytes != 0) + { + switch (base) + { + case M6811_PPROG: + case M6811_CONFIG: + *((uint8*) dest) = cpu->ios[base]; + break; + + default: + hw_abort (me, "reading wrong register 0x%04x", base); + } + dest = (uint8*) (dest) + 1; + base++; + nr_bytes--; + cnt++; + } + return cnt; + } + + /* In theory, we can't read the EEPROM when it's being programmed. */ + if ((cpu->ios[M6811_PPROG] & M6811_EELAT) != 0 + && cpu_is_running (cpu)) + { + sim_memory_error (cpu, SIM_SIGBUS, base, + "EEprom not configured for reading"); + } + + base = base - controller->base_address; + memcpy (dest, &controller->eeprom[base], nr_bytes); + return nr_bytes; +} + + +static unsigned +m68hc11eepr_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11eepr *controller; + sim_cpu *cpu; + uint8 val; + + HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + controller = hw_data (me); + cpu = STATE_CPU (sd, 0); + + /* Programming several bytes at a time is not possible. */ + if (space != io_map && nr_bytes != 1) + { + sim_memory_error (cpu, SIM_SIGBUS, base, + "EEprom write error (only 1 byte can be programmed)"); + return 0; + } + + if (nr_bytes != 1) + hw_abort (me, "Cannot write more than 1 byte to EEPROM device at a time"); + + val = *((const uint8*) source); + + /* Write to the EEPROM control register. */ + if (space == io_map && base == M6811_PPROG) + { + uint8 wrong_bits; + uint16 addr; + + addr = base + cpu_get_io_base (cpu); + + /* Setting EELAT and EEPGM at the same time is an error. + Clearing them both is ok. */ + wrong_bits = (cpu->ios[M6811_PPROG] ^ val) & val; + wrong_bits &= (M6811_EELAT | M6811_EEPGM); + + if (wrong_bits == (M6811_EEPGM|M6811_EELAT)) + { + sim_memory_error (cpu, SIM_SIGBUS, addr, + "Wrong eeprom programing value"); + return 0; + } + + if ((val & M6811_EELAT) == 0) + { + val = 0; + } + if ((val & M6811_EEPGM) && !(cpu->ios[M6811_PPROG] & M6811_EELAT)) + { + sim_memory_error (cpu, SIM_SIGBUS, addr, + "EEProm high voltage applied after EELAT"); + } + if ((val & M6811_EEPGM) && controller->eeprom_wmode == 0) + { + sim_memory_error (cpu, SIM_SIGSEGV, addr, + "EEProm high voltage applied without address"); + } + if (val & M6811_EEPGM) + { + controller->eeprom_wcycle = cpu_current_cycle (cpu); + } + else if (cpu->ios[M6811_PPROG] & M6811_PPROG) + { + int i; + unsigned long t = cpu_current_cycle (cpu); + + t -= controller->eeprom_wcycle; + if (t < controller->eeprom_min_cycles) + { + sim_memory_error (cpu, SIM_SIGILL, addr, + "EEprom programmed only for %lu cycles", + t); + } + + /* Program the byte by clearing some bits. */ + if (!(cpu->ios[M6811_PPROG] & M6811_ERASE)) + { + controller->eeprom[controller->eeprom_waddr] + &= controller->eeprom_wbyte; + } + + /* Erase a byte, row or the complete eeprom. Erased value is 0xFF. + Ignore row or complete eeprom erase when we are programming the + CONFIG register (last EEPROM byte). */ + else if ((cpu->ios[M6811_PPROG] & M6811_BYTE) + || controller->eeprom_waddr == controller->size - 1) + { + controller->eeprom[controller->eeprom_waddr] = 0xff; + } + else if (cpu->ios[M6811_BYTE] & M6811_ROW) + { + size_t max_size; + + /* Size of EEPROM (-1 because the last byte is the + CONFIG register. */ + max_size = controller->size; + controller->eeprom_waddr &= 0xFFF0; + for (i = 0; i < 16 + && controller->eeprom_waddr < max_size; i++) + { + controller->eeprom[controller->eeprom_waddr] = 0xff; + controller->eeprom_waddr ++; + } + } + else + { + size_t max_size; + + max_size = controller->size; + for (i = 0; i < max_size; i++) + { + controller->eeprom[i] = 0xff; + } + } + + /* Save the eeprom in a file. We have to save after each + change because the simulator can be stopped or crash... */ + if (m6811eepr_memory_rw (controller, O_WRONLY | O_CREAT) != 0) + { + sim_memory_error (cpu, SIM_SIGABRT, addr, + "EEPROM programing failed: errno=%d", errno); + } + controller->eeprom_wmode = 0; + } + cpu->ios[M6811_PPROG] = val; + return 1; + } + + /* The CONFIG IO register is mapped at end of EEPROM. + It's not visible. */ + if (space == io_map && base == M6811_CONFIG) + { + base = controller->size - 1; + } + else + { + base = base - controller->base_address; + } + + /* Writing the memory is allowed for the Debugger or simulator + (cpu not running). */ + if (cpu_is_running (cpu)) + { + if ((cpu->ios[M6811_PPROG] & M6811_EELAT) == 0) + { + sim_memory_error (cpu, SIM_SIGSEGV, base, + "EEprom not configured for writing"); + return 0; + } + if (controller->eeprom_wmode != 0) + { + sim_memory_error (cpu, SIM_SIGSEGV, base, + "EEprom write error"); + return 0; + } + controller->eeprom_wmode = 1; + controller->eeprom_waddr = base; + controller->eeprom_wbyte = val; + } + else + { + controller->eeprom[base] = val; + m6811eepr_memory_rw (controller, O_WRONLY); + } + + return 1; +} + +const struct hw_descriptor dv_m68hc11eepr_descriptor[] = { + { "m68hc11eepr", m68hc11eepr_finish }, + { "m68hc12eepr", m68hc11eepr_finish }, + { NULL }, +}; +
dv-m68hc11eepr.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dv-m68hc11spi.c =================================================================== --- dv-m68hc11spi.c (nonexistent) +++ dv-m68hc11spi.c (revision 33) @@ -0,0 +1,535 @@ +/* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI + Copyright (C) 2000, 2002, 2003, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.fr) + (From a driver model Contributed by Cygnus Solutions.) + + This file is part of the program 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 3 of the License, 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, see . + + */ + + +#include "sim-main.h" +#include "hw-main.h" +#include "dv-sockser.h" +#include "sim-assert.h" + + +/* DEVICE + + m68hc11spi - m68hc11 SPI interface + + + DESCRIPTION + + Implements the m68hc11 Synchronous Serial Peripheral Interface + described in the m68hc11 user guide (Chapter 8 in pink book). + The SPI I/O controller is directly connected to the CPU + interrupt. The simulator implements: + + - SPI clock emulation + - Data transfer + - Write collision detection + + + PROPERTIES + + None + + + PORTS + + reset (input) + + Reset port. This port is only used to simulate a reset of the SPI + I/O controller. It should be connected to the RESET output of the cpu. + + */ + + + +/* port ID's */ + +enum +{ + RESET_PORT +}; + + +static const struct hw_port_descriptor m68hc11spi_ports[] = +{ + { "reset", RESET_PORT, 0, input_port, }, + { NULL, }, +}; + + +/* SPI */ +struct m68hc11spi +{ + /* Information about next character to be transmited. */ + unsigned char tx_char; + int tx_bit; + unsigned char mode; + + unsigned char rx_char; + unsigned char rx_clear_scsr; + unsigned char clk_pin; + + /* SPI clock rate (twice the real clock). */ + unsigned int clock; + + /* Periodic SPI event. */ + struct hw_event* spi_event; +}; + + + +/* Finish off the partially created hw device. Attach our local + callbacks. Wire up our port names etc */ + +static hw_io_read_buffer_method m68hc11spi_io_read_buffer; +static hw_io_write_buffer_method m68hc11spi_io_write_buffer; +static hw_port_event_method m68hc11spi_port_event; +static hw_ioctl_method m68hc11spi_ioctl; + +#define M6811_SPI_FIRST_REG (M6811_SPCR) +#define M6811_SPI_LAST_REG (M6811_SPDR) + + +static void +attach_m68hc11spi_regs (struct hw *me, + struct m68hc11spi *controller) +{ + hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map, + M6811_SPI_FIRST_REG, + M6811_SPI_LAST_REG - M6811_SPI_FIRST_REG + 1, + me); +} + +static void +m68hc11spi_finish (struct hw *me) +{ + struct m68hc11spi *controller; + + controller = HW_ZALLOC (me, struct m68hc11spi); + set_hw_data (me, controller); + set_hw_io_read_buffer (me, m68hc11spi_io_read_buffer); + set_hw_io_write_buffer (me, m68hc11spi_io_write_buffer); + set_hw_ports (me, m68hc11spi_ports); + set_hw_port_event (me, m68hc11spi_port_event); +#ifdef set_hw_ioctl + set_hw_ioctl (me, m68hc11spi_ioctl); +#else + me->to_ioctl = m68hc11spi_ioctl; +#endif + + /* Attach ourself to our parent bus. */ + attach_m68hc11spi_regs (me, controller); + + /* Initialize to reset state. */ + controller->spi_event = NULL; + controller->rx_clear_scsr = 0; +} + + + +/* An event arrives on an interrupt port */ + +static void +m68hc11spi_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + SIM_DESC sd; + struct m68hc11spi *controller; + sim_cpu* cpu; + unsigned8 val; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + switch (my_port) + { + case RESET_PORT: + { + HW_TRACE ((me, "SPI reset")); + + /* Reset the state of SPI registers. */ + controller->rx_clear_scsr = 0; + if (controller->spi_event) + { + hw_event_queue_deschedule (me, controller->spi_event); + controller->spi_event = 0; + } + + val = 0; + m68hc11spi_io_write_buffer (me, &val, io_map, + (unsigned_word) M6811_SPCR, 1); + break; + } + + default: + hw_abort (me, "Event on unknown port %d", my_port); + break; + } +} + +static void +set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value) +{ + uint8 val; + + if (value) + val = cpu->ios[port] | mask; + else + val = cpu->ios[port] & ~mask; + + /* Set the new value and post an event to inform other devices + that pin 'port' changed. */ + m68hc11cpu_set_port (me, cpu, port, val); +} + + +/* When a character is sent/received by the SPI, the PD2..PD5 line + are driven by the following signals: + + B7 B6 + -----+---------+--------+---/-+------- + MOSI | | | | | | + MISO +---------+--------+---/-+ + ____ ___ + CLK _______/ \____/ \__ CPOL=0, CPHA=0 + _______ ____ __ + \____/ \___/ CPOL=1, CPHA=0 + ____ ____ __ + __/ \____/ \___/ CPOL=0, CPHA=1 + __ ____ ___ + \____/ \____/ \__ CPOL=1, CPHA=1 + + SS ___ ____ + \__________________________//___/ + + MISO = PD2 + MOSI = PD3 + SCK = PD4 + SS = PD5 + +*/ + +#define SPI_START_BYTE 0 +#define SPI_START_BIT 1 +#define SPI_MIDDLE_BIT 2 + +void +m68hc11spi_clock (struct hw *me, void *data) +{ + SIM_DESC sd; + struct m68hc11spi* controller; + sim_cpu *cpu; + int check_interrupt = 0; + + controller = hw_data (me); + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + + /* Cleanup current event. */ + if (controller->spi_event) + { + hw_event_queue_deschedule (me, controller->spi_event); + controller->spi_event = 0; + } + + /* Change a bit of data at each two SPI event. */ + if (controller->mode == SPI_START_BIT) + { + /* Reflect the bit value on bit 2 of port D. */ + set_bit_port (me, cpu, M6811_PORTD, (1 << 2), + (controller->tx_char & (1 << controller->tx_bit))); + controller->tx_bit--; + controller->mode = SPI_MIDDLE_BIT; + } + else if (controller->mode == SPI_MIDDLE_BIT) + { + controller->mode = SPI_START_BIT; + } + + if (controller->mode == SPI_START_BYTE) + { + /* Start a new SPI transfer. */ + + /* TBD: clear SS output. */ + controller->mode = SPI_START_BIT; + controller->tx_bit = 7; + set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin); + } + else + { + /* Change the SPI clock at each event on bit 4 of port D. */ + controller->clk_pin = ~controller->clk_pin; + set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin); + } + + /* Transmit is now complete for this byte. */ + if (controller->mode == SPI_START_BIT && controller->tx_bit < 0) + { + controller->rx_clear_scsr = 0; + cpu->ios[M6811_SPSR] |= M6811_SPIF; + if (cpu->ios[M6811_SPCR] & M6811_SPIE) + check_interrupt = 1; + } + else + { + controller->spi_event = hw_event_queue_schedule (me, controller->clock, + m68hc11spi_clock, + NULL); + } + + if (check_interrupt) + interrupts_update_pending (&cpu->cpu_interrupts); +} + +/* Flags of the SPCR register. */ +io_reg_desc spcr_desc[] = { + { M6811_SPIE, "SPIE ", "Serial Peripheral Interrupt Enable" }, + { M6811_SPE, "SPE ", "Serial Peripheral System Enable" }, + { M6811_DWOM, "DWOM ", "Port D Wire-OR mode option" }, + { M6811_MSTR, "MSTR ", "Master Mode Select" }, + { M6811_CPOL, "CPOL ", "Clock Polarity" }, + { M6811_CPHA, "CPHA ", "Clock Phase" }, + { M6811_SPR1, "SPR1 ", "SPI Clock Rate Select" }, + { M6811_SPR0, "SPR0 ", "SPI Clock Rate Select" }, + { 0, 0, 0 } +}; + + +/* Flags of the SPSR register. */ +io_reg_desc spsr_desc[] = { + { M6811_SPIF, "SPIF ", "SPI Transfer Complete flag" }, + { M6811_WCOL, "WCOL ", "Write Collision" }, + { M6811_MODF, "MODF ", "Mode Fault" }, + { 0, 0, 0 } +}; + +static void +m68hc11spi_info (struct hw *me) +{ + SIM_DESC sd; + uint16 base = 0; + sim_cpu *cpu; + struct m68hc11spi *controller; + uint8 val; + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + sim_io_printf (sd, "M68HC11 SPI:\n"); + + base = cpu_get_io_base (cpu); + + val = cpu->ios[M6811_SPCR]; + print_io_byte (sd, "SPCR", spcr_desc, val, base + M6811_SPCR); + sim_io_printf (sd, "\n"); + + val = cpu->ios[M6811_SPSR]; + print_io_byte (sd, "SPSR", spsr_desc, val, base + M6811_SPSR); + sim_io_printf (sd, "\n"); + + if (controller->spi_event) + { + signed64 t; + + sim_io_printf (sd, " SPI has %d bits to send\n", + controller->tx_bit + 1); + t = hw_event_remain_time (me, controller->spi_event); + sim_io_printf (sd, " SPI current bit-cycle finished in %s\n", + cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE)); + + t += (controller->tx_bit + 1) * 2 * controller->clock; + sim_io_printf (sd, " SPI operation finished in %s\n", + cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE)); + } +} + +static int +m68hc11spi_ioctl (struct hw *me, + hw_ioctl_request request, + va_list ap) +{ + m68hc11spi_info (me); + return 0; +} + +/* generic read/write */ + +static unsigned +m68hc11spi_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11spi *controller; + sim_cpu *cpu; + unsigned8 val; + + HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + switch (base) + { + case M6811_SPSR: + controller->rx_clear_scsr = cpu->ios[M6811_SCSR] + & (M6811_SPIF | M6811_WCOL | M6811_MODF); + + case M6811_SPCR: + val = cpu->ios[base]; + break; + + case M6811_SPDR: + if (controller->rx_clear_scsr) + { + cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr; + controller->rx_clear_scsr = 0; + interrupts_update_pending (&cpu->cpu_interrupts); + } + val = controller->rx_char; + break; + + default: + return 0; + } + *((unsigned8*) dest) = val; + return 1; +} + +static unsigned +m68hc11spi_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + SIM_DESC sd; + struct m68hc11spi *controller; + sim_cpu *cpu; + unsigned8 val; + + HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + controller = hw_data (me); + + val = *((const unsigned8*) source); + switch (base) + { + case M6811_SPCR: + cpu->ios[M6811_SPCR] = val; + + /* The SPI clock rate is 2, 4, 16, 32 of the internal CPU clock. + We have to drive the clock pin and need a 2x faster clock. */ + switch (val & (M6811_SPR1 | M6811_SPR0)) + { + case 0: + controller->clock = 1; + break; + + case 1: + controller->clock = 2; + break; + + case 2: + controller->clock = 8; + break; + + default: + controller->clock = 16; + break; + } + + /* Set the clock pin. */ + if ((val & M6811_CPOL) + && (controller->spi_event == 0 + || ((val & M6811_CPHA) && controller->mode == 1))) + controller->clk_pin = 1; + else + controller->clk_pin = 0; + + set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin); + break; + + /* Can't write to SPSR. */ + case M6811_SPSR: + break; + + case M6811_SPDR: + if (!(cpu->ios[M6811_SPCR] & M6811_SPE)) + { + return 0; + } + + if (controller->rx_clear_scsr) + { + cpu->ios[M6811_SPSR] &= ~controller->rx_clear_scsr; + controller->rx_clear_scsr = 0; + interrupts_update_pending (&cpu->cpu_interrupts); + } + + /* If transfer is taking place, a write to SPDR + generates a collision. */ + if (controller->spi_event) + { + cpu->ios[M6811_SPSR] |= M6811_WCOL; + break; + } + + /* Refuse the write if there was no read of SPSR. */ + /* ???? TBD. */ + + /* Prepare to send a byte. */ + controller->tx_char = val; + controller->mode = SPI_START_BYTE; + + /* Toggle clock pin internal value when CPHA is 0 so that + it will really change in the middle of a bit. */ + if (!(cpu->ios[M6811_SPCR] & M6811_CPHA)) + controller->clk_pin = ~controller->clk_pin; + + cpu->ios[M6811_SPDR] = val; + + /* Activate transmission. */ + m68hc11spi_clock (me, NULL); + break; + + default: + return 0; + } + return nr_bytes; +} + + +const struct hw_descriptor dv_m68hc11spi_descriptor[] = { + { "m68hc11spi", m68hc11spi_finish }, + { "m68hc12spi", m68hc11spi_finish }, + { NULL }, +}; +
dv-m68hc11spi.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: interrupts.c =================================================================== --- interrupts.c (nonexistent) +++ interrupts.c (revision 33) @@ -0,0 +1,646 @@ +/* interrupts.c -- 68HC11 Interrupts Emulation + 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. + +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. + +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, see . */ + +#include "sim-main.h" +#include "sim-options.h" + +static const char *interrupt_names[] = { + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "R8", + "R9", + "R10", + "R11", + + "SCI", + "SPI", + "AINPUT", + "AOVERFLOW", + "TOVERFLOW", + "OUT5", + "OUT4", + "OUT3", + "OUT2", + "OUT1", + "INC3", + "INC2", + "INC1", + "RT", + "IRQ", + "XIRQ", + "SWI", + "ILL", + "COPRESET", + "COPFAIL", + "RESET" +}; + +struct interrupt_def idefs[] = { + /* Serial interrupts. */ + { M6811_INT_SCI, M6811_SCSR, M6811_TDRE, M6811_SCCR2, M6811_TIE }, + { M6811_INT_SCI, M6811_SCSR, M6811_TC, M6811_SCCR2, M6811_TCIE }, + { M6811_INT_SCI, M6811_SCSR, M6811_RDRF, M6811_SCCR2, M6811_RIE }, + { M6811_INT_SCI, M6811_SCSR, M6811_IDLE, M6811_SCCR2, M6811_ILIE }, + + /* SPI interrupts. */ + { M6811_INT_SPI, M6811_SPSR, M6811_SPIF, M6811_SPCR, M6811_SPIE }, + + /* Realtime interrupts. */ + { M6811_INT_TCTN, M6811_TFLG2, M6811_TOF, M6811_TMSK2, M6811_TOI }, + { M6811_INT_RT, M6811_TFLG2, M6811_RTIF, M6811_TMSK2, M6811_RTII }, + + /* Output compare interrupts. */ + { M6811_INT_OUTCMP1, M6811_TFLG1, M6811_OC1F, M6811_TMSK1, M6811_OC1I }, + { M6811_INT_OUTCMP2, M6811_TFLG1, M6811_OC2F, M6811_TMSK1, M6811_OC2I }, + { M6811_INT_OUTCMP3, M6811_TFLG1, M6811_OC3F, M6811_TMSK1, M6811_OC3I }, + { M6811_INT_OUTCMP4, M6811_TFLG1, M6811_OC4F, M6811_TMSK1, M6811_OC4I }, + { M6811_INT_OUTCMP5, M6811_TFLG1, M6811_OC5F, M6811_TMSK1, M6811_OC5I }, + + /* Input compare interrupts. */ + { M6811_INT_INCMP1, M6811_TFLG1, M6811_IC1F, M6811_TMSK1, M6811_IC1I }, + { M6811_INT_INCMP2, M6811_TFLG1, M6811_IC2F, M6811_TMSK1, M6811_IC2I }, + { M6811_INT_INCMP3, M6811_TFLG1, M6811_IC3F, M6811_TMSK1, M6811_IC3I }, + + /* Pulse accumulator. */ + { M6811_INT_AINPUT, M6811_TFLG2, M6811_PAIF, M6811_TMSK2, M6811_PAII }, + { M6811_INT_AOVERFLOW,M6811_TFLG2, M6811_PAOVF, M6811_TMSK2, M6811_PAOVI}, +#if 0 + { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0, 0 }, + { M6811_INT_COPFAIL, M6811_CONFIG, M6811_NOCOP, 0, 0 } +#endif +}; + +#define TableSize(X) (sizeof X / sizeof(X[0])) +#define CYCLES_MAX ((((signed64) 1) << 62) - 1) + +enum +{ + OPTION_INTERRUPT_INFO = OPTION_START, + OPTION_INTERRUPT_CATCH, + OPTION_INTERRUPT_CLEAR +}; + +static DECLARE_OPTION_HANDLER (interrupt_option_handler); + +static const OPTION interrupt_options[] = +{ + { {"interrupt-info", no_argument, NULL, OPTION_INTERRUPT_INFO }, + '\0', NULL, "Print information about interrupts", + interrupt_option_handler }, + { {"interrupt-catch", required_argument, NULL, OPTION_INTERRUPT_CATCH }, + '\0', "NAME[,MODE]", + "Catch interrupts when they are raised or taken\n" + "NAME Name of the interrupt\n" + "MODE Optional mode (`taken' or `raised')", + interrupt_option_handler }, + { {"interrupt-clear", required_argument, NULL, OPTION_INTERRUPT_CLEAR }, + '\0', "NAME", "No longer catch the interrupt", + interrupt_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +/* Initialize the interrupts module. */ +void +interrupts_initialize (SIM_DESC sd, struct _sim_cpu *proc) +{ + struct interrupts *interrupts = &proc->cpu_interrupts; + + interrupts->cpu = proc; + + sim_add_option_table (sd, 0, interrupt_options); +} + +/* Initialize the interrupts of the processor. */ +void +interrupts_reset (struct interrupts *interrupts) +{ + int i; + + interrupts->pending_mask = 0; + if (interrupts->cpu->cpu_mode & M6811_SMOD) + interrupts->vectors_addr = 0xbfc0; + else + interrupts->vectors_addr = 0xffc0; + interrupts->nb_interrupts_raised = 0; + interrupts->min_mask_cycles = CYCLES_MAX; + interrupts->max_mask_cycles = 0; + interrupts->last_mask_cycles = 0; + interrupts->start_mask_cycle = -1; + interrupts->xirq_start_mask_cycle = -1; + interrupts->xirq_max_mask_cycles = 0; + interrupts->xirq_min_mask_cycles = CYCLES_MAX; + interrupts->xirq_last_mask_cycles = 0; + + for (i = 0; i < M6811_INT_NUMBER; i++) + { + interrupts->interrupt_order[i] = i; + } + + /* Clear the interrupt history table. */ + interrupts->history_index = 0; + memset (interrupts->interrupts_history, 0, + sizeof (interrupts->interrupts_history)); + + memset (interrupts->interrupts, 0, + sizeof (interrupts->interrupts)); + + /* In bootstrap mode, initialize the vector table to point + to the RAM location. */ + if (interrupts->cpu->cpu_mode == M6811_SMOD) + { + bfd_vma addr = interrupts->vectors_addr; + uint16 vector = 0x0100 - 3 * (M6811_INT_NUMBER - 1); + for (i = 0; i < M6811_INT_NUMBER; i++) + { + memory_write16 (interrupts->cpu, addr, vector); + addr += 2; + vector += 3; + } + } +} + +static int +find_interrupt (const char *name) +{ + int i; + + if (name) + for (i = 0; i < M6811_INT_NUMBER; i++) + if (strcasecmp (name, interrupt_names[i]) == 0) + return i; + + return -1; +} + +static SIM_RC +interrupt_option_handler (SIM_DESC sd, sim_cpu *cpu, + int opt, char *arg, int is_command) +{ + char *p; + int mode; + int id; + struct interrupts *interrupts; + + if (cpu == 0) + cpu = STATE_CPU (sd, 0); + + interrupts = &cpu->cpu_interrupts; + switch (opt) + { + case OPTION_INTERRUPT_INFO: + for (id = 0; id < M6811_INT_NUMBER; id++) + { + sim_io_eprintf (sd, "%-10.10s ", interrupt_names[id]); + switch (interrupts->interrupts[id].stop_mode) + { + case SIM_STOP_WHEN_RAISED: + sim_io_eprintf (sd, "catch raised "); + break; + + case SIM_STOP_WHEN_TAKEN: + sim_io_eprintf (sd, "catch taken "); + break; + + case SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN: + sim_io_eprintf (sd, "catch all "); + break; + + default: + sim_io_eprintf (sd, " "); + break; + } + sim_io_eprintf (sd, "%ld\n", + interrupts->interrupts[id].raised_count); + } + break; + + case OPTION_INTERRUPT_CATCH: + p = strchr (arg, ','); + if (p) + *p++ = 0; + + mode = SIM_STOP_WHEN_RAISED; + id = find_interrupt (arg); + if (id < 0) + sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); + + if (p && strcasecmp (p, "raised") == 0) + mode = SIM_STOP_WHEN_RAISED; + else if (p && strcasecmp (p, "taken") == 0) + mode = SIM_STOP_WHEN_TAKEN; + else if (p && strcasecmp (p, "all") == 0) + mode = SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN; + else if (p) + { + sim_io_eprintf (sd, "Invalid argument: %s\n", p); + break; + } + if (id >= 0) + interrupts->interrupts[id].stop_mode = mode; + break; + + case OPTION_INTERRUPT_CLEAR: + mode = SIM_STOP_WHEN_RAISED; + id = find_interrupt (arg); + if (id < 0) + sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); + else + interrupts->interrupts[id].stop_mode = 0; + break; + } + + return SIM_RC_OK; +} + +/* Update the mask of pending interrupts. This operation must be called + when the state of some 68HC11 IO register changes. It looks the + different registers that indicate a pending interrupt (timer, SCI, SPI, + ...) and records the interrupt if it's there and enabled. */ +void +interrupts_update_pending (struct interrupts *interrupts) +{ + int i; + uint8 *ioregs; + unsigned long clear_mask; + unsigned long set_mask; + + clear_mask = 0; + set_mask = 0; + ioregs = &interrupts->cpu->ios[0]; + + for (i = 0; i < TableSize(idefs); i++) + { + struct interrupt_def *idef = &idefs[i]; + uint8 data; + + /* Look if the interrupt is enabled. */ + if (idef->enable_paddr) + { + data = ioregs[idef->enable_paddr]; + if (!(data & idef->enabled_mask)) + { + /* Disable it. */ + clear_mask |= (1 << idef->int_number); + continue; + } + } + + /* Interrupt is enabled, see if it's there. */ + data = ioregs[idef->int_paddr]; + if (!(data & idef->int_mask)) + { + /* Disable it. */ + clear_mask |= (1 << idef->int_number); + continue; + } + + /* Ok, raise it. */ + set_mask |= (1 << idef->int_number); + } + + /* Some interrupts are shared (M6811_INT_SCI) so clear + the interrupts before setting the new ones. */ + interrupts->pending_mask &= ~clear_mask; + interrupts->pending_mask |= set_mask; + + /* Keep track of when the interrupt is raised by the device. + Also implements the breakpoint-on-interrupt. */ + if (set_mask) + { + signed64 cycle = cpu_current_cycle (interrupts->cpu); + int must_stop = 0; + + for (i = 0; i < M6811_INT_NUMBER; i++) + { + if (!(set_mask & (1 << i))) + continue; + + interrupts->interrupts[i].cpu_cycle = cycle; + if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED) + { + must_stop = 1; + sim_io_printf (CPU_STATE (interrupts->cpu), + "Interrupt %s raised\n", + interrupt_names[i]); + } + } + if (must_stop) + sim_engine_halt (CPU_STATE (interrupts->cpu), + interrupts->cpu, + 0, cpu_get_pc (interrupts->cpu), + sim_stopped, + SIM_SIGTRAP); + } +} + + +/* Finds the current active and non-masked interrupt. + Returns the interrupt number (index in the vector table) or -1 + if no interrupt can be serviced. */ +int +interrupts_get_current (struct interrupts *interrupts) +{ + int i; + + if (interrupts->pending_mask == 0) + return -1; + + /* SWI and illegal instructions are simulated by an interrupt. + They are not maskable. */ + if (interrupts->pending_mask & (1 << M6811_INT_SWI)) + { + interrupts->pending_mask &= ~(1 << M6811_INT_SWI); + return M6811_INT_SWI; + } + if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL)) + { + interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL); + return M6811_INT_ILLEGAL; + } + + /* If there is a non maskable interrupt, go for it (unless we are masked + by the X-bit. */ + if (interrupts->pending_mask & (1 << M6811_INT_XIRQ)) + { + if (cpu_get_ccr_X (interrupts->cpu) == 0) + { + interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ); + return M6811_INT_XIRQ; + } + return -1; + } + + /* Interrupts are masked, do nothing. */ + if (cpu_get_ccr_I (interrupts->cpu) == 1) + { + return -1; + } + + /* Returns the first interrupt number which is pending. + The interrupt priority is specified by the table `interrupt_order'. + For these interrupts, the pending mask is cleared when the program + performs some actions on the corresponding device. If the device + is not reset, the interrupt remains and will be re-raised when + we return from the interrupt (see 68HC11 pink book). */ + for (i = 0; i < M6811_INT_NUMBER; i++) + { + enum M6811_INT int_number = interrupts->interrupt_order[i]; + + if (interrupts->pending_mask & (1 << int_number)) + { + return int_number; + } + } + return -1; +} + + +/* Process the current interrupt if there is one. This operation must + be called after each instruction to handle the interrupts. If interrupts + are masked, it does nothing. */ +int +interrupts_process (struct interrupts *interrupts) +{ + int id; + uint8 ccr; + + /* See if interrupts are enabled/disabled and keep track of the + number of cycles the interrupts are masked. Such information is + then reported by the info command. */ + ccr = cpu_get_ccr (interrupts->cpu); + if (ccr & M6811_I_BIT) + { + if (interrupts->start_mask_cycle < 0) + interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); + } + else if (interrupts->start_mask_cycle >= 0 + && (ccr & M6811_I_BIT) == 0) + { + signed64 t = cpu_current_cycle (interrupts->cpu); + + t -= interrupts->start_mask_cycle; + if (t < interrupts->min_mask_cycles) + interrupts->min_mask_cycles = t; + if (t > interrupts->max_mask_cycles) + interrupts->max_mask_cycles = t; + interrupts->start_mask_cycle = -1; + interrupts->last_mask_cycles = t; + } + if (ccr & M6811_X_BIT) + { + if (interrupts->xirq_start_mask_cycle < 0) + interrupts->xirq_start_mask_cycle + = cpu_current_cycle (interrupts->cpu); + } + else if (interrupts->xirq_start_mask_cycle >= 0 + && (ccr & M6811_X_BIT) == 0) + { + signed64 t = cpu_current_cycle (interrupts->cpu); + + t -= interrupts->xirq_start_mask_cycle; + if (t < interrupts->xirq_min_mask_cycles) + interrupts->xirq_min_mask_cycles = t; + if (t > interrupts->xirq_max_mask_cycles) + interrupts->xirq_max_mask_cycles = t; + interrupts->xirq_start_mask_cycle = -1; + interrupts->xirq_last_mask_cycles = t; + } + + id = interrupts_get_current (interrupts); + if (id >= 0) + { + uint16 addr; + struct interrupt_history *h; + + /* Implement the breakpoint-on-interrupt. */ + if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN) + { + sim_io_printf (CPU_STATE (interrupts->cpu), + "Interrupt %s will be handled\n", + interrupt_names[id]); + sim_engine_halt (CPU_STATE (interrupts->cpu), + interrupts->cpu, + 0, cpu_get_pc (interrupts->cpu), + sim_stopped, + SIM_SIGTRAP); + } + + cpu_push_all (interrupts->cpu); + addr = memory_read16 (interrupts->cpu, + interrupts->vectors_addr + id * 2); + cpu_call (interrupts->cpu, addr); + + /* Now, protect from nested interrupts. */ + if (id == M6811_INT_XIRQ) + { + cpu_set_ccr_X (interrupts->cpu, 1); + } + else + { + cpu_set_ccr_I (interrupts->cpu, 1); + } + + /* Update the interrupt history table. */ + h = &interrupts->interrupts_history[interrupts->history_index]; + h->type = id; + h->taken_cycle = cpu_current_cycle (interrupts->cpu); + h->raised_cycle = interrupts->interrupts[id].cpu_cycle; + + if (interrupts->history_index >= MAX_INT_HISTORY-1) + interrupts->history_index = 0; + else + interrupts->history_index++; + + interrupts->nb_interrupts_raised++; + cpu_add_cycles (interrupts->cpu, 14); + return 1; + } + return 0; +} + +void +interrupts_raise (struct interrupts *interrupts, enum M6811_INT number) +{ + interrupts->pending_mask |= (1 << number); + interrupts->nb_interrupts_raised ++; +} + +void +interrupts_info (SIM_DESC sd, struct interrupts *interrupts) +{ + signed64 t, prev_interrupt; + int i; + + sim_io_printf (sd, "Interrupts Info:\n"); + sim_io_printf (sd, " Interrupts raised: %lu\n", + interrupts->nb_interrupts_raised); + + if (interrupts->start_mask_cycle >= 0) + { + t = cpu_current_cycle (interrupts->cpu); + + t -= interrupts->start_mask_cycle; + if (t > interrupts->max_mask_cycles) + interrupts->max_mask_cycles = t; + + sim_io_printf (sd, " Current interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + } + t = interrupts->min_mask_cycles == CYCLES_MAX ? + interrupts->max_mask_cycles : + interrupts->min_mask_cycles; + sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + t = interrupts->max_mask_cycles; + sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + t = interrupts->last_mask_cycles; + sim_io_printf (sd, " Last interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + if (interrupts->xirq_start_mask_cycle >= 0) + { + t = cpu_current_cycle (interrupts->cpu); + + t -= interrupts->xirq_start_mask_cycle; + if (t > interrupts->xirq_max_mask_cycles) + interrupts->xirq_max_mask_cycles = t; + + sim_io_printf (sd, " XIRQ Current interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + } + + t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ? + interrupts->xirq_max_mask_cycles : + interrupts->xirq_min_mask_cycles; + sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + t = interrupts->xirq_max_mask_cycles; + sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + t = interrupts->xirq_last_mask_cycles; + sim_io_printf (sd, " XIRQ Last interrupts masked sequence: %s\n", + cycle_to_string (interrupts->cpu, t, + PRINT_TIME | PRINT_CYCLE)); + + if (interrupts->pending_mask) + { + sim_io_printf (sd, " Pending interrupts : "); + for (i = 0; i < M6811_INT_NUMBER; i++) + { + enum M6811_INT int_number = interrupts->interrupt_order[i]; + + if (interrupts->pending_mask & (1 << int_number)) + { + sim_io_printf (sd, "%s ", interrupt_names[int_number]); + } + } + sim_io_printf (sd, "\n"); + } + + prev_interrupt = 0; + sim_io_printf (sd, "N Interrupt Cycle Taken Latency" + " Delta between interrupts\n"); + for (i = 0; i < MAX_INT_HISTORY; i++) + { + int which; + struct interrupt_history *h; + signed64 dt; + + which = interrupts->history_index - i - 1; + if (which < 0) + which += MAX_INT_HISTORY; + h = &interrupts->interrupts_history[which]; + if (h->taken_cycle == 0) + break; + + dt = h->taken_cycle - h->raised_cycle; + sim_io_printf (sd, "%2d %-9.9s %15.15s ", i, + interrupt_names[h->type], + cycle_to_string (interrupts->cpu, h->taken_cycle, 0)); + sim_io_printf (sd, "%15.15s", + cycle_to_string (interrupts->cpu, dt, 0)); + if (prev_interrupt) + { + dt = prev_interrupt - h->taken_cycle; + sim_io_printf (sd, " %s", + cycle_to_string (interrupts->cpu, dt, PRINT_TIME)); + } + sim_io_printf (sd, "\n"); + prev_interrupt = h->taken_cycle; + } +}
interrupts.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: sim-main.h =================================================================== --- sim-main.h (nonexistent) +++ sim-main.h (revision 33) @@ -0,0 +1,601 @@ +/* sim-main.h -- Simulator for Motorola 68HC11 & 68HC12 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2007, 2008 + Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@nerim.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 3 of the License, 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, see . */ + +#ifndef _SIM_MAIN_H +#define _SIM_MAIN_H + +#define WITH_MODULO_MEMORY 1 +#define WITH_WATCHPOINTS 1 +#define SIM_HANDLES_LMA 1 + +#include "sim-basics.h" + +typedef address_word sim_cia; + +#include "sim-signal.h" +#include "sim-base.h" + +#include "bfd.h" + +#include "opcode/m68hc11.h" + +#include "gdb/callback.h" +#include "gdb/remote-sim.h" +#include "opcode/m68hc11.h" +#include "sim-types.h" + +typedef unsigned8 uint8; +typedef unsigned16 uint16; +typedef signed16 int16; +typedef unsigned32 uint32; +typedef signed32 int32; +typedef unsigned64 uint64; +typedef signed64 int64; + +struct _sim_cpu; + +#include "interrupts.h" +#include + +/* Specifies the level of mapping for the IO, EEprom, nvram and external + RAM. IO registers are mapped over everything and the external RAM + is last (ie, it can be hidden by everything above it in the list). */ +enum m68hc11_map_level +{ + M6811_IO_LEVEL, + M6811_EEPROM_LEVEL, + M6811_NVRAM_LEVEL, + M6811_RAM_LEVEL +}; + +enum cpu_type +{ + CPU_M6811, + CPU_M6812 +}; + +#define X_REGNUM 0 +#define D_REGNUM 1 +#define Y_REGNUM 2 +#define SP_REGNUM 3 +#define PC_REGNUM 4 +#define A_REGNUM 5 +#define B_REGNUM 6 +#define PSW_REGNUM 7 +#define PAGE_REGNUM 8 +#define Z_REGNUM 9 + +typedef struct m6811_regs { + unsigned short d; + unsigned short ix; + unsigned short iy; + unsigned short sp; + unsigned short pc; + unsigned char ccr; + unsigned short page; +} m6811_regs; + + +/* Description of 68HC11 IO registers. Such description is only provided + for the info command to display the current setting of IO registers + from GDB. */ +struct io_reg_desc +{ + int mask; + const char *short_name; + const char *long_name; +}; +typedef struct io_reg_desc io_reg_desc; + +extern void print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, + int mode); +extern void print_io_byte (SIM_DESC sd, const char *name, + io_reg_desc *desc, uint8 val, uint16 addr); +extern void print_io_word (SIM_DESC sd, const char *name, + io_reg_desc *desc, uint16 val, uint16 addr); + + +/* List of special 68HC11&68HC12 instructions that are not handled by the + 'gencode.c' generator. These complex instructions are implemented + by 'cpu_special'. */ +enum M6811_Special +{ + /* 68HC11 instructions. */ + M6811_DAA, + M6811_EMUL_SYSCALL, + M6811_ILLEGAL, + M6811_RTI, + M6811_STOP, + M6811_SWI, + M6811_TEST, + M6811_WAI, + + /* 68HC12 instructions. */ + M6812_BGND, + M6812_CALL, + M6812_CALL_INDIRECT, + M6812_IDIVS, + M6812_EDIV, + M6812_EDIVS, + M6812_EMACS, + M6812_EMUL, + M6812_EMULS, + M6812_ETBL, + M6812_MEM, + M6812_REV, + M6812_REVW, + M6812_RTC, + M6812_RTI, + M6812_WAV +}; + +#define M6811_MAX_PORTS (0x03f+1) +#define M6812_MAX_PORTS (0x3ff+1) +#define MAX_PORTS (M6812_MAX_PORTS) + +struct _sim_cpu; + +typedef void (* cpu_interp) (struct _sim_cpu*); + +struct _sim_cpu { + /* CPU registers. */ + struct m6811_regs cpu_regs; + + /* CPU interrupts. */ + struct interrupts cpu_interrupts; + + /* Pointer to the interpretor routine. */ + cpu_interp cpu_interpretor; + + /* Pointer to the architecture currently configured in the simulator. */ + const struct bfd_arch_info *cpu_configured_arch; + + /* CPU absolute cycle time. The cycle time is updated after + each instruction, by the number of cycles taken by the instruction. + It is cleared only when reset occurs. */ + signed64 cpu_absolute_cycle; + + /* Number of cycles to increment after the current instruction. + This is also the number of ticks for the generic event scheduler. */ + uint8 cpu_current_cycle; + int cpu_emul_syscall; + int cpu_is_initialized; + int cpu_running; + int cpu_check_memory; + int cpu_stop_on_interrupt; + + /* When this is set, start execution of program at address specified + in the ELF header. This is used for testing some programs that do not + have an interrupt table linked with them. Programs created during the + GCC validation are like this. A normal 68HC11 does not behave like + this (unless there is some OS or downloadable feature). */ + int cpu_use_elf_start; + + /* The starting address specified in ELF header. */ + int cpu_elf_start; + + uint16 cpu_insn_pc; + + /* CPU frequency. This is the quartz frequency. It is divided by 4 to + get the cycle time. This is used for the timer rate and for the baud + rate generation. */ + unsigned long cpu_frequency; + + /* The mode in which the CPU is configured (MODA and MODB pins). */ + unsigned int cpu_mode; + const char* cpu_start_mode; + + /* The cpu being configured. */ + enum cpu_type cpu_type; + + /* Initial value of the CONFIG register. */ + uint8 cpu_config; + uint8 cpu_use_local_config; + + uint8 ios[MAX_PORTS]; + + /* Memory bank parameters which describe how the memory bank window + is mapped in memory and how to convert it in virtual address. */ + uint16 bank_start; + uint16 bank_end; + address_word bank_virtual; + unsigned bank_shift; + + + struct hw *hw_cpu; + + /* ... base type ... */ + sim_cpu_base base; +}; + +/* Returns the cpu absolute cycle time (A virtual counter incremented + at each 68HC11 E clock). */ +#define cpu_current_cycle(PROC) ((PROC)->cpu_absolute_cycle) +#define cpu_add_cycles(PROC,T) ((PROC)->cpu_current_cycle += (signed64) (T)) +#define cpu_is_running(PROC) ((PROC)->cpu_running) + +/* Get the IO/RAM base addresses depending on the M6811_INIT register. */ +#define cpu_get_io_base(PROC) \ + (((uint16)(((PROC)->ios[M6811_INIT]) & 0x0F))<<12) +#define cpu_get_reg_base(PROC) \ + (((uint16)(((PROC)->ios[M6811_INIT]) & 0xF0))<<8) + +/* Returns the different CPU registers. */ +#define cpu_get_ccr(PROC) ((PROC)->cpu_regs.ccr) +#define cpu_get_pc(PROC) ((PROC)->cpu_regs.pc) +#define cpu_get_d(PROC) ((PROC)->cpu_regs.d) +#define cpu_get_x(PROC) ((PROC)->cpu_regs.ix) +#define cpu_get_y(PROC) ((PROC)->cpu_regs.iy) +#define cpu_get_sp(PROC) ((PROC)->cpu_regs.sp) +#define cpu_get_a(PROC) ((PROC->cpu_regs.d >> 8) & 0x0FF) +#define cpu_get_b(PROC) ((PROC->cpu_regs.d) & 0x0FF) +#define cpu_get_page(PROC) ((PROC)->cpu_regs.page) + +/* 68HC12 specific and Motorola internal registers. */ +#define cpu_get_tmp3(PROC) (0) +#define cpu_get_tmp2(PROC) (0) + +#define cpu_set_d(PROC,VAL) (((PROC)->cpu_regs.d) = (VAL)) +#define cpu_set_x(PROC,VAL) (((PROC)->cpu_regs.ix) = (VAL)) +#define cpu_set_y(PROC,VAL) (((PROC)->cpu_regs.iy) = (VAL)) +#define cpu_set_page(PROC,VAL) (((PROC)->cpu_regs.page) = (VAL)) + +/* 68HC12 specific and Motorola internal registers. */ +#define cpu_set_tmp3(PROC,VAL) (0) +#define cpu_set_tmp2(PROC,VAL) (void) (0) + +#if 0 +/* This is a function in m68hc11_sim.c to keep track of the frame. */ +#define cpu_set_sp(PROC,VAL) (((PROC)->cpu_regs.sp) = (VAL)) +#endif + +#define cpu_set_pc(PROC,VAL) (((PROC)->cpu_regs.pc) = (VAL)) + +#define cpu_set_a(PROC,VAL) \ + cpu_set_d(PROC,((VAL) << 8) | cpu_get_b(PROC)) +#define cpu_set_b(PROC,VAL) \ + cpu_set_d(PROC,((cpu_get_a(PROC)) << 8)|(VAL & 0x0FF)) + +#define cpu_set_ccr(PROC,VAL) ((PROC)->cpu_regs.ccr = (VAL)) +#define cpu_get_ccr_H(PROC) ((cpu_get_ccr(PROC) & M6811_H_BIT) ? 1: 0) +#define cpu_get_ccr_X(PROC) ((cpu_get_ccr(PROC) & M6811_X_BIT) ? 1: 0) +#define cpu_get_ccr_S(PROC) ((cpu_get_ccr(PROC) & M6811_S_BIT) ? 1: 0) +#define cpu_get_ccr_N(PROC) ((cpu_get_ccr(PROC) & M6811_N_BIT) ? 1: 0) +#define cpu_get_ccr_V(PROC) ((cpu_get_ccr(PROC) & M6811_V_BIT) ? 1: 0) +#define cpu_get_ccr_C(PROC) ((cpu_get_ccr(PROC) & M6811_C_BIT) ? 1: 0) +#define cpu_get_ccr_Z(PROC) ((cpu_get_ccr(PROC) & M6811_Z_BIT) ? 1: 0) +#define cpu_get_ccr_I(PROC) ((cpu_get_ccr(PROC) & M6811_I_BIT) ? 1: 0) + +#define cpu_set_ccr_flag(S,B,V) \ +cpu_set_ccr(S,(cpu_get_ccr(S) & ~(B)) | ((V) ? B : 0)) + +#define cpu_set_ccr_H(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_H_BIT, VAL) +#define cpu_set_ccr_X(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_X_BIT, VAL) +#define cpu_set_ccr_S(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_S_BIT, VAL) +#define cpu_set_ccr_N(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_N_BIT, VAL) +#define cpu_set_ccr_V(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_V_BIT, VAL) +#define cpu_set_ccr_C(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_C_BIT, VAL) +#define cpu_set_ccr_Z(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_Z_BIT, VAL) +#define cpu_set_ccr_I(PROC,VAL) cpu_set_ccr_flag(PROC, M6811_I_BIT, VAL) + +#undef inline +#define inline static __inline__ + +extern void cpu_memory_exception (struct _sim_cpu *proc, + SIM_SIGNAL excep, + uint16 addr, + const char *message); + +inline address_word +phys_to_virt (sim_cpu *cpu, address_word addr) +{ + if (addr >= cpu->bank_start && addr < cpu->bank_end) + return ((address_word) (addr - cpu->bank_start) + + (((address_word) cpu->cpu_regs.page) << cpu->bank_shift) + + cpu->bank_virtual); + else + return (address_word) (addr); +} + +inline uint8 +memory_read8 (sim_cpu *cpu, uint16 addr) +{ + uint8 val; + + if (sim_core_read_buffer (CPU_STATE (cpu), cpu, 0, &val, addr, 1) != 1) + { + cpu_memory_exception (cpu, SIM_SIGSEGV, addr, + "Read error"); + } + return val; +} + +inline void +memory_write8 (sim_cpu *cpu, uint16 addr, uint8 val) +{ + if (sim_core_write_buffer (CPU_STATE (cpu), cpu, 0, &val, addr, 1) != 1) + { + cpu_memory_exception (cpu, SIM_SIGSEGV, addr, + "Write error"); + } +} + +inline uint16 +memory_read16 (sim_cpu *cpu, uint16 addr) +{ + uint8 b[2]; + + if (sim_core_read_buffer (CPU_STATE (cpu), cpu, 0, b, addr, 2) != 2) + { + cpu_memory_exception (cpu, SIM_SIGSEGV, addr, + "Read error"); + } + return (((uint16) (b[0])) << 8) | ((uint16) b[1]); +} + +inline void +memory_write16 (sim_cpu *cpu, uint16 addr, uint16 val) +{ + uint8 b[2]; + + b[0] = val >> 8; + b[1] = val; + if (sim_core_write_buffer (CPU_STATE (cpu), cpu, 0, b, addr, 2) != 2) + { + cpu_memory_exception (cpu, SIM_SIGSEGV, addr, + "Write error"); + } +} +extern void +cpu_ccr_update_tst8 (sim_cpu *proc, uint8 val); + + inline void +cpu_ccr_update_tst16 (sim_cpu *proc, uint16 val) +{ + cpu_set_ccr_V (proc, 0); + cpu_set_ccr_N (proc, val & 0x8000 ? 1 : 0); + cpu_set_ccr_Z (proc, val == 0 ? 1 : 0); +} + + inline void +cpu_ccr_update_shift8 (sim_cpu *proc, uint8 val) +{ + cpu_set_ccr_N (proc, val & 0x80 ? 1 : 0); + cpu_set_ccr_Z (proc, val == 0 ? 1 : 0); + cpu_set_ccr_V (proc, cpu_get_ccr_N (proc) ^ cpu_get_ccr_C (proc)); +} + + inline void +cpu_ccr_update_shift16 (sim_cpu *proc, uint16 val) +{ + cpu_set_ccr_N (proc, val & 0x8000 ? 1 : 0); + cpu_set_ccr_Z (proc, val == 0 ? 1 : 0); + cpu_set_ccr_V (proc, cpu_get_ccr_N (proc) ^ cpu_get_ccr_C (proc)); +} + +inline void +cpu_ccr_update_add8 (sim_cpu *proc, uint8 r, uint8 a, uint8 b) +{ + cpu_set_ccr_C (proc, ((a & b) | (b & ~r) | (a & ~r)) & 0x80 ? 1 : 0); + cpu_set_ccr_V (proc, ((a & b & ~r) | (~a & ~b & r)) & 0x80 ? 1 : 0); + cpu_set_ccr_Z (proc, r == 0); + cpu_set_ccr_N (proc, r & 0x80 ? 1 : 0); +} + + +inline void +cpu_ccr_update_sub8 (sim_cpu *proc, uint8 r, uint8 a, uint8 b) +{ + cpu_set_ccr_C (proc, ((~a & b) | (b & r) | (~a & r)) & 0x80 ? 1 : 0); + cpu_set_ccr_V (proc, ((a & ~b & ~r) | (~a & b & r)) & 0x80 ? 1 : 0); + cpu_set_ccr_Z (proc, r == 0); + cpu_set_ccr_N (proc, r & 0x80 ? 1 : 0); +} + +inline void +cpu_ccr_update_add16 (sim_cpu *proc, uint16 r, uint16 a, uint16 b) +{ + cpu_set_ccr_C (proc, ((a & b) | (b & ~r) | (a & ~r)) & 0x8000 ? 1 : 0); + cpu_set_ccr_V (proc, ((a & b & ~r) | (~a & ~b & r)) & 0x8000 ? 1 : 0); + cpu_set_ccr_Z (proc, r == 0); + cpu_set_ccr_N (proc, r & 0x8000 ? 1 : 0); +} + +inline void +cpu_ccr_update_sub16 (sim_cpu *proc, uint16 r, uint16 a, uint16 b) +{ + cpu_set_ccr_C (proc, ((~a & b) | (b & r) | (~a & r)) & 0x8000 ? 1 : 0); + cpu_set_ccr_V (proc, ((a & ~b & ~r) | (~a & b & r)) & 0x8000 ? 1 : 0); + cpu_set_ccr_Z (proc, r == 0); + cpu_set_ccr_N (proc, r & 0x8000 ? 1 : 0); +} + +/* Push and pop instructions for 68HC11 (next-available stack mode). */ +inline void +cpu_m68hc11_push_uint8 (sim_cpu *proc, uint8 val) +{ + uint16 addr = proc->cpu_regs.sp; + + memory_write8 (proc, addr, val); + proc->cpu_regs.sp = addr - 1; +} + +inline void +cpu_m68hc11_push_uint16 (sim_cpu *proc, uint16 val) +{ + uint16 addr = proc->cpu_regs.sp - 1; + + memory_write16 (proc, addr, val); + proc->cpu_regs.sp = addr - 1; +} + +inline uint8 +cpu_m68hc11_pop_uint8 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.sp; + uint8 val; + + val = memory_read8 (proc, addr + 1); + proc->cpu_regs.sp = addr + 1; + return val; +} + +inline uint16 +cpu_m68hc11_pop_uint16 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.sp; + uint16 val; + + val = memory_read16 (proc, addr + 1); + proc->cpu_regs.sp = addr + 2; + return val; +} + +/* Push and pop instructions for 68HC12 (last-used stack mode). */ +inline void +cpu_m68hc12_push_uint8 (sim_cpu *proc, uint8 val) +{ + uint16 addr = proc->cpu_regs.sp; + + addr --; + memory_write8 (proc, addr, val); + proc->cpu_regs.sp = addr; +} + +inline void +cpu_m68hc12_push_uint16 (sim_cpu *proc, uint16 val) +{ + uint16 addr = proc->cpu_regs.sp; + + addr -= 2; + memory_write16 (proc, addr, val); + proc->cpu_regs.sp = addr; +} + +inline uint8 +cpu_m68hc12_pop_uint8 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.sp; + uint8 val; + + val = memory_read8 (proc, addr); + proc->cpu_regs.sp = addr + 1; + return val; +} + +inline uint16 +cpu_m68hc12_pop_uint16 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.sp; + uint16 val; + + val = memory_read16 (proc, addr); + proc->cpu_regs.sp = addr + 2; + return val; +} + +/* Fetch a 8/16 bit value and update the PC. */ +inline uint8 +cpu_fetch8 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.pc; + uint8 val; + + val = memory_read8 (proc, addr); + proc->cpu_regs.pc = addr + 1; + return val; +} + +inline uint16 +cpu_fetch16 (sim_cpu *proc) +{ + uint16 addr = proc->cpu_regs.pc; + uint16 val; + + val = memory_read16 (proc, addr); + proc->cpu_regs.pc = addr + 2; + return val; +} + +extern void cpu_call (sim_cpu* proc, uint16 addr); +extern void cpu_exg (sim_cpu* proc, uint8 code); +extern void cpu_dbcc (sim_cpu* proc); +extern void cpu_special (sim_cpu *proc, enum M6811_Special special); +extern void cpu_move8 (sim_cpu *proc, uint8 op); +extern void cpu_move16 (sim_cpu *proc, uint8 op); + +extern uint16 cpu_fetch_relbranch (sim_cpu *proc); +extern uint16 cpu_fetch_relbranch16 (sim_cpu *proc); +extern void cpu_push_all (sim_cpu *proc); +extern void cpu_single_step (sim_cpu *proc); + +extern void cpu_info (SIM_DESC sd, sim_cpu *proc); + +extern int cpu_initialize (SIM_DESC sd, sim_cpu *cpu); + +/* Returns the address of a 68HC12 indexed operand. + Pre and post modifications are handled on the source register. */ +extern uint16 cpu_get_indexed_operand_addr (sim_cpu* cpu, int restrict); + +extern void cpu_return (sim_cpu *cpu); +extern void cpu_set_sp (sim_cpu *cpu, uint16 val); +extern int cpu_reset (sim_cpu *cpu); +extern int cpu_restart (sim_cpu *cpu); +extern void sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep, + uint16 addr, const char *message, ...); +extern void emul_os (int op, sim_cpu *cpu); +extern void cpu_interp_m6811 (sim_cpu *cpu); +extern void cpu_interp_m6812 (sim_cpu *cpu); + +extern int m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port, + double ton, double toff, + signed64 repeat); +extern int m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port); +extern void m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu, + unsigned addr, uint8 val); + +/* The current state of the processor; registers, memory, etc. */ + +#define CIA_GET(CPU) (cpu_get_pc (CPU)) +#define CIA_SET(CPU,VAL) (cpu_set_pc ((CPU), (VAL))) + +#if (WITH_SMP) +#define STATE_CPU(sd,n) (&(sd)->cpu[n]) +#else +#define STATE_CPU(sd,n) (&(sd)->cpu[0]) +#endif + +struct sim_state { + sim_cpu cpu[MAX_NR_PROCESSORS]; + device *devices; + sim_state_base base; +}; + +extern void sim_set_profile (int n); +extern void sim_set_profile_size (int n); +extern void sim_board_reset (SIM_DESC sd); + +#define PRINT_TIME 0x01 +#define PRINT_CYCLE 0x02 +extern const char *cycle_to_string (sim_cpu *cpu, signed64 t, int flags); + +#endif + +
sim-main.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: configure.ac =================================================================== --- configure.ac (nonexistent) +++ configure.ac (revision 33) @@ -0,0 +1,39 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.59)dnl +AC_INIT(Makefile.in) +AC_CONFIG_HEADER(config.h:config.in) + +sinclude(../common/aclocal.m4) + +# Bugs in autoconf 2.59 break the call to SIM_AC_COMMON, hack around +# it by inlining the macro's contents. +sinclude(../common/common.m4) + +dnl Options available in this module +SIM_AC_OPTION_INLINE() +SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT) +SIM_AC_OPTION_HOSTENDIAN +SIM_AC_OPTION_WARNINGS + +# +# Add simulated hardware devices +# +hw_enabled=no +case "${target}" in + m68hc11-*-*|m6811-*-*) + hw_enabled=yes + hw_extra_devices="m68hc11 m68hc11sio m68hc11eepr m68hc11tim m68hc11spi nvram" + m68hc11_extra_objs="dv-sockser.o" + SIM_SUBTARGET="$SIM_SUBTARGET -DTARGET_M68HC11=1" + ;; + *) + m68hc11_extra_objs="" + ;; +esac +SIM_AC_OPTION_HARDWARE($hw_enabled,$hw_devices,$hw_extra_devices) + +AC_CHECK_HEADERS(string.h strings.h stdlib.h stdlib.h fcntl.h) + +AC_SUBST(m68hc11_extra_objs) + +SIM_AC_OUTPUT
configure.ac Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: interrupts.h =================================================================== --- interrupts.h (nonexistent) +++ interrupts.h (revision 33) @@ -0,0 +1,173 @@ +/* interrupts.h -- 68HC11 Interrupts Emulation + Copyright 1999, 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@worldnet.fr) + +This file is part of GDB, GAS, and the GNU binutils. + +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. + +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, see . */ + +#ifndef _M6811_SIM_INTERRUPTS_H +#define _M6811_SIM_INTERRUPTS_H + +/* Definition of 68HC11 interrupts. These enum are used as an index + in the interrupt table. */ +enum M6811_INT +{ + M6811_INT_RESERVED1 = 0, + M6811_INT_RESERVED2, + M6811_INT_RESERVED3, + M6811_INT_RESERVED4, + M6811_INT_RESERVED5, + M6811_INT_RESERVED6, + M6811_INT_RESERVED7, + M6811_INT_RESERVED8, + + M6811_INT_RESERVED9, + M6811_INT_RESERVED10, + M6811_INT_RESERVED11, + + M6811_INT_SCI, + M6811_INT_SPI, + M6811_INT_AINPUT, + M6811_INT_AOVERFLOW, + M6811_INT_TCTN, + + M6811_INT_OUTCMP5, + M6811_INT_OUTCMP4, + M6811_INT_OUTCMP3, + M6811_INT_OUTCMP2, + M6811_INT_OUTCMP1, + + M6811_INT_INCMP3, + M6811_INT_INCMP2, + M6811_INT_INCMP1, + + M6811_INT_RT, + M6811_INT_IRQ, + M6811_INT_XIRQ, + M6811_INT_SWI, + M6811_INT_ILLEGAL, + + M6811_INT_COPRESET, + M6811_INT_COPFAIL, + + M6811_INT_RESET, + M6811_INT_NUMBER +}; + + +/* Structure to describe how to recognize an interrupt in the + 68hc11 IO regs. */ +struct interrupt_def +{ + enum M6811_INT int_number; + unsigned char int_paddr; + unsigned char int_mask; + unsigned char enable_paddr; + unsigned char enabled_mask; +}; + +#define MAX_INT_HISTORY 64 + +/* Structure used to keep track of interrupt history. + This is used to understand in which order interrupts were + raised and when. */ +struct interrupt_history +{ + enum M6811_INT type; + + /* CPU cycle when interrupt handler is called. */ + signed64 taken_cycle; + + /* CPU cycle when the interrupt is first raised by the device. */ + signed64 raised_cycle; +}; + +#define SIM_STOP_WHEN_RAISED 1 +#define SIM_STOP_WHEN_TAKEN 2 + +/* Information and control of pending interrupts. */ +struct interrupt +{ + /* CPU cycle when the interrupt is raised by the device. */ + signed64 cpu_cycle; + + /* Number of times the interrupt was raised. */ + unsigned long raised_count; + + /* Controls whether we must stop the simulator. */ + int stop_mode; +}; + + +/* Management of 68HC11 interrupts: + - We use a table of 'interrupt_def' to describe the interrupts that must be + raised depending on IO register flags (enable and present flags). + - We keep a mask of pending interrupts. This mask is refreshed by + calling 'interrupts_update_pending'. It must be refreshed each time + an IO register is changed. + - 'interrupts_process' must be called after each insn. It has two purposes: + first it maintains a min/max count of CPU cycles between which interrupts + are masked; second it checks for pending interrupts and raise one if + interrupts are enabled. */ +struct interrupts { + struct _sim_cpu *cpu; + + /* Mask of current pending interrupts. */ + unsigned long pending_mask; + + /* Address of vector table. This is set depending on the + 68hc11 init mode. */ + uint16 vectors_addr; + + /* Priority order of interrupts. This is controlled by setting the HPRIO + IO register. */ + enum M6811_INT interrupt_order[M6811_INT_NUMBER]; + struct interrupt interrupts[M6811_INT_NUMBER]; + + /* Simulator statistics to report useful debug information to users. */ + + /* - Max/Min number of CPU cycles executed with interrupts masked. */ + signed64 start_mask_cycle; + signed64 min_mask_cycles; + signed64 max_mask_cycles; + signed64 last_mask_cycles; + + /* - Same for XIRQ. */ + signed64 xirq_start_mask_cycle; + signed64 xirq_min_mask_cycles; + signed64 xirq_max_mask_cycles; + signed64 xirq_last_mask_cycles; + + /* - Total number of interrupts raised. */ + unsigned long nb_interrupts_raised; + + /* Interrupt history to help understand which interrupts + were raised recently and in which order. */ + int history_index; + struct interrupt_history interrupts_history[MAX_INT_HISTORY]; +}; + +extern void interrupts_initialize (SIM_DESC sd, struct _sim_cpu* cpu); +extern void interrupts_reset (struct interrupts* interrupts); +extern void interrupts_update_pending (struct interrupts* interrupts); +extern int interrupts_get_current (struct interrupts* interrupts); +extern int interrupts_process (struct interrupts* interrupts); +extern void interrupts_raise (struct interrupts* interrupts, + enum M6811_INT number); + +extern void interrupts_info (SIM_DESC sd, + struct interrupts* interrupts); + +#endif
interrupts.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: config.in =================================================================== --- config.in (nonexistent) +++ config.in (revision 33) @@ -0,0 +1,96 @@ +/* config.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#undef ENABLE_NLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FPU_CONTROL_H + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the `time' function. */ +#undef HAVE_TIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `__setfpucw' function. */ +#undef HAVE___SETFPUCW + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN Index: dv-nvram.c =================================================================== --- dv-nvram.c (nonexistent) +++ dv-nvram.c (revision 33) @@ -0,0 +1,350 @@ +/* dv-nvram.c -- Generic driver for a non volatile ram (battery saved) + Copyright (C) 1999, 2000, 2007, 2008 Free Software Foundation, Inc. + Written by Stephane Carrez (stcarrez@worldnet.fr) + (From a driver model Contributed by Cygnus Solutions.) + + 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. + + 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, see . + + */ + + +#include "sim-main.h" +#include "hw-main.h" +#include "sim-assert.h" + +#include +#include +#include + + +/* DEVICE + + nvram - Non Volatile Ram + + + DESCRIPTION + + Implements a generic battery saved CMOS ram. This ram device does + not contain any realtime clock and does not generate any interrupt. + The ram content is loaded from a file and saved when it is changed. + It is intended to be generic. + + + PROPERTIES + + reg + + Base and size of the non-volatile ram bank. + + file + + Path where the memory must be saved or loaded when we start. + + mode {map | save-modified | save-all} + + Controls how to load and save the memory content. + + map The file is mapped in memory + save-modified The simulator keeps an open file descriptor to + the file and saves portion of memory which are + modified. + save-all The simulator saves the complete memory each time + it's modified (it does not keep an open file + descriptor). + + + PORTS + + None. + + + NOTES + + This device is independent of the Motorola 68hc11. + + */ + + + +/* static functions */ + +/* Control of how to access the ram and save its content. */ + +enum nvram_mode +{ + /* Save the complete ram block each time it's changed. + We don't keep an open file descriptor. This should be + ok for small memory banks. */ + NVRAM_SAVE_ALL, + + /* Save only the memory bytes which are modified. + This mode means that we have to keep an open file + descriptor (O_RDWR). It's good for middle sized memory banks. */ + NVRAM_SAVE_MODIFIED, + + /* Map file in memory (not yet implemented). + This mode is suitable for large memory banks. We don't allocate + a buffer to represent the ram, instead it's mapped in memory + with mmap. */ + NVRAM_MAP_FILE +}; + +struct nvram +{ + address_word base_address; /* Base address of ram. */ + unsigned size; /* Size of ram. */ + unsigned8 *data; /* Pointer to ram memory. */ + const char *file_name; /* Path of ram file. */ + int fd; /* File description of opened ram file. */ + enum nvram_mode mode; /* How load/save ram file. */ +}; + + + +/* Finish off the partially created hw device. Attach our local + callbacks. Wire up our port names etc. */ + +static hw_io_read_buffer_method nvram_io_read_buffer; +static hw_io_write_buffer_method nvram_io_write_buffer; + + + +static void +attach_nvram_regs (struct hw *me, struct nvram *controller) +{ + unsigned_word attach_address; + int attach_space; + unsigned attach_size; + reg_property_spec reg; + int result, oerrno; + + /* Get ram bank description (base and size). */ + if (hw_find_property (me, "reg") == NULL) + hw_abort (me, "Missing \"reg\" property"); + + if (!hw_find_reg_array_property (me, "reg", 0, ®)) + hw_abort (me, "\"reg\" property must contain one addr/size entry"); + + hw_unit_address_to_attach_address (hw_parent (me), + ®.address, + &attach_space, + &attach_address, + me); + hw_unit_size_to_attach_size (hw_parent (me), + ®.size, + &attach_size, me); + + hw_attach_address (hw_parent (me), 0, + attach_space, attach_address, attach_size, + me); + + controller->mode = NVRAM_SAVE_ALL; + controller->base_address = attach_address; + controller->size = attach_size; + controller->fd = -1; + + /* Get the file where the ram content must be loaded/saved. */ + if(hw_find_property (me, "file") == NULL) + hw_abort (me, "Missing \"file\" property"); + + controller->file_name = hw_find_string_property (me, "file"); + + /* Get the mode which defines how to save the memory. */ + if(hw_find_property (me, "mode") != NULL) + { + const char *value = hw_find_string_property (me, "mode"); + + if (strcmp (value, "map") == 0) + controller->mode = NVRAM_MAP_FILE; + else if (strcmp (value, "save-modified") == 0) + controller->mode = NVRAM_SAVE_MODIFIED; + else if (strcmp (value, "save-all") == 0) + controller->mode = NVRAM_SAVE_ALL; + else + hw_abort (me, "illegal value for mode parameter `%s': " + "use map, save-modified or save-all", value); + } + + /* Initialize the ram by loading/mapping the file in memory. + If the file does not exist, create and give it some content. */ + switch (controller->mode) + { + case NVRAM_MAP_FILE: + hw_abort (me, "'map' mode is not yet implemented, use 'save-modified'"); + break; + + case NVRAM_SAVE_MODIFIED: + case NVRAM_SAVE_ALL: + controller->data = (char*) hw_malloc (me, attach_size); + if (controller->data == 0) + hw_abort (me, "Not enough memory, try to use the mode 'map'"); + + memset (controller->data, 0, attach_size); + controller->fd = open (controller->file_name, O_RDWR); + if (controller->fd < 0) + { + controller->fd = open (controller->file_name, + O_RDWR | O_CREAT, 0644); + if (controller->fd < 0) + hw_abort (me, "Cannot open or create file '%s'", + controller->file_name); + result = write (controller->fd, controller->data, attach_size); + if (result != attach_size) + { + oerrno = errno; + hw_free (me, controller->data); + close (controller->fd); + errno = oerrno; + hw_abort (me, "Failed to save the ram content"); + } + } + else + { + result = read (controller->fd, controller->data, attach_size); + if (result != attach_size) + { + oerrno = errno; + hw_free (me, controller->data); + close (controller->fd); + errno = oerrno; + hw_abort (me, "Failed to load the ram content"); + } + } + if (controller->mode == NVRAM_SAVE_ALL) + { + close (controller->fd); + controller->fd = -1; + } + break; + + default: + break; + } +} + + +static void +nvram_finish (struct hw *me) +{ + struct nvram *controller; + + controller = HW_ZALLOC (me, struct nvram); + + set_hw_data (me, controller); + set_hw_io_read_buffer (me, nvram_io_read_buffer); + set_hw_io_write_buffer (me, nvram_io_write_buffer); + + /* Attach ourself to our parent bus. */ + attach_nvram_regs (me, controller); +} + + + +/* generic read/write */ + +static unsigned +nvram_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + struct nvram *controller = hw_data (me); + + HW_TRACE ((me, "read 0x%08lx %d [%ld]", + (long) base, (int) nr_bytes, + (long) (base - controller->base_address))); + + base -= controller->base_address; + if (base + nr_bytes > controller->size) + nr_bytes = controller->size - base; + + memcpy (dest, &controller->data[base], nr_bytes); + return nr_bytes; +} + + + +static unsigned +nvram_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word base, + unsigned nr_bytes) +{ + struct nvram *controller = hw_data (me); + + HW_TRACE ((me, "write 0x%08lx %d [%ld]", + (long) base, (int) nr_bytes, + (long) (base - controller->base_address))); + + base -= controller->base_address; + if (base + nr_bytes > controller->size) + nr_bytes = controller->size - base; + + switch (controller->mode) + { + case NVRAM_SAVE_ALL: + { + int fd, result, oerrno; + + fd = open (controller->file_name, O_WRONLY, 0644); + if (fd < 0) + { + return 0; + } + + memcpy (&controller->data[base], source, nr_bytes); + result = write (fd, controller->data, controller->size); + oerrno = errno; + close (fd); + errno = oerrno; + + if (result != controller->size) + { + return 0; + } + return nr_bytes; + } + + case NVRAM_SAVE_MODIFIED: + { + off_t pos; + int result; + + pos = lseek (controller->fd, (off_t) base, SEEK_SET); + if (pos != (off_t) base) + return 0; + + result = write (controller->fd, source, nr_bytes); + if (result < 0) + return 0; + + nr_bytes = result; + break; + } + + default: + break; + } + memcpy (&controller->data[base], source, nr_bytes); + return nr_bytes; +} + + +const struct hw_descriptor dv_nvram_descriptor[] = { + { "nvram", nvram_finish, }, + { NULL }, +}; +
dv-nvram.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.