xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/dv-m68hc11tim.c (revision 9b2a9e00295c5af9c57a466f299054d5910e47d6)
1 /*  dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
2     Copyright (C) 1999-2024 Free Software Foundation, Inc.
3     Written by Stephane Carrez (stcarrez@nerim.fr)
4     (From a driver model Contributed by Cygnus Solutions.)
5 
6     This file is part of the program GDB, the GNU debugger.
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 
21     */
22 
23 /* This must come before any other includes.  */
24 #include "defs.h"
25 
26 #include "sim-main.h"
27 #include "hw-main.h"
28 #include "sim-assert.h"
29 #include <limits.h>
30 
31 #include "m68hc11-sim.h"
32 
33 /* DEVICE
34 
35         m68hc11tim - m68hc11 timer devices
36 
37 
38    DESCRIPTION
39 
40         Implements the m68hc11 timer as described in Chapter 10
41         of the pink book.
42 
43 
44    PROPERTIES
45 
46         none
47 
48 
49    PORTS
50 
51    reset (input)
52 
53         Reset the timer device.  This port must be connected to
54         the cpu-reset output port.
55 
56    capture (input)
57 
58         Input capture.  This port must be connected to the input
59         captures.  It latches the current TCNT free running counter
60         into one of the three input capture registers.
61 
62    */
63 
64 
65 
66 /* port ID's */
67 
68 enum
69 {
70   RESET_PORT,
71   CAPTURE
72 };
73 
74 
75 static const struct hw_port_descriptor m68hc11tim_ports[] =
76 {
77   { "reset",   RESET_PORT, 0, input_port, },
78   { "capture", CAPTURE,    0, input_port, },
79   { NULL, },
80 };
81 
82 
83 /* Timer Controller information.  */
84 struct m68hc11tim
85 {
86   unsigned long cop_delay;
87   unsigned long rti_delay;
88   unsigned long ovf_delay;
89   int64_t      clock_prescaler;
90   int64_t      tcnt_adjust;
91   int64_t      cop_prev_interrupt;
92   int64_t      rti_prev_interrupt;
93 
94   /* Periodic timers.  */
95   struct hw_event *rti_timer_event;
96   struct hw_event *cop_timer_event;
97   struct hw_event *tof_timer_event;
98   struct hw_event *cmp_timer_event;
99 };
100 
101 
102 
103 /* Finish off the partially created hw device.  Attach our local
104    callbacks.  Wire up our port names etc.  */
105 
106 static hw_io_read_buffer_method m68hc11tim_io_read_buffer;
107 static hw_io_write_buffer_method m68hc11tim_io_write_buffer;
108 static hw_port_event_method m68hc11tim_port_event;
109 static hw_ioctl_method m68hc11tim_ioctl;
110 
111 #define M6811_TIMER_FIRST_REG (M6811_TCTN)
112 #define M6811_TIMER_LAST_REG  (M6811_PACNT)
113 
114 
115 static void
116 attach_m68hc11tim_regs (struct hw *me,
117                         struct m68hc11tim *controller)
118 {
119   hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
120                      M6811_TIMER_FIRST_REG,
121                      M6811_TIMER_LAST_REG - M6811_TIMER_FIRST_REG + 1,
122 		     me);
123 }
124 
125 static void
126 m68hc11tim_finish (struct hw *me)
127 {
128   struct m68hc11tim *controller;
129 
130   controller = HW_ZALLOC (me, struct m68hc11tim);
131   set_hw_data (me, controller);
132   set_hw_io_read_buffer (me, m68hc11tim_io_read_buffer);
133   set_hw_io_write_buffer (me, m68hc11tim_io_write_buffer);
134   set_hw_ports (me, m68hc11tim_ports);
135   set_hw_port_event (me, m68hc11tim_port_event);
136 #ifdef set_hw_ioctl
137   set_hw_ioctl (me, m68hc11tim_ioctl);
138 #else
139   me->to_ioctl = m68hc11tim_ioctl;
140 #endif
141 
142   /* Preset defaults.  */
143   controller->clock_prescaler = 1;
144   controller->tcnt_adjust = 0;
145 
146   /* Attach ourself to our parent bus.  */
147   attach_m68hc11tim_regs (me, controller);
148 }
149 
150 
151 /* An event arrives on an interrupt port.  */
152 
153 static void
154 m68hc11tim_port_event (struct hw *me,
155                        int my_port,
156                        struct hw *source,
157                        int source_port,
158                        int level)
159 {
160   SIM_DESC sd;
161   struct m68hc11tim *controller;
162   sim_cpu *cpu;
163   struct m68hc11_sim_cpu *m68hc11_cpu;
164   uint8_t val;
165   uint16_t tcnt;
166 
167   controller = hw_data (me);
168   sd         = hw_system (me);
169   cpu        = STATE_CPU (sd, 0);
170   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
171   switch (my_port)
172     {
173     case RESET_PORT:
174       {
175 	HW_TRACE ((me, "Timer reset"));
176 
177         /* Cancel all timer events.  */
178         if (controller->rti_timer_event)
179           {
180             hw_event_queue_deschedule (me, controller->rti_timer_event);
181             controller->rti_timer_event = 0;
182             controller->rti_prev_interrupt = 0;
183           }
184         if (controller->cop_timer_event)
185           {
186             hw_event_queue_deschedule (me, controller->cop_timer_event);
187             controller->cop_timer_event = 0;
188             controller->cop_prev_interrupt = 0;
189           }
190         if (controller->tof_timer_event)
191           {
192             hw_event_queue_deschedule (me, controller->tof_timer_event);
193             controller->tof_timer_event = 0;
194           }
195         if (controller->cmp_timer_event)
196           {
197             hw_event_queue_deschedule (me, controller->cmp_timer_event);
198             controller->cmp_timer_event = 0;
199           }
200 
201         /* Reset the state of Timer registers.  This also restarts
202            the timer events (overflow and RTI clock).  The pending
203            flags (TFLG2) must be cleared explicitly here.  */
204         val = 0;
205         m68hc11_cpu->ios[M6811_TFLG2] = 0;
206         m68hc11tim_io_write_buffer (me, &val, io_map,
207                                     (unsigned_word) M6811_TMSK2, 1);
208         m68hc11tim_io_write_buffer (me, &val, io_map,
209                                     (unsigned_word) M6811_PACTL, 1);
210         break;
211       }
212 
213     case CAPTURE:
214       tcnt = (uint16_t) ((m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust)
215                        / controller->clock_prescaler);
216       switch (level)
217         {
218         case M6811_TIC1:
219         case M6811_TIC2:
220         case M6811_TIC3:
221           m68hc11_cpu->ios[level] = tcnt >> 8;
222           m68hc11_cpu->ios[level + 1] = tcnt;
223           break;
224 
225         default:
226           hw_abort (me, "Invalid event parameter %d", level);
227           break;
228         }
229       break;
230 
231     default:
232       hw_abort (me, "Event on unknown port %d", my_port);
233       break;
234     }
235 }
236 
237 enum event_type
238 {
239   COP_EVENT,
240   RTI_EVENT,
241   OVERFLOW_EVENT,
242   COMPARE_EVENT
243 };
244 
245 static void
246 m68hc11tim_timer_event (struct hw *me, void *data)
247 {
248   SIM_DESC sd;
249   struct m68hc11tim *controller;
250   sim_cpu *cpu;
251   struct m68hc11_sim_cpu *m68hc11_cpu;
252   enum event_type type;
253   unsigned long delay;
254   struct hw_event **eventp;
255   int check_interrupt = 0;
256   unsigned mask;
257   unsigned flags;
258   unsigned long tcnt_internal;
259   unsigned long tcnt, tcnt_prev;
260   int64_t tcnt_insn_end;
261   int64_t tcnt_insn_start;
262   int i;
263   sim_events *events;
264 
265   controller = hw_data (me);
266   sd         = hw_system (me);
267   cpu        = STATE_CPU (sd, 0);
268   m68hc11_cpu  = M68HC11_SIM_CPU (cpu);
269   type       = (enum event_type) ((uintptr_t) data) & 0x0FF;
270   events     = STATE_EVENTS (sd);
271 
272   delay = 0;
273   switch (type)
274     {
275     case COP_EVENT:
276       eventp = &controller->cop_timer_event;
277       delay  = controller->cop_delay;
278       delay  = controller->cop_prev_interrupt + controller->cop_delay;
279       controller->cop_prev_interrupt = delay;
280       delay  = delay - m68hc11_cpu->cpu_absolute_cycle;
281       check_interrupt = 1;
282       delay += events->nr_ticks_to_process;
283       break;
284 
285     case RTI_EVENT:
286       eventp = &controller->rti_timer_event;
287       delay  = controller->rti_prev_interrupt + controller->rti_delay;
288 
289       if (((uintptr_t) data & 0x0100) == 0)
290         {
291           m68hc11_cpu->ios[M6811_TFLG2] |= M6811_RTIF;
292           check_interrupt = 1;
293           controller->rti_prev_interrupt = delay;
294           delay += controller->rti_delay;
295         }
296       delay = delay - m68hc11_cpu->cpu_absolute_cycle;
297       delay += events->nr_ticks_to_process;
298       break;
299 
300     case OVERFLOW_EVENT:
301       /* Compute the 68HC11 internal free running counter.  */
302       tcnt_internal = (m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust);
303 
304       /* We must take into account the prescaler that comes
305          before the counter (it's a power of 2).  */
306       tcnt_internal &= 0x0ffff * controller->clock_prescaler;
307 
308       /* Compute the time when the overflow will occur.  It occurs when
309          the counter increments from 0x0ffff to 0x10000 (and thus resets).  */
310       delay = (0x10000 * controller->clock_prescaler) - tcnt_internal;
311 
312       /* The 'nr_ticks_to_process' will be subtracted when the event
313          is scheduled.  */
314       delay += events->nr_ticks_to_process;
315 
316       eventp = &controller->tof_timer_event;
317       if (((uintptr_t) data & 0x100) == 0)
318         {
319           m68hc11_cpu->ios[M6811_TFLG2] |= M6811_TOF;
320           check_interrupt = 1;
321         }
322       break;
323 
324     case COMPARE_EVENT:
325       /* Compute value of TCNT register (64-bit precision) at beginning
326          and end of instruction.  */
327       tcnt_insn_end = (m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust);
328       tcnt_insn_start = (tcnt_insn_end - m68hc11_cpu->cpu_current_cycle);
329 
330       /* TCNT value at beginning of current instruction.  */
331       tcnt_prev = (tcnt_insn_start / controller->clock_prescaler) & 0x0ffff;
332 
333       /* TCNT value at end of current instruction.  */
334       tcnt = (tcnt_insn_end / controller->clock_prescaler) & 0x0ffff;
335 
336       /* We must take into account the prescaler that comes
337          before the counter (it's a power of 2).  */
338       tcnt_internal = tcnt_insn_end;
339       tcnt_internal &= 0x0ffff * controller->clock_prescaler;
340 
341       flags = m68hc11_cpu->ios[M6811_TMSK1];
342       mask  = 0x80;
343       delay = 65536 * controller->clock_prescaler;
344 
345       /* Scan each output compare register to see if one matches
346          the free running counter.  Set the corresponding OCi flag
347          if the output compare is enabled.  */
348       for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1)
349         {
350           unsigned long compare;
351 
352           compare = (m68hc11_cpu->ios[i] << 8) + m68hc11_cpu->ios[i + 1];
353 
354           /* See if compare is reached; handle wrap arround.  */
355           if ((compare >= tcnt_prev && compare <= tcnt && tcnt_prev < tcnt)
356               || (compare >= tcnt_prev && tcnt_prev > tcnt)
357               || (compare < tcnt && tcnt_prev > tcnt))
358             {
359               unsigned dt;
360 
361               if (compare > tcnt)
362                 dt = 0x10000 - compare - tcnt;
363               else
364                 dt = tcnt - compare;
365 
366               m68hc11_cpu->ios[M6811_TFLG1] |= mask;
367 
368               /* Raise interrupt now at the correct CPU cycle so that
369                  we can find the interrupt latency.  */
370               m68hc11_cpu->cpu_absolute_cycle -= dt;
371               interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
372               m68hc11_cpu->cpu_absolute_cycle += dt;
373             }
374 
375           /* Compute how many times for the next match.
376              Use the internal counter value to take into account the
377              prescaler accurately.  */
378           compare = compare * controller->clock_prescaler;
379           if (compare > tcnt_internal)
380             compare = compare - tcnt_internal;
381           else
382             compare = compare - tcnt_internal
383               + 65536 * controller->clock_prescaler;
384 
385           if (compare < delay)
386             delay = compare;
387         }
388 
389       /* Deactivate the compare timer if no output compare is enabled.  */
390       if ((flags & 0xF8) == 0)
391         delay = 0;
392       else
393         delay += events->nr_ticks_to_process;
394 
395       eventp = &controller->cmp_timer_event;
396       break;
397 
398     default:
399       eventp = 0;
400       break;
401     }
402 
403   if (*eventp)
404     {
405       hw_event_queue_deschedule (me, *eventp);
406       *eventp = 0;
407     }
408 
409   if (delay != 0)
410     {
411       *eventp = hw_event_queue_schedule (me, delay,
412                                          m68hc11tim_timer_event,
413                                          (void*) type);
414     }
415 
416   if (check_interrupt)
417     interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
418 }
419 
420 
421 /* Descriptions of the Timer I/O ports.  These descriptions are only used to
422    give information of the Timer device under GDB.  */
423 io_reg_desc tmsk1_desc[] = {
424   { M6811_OC1I,  "OC1I ", "Timer Output Compare 1 Interrupt Enable" },
425   { M6811_OC2I,  "OC2I ", "Timer Output Compare 2 Interrupt Enable" },
426   { M6811_OC3I,  "OC3I ", "Timer Output Compare 3 Interrupt Enable" },
427   { M6811_OC4I,  "OC4I ", "Timer Output Compare 4 Interrupt Enable" },
428   { M6811_OC5I,  "OC5I ", "Timer Input Capture 4 / Output Compare 5 Enable" },
429   { M6811_IC1I,  "IC1I ", "Timer Input Capture 1 Interrupt Enable" },
430   { M6811_IC2I,  "IC2I ", "Timer Input Capture 2 Interrupt Enable" },
431   { M6811_IC3I,  "IC3I ", "Timer Input Capture 3 Interrupt Enable" },
432   { 0, 0, 0 }
433 };
434 
435 io_reg_desc tflg1_desc[] = {
436   { M6811_OC1F,  "OC1F ", "Timer Output Compare 1 Interrupt Flag" },
437   { M6811_OC2F,  "OC2F ", "Timer Output Compare 2 Interrupt Flag" },
438   { M6811_OC3F,  "OC3F ", "Timer Output Compare 3 Interrupt Flag" },
439   { M6811_OC4F,  "OC4F ", "Timer Output Compare 4 Interrupt Flag" },
440   { M6811_OC5F,  "OC5F ", "Timer Input Capture 4 / Output Compare 5 Flag" },
441   { M6811_IC1F,  "IC1F ", "Timer Input Capture 1 Interrupt Flag" },
442   { M6811_IC2F,  "IC2F ", "Timer Input Capture 2 Interrupt Flag" },
443   { M6811_IC3F,  "IC3F ", "Timer Input Capture 3 Interrupt Flag" },
444   { 0, 0, 0 }
445 };
446 
447 io_reg_desc tmsk2_desc[] = {
448   { M6811_TOI,    "TOI   ", "Timer Overflow Interrupt Enable" },
449   { M6811_RTII,   "RTII  ", "RTI Interrupt Enable" },
450   { M6811_PAOVI,  "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" },
451   { M6811_PAII,   "PAII  ", "Pulse Accumulator Interrupt Enable" },
452   { M6811_PR1,    "PR1   ", "Timer prescaler (PR1)" },
453   { M6811_PR0,    "PR0   ", "Timer prescaler (PR0)" },
454   { M6811_TPR_1,  "TPR_1 ", "Timer prescaler div 1" },
455   { M6811_TPR_4,  "TPR_4 ", "Timer prescaler div 4" },
456   { M6811_TPR_8,  "TPR_8 ", "Timer prescaler div 8" },
457   { M6811_TPR_16, "TPR_16", "Timer prescaler div 16" },
458   { 0,  0, 0 }
459 };
460 
461 io_reg_desc tflg2_desc[] = {
462   { M6811_TOF,   "TOF   ", "Timer Overflow Bit" },
463   { M6811_RTIF,  "RTIF  ", "Read Time Interrupt Flag" },
464   { M6811_PAOVF, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" },
465   { M6811_PAIF,  "PAIF  ", "Pulse Accumulator Input Edge" },
466   { 0,  0, 0 }
467 };
468 
469 io_reg_desc pactl_desc[] = {
470   { M6811_DDRA7,  "DDRA7 ", "Data Direction for Port A bit-7" },
471   { M6811_PAEN,   "PAEN  ", "Pulse Accumulator System Enable" },
472   { M6811_PAMOD,  "PAMOD ", "Pulse Accumulator Mode" },
473   { M6811_PEDGE,  "PEDGE ", "Pulse Accumulator Edge Control" },
474   { M6811_RTR1,   "RTR1  ", "RTI Interrupt rate select (RTR1)" },
475   { M6811_RTR0,   "RTR0  ", "RTI Interrupt rate select (RTR0)" },
476   { 0,  0, 0 }
477 };
478 
479 static double
480 to_realtime (sim_cpu *cpu, int64_t t)
481 {
482   return (double) (t) / (double) (M68HC11_SIM_CPU (cpu)->cpu_frequency / 4);
483 }
484 
485 const char*
486 cycle_to_string (sim_cpu *cpu, int64_t t, int flags)
487 {
488   char time_buf[32];
489   char cycle_buf[32];
490   /* Big enough to handle 64-bit t, time_buf, and cycle_buf.  */
491   static char buf[128];
492 
493   time_buf[0] = 0;
494   cycle_buf[0] = 0;
495   if (flags & PRINT_TIME)
496     {
497       double dt;
498 
499       dt = to_realtime (cpu, t);
500       if (dt < 0.001)
501         sprintf (time_buf, " (%3.1f us)", dt * 1000000.0);
502       else if (dt < 1.0)
503         sprintf (time_buf, " (%3.1f ms)", dt * 1000.0);
504       else
505         sprintf (time_buf, " (%3.1f s)", dt);
506     }
507 
508   if (flags & PRINT_CYCLE)
509     sprintf (cycle_buf, " cycle%s",
510              (t > 1 ? "s" : ""));
511 
512   sprintf (buf, "%9" PRIi64 "%s%s", t, cycle_buf, time_buf);
513   return buf;
514 }
515 
516 static void
517 m68hc11tim_print_timer (struct hw *me, const char *name,
518                         struct hw_event *event)
519 {
520   SIM_DESC sd;
521 
522   sd = hw_system (me);
523   if (event == 0)
524     {
525       sim_io_printf (sd, "  No %s interrupt will be raised.\n", name);
526     }
527   else
528     {
529       int64_t t;
530       sim_cpu *cpu;
531 
532       cpu = STATE_CPU (sd, 0);
533 
534       t  = hw_event_remain_time (me, event);
535       sim_io_printf (sd, "  Next %s interrupt in %s\n",
536                      name, cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
537     }
538 }
539 
540 static void
541 m68hc11tim_info (struct hw *me)
542 {
543   SIM_DESC sd;
544   uint16_t base = 0;
545   sim_cpu *cpu;
546   struct m68hc11_sim_cpu *m68hc11_cpu;
547   struct m68hc11tim *controller;
548   uint8_t val;
549   uint16_t val16;
550 
551   sd = hw_system (me);
552   cpu = STATE_CPU (sd, 0);
553   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
554   controller = hw_data (me);
555 
556   sim_io_printf (sd, "M68HC11 Timer:\n");
557 
558   base = cpu_get_io_base (cpu);
559 
560   /* Info for TIC1 */
561   val16  = (m68hc11_cpu->ios[M6811_TIC1_H] << 8) + m68hc11_cpu->ios[M6811_TIC1_L];
562   print_io_word (sd, "TIC1 ", 0, val16, base + M6811_TIC1);
563   sim_io_printf (sd, "\n");
564 
565   /* Info for TIC2 */
566   val16  = (m68hc11_cpu->ios[M6811_TIC2_H] << 8) + m68hc11_cpu->ios[M6811_TIC2_L];
567   print_io_word (sd, "TIC2 ", 0, val16, base + M6811_TIC2);
568   sim_io_printf (sd, "\n");
569 
570   /* Info for TIC3 */
571   val16  = (m68hc11_cpu->ios[M6811_TIC3_H] << 8) + m68hc11_cpu->ios[M6811_TIC3_L];
572   print_io_word (sd, "TIC3 ", 0, val16, base + M6811_TIC3);
573   sim_io_printf (sd, "\n");
574 
575   /* Info for TOC1 */
576   val16  = (m68hc11_cpu->ios[M6811_TOC1_H] << 8) + m68hc11_cpu->ios[M6811_TOC1_L];
577   print_io_word (sd, "TOC1 ", 0, val16, base + M6811_TOC1);
578   sim_io_printf (sd, "\n");
579 
580   /* Info for TOC2 */
581   val16  = (m68hc11_cpu->ios[M6811_TOC2_H] << 8) + m68hc11_cpu->ios[M6811_TOC2_L];
582   print_io_word (sd, "TOC2 ", 0, val16, base + M6811_TOC2);
583   sim_io_printf (sd, "\n");
584 
585   /* Info for TOC3 */
586   val16  = (m68hc11_cpu->ios[M6811_TOC3_H] << 8) + m68hc11_cpu->ios[M6811_TOC3_L];
587   print_io_word (sd, "TOC3 ", 0, val16, base + M6811_TOC3);
588   sim_io_printf (sd, "\n");
589 
590   /* Info for TOC4 */
591   val16  = (m68hc11_cpu->ios[M6811_TOC4_H] << 8) + m68hc11_cpu->ios[M6811_TOC4_L];
592   print_io_word (sd, "TOC4 ", 0, val16, base + M6811_TOC4);
593   sim_io_printf (sd, "\n");
594 
595   /* Info for TOC5 */
596   val16  = (m68hc11_cpu->ios[M6811_TOC5_H] << 8) + m68hc11_cpu->ios[M6811_TOC5_L];
597   print_io_word (sd, "TOC5 ", 0, val16, base + M6811_TOC5);
598   sim_io_printf (sd, "\n");
599 
600   /* Info for TMSK1 */
601   val  = m68hc11_cpu->ios[M6811_TMSK1];
602   print_io_byte (sd, "TMSK1 ", tmsk1_desc, val, base + M6811_TMSK1);
603   sim_io_printf (sd, "\n");
604 
605   /* Info for TFLG1 */
606   val = m68hc11_cpu->ios[M6811_TFLG1];
607   print_io_byte (sd, "TFLG1", tflg1_desc, val, base + M6811_TFLG1);
608   sim_io_printf (sd, "\n");
609 
610   val  = m68hc11_cpu->ios[M6811_TMSK2];
611   print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2);
612   sim_io_printf (sd, "\n");
613 
614   val = m68hc11_cpu->ios[M6811_TFLG2];
615   print_io_byte (sd, "TFLG2", tflg2_desc, val, base + M6811_TFLG2);
616   sim_io_printf (sd, "\n");
617 
618   val = m68hc11_cpu->ios[M6811_PACTL];
619   print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL);
620   sim_io_printf (sd, "\n");
621 
622   val = m68hc11_cpu->ios[M6811_PACNT];
623   print_io_byte (sd, "PACNT", 0, val, base + M6811_PACNT);
624   sim_io_printf (sd, "\n");
625 
626   /* Give info about the next timer interrupts.  */
627   m68hc11tim_print_timer (me, "RTI", controller->rti_timer_event);
628   m68hc11tim_print_timer (me, "COP", controller->cop_timer_event);
629   m68hc11tim_print_timer (me, "OVERFLOW", controller->tof_timer_event);
630   m68hc11tim_print_timer (me, "COMPARE", controller->cmp_timer_event);
631 }
632 
633 static int
634 m68hc11tim_ioctl (struct hw *me,
635                   hw_ioctl_request request,
636                   va_list ap)
637 {
638   m68hc11tim_info (me);
639   return 0;
640 }
641 
642 /* generic read/write */
643 
644 static unsigned
645 m68hc11tim_io_read_buffer (struct hw *me,
646                            void *dest,
647                            int space,
648                            unsigned_word base,
649                            unsigned nr_bytes)
650 {
651   SIM_DESC sd;
652   struct m68hc11tim *controller;
653   sim_cpu *cpu;
654   struct m68hc11_sim_cpu *m68hc11_cpu;
655   uint8_t val;
656   unsigned cnt = 0;
657 
658   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
659 
660   sd  = hw_system (me);
661   cpu = STATE_CPU (sd, 0);
662   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
663   controller = hw_data (me);
664 
665   while (nr_bytes)
666     {
667       switch (base)
668         {
669           /* The cpu_absolute_cycle is updated after each instruction.
670              Reading in a 16-bit register will be split in two accesses
671              but this will be atomic within the simulator.  */
672         case M6811_TCTN_H:
673           val = (uint8_t) ((m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust)
674                            / (controller->clock_prescaler * 256));
675           break;
676 
677         case M6811_TCTN_L:
678           val = (uint8_t) ((m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust)
679                            / controller->clock_prescaler);
680           break;
681 
682         default:
683           val = m68hc11_cpu->ios[base];
684           break;
685         }
686       *((uint8_t*) dest) = val;
687       dest = (char*) dest + 1;
688       base++;
689       nr_bytes--;
690       cnt++;
691     }
692   return cnt;
693 }
694 
695 static unsigned
696 m68hc11tim_io_write_buffer (struct hw *me,
697                             const void *source,
698                             int space,
699                             unsigned_word base,
700                             unsigned nr_bytes)
701 {
702   SIM_DESC sd;
703   struct m68hc11tim *controller;
704   sim_cpu *cpu;
705   struct m68hc11_sim_cpu *m68hc11_cpu;
706   uint8_t val, n;
707   int64_t adj;
708   int reset_compare = 0;
709   int reset_overflow = 0;
710   int cnt = 0;
711 
712   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
713 
714   sd  = hw_system (me);
715   cpu = STATE_CPU (sd, 0);
716   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
717   controller = hw_data (me);
718 
719   while (nr_bytes)
720     {
721       val = *((const uint8_t*) source);
722       switch (base)
723         {
724           /* Set the timer counter low part, trying to preserve the low part.
725              We compute the absolute cycle adjustment that we have to apply
726              to obtain the timer current value.  Computation must be made
727              in 64-bit to avoid overflow problems.  */
728         case M6811_TCTN_L:
729           adj = ((m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust)
730                  / (controller->clock_prescaler * (int64_t) 256)) & 0x0FF;
731           adj = m68hc11_cpu->cpu_absolute_cycle
732             - (adj * controller->clock_prescaler * (int64_t) 256)
733             - ((int64_t) adj * controller->clock_prescaler);
734           controller->tcnt_adjust = adj;
735           reset_compare = 1;
736           reset_overflow = 1;
737           break;
738 
739         case M6811_TCTN_H:
740           adj = ((m68hc11_cpu->cpu_absolute_cycle - controller->tcnt_adjust)
741                  / controller->clock_prescaler) & 0x0ff;
742           adj = m68hc11_cpu->cpu_absolute_cycle
743             - ((int64_t) val * controller->clock_prescaler * (int64_t) 256)
744             - (adj * controller->clock_prescaler);
745           controller->tcnt_adjust = adj;
746           reset_compare = 1;
747           reset_overflow = 1;
748           break;
749 
750         case M6811_TMSK2:
751 
752           /* Timer prescaler cannot be changed after 64 bus cycles.  */
753           if (m68hc11_cpu->cpu_absolute_cycle >= 64)
754             {
755               val &= ~(M6811_PR1 | M6811_PR0);
756               val |= m68hc11_cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0);
757             }
758           switch (val & (M6811_PR1 | M6811_PR0))
759             {
760             case 0:
761               n = 1;
762               break;
763             case M6811_PR0:
764               n = 4;
765               break;
766             case M6811_PR1:
767               n = 8;
768               break;
769             default:
770             case M6811_PR1 | M6811_PR0:
771               n = 16;
772               break;
773             }
774           if (m68hc11_cpu->cpu_absolute_cycle < 64)
775             {
776               reset_overflow = 1;
777               controller->clock_prescaler = n;
778             }
779           m68hc11_cpu->ios[base] = val;
780           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
781           break;
782 
783         case M6811_PACTL:
784           n = (1 << ((val & (M6811_RTR1 | M6811_RTR0))));
785           m68hc11_cpu->ios[base] = val;
786 
787           controller->rti_delay = (long) (n) * 8192;
788           m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100));
789           break;
790 
791         case M6811_TFLG2:
792           val &= m68hc11_cpu->ios[M6811_TFLG2];
793           m68hc11_cpu->ios[M6811_TFLG2] &= ~val;
794           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
795           break;
796 
797         case M6811_TMSK1:
798           m68hc11_cpu->ios[M6811_TMSK1] = val;
799           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
800           reset_compare = 1;
801           break;
802 
803         case M6811_TFLG1:
804           val &= m68hc11_cpu->ios[M6811_TFLG1];
805           m68hc11_cpu->ios[M6811_TFLG1] &= ~val;
806           interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
807           break;
808 
809         case M6811_TOC1:
810         case M6811_TOC2:
811         case M6811_TOC3:
812         case M6811_TOC4:
813         case M6811_TOC5:
814           m68hc11_cpu->ios[base] = val;
815           reset_compare = 1;
816           break;
817 
818         case M6811_TCTL1:
819         case M6811_TCTL2:
820           m68hc11_cpu->ios[base] = val;
821           break;
822 
823         default:
824           m68hc11_cpu->ios[base] = val;
825           break;
826         }
827 
828       base++;
829       nr_bytes--;
830       cnt++;
831       source = (char*) source + 1;
832     }
833 
834   /* Re-compute the next timer compare event.  */
835   if (reset_compare)
836     {
837       m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT));
838     }
839   if (reset_overflow)
840     {
841       m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100));
842     }
843   return cnt;
844 }
845 
846 
847 const struct hw_descriptor dv_m68hc11tim_descriptor[] = {
848   { "m68hc11tim", m68hc11tim_finish },
849   { "m68hc12tim", m68hc11tim_finish },
850   { NULL },
851 };
852 
853