123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- /* dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
- Copyright (C) 1999-2015 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 <http://www.gnu.org/licenses/>.
-
- */
- #include "sim-main.h"
- #include "hw-main.h"
- #include "sim-assert.h"
- #include <limits.h>
- /* 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 },
- };
|