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 <stcarrez@nerim.fr>
+
+ * 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 <stcarrez@nerim.fr>
* sim-main.h (phys_to_virt): Use memory bank parameters to translate
" %d %d %35.35s\n",
osc->name, freq,
cur_value, next_value,
- cycle_to_string (cpu, t));
+ 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));
+ cycle_to_string (cpu, t,
+ PRINT_TIME | PRINT_CYCLE));
}
}
break;
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), n, (n > 1 ? "s" : ""));
+ cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
+ n, (n > 1 ? "s" : ""));
}
if (controller->rx_poll_event)
{
t = hw_event_remain_time (me, controller->rx_poll_event);
sim_io_printf (sd, " Receive finished in %s\n",
- cycle_to_string (cpu, t));
+ cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
}
}
/* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI
- Copyright (C) 2000, 2002 Free Software Foundation, Inc.
- Written by Stephane Carrez (stcarrez@worldnet.fr)
+ Copyright (C) 2000, 2002, 2003 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.
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));
+ 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));
+ cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
}
}
#include "sim-main.h"
#include "hw-main.h"
#include "sim-assert.h"
-
+#include <limits.h>
/* DEVICE
unsigned mask;
unsigned flags;
unsigned long tcnt_internal;
- unsigned long tcnt;
+ unsigned long tcnt, tcnt_prev;
+ signed64 tcnt_insn_end;
+ signed64 tcnt_insn_start;
int i;
sim_events *events;
break;
case OVERFLOW_EVENT:
- /* Compute the 68HC11 internal free running counter.
- There may be 'nr_ticks_to_process' pending cycles that are
- not (yet) taken into account by 'sim_events_time'. */
- tcnt_internal = sim_events_time (sd) - controller->tcnt_adjust;
- tcnt_internal += events->nr_ticks_to_process;
+ /* 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). */
break;
case COMPARE_EVENT:
- eventp = &controller->cmp_timer_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;
- /* Compute the 68HC11 internal free running counter.
- There may be 'nr_ticks_to_process' pending cycles that are
- not (yet) taken into account by 'sim_events_time'. */
- events = STATE_EVENTS (sd);
- tcnt_internal = sim_events_time (sd) - controller->tcnt_adjust;
- tcnt_internal += events->nr_ticks_to_process;
+ /* 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;
- /* Get current visible TCNT register value. */
- tcnt = tcnt_internal / controller->clock_prescaler;
-
flags = cpu->ios[M6811_TMSK1];
mask = 0x80;
delay = 65536 * controller->clock_prescaler;
for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1)
{
unsigned long compare;
-
- compare = (cpu->ios[i] << 8) + cpu->ios[i+1];
- if (compare == tcnt && (flags & mask))
+
+ 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;
- check_interrupt++;
+
+ /* 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.
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 & 0xF0) == 0)
+ if ((flags & 0xF8) == 0)
delay = 0;
+ else
+ delay += events->nr_ticks_to_process;
+
+ eventp = &controller->cmp_timer_event;
break;
default:
}
const char*
-cycle_to_string (sim_cpu *cpu, signed64 t)
+cycle_to_string (sim_cpu *cpu, signed64 t, int flags)
{
- double dt;
- char tbuf[32];
+ char time_buf[32];
+ char cycle_buf[32];
static char buf[64];
- dt = to_realtime (cpu, t);
- if (dt < 0.001)
- sprintf (tbuf, "(%3.1f us)", dt * 1000000.0);
- else if (dt < 1.0)
- sprintf (tbuf, "(%3.1f ms)", dt * 1000.0);
- else
- sprintf (tbuf, "(%3.1f s)", dt);
+ 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);
+ }
- sprintf (buf, "%llu cycle%s %10.10s", t,
- (t > 1 ? "s" : ""), tbuf);
+ 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;
}
t = hw_event_remain_time (me, event);
sim_io_printf (sd, " Next %s interrupt in %s\n",
- name, cycle_to_string (cpu, t));
+ name, cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
}
}
break;
}
*((unsigned8*) dest) = val;
- dest++;
+ dest = (char*) dest + 1;
base++;
nr_bytes--;
cnt++;
case M6811_TMSK1:
cpu->ios[M6811_TMSK1] = val;
interrupts_update_pending (&cpu->cpu_interrupts);
+ reset_compare = 1;
break;
case M6811_TFLG1:
cpu->ios[base] = val;
reset_compare = 1;
break;
-
+
case M6811_TCTL1:
case M6811_TCTL2:
cpu->ios[base] = val;
base++;
nr_bytes--;
cnt++;
- source++;
+ source = (char*) source + 1;
}
/* Re-compute the next timer compare event. */
/* interrupts.c -- 68HC11 Interrupts Emulation
- Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- Written by Stephane Carrez (stcarrez@worldnet.fr)
+ Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Written by Stephane Carrez (stcarrez@nerim.fr)
This file is part of GDB, GAS, and the GNU binutils.
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
void
interrupts_info (SIM_DESC sd, struct interrupts *interrupts)
{
- signed64 t;
+ signed64 t, prev_interrupt;
int i;
sim_io_printf (sd, "Interrupts Info:\n");
interrupts->max_mask_cycles = t;
sim_io_printf (sd, " Current interrupts masked sequence: %s\n",
- cycle_to_string (interrupts->cpu, t));
+ 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));
+ 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));
+ 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));
+ cycle_to_string (interrupts->cpu, t,
+ PRINT_TIME | PRINT_CYCLE));
if (interrupts->xirq_start_mask_cycle >= 0)
{
interrupts->xirq_max_mask_cycles = t;
sim_io_printf (sd, " XIRQ Current interrupts masked sequence: %s\n",
- cycle_to_string (interrupts->cpu, t));
+ 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));
+ 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));
+ 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));
+ cycle_to_string (interrupts->cpu, t,
+ PRINT_TIME | PRINT_CYCLE));
if (interrupts->pending_mask)
{
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;
break;
dt = h->taken_cycle - h->raised_cycle;
- sim_io_printf (sd, "%2d %-10.10s %30.30s ", i,
+ sim_io_printf (sd, "%2d %-9.9s %15.15s ", i,
interrupt_names[h->type],
- cycle_to_string (interrupts->cpu, h->taken_cycle));
- sim_io_printf (sd, "%s\n",
- cycle_to_string (interrupts->cpu, dt));
+ 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;
}
}
OPTION_CPU_RESET = OPTION_START,
OPTION_EMUL_OS,
OPTION_CPU_CONFIG,
+ OPTION_CPU_BOOTSTRAP,
OPTION_CPU_MODE
};
'\0', NULL, "Specify the initial CPU configuration register",
cpu_option_handler },
+ { {"bootstrap", no_argument, NULL, OPTION_CPU_BOOTSTRAP },
+ '\0', NULL, "Start the processing in bootstrap mode",
+ cpu_option_handler },
+
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
else
cpu->cpu_use_local_config = 0;
break;
-
+
+ case OPTION_CPU_BOOTSTRAP:
+ cpu->cpu_start_mode = "bootstrap";
+ break;
+
case OPTION_CPU_MODE:
break;
}
{
sim_io_printf (sd, "CPU info:\n");
sim_io_printf (sd, " Absolute cycle: %s\n",
- cycle_to_string (cpu, cpu->cpu_absolute_cycle));
+ cycle_to_string (cpu, cpu->cpu_absolute_cycle,
+ PRINT_TIME | PRINT_CYCLE));
sim_io_printf (sd, " Syscall emulation: %s\n",
cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
/* 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;
extern void sim_set_profile_size (int n);
extern void sim_board_reset (SIM_DESC sd);
-extern const char *cycle_to_string (sim_cpu *cpu, signed64 t);
+#define PRINT_TIME 0x01
+#define PRINT_CYCLE 0x02
+extern const char *cycle_to_string (sim_cpu *cpu, signed64 t, int flags);
#endif