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,
116 m68hc11tim_finish (struct hw
*me
)
118 struct m68hc11tim
*controller
;
120 controller
= HW_ZALLOC (me
, struct m68hc11tim
);
121 set_hw_data (me
, controller
);
122 set_hw_io_read_buffer (me
, m68hc11tim_io_read_buffer
);
123 set_hw_io_write_buffer (me
, m68hc11tim_io_write_buffer
);
124 set_hw_ports (me
, m68hc11tim_ports
);
125 set_hw_port_event (me
, m68hc11tim_port_event
);
127 set_hw_ioctl (me
, m68hc11tim_ioctl
);
129 me
->to_ioctl
= m68hc11tim_ioctl
;
132 /* Preset defaults. */
133 controller
->clock_prescaler
= 1;
134 controller
->tcnt_adjust
= 0;
136 /* Attach ourself to our parent bus. */
137 attach_m68hc11tim_regs (me
, controller
);
142 /* An event arrives on an interrupt port. */
145 m68hc11tim_port_event (struct hw
*me
,
152 struct m68hc11tim
*controller
;
156 controller
= hw_data (me
);
158 cpu
= STATE_CPU (sd
, 0);
163 HW_TRACE ((me
, "Timer reset"));
165 /* Cancel all timer events. */
166 if (controller
->rti_timer_event
)
168 hw_event_queue_deschedule (me
, controller
->rti_timer_event
);
169 controller
->rti_timer_event
= 0;
170 controller
->rti_prev_interrupt
= 0;
172 if (controller
->cop_timer_event
)
174 hw_event_queue_deschedule (me
, controller
->cop_timer_event
);
175 controller
->cop_timer_event
= 0;
176 controller
->cop_prev_interrupt
= 0;
178 if (controller
->tof_timer_event
)
180 hw_event_queue_deschedule (me
, controller
->tof_timer_event
);
181 controller
->tof_timer_event
= 0;
183 if (controller
->cmp_timer_event
)
185 hw_event_queue_deschedule (me
, controller
->cmp_timer_event
);
186 controller
->cmp_timer_event
= 0;
189 /* Reset the state of Timer registers. This also restarts
190 the timer events (overflow and RTI clock). */
192 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
193 (unsigned_word
) M6811_TMSK2
, 1);
194 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
195 (unsigned_word
) M6811_TFLG2
, 1);
196 m68hc11tim_io_write_buffer (me
, &val
, io_map
,
197 (unsigned_word
) M6811_PACTL
, 1);
202 hw_abort (me
, "Event on unknown port %d", my_port
);
216 m68hc11tim_timer_event (struct hw
*me
, void *data
)
219 struct m68hc11tim
*controller
;
221 enum event_type type
;
223 struct hw_event
**eventp
;
224 int check_interrupt
= 0;
227 unsigned long tcnt_internal
;
232 controller
= hw_data (me
);
234 cpu
= STATE_CPU (sd
, 0);
235 type
= (enum event_type
) ((long) data
) & 0x0FF;
236 events
= STATE_EVENTS (sd
);
242 eventp
= &controller
->cop_timer_event
;
243 delay
= controller
->cop_delay
;
244 delay
= controller
->cop_prev_interrupt
+ controller
->cop_delay
;
245 controller
->cop_prev_interrupt
= delay
;
246 delay
= delay
- cpu
->cpu_absolute_cycle
;
248 delay
+= events
->nr_ticks_to_process
;
252 eventp
= &controller
->rti_timer_event
;
253 delay
= controller
->rti_prev_interrupt
+ controller
->rti_delay
;
255 if (((long) (data
) & 0x0100) == 0)
257 cpu
->ios
[M6811_TFLG2
] |= M6811_RTIF
;
259 controller
->rti_prev_interrupt
= delay
;
260 delay
+= controller
->rti_delay
;
262 delay
= delay
- cpu
->cpu_absolute_cycle
;
263 delay
+= events
->nr_ticks_to_process
;
267 /* Compute the 68HC11 internal free running counter.
268 There may be 'nr_ticks_to_process' pending cycles that are
269 not (yet) taken into account by 'sim_events_time'. */
270 tcnt_internal
= sim_events_time (sd
) - controller
->tcnt_adjust
;
271 tcnt_internal
+= events
->nr_ticks_to_process
;
273 /* We must take into account the prescaler that comes
274 before the counter (it's a power of 2). */
275 tcnt_internal
&= 0x0ffff * controller
->clock_prescaler
;
277 /* Compute the time when the overflow will occur. It occurs when
278 the counter increments from 0x0ffff to 0x10000 (and thus resets). */
279 delay
= (0x10000 * controller
->clock_prescaler
) - tcnt_internal
;
281 /* The 'nr_ticks_to_process' will be subtracted when the event
283 delay
+= events
->nr_ticks_to_process
;
285 eventp
= &controller
->tof_timer_event
;
286 if (((long) (data
) & 0x100) == 0)
288 cpu
->ios
[M6811_TFLG2
] |= M6811_TOF
;
294 eventp
= &controller
->cmp_timer_event
;
296 /* Compute the 68HC11 internal free running counter.
297 There may be 'nr_ticks_to_process' pending cycles that are
298 not (yet) taken into account by 'sim_events_time'. */
299 events
= STATE_EVENTS (sd
);
300 tcnt_internal
= sim_events_time (sd
) - controller
->tcnt_adjust
;
301 tcnt_internal
+= events
->nr_ticks_to_process
;
303 /* We must take into account the prescaler that comes
304 before the counter (it's a power of 2). */
305 tcnt_internal
&= 0x0ffff * controller
->clock_prescaler
;
307 /* Get current visible TCNT register value. */
308 tcnt
= tcnt_internal
/ controller
->clock_prescaler
;
310 flags
= cpu
->ios
[M6811_TMSK1
];
312 delay
= 65536 * controller
->clock_prescaler
;
314 /* Scan each output compare register to see if one matches
315 the free running counter. Set the corresponding OCi flag
316 if the output compare is enabled. */
317 for (i
= M6811_TOC1
; i
<= M6811_TOC5
; i
+= 2, mask
>>= 1)
319 unsigned long compare
;
321 compare
= (cpu
->ios
[i
] << 8) + cpu
->ios
[i
+1];
322 if (compare
== tcnt
&& (flags
& mask
))
324 cpu
->ios
[M6811_TFLG1
] |= mask
;
328 /* Compute how many times for the next match.
329 Use the internal counter value to take into account the
330 prescaler accurately. */
331 compare
= compare
* controller
->clock_prescaler
;
332 if (compare
> tcnt_internal
)
333 compare
= compare
- tcnt_internal
;
335 compare
= compare
- tcnt_internal
336 + 65536 * controller
->clock_prescaler
;
342 /* Deactivate the compare timer if no output compare is enabled. */
343 if ((flags
& 0xF0) == 0)
354 hw_event_queue_deschedule (me
, *eventp
);
360 *eventp
= hw_event_queue_schedule (me
, delay
,
361 m68hc11tim_timer_event
,
366 interrupts_update_pending (&cpu
->cpu_interrupts
);
370 /* Descriptions of the Timer I/O ports. These descriptions are only used to
371 give information of the Timer device under GDB. */
372 io_reg_desc tmsk2_desc
[] = {
373 { M6811_TOI
, "TOI ", "Timer Overflow Interrupt Enable" },
374 { M6811_RTII
, "RTII ", "RTI Interrupt Enable" },
375 { M6811_PAOVI
, "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" },
376 { M6811_PAII
, "PAII ", "Pulse Accumulator Interrupt Enable" },
377 { M6811_PR1
, "PR1 ", "Timer prescaler (PR1)" },
378 { M6811_PR0
, "PR0 ", "Timer prescaler (PR0)" },
379 { M6811_TPR_1
, "TPR_1 ", "Timer prescaler div 1" },
380 { M6811_TPR_4
, "TPR_4 ", "Timer prescaler div 4" },
381 { M6811_TPR_8
, "TPR_8 ", "Timer prescaler div 8" },
382 { M6811_TPR_16
, "TPR_16", "Timer prescaler div 16" },
386 io_reg_desc tflg2_desc
[] = {
387 { M6811_TOF
, "TOF ", "Timer Overflow Bit" },
388 { M6811_RTIF
, "RTIF ", "Read Time Interrupt Flag" },
389 { M6811_PAOVF
, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" },
390 { M6811_PAIF
, "PAIF ", "Pulse Accumulator Input Edge" },
394 io_reg_desc pactl_desc
[] = {
395 { M6811_DDRA7
, "DDRA7 ", "Data Direction for Port A bit-7" },
396 { M6811_PAEN
, "PAEN ", "Pulse Accumulator System Enable" },
397 { M6811_PAMOD
, "PAMOD ", "Pulse Accumulator Mode" },
398 { M6811_PEDGE
, "PEDGE ", "Pulse Accumulator Edge Control" },
399 { M6811_RTR1
, "RTR1 ", "RTI Interrupt rate select (RTR1)" },
400 { M6811_RTR0
, "RTR0 ", "RTI Interrupt rate select (RTR0)" },
405 to_realtime (sim_cpu
*cpu
, signed64 t
)
407 return (double) (t
) / (double) (cpu
->cpu_frequency
/ 4);
411 cycle_to_string (sim_cpu
*cpu
, signed64 t
)
416 dt
= to_realtime (cpu
, t
);
418 sprintf (buf
, "%llu cycle%s (%3.1f us)", t
,
419 (t
> 1 ? "s" : ""), dt
* 1000000.0);
421 sprintf (buf
, "%llu cycles (%3.1f ms)", t
, dt
* 1000.0);
423 sprintf (buf
, "%llu cycles (%3.1f s)", t
, dt
);
429 m68hc11tim_print_timer (struct hw
*me
, const char *name
,
430 struct hw_event
*event
)
437 sim_io_printf (sd
, " No %s interrupt will be raised.\n", name
);
444 cpu
= STATE_CPU (sd
, 0);
446 t
= hw_event_remain_time (me
, event
);
447 sim_io_printf (sd
, " Next %s interrupt in %s\n",
448 name
, cycle_to_string (cpu
, t
));
453 m68hc11tim_info (struct hw
*me
)
458 struct m68hc11tim
*controller
;
462 cpu
= STATE_CPU (sd
, 0);
463 controller
= hw_data (me
);
465 sim_io_printf (sd
, "M68HC11 Timer:\n");
467 base
= cpu_get_io_base (cpu
);
469 val
= cpu
->ios
[M6811_TMSK2
];
470 print_io_byte (sd
, "TMSK2 ", tmsk2_desc
, val
, base
+ M6811_TMSK2
);
471 sim_io_printf (sd
, "\n");
473 val
= cpu
->ios
[M6811_TFLG2
];
474 print_io_byte (sd
, "TFLG2", tflg2_desc
, val
, base
+ M6811_TFLG2
);
475 sim_io_printf (sd
, "\n");
477 val
= cpu
->ios
[M6811_PACTL
];
478 print_io_byte (sd
, "PACTL", pactl_desc
, val
, base
+ M6811_PACTL
);
479 sim_io_printf (sd
, "\n");
481 /* Give info about the next timer interrupts. */
482 m68hc11tim_print_timer (me
, "RTI", controller
->rti_timer_event
);
483 m68hc11tim_print_timer (me
, "COP", controller
->cop_timer_event
);
484 m68hc11tim_print_timer (me
, "OVERFLOW", controller
->tof_timer_event
);
485 m68hc11tim_print_timer (me
, "COMPARE", controller
->cmp_timer_event
);
489 m68hc11tim_ioctl (struct hw
*me
,
490 hw_ioctl_request request
,
493 m68hc11tim_info (me
);
497 /* generic read/write */
500 m68hc11tim_io_read_buffer (struct hw
*me
,
507 struct m68hc11tim
*controller
;
512 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
515 cpu
= STATE_CPU (sd
, 0);
516 controller
= hw_data (me
);
522 /* The cpu_absolute_cycle is updated after each instruction.
523 Reading in a 16-bit register will be split in two accesses
524 but this will be atomic within the simulator. */
526 val
= (uint8
) ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
527 / (controller
->clock_prescaler
* 256));
531 val
= (uint8
) ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
532 / controller
->clock_prescaler
);
536 val
= cpu
->ios
[base
];
539 *((unsigned8
*) dest
) = val
;
549 m68hc11tim_io_write_buffer (struct hw
*me
,
556 struct m68hc11tim
*controller
;
560 int reset_compare
= 0;
561 int reset_overflow
= 0;
564 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
567 cpu
= STATE_CPU (sd
, 0);
568 controller
= hw_data (me
);
572 val
= *((const unsigned8
*) source
);
575 /* Set the timer counter low part, trying to preserve the low part.
576 We compute the absolute cycle adjustment that we have to apply
577 to obtain the timer current value. Computation must be made
578 in 64-bit to avoid overflow problems. */
580 adj
= ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
581 / (controller
->clock_prescaler
* (signed64
) 256)) & 0x0FF;
582 adj
= cpu
->cpu_absolute_cycle
583 - (adj
* controller
->clock_prescaler
* (signed64
) 256)
584 - ((signed64
) adj
* controller
->clock_prescaler
);
585 controller
->tcnt_adjust
= adj
;
591 adj
= ((cpu
->cpu_absolute_cycle
- controller
->tcnt_adjust
)
592 / controller
->clock_prescaler
) & 0x0ff;
593 adj
= cpu
->cpu_absolute_cycle
594 - ((signed64
) val
* controller
->clock_prescaler
* (signed64
) 256)
595 - (adj
* controller
->clock_prescaler
);
596 controller
->tcnt_adjust
= adj
;
603 /* Timer prescaler cannot be changed after 64 bus cycles. */
604 if (cpu
->cpu_absolute_cycle
>= 64)
606 val
&= ~(M6811_PR1
| M6811_PR0
);
607 val
|= cpu
->ios
[M6811_TMSK2
] & (M6811_PR1
| M6811_PR0
);
609 switch (val
& (M6811_PR1
| M6811_PR0
))
621 case M6811_PR1
| M6811_PR0
:
625 if (cpu
->cpu_absolute_cycle
< 64)
628 controller
->clock_prescaler
= n
;
630 cpu
->ios
[base
] = val
;
631 interrupts_update_pending (&cpu
->cpu_interrupts
);
635 n
= (1 << ((val
& (M6811_RTR1
| M6811_RTR0
))));
636 cpu
->ios
[base
] = val
;
638 controller
->rti_delay
= (long) (n
) * 8192;
639 m68hc11tim_timer_event (me
, (void*) (RTI_EVENT
| 0x100));
646 val
|= cpu
->ios
[M6811_TFLG2
] & M6811_TOF
;
648 /* Clear the Real Time interrupt flag. */
649 if (val
& M6811_RTIF
)
652 val
|= cpu
->ios
[M6811_TFLG2
] & M6811_RTIF
;
654 cpu
->ios
[base
] = val
;
655 interrupts_update_pending (&cpu
->cpu_interrupts
);
663 cpu
->ios
[base
] = val
;
677 /* Re-compute the next timer compare event. */
680 m68hc11tim_timer_event (me
, (void*) (COMPARE_EVENT
));
684 m68hc11tim_timer_event (me
, (void*) (OVERFLOW_EVENT
| 0x100));
690 const struct hw_descriptor dv_m68hc11tim_descriptor
[] = {
691 { "m68hc11tim", m68hc11tim_finish
, },