diff --git a/sim/m68hc11/ChangeLog b/sim/m68hc11/ChangeLog index 5cd46d0efe..3d019d7658 100644 --- a/sim/m68hc11/ChangeLog +++ b/sim/m68hc11/ChangeLog @@ -1,3 +1,26 @@ +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 diff --git a/sim/m68hc11/dv-m68hc11.c b/sim/m68hc11/dv-m68hc11.c index cad100a9b5..5cc716182b 100644 --- a/sim/m68hc11/dv-m68hc11.c +++ b/sim/m68hc11/dv-m68hc11.c @@ -808,13 +808,15 @@ m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu, " %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; diff --git a/sim/m68hc11/dv-m68hc11sio.c b/sim/m68hc11/dv-m68hc11sio.c index ec7a46de50..655a6dbe0d 100644 --- a/sim/m68hc11/dv-m68hc11sio.c +++ b/sim/m68hc11/dv-m68hc11sio.c @@ -463,7 +463,8 @@ m68hc11sio_info (struct hw *me) 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) { @@ -471,7 +472,7 @@ m68hc11sio_info (struct hw *me) 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)); } } diff --git a/sim/m68hc11/dv-m68hc11spi.c b/sim/m68hc11/dv-m68hc11spi.c index 5f5e0bbe9c..619a2d31fc 100644 --- a/sim/m68hc11/dv-m68hc11spi.c +++ b/sim/m68hc11/dv-m68hc11spi.c @@ -1,6 +1,6 @@ /* 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. @@ -358,11 +358,11 @@ m68hc11spi_info (struct hw *me) 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)); } } diff --git a/sim/m68hc11/dv-m68hc11tim.c b/sim/m68hc11/dv-m68hc11tim.c index b0ff2c35fa..0456f67891 100644 --- a/sim/m68hc11/dv-m68hc11tim.c +++ b/sim/m68hc11/dv-m68hc11tim.c @@ -25,7 +25,7 @@ #include "sim-main.h" #include "hw-main.h" #include "sim-assert.h" - +#include /* DEVICE @@ -250,7 +250,9 @@ m68hc11tim_timer_event (struct hw *me, void *data) 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; @@ -289,11 +291,8 @@ m68hc11tim_timer_event (struct hw *me, void *data) 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). */ @@ -316,22 +315,22 @@ m68hc11tim_timer_event (struct hw *me, void *data) 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); - /* 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 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; - /* Get current visible TCNT register value. */ - tcnt = tcnt_internal / controller->clock_prescaler; - flags = cpu->ios[M6811_TMSK1]; mask = 0x80; delay = 65536 * controller->clock_prescaler; @@ -342,12 +341,28 @@ m68hc11tim_timer_event (struct hw *me, void *data) 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. @@ -359,14 +374,18 @@ m68hc11tim_timer_event (struct hw *me, void *data) 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: @@ -457,22 +476,35 @@ to_realtime (sim_cpu *cpu, signed64 t) } 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; - sprintf (buf, "%llu cycle%s %10.10s", t, - (t > 1 ? "s" : ""), tbuf); + 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; } @@ -496,7 +528,7 @@ m68hc11tim_print_timer (struct hw *me, const char *name, 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)); } } @@ -643,7 +675,7 @@ m68hc11tim_io_read_buffer (struct hw *me, break; } *((unsigned8*) dest) = val; - dest++; + dest = (char*) dest + 1; base++; nr_bytes--; cnt++; @@ -754,6 +786,7 @@ m68hc11tim_io_write_buffer (struct hw *me, case M6811_TMSK1: cpu->ios[M6811_TMSK1] = val; interrupts_update_pending (&cpu->cpu_interrupts); + reset_compare = 1; break; case M6811_TFLG1: @@ -770,7 +803,7 @@ m68hc11tim_io_write_buffer (struct hw *me, cpu->ios[base] = val; reset_compare = 1; break; - + case M6811_TCTL1: case M6811_TCTL2: cpu->ios[base] = val; @@ -784,7 +817,7 @@ m68hc11tim_io_write_buffer (struct hw *me, base++; nr_bytes--; cnt++; - source++; + source = (char*) source + 1; } /* Re-compute the next timer compare event. */ diff --git a/sim/m68hc11/interrupts.c b/sim/m68hc11/interrupts.c index 5844c74ea1..b466d69dac 100644 --- a/sim/m68hc11/interrupts.c +++ b/sim/m68hc11/interrupts.c @@ -1,6 +1,6 @@ /* 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. @@ -166,6 +166,20 @@ interrupts_reset (struct interrupts *interrupts) 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 @@ -517,7 +531,7 @@ interrupts_raise (struct interrupts *interrupts, enum M6811_INT number) void interrupts_info (SIM_DESC sd, struct interrupts *interrupts) { - signed64 t; + signed64 t, prev_interrupt; int i; sim_io_printf (sd, "Interrupts Info:\n"); @@ -533,21 +547,25 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) 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) { @@ -558,22 +576,26 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) 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) { @@ -590,6 +612,9 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) 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; @@ -604,10 +629,18 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) 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; } } diff --git a/sim/m68hc11/m68hc11_sim.c b/sim/m68hc11/m68hc11_sim.c index 1daa39c13e..444147b949 100644 --- a/sim/m68hc11/m68hc11_sim.c +++ b/sim/m68hc11/m68hc11_sim.c @@ -27,6 +27,7 @@ enum { OPTION_CPU_RESET = OPTION_START, OPTION_EMUL_OS, OPTION_CPU_CONFIG, + OPTION_CPU_BOOTSTRAP, OPTION_CPU_MODE }; @@ -46,6 +47,10 @@ static const OPTION cpu_options[] = '\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 } }; @@ -77,7 +82,11 @@ cpu_option_handler (SIM_DESC sd, sim_cpu *cpu, else cpu->cpu_use_local_config = 0; break; - + + case OPTION_CPU_BOOTSTRAP: + cpu->cpu_start_mode = "bootstrap"; + break; + case OPTION_CPU_MODE: break; } @@ -1049,7 +1058,8 @@ 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)); + 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"); diff --git a/sim/m68hc11/sim-main.h b/sim/m68hc11/sim-main.h index 054933b1bc..a4bd3a62bf 100644 --- a/sim/m68hc11/sim-main.h +++ b/sim/m68hc11/sim-main.h @@ -200,6 +200,7 @@ struct _sim_cpu { /* 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; @@ -591,7 +592,9 @@ extern void sim_set_profile (int n); 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