1 /* dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 Written by Stephane Carrez (stcarrez@worldnet.fr)
4 (From a driver model Contributed by Cygnus Solutions.)
6 This file is part of the program GDB, the GNU debugger.
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 vertimn 2 of the License, or
11 (at your option) any later vertimn.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include "sim-assert.h"
32 m68hc11tim - m68hc11 timer devices
37 Implements the m68hc11 timer as described in Chapter 10
50 Reset the timer device. This port must be connected to
51 the cpu-reset output port.
65 static const struct hw_port_descriptor m68hc11tim_ports
[] =
67 { "reset", RESET_PORT
, 0, input_port
, },
72 /* Timer Controller information. */
75 unsigned long cop_delay
;
76 unsigned long rti_delay
;
77 unsigned long ovf_delay
;
78 signed64 clock_prescaler
;
80 signed64 cop_prev_interrupt
;
81 signed64 rti_prev_interrupt
;
83 /* Periodic timers. */
84 struct hw_event
*rti_timer_event
;
85 struct hw_event
*cop_timer_event
;
86 struct hw_event
*tof_timer_event
;
87 struct hw_event
*cmp_timer_event
;
92 /* Finish off the partially created hw device. Attach our local
93 callbacks. Wire up our port names etc. */
95 static hw_io_read_buffer_method m68hc11tim_io_read_buffer
;
96 static hw_io_write_buffer_method m68hc11tim_io_write_buffer
;
97 static hw_port_event_method m68hc11tim_port_event
;
98 static hw_ioctl_method m68hc11tim_ioctl
;
100 #define M6811_TIMER_FIRST_REG (M6811_TCTN)
101 #define M6811_TIMER_LAST_REG (M6811_PACNT)
105 attach_m68hc11tim_regs (struct hw
*me
,
106 struct m68hc11tim
*controller
)
108 hw_attach_address (hw_parent (me
), M6811_IO_LEVEL
, io_map
,
109 M6811_TIMER_FIRST_REG
,
110 M6811_TIMER_LAST_REG
- M6811_TIMER_FIRST_REG
+ 1,
115 m68hc11tim_finish (struct hw
*me
)
117 struct m68hc11tim
*controller
;
119 controller
= HW_ZALLOC (me
, struct m68hc11tim
);
120 set_hw_data (me
, controller
);
121 set_hw_io_read_buffer (me
, m68hc11tim_io_read_buffer
);
122 set_hw_io_write_buffer (me
, m68hc11tim_io_write_buffer
);
123 set_hw_ports (me
, m68hc11tim_ports
);
124 set_hw_port_event (me
, m68hc11tim_port_event
);
126 set_hw_ioctl (me
, m68hc11tim_ioctl
);
128 me
->to_ioctl
= m68hc11tim_ioctl
;
131 /* Preset defaults. */
132 controller
->clock_prescaler
= 1;
133 controller
->tcnt_adjust
= 0;
135 /* Attach ourself to our parent bus. */
136 attach_m68hc11tim_regs (me
, controller
);
141 /* An event arrives on an interrupt port. */
144 m68hc11tim_port_event (struct hw
*me
,
151 struct m68hc11tim
*controller
;
155 controller
= hw_data (me
);
157 cpu
= STATE_CPU (sd
, 0);
162 HW_TRACE ((me
, "Timer reset"));
164 /* Cancel all timer events. */
165 if (controller
->rti_timer_event
)
167 hw_event_queue_deschedule (me
, controller
->rti_timer_event
);
168 controller
->rti_timer_event
= 0;
169 controller
->rti_prev_interrupt
= 0;
171 if (controller
->cop_timer_event
)
173 hw_event_queue_deschedule (me
, controller
->cop_timer_event
);
174 controller
->cop_timer_event
= 0;
175 controller
->cop_prev_interrupt
= 0;
177 if (controller
->tof_timer_event
)
179 hw_event_queue_deschedule (me
, controller
->tof_timer_event
);
180 controller
->tof_timer_event
= 0;
182 if (controller
->cmp_timer_event
)
184 hw_event_queue_deschedule (me
, controller
->cmp_timer_event
);
185 controller
->cmp_timer_event
= 0;
188 /* Reset the state of Timer registers. This also restarts
189 the timer events (overflow and RTI clock). */
191 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
192 (unsigned_word
) M6811_TMSK2
, 1);
193 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
194 (unsigned_word
) M6811_TFLG2
, 1);
195 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
196 (unsigned_word
) M6811_PACTL
, 1);
201 hw_abort (me
, "Event on unknown port %d", my_port
);
215 m68hc11tim_timer_event (struct hw
*me
, void *data
)
218 struct m68hc11tim
*controller
;
220 enum event_type type
;
222 struct hw_event
**eventp
;
223 int check_interrupt
= 0;
226 unsigned long tcnt_internal
;
231 controller
= hw_data (me
);
233 cpu
= STATE_CPU (sd
, 0);
234 type
= (enum event_type
) ((long) data
) & 0x0FF;
235 events
= STATE_EVENTS (sd
);
241 eventp
= &controller
->cop_timer_event
;
242 delay
= controller
->cop_delay
;
243 delay
= controller
->cop_prev_interrupt
+ controller
->cop_delay
;
244 controller
->cop_prev_interrupt
= delay
;
245 delay
= delay
- cpu
->cpu_absolute_cycle
;
247 delay
+= events
->nr_ticks_to_process
;
251 eventp
= &controller
->rti_timer_event
;
252 delay
= controller
->rti_prev_interrupt
+ controller
->rti_delay
;
254 if (((long) (data
) & 0x0100) == 0)
256 cpu
->ios
[M6811_TFLG2
] |= M6811_RTIF
;
258 controller
->rti_prev_interrupt
= delay
;
259 delay
+= controller
->rti_delay
;
261 delay
= delay
- cpu
->cpu_absolute_cycle
;
262 delay
+= events
->nr_ticks_to_process
;
266 /* Compute the 68HC11 internal free running counter.
267 There may be 'nr_ticks_to_process' pending cycles that are
268 not (yet) taken into account by 'sim_events_time'. */
269 tcnt_internal
= sim_events_time (sd
) - controller
->tcnt_adjust
;
270 tcnt_internal
+= events
->nr_ticks_to_process
;
272 /* We must take into account the prescaler that comes
273 before the counter (it's a power of 2). */
274 tcnt_internal
&= 0x0ffff * controller
->clock_prescaler
;
276 /* Compute the time when the overflow will occur. It occurs when
277 the counter increments from 0x0ffff to 0x10000 (and thus resets). */
278 delay
= (0x10000 * controller
->clock_prescaler
) - tcnt_internal
;
280 /* The 'nr_ticks_to_process' will be subtracted when the event
282 delay
+= events
->nr_ticks_to_process
;
284 eventp
= &controller
->tof_timer_event
;
285 if (((long) (data
) & 0x100) == 0)
287 cpu
->ios
[M6811_TFLG2
] |= M6811_TOF
;
293 eventp
= &controller
->cmp_timer_event
;
295 /* Compute the 68HC11 internal free running counter.
296 There may be 'nr_ticks_to_process' pending cycles that are
297 not (yet) taken into account by 'sim_events_time'. */
298 events
= STATE_EVENTS (sd
);
299 tcnt_internal
= sim_events_time (sd
) - controller
->tcnt_adjust
;
300 tcnt_internal
+= events
->nr_ticks_to_process
;
302 /* We must take into account the prescaler that comes
303 before the counter (it's a power of 2). */
304 tcnt_internal
&= 0x0ffff * controller
->clock_prescaler
;
306 /* Get current visible TCNT register value. */
307 tcnt
= tcnt_internal
/ controller
->clock_prescaler
;
309 flags
= cpu
->ios
[M6811_TMSK1
];
311 delay
= 65536 * controller
->clock_prescaler
;
313 /* Scan each output compare register to see if one matches
314 the free running counter. Set the corresponding OCi flag
315 if the output compare is enabled. */
316 for (i
= M6811_TOC1
; i
<= M6811_TOC5
; i
+= 2, mask
>>= 1)
318 unsigned long compare
;
320 compare
= (cpu
->ios
[i
] << 8) + cpu
->ios
[i
+1];
321 if (compare
== tcnt
&& (flags
& mask
))
323 cpu
->ios
[M6811_TFLG1
] |= mask
;
327 /* Compute how many times for the next match.
328 Use the internal counter value to take into account the
329 prescaler accurately. */
330 compare
= compare
* controller
->clock_prescaler
;
331 if (compare
> tcnt_internal
)
332 compare
= compare
- tcnt_internal
;
334 compare
= compare
- tcnt_internal
335 + 65536 * controller
->clock_prescaler
;
341 /* Deactivate the compare timer if no output compare is enabled. */
342 if ((flags
& 0xF0) == 0)
353 hw_event_queue_deschedule (me
, *eventp
);
359 *eventp
= hw_event_queue_schedule (me
, delay
,
360 m68hc11tim_timer_event
,
365 interrupts_update_pending (&cpu
->cpu_interrupts
);
369 /* Descriptions of the Timer I/O ports. These descriptions are only used to
370 give information of the Timer device under GDB. */
371 io_reg_desc tmsk2_desc
[] = {
372 { M6811_TOI
, "TOI ", "Timer Overflow Interrupt Enable" },
373 { M6811_RTII
, "RTII ", "RTI Interrupt Enable" },
374 { M6811_PAOVI
, "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" },
375 { M6811_PAII
, "PAII ", "Pulse Accumulator Interrupt Enable" },
376 { M6811_PR1
, "PR1 ", "Timer prescaler (PR1)" },
377 { M6811_PR0
, "PR0 ", "Timer prescaler (PR0)" },
378 { M6811_TPR_1
, "TPR_1 ", "Timer prescaler div 1" },
379 { M6811_TPR_4
, "TPR_4 ", "Timer prescaler div 4" },
380 { M6811_TPR_8
, "TPR_8 ", "Timer prescaler div 8" },
381 { M6811_TPR_16
, "TPR_16", "Timer prescaler div 16" },
385 io_reg_desc tflg2_desc
[] = {
386 { M6811_TOF
, "TOF ", "Timer Overflow Bit" },
387 { M6811_RTIF
, "RTIF ", "Read Time Interrupt Flag" },
388 { M6811_PAOVF
, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" },
389 { M6811_PAIF
, "PAIF ", "Pulse Accumulator Input Edge" },
393 io_reg_desc pactl_desc
[] = {
394 { M6811_DDRA7
, "DDRA7 ", "Data Direction for Port A bit-7" },
395 { M6811_PAEN
, "PAEN ", "Pulse Accumulator System Enable" },
396 { M6811_PAMOD
, "PAMOD ", "Pulse Accumulator Mode" },
397 { M6811_PEDGE
, "PEDGE ", "Pulse Accumulator Edge Control" },
398 { M6811_RTR1
, "RTR1 ", "RTI Interrupt rate select (RTR1)" },
399 { M6811_RTR0
, "RTR0 ", "RTI Interrupt rate select (RTR0)" },
404 to_realtime (sim_cpu
*cpu
, signed64 t
)
406 return (double) (t
) / (double) (cpu
->cpu_frequency
/ 4);
410 cycle_to_string (sim_cpu
*cpu
, signed64 t
)
415 dt
= to_realtime (cpu
, t
);
417 sprintf (buf
, "%llu cycle%s (%3.1f us)", t
,
418 (t
> 1 ? "s" : ""), dt
* 1000000.0);
420 sprintf (buf
, "%llu cycles (%3.1f ms)", t
, dt
* 1000.0);
422 sprintf (buf
, "%llu cycles (%3.1f s)", t
, dt
);
428 m68hc11tim_print_timer (struct hw
*me
, const char *name
,
429 struct hw_event
*event
)
436 sim_io_printf (sd
, " No %s interrupt will be raised.\n", name
);
443 cpu
= STATE_CPU (sd
, 0);
445 t
= hw_event_remain_time (me
, event
);
446 sim_io_printf (sd
, " Next %s interrupt in %s\n",
447 name
, cycle_to_string (cpu
, t
));
452 m68hc11tim_info (struct hw
*me
)
457 struct m68hc11tim
*controller
;
461 cpu
= STATE_CPU (sd
, 0);
462 controller
= hw_data (me
);
464 sim_io_printf (sd
, "M68HC11 Timer:\n");
466 base
= cpu_get_io_base (cpu
);
468 val
= cpu
->ios
[M6811_TMSK2
];
469 print_io_byte (sd
, "TMSK2 ", tmsk2_desc
, val
, base
+ M6811_TMSK2
);
470 sim_io_printf (sd
, "\n");
472 val
= cpu
->ios
[M6811_TFLG2
];
473 print_io_byte (sd
, "TFLG2", tflg2_desc
, val
, base
+ M6811_TFLG2
);
474 sim_io_printf (sd
, "\n");
476 val
= cpu
->ios
[M6811_PACTL
];
477 print_io_byte (sd
, "PACTL", pactl_desc
, val
, base
+ M6811_PACTL
);
478 sim_io_printf (sd
, "\n");
480 /* Give info about the next timer interrupts. */
481 m68hc11tim_print_timer (me
, "RTI", controller
->rti_timer_event
);
482 m68hc11tim_print_timer (me
, "COP", controller
->cop_timer_event
);
483 m68hc11tim_print_timer (me
, "OVERFLOW", controller
->tof_timer_event
);
484 m68hc11tim_print_timer (me
, "COMPARE", controller
->cmp_timer_event
);
488 m68hc11tim_ioctl (struct hw
*me
,
489 hw_ioctl_request request
,
492 m68hc11tim_info (me
);
496 /* generic read/write */
499 m68hc11tim_io_read_buffer (struct hw
*me
,
506 struct m68hc11tim
*controller
;
511 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
514 cpu
= STATE_CPU (sd
, 0);
515 controller
= hw_data (me
);
521 /* The cpu_absolute_cycle is updated after each instruction.
522 Reading in a 16-bit register will be split in two accesses
523 but this will be atomic within the simulator. */
525 val
= (uint8
) ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
526 / (controller
->clock_prescaler
* 256));
530 val
= (uint8
) ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
531 / controller
->clock_prescaler
);
535 val
= cpu
->ios
[base
];
538 *((unsigned8
*) dest
) = val
;
548 m68hc11tim_io_write_buffer (struct hw
*me
,
555 struct m68hc11tim
*controller
;
559 int reset_compare
= 0;
560 int reset_overflow
= 0;
563 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
566 cpu
= STATE_CPU (sd
, 0);
567 controller
= hw_data (me
);
571 val
= *((const unsigned8
*) source
);
574 /* Set the timer counter low part, trying to preserve the low part.
575 We compute the absolute cycle adjustment that we have to apply
576 to obtain the timer current value. Computation must be made
577 in 64-bit to avoid overflow problems. */
579 adj
= ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
580 / (controller
->clock_prescaler
* (signed64
) 256)) & 0x0FF;
581 adj
= cpu
->cpu_absolute_cycle
582 - (adj
* controller
->clock_prescaler
* (signed64
) 256)
583 - ((signed64
) adj
* controller
->clock_prescaler
);
584 controller
->tcnt_adjust
= adj
;
590 adj
= ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
591 / controller
->clock_prescaler
) & 0x0ff;
592 adj
= cpu
->cpu_absolute_cycle
593 - ((signed64
) val
* controller
->clock_prescaler
* (signed64
) 256)
594 - (adj
* controller
->clock_prescaler
);
595 controller
->tcnt_adjust
= adj
;
602 /* Timer prescaler cannot be changed after 64 bus cycles. */
603 if (cpu
->cpu_absolute_cycle
>= 64)
605 val
&= ~(M6811_PR1
| M6811_PR0
);
606 val
|= cpu
->ios
[M6811_TMSK2
] & (M6811_PR1
| M6811_PR0
);
608 switch (val
& (M6811_PR1
| M6811_PR0
))
620 case M6811_PR1
| M6811_PR0
:
624 if (cpu
->cpu_absolute_cycle
< 64)
627 controller
->clock_prescaler
= n
;
629 cpu
->ios
[base
] = val
;
630 interrupts_update_pending (&cpu
->cpu_interrupts
);
634 n
= (1 << ((val
& (M6811_RTR1
| M6811_RTR0
))));
635 cpu
->ios
[base
] = val
;
637 controller
->rti_delay
= (long) (n
) * 8192;
638 m68hc11tim_timer_event (me
, (void*) (RTI_EVENT
| 0x100));
645 val
|= cpu
->ios
[M6811_TFLG2
] & M6811_TOF
;
647 /* Clear the Real Time interrupt flag. */
648 if (val
& M6811_RTIF
)
651 val
|= cpu
->ios
[M6811_TFLG2
] & M6811_RTIF
;
653 cpu
->ios
[base
] = val
;
654 interrupts_update_pending (&cpu
->cpu_interrupts
);
662 cpu
->ios
[base
] = val
;
676 /* Re-compute the next timer compare event. */
679 m68hc11tim_timer_event (me
, (void*) (COMPARE_EVENT
));
683 m68hc11tim_timer_event (me
, (void*) (OVERFLOW_EVENT
| 0x100));
689 const struct hw_descriptor dv_m68hc11tim_descriptor
[] = {
690 { "m68hc11tim", m68hc11tim_finish
},
691 { "m68hc12tim", m68hc11tim_finish
},