144ae4bf2037f18e7437b161083bdc6552c8334b
[deliverable/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11tim.c
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.)
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 vertimn 2 of the License, or
11 (at your option) any later vertimn.
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, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22 */
23
24
25 #include "sim-main.h"
26 #include "hw-main.h"
27 #include "sim-assert.h"
28
29
30 /* DEVICE
31
32 m68hc11tim - m68hc11 timer devices
33
34
35 DESCRIPTION
36
37 Implements the m68hc11 timer as described in Chapter 10
38 of the pink book.
39
40
41 PROPERTIES
42
43 none
44
45
46 PORTS
47
48 reset (input)
49
50 Reset the timer device. This port must be connected to
51 the cpu-reset output port.
52
53 */
54
55
56
57 /* port ID's */
58
59 enum
60 {
61 RESET_PORT
62 };
63
64
65 static const struct hw_port_descriptor m68hc11tim_ports[] =
66 {
67 { "reset", RESET_PORT, 0, input_port, },
68 { NULL, },
69 };
70
71
72 /* Timer Controller information. */
73 struct m68hc11tim
74 {
75 unsigned long cop_delay;
76 unsigned long rti_delay;
77 unsigned long ovf_delay;
78 signed64 clock_prescaler;
79 signed64 tcnt_adjust;
80 signed64 cop_prev_interrupt;
81 signed64 rti_prev_interrupt;
82
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;
88 };
89
90
91
92 /* Finish off the partially created hw device. Attach our local
93 callbacks. Wire up our port names etc. */
94
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;
99
100 #define M6811_TIMER_FIRST_REG (M6811_TCTN)
101 #define M6811_TIMER_LAST_REG (M6811_PACNT)
102
103
104 static void
105 attach_m68hc11tim_regs (struct hw *me,
106 struct m68hc11tim *controller)
107 {
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,
111 me);
112 }
113
114 static void
115 m68hc11tim_finish (struct hw *me)
116 {
117 struct m68hc11tim *controller;
118
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);
125 #ifdef set_hw_ioctl
126 set_hw_ioctl (me, m68hc11tim_ioctl);
127 #else
128 me->to_ioctl = m68hc11tim_ioctl;
129 #endif
130
131 /* Preset defaults. */
132 controller->clock_prescaler = 1;
133 controller->tcnt_adjust = 0;
134
135 /* Attach ourself to our parent bus. */
136 attach_m68hc11tim_regs (me, controller);
137 }
138
139
140
141 /* An event arrives on an interrupt port. */
142
143 static void
144 m68hc11tim_port_event (struct hw *me,
145 int my_port,
146 struct hw *source,
147 int source_port,
148 int level)
149 {
150 SIM_DESC sd;
151 struct m68hc11tim *controller;
152 sim_cpu *cpu;
153 unsigned8 val;
154
155 controller = hw_data (me);
156 sd = hw_system (me);
157 cpu = STATE_CPU (sd, 0);
158 switch (my_port)
159 {
160 case RESET_PORT:
161 {
162 HW_TRACE ((me, "Timer reset"));
163
164 /* Cancel all timer events. */
165 if (controller->rti_timer_event)
166 {
167 hw_event_queue_deschedule (me, controller->rti_timer_event);
168 controller->rti_timer_event = 0;
169 controller->rti_prev_interrupt = 0;
170 }
171 if (controller->cop_timer_event)
172 {
173 hw_event_queue_deschedule (me, controller->cop_timer_event);
174 controller->cop_timer_event = 0;
175 controller->cop_prev_interrupt = 0;
176 }
177 if (controller->tof_timer_event)
178 {
179 hw_event_queue_deschedule (me, controller->tof_timer_event);
180 controller->tof_timer_event = 0;
181 }
182 if (controller->cmp_timer_event)
183 {
184 hw_event_queue_deschedule (me, controller->cmp_timer_event);
185 controller->cmp_timer_event = 0;
186 }
187
188 /* Reset the state of Timer registers. This also restarts
189 the timer events (overflow and RTI clock). */
190 val = 0;
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);
197 break;
198 }
199
200 default:
201 hw_abort (me, "Event on unknown port %d", my_port);
202 break;
203 }
204 }
205
206 enum event_type
207 {
208 COP_EVENT,
209 RTI_EVENT,
210 OVERFLOW_EVENT,
211 COMPARE_EVENT
212 };
213
214 void
215 m68hc11tim_timer_event (struct hw *me, void *data)
216 {
217 SIM_DESC sd;
218 struct m68hc11tim *controller;
219 sim_cpu *cpu;
220 enum event_type type;
221 unsigned long delay;
222 struct hw_event **eventp;
223 int check_interrupt = 0;
224 unsigned mask;
225 unsigned flags;
226 unsigned long tcnt_internal;
227 unsigned long tcnt;
228 int i;
229 sim_events *events;
230
231 controller = hw_data (me);
232 sd = hw_system (me);
233 cpu = STATE_CPU (sd, 0);
234 type = (enum event_type) ((long) data) & 0x0FF;
235 events = STATE_EVENTS (sd);
236
237 delay = 0;
238 switch (type)
239 {
240 case COP_EVENT:
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;
246 check_interrupt = 1;
247 delay += events->nr_ticks_to_process;
248 break;
249
250 case RTI_EVENT:
251 eventp = &controller->rti_timer_event;
252 delay = controller->rti_prev_interrupt + controller->rti_delay;
253
254 if (((long) (data) & 0x0100) == 0)
255 {
256 cpu->ios[M6811_TFLG2] |= M6811_RTIF;
257 check_interrupt = 1;
258 controller->rti_prev_interrupt = delay;
259 delay += controller->rti_delay;
260 }
261 delay = delay - cpu->cpu_absolute_cycle;
262 delay += events->nr_ticks_to_process;
263 break;
264
265 case OVERFLOW_EVENT:
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;
271
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;
275
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;
279
280 /* The 'nr_ticks_to_process' will be subtracted when the event
281 is scheduled. */
282 delay += events->nr_ticks_to_process;
283
284 eventp = &controller->tof_timer_event;
285 if (((long) (data) & 0x100) == 0)
286 {
287 cpu->ios[M6811_TFLG2] |= M6811_TOF;
288 check_interrupt = 1;
289 }
290 break;
291
292 case COMPARE_EVENT:
293 eventp = &controller->cmp_timer_event;
294
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;
301
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;
305
306 /* Get current visible TCNT register value. */
307 tcnt = tcnt_internal / controller->clock_prescaler;
308
309 flags = cpu->ios[M6811_TMSK1];
310 mask = 0x80;
311 delay = 65536 * controller->clock_prescaler;
312
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)
317 {
318 unsigned long compare;
319
320 compare = (cpu->ios[i] << 8) + cpu->ios[i+1];
321 if (compare == tcnt && (flags & mask))
322 {
323 cpu->ios[M6811_TFLG1] |= mask;
324 check_interrupt++;
325 }
326
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;
333 else
334 compare = compare - tcnt_internal
335 + 65536 * controller->clock_prescaler;
336
337 if (compare < delay)
338 delay = compare;
339 }
340
341 /* Deactivate the compare timer if no output compare is enabled. */
342 if ((flags & 0xF0) == 0)
343 delay = 0;
344 break;
345
346 default:
347 eventp = 0;
348 break;
349 }
350
351 if (*eventp)
352 {
353 hw_event_queue_deschedule (me, *eventp);
354 *eventp = 0;
355 }
356
357 if (delay != 0)
358 {
359 *eventp = hw_event_queue_schedule (me, delay,
360 m68hc11tim_timer_event,
361 (void*) type);
362 }
363
364 if (check_interrupt)
365 interrupts_update_pending (&cpu->cpu_interrupts);
366 }
367
368
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" },
382 { 0, 0, 0 }
383 };
384
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" },
390 { 0, 0, 0 }
391 };
392
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)" },
400 { 0, 0, 0 }
401 };
402
403 static double
404 to_realtime (sim_cpu *cpu, signed64 t)
405 {
406 return (double) (t) / (double) (cpu->cpu_frequency / 4);
407 }
408
409 const char*
410 cycle_to_string (sim_cpu *cpu, signed64 t)
411 {
412 double dt;
413 static char buf[64];
414
415 dt = to_realtime (cpu, t);
416 if (dt < 0.001)
417 sprintf (buf, "%llu cycle%s (%3.1f us)", t,
418 (t > 1 ? "s" : ""), dt * 1000000.0);
419 else if (dt < 1.0)
420 sprintf (buf, "%llu cycles (%3.1f ms)", t, dt * 1000.0);
421 else
422 sprintf (buf, "%llu cycles (%3.1f s)", t, dt);
423
424 return buf;
425 }
426
427 static void
428 m68hc11tim_print_timer (struct hw *me, const char *name,
429 struct hw_event *event)
430 {
431 SIM_DESC sd;
432
433 sd = hw_system (me);
434 if (event == 0)
435 {
436 sim_io_printf (sd, " No %s interrupt will be raised.\n", name);
437 }
438 else
439 {
440 signed64 t;
441 sim_cpu* cpu;
442
443 cpu = STATE_CPU (sd, 0);
444
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));
448 }
449 }
450
451 static void
452 m68hc11tim_info (struct hw *me)
453 {
454 SIM_DESC sd;
455 uint16 base = 0;
456 sim_cpu *cpu;
457 struct m68hc11tim *controller;
458 uint8 val;
459
460 sd = hw_system (me);
461 cpu = STATE_CPU (sd, 0);
462 controller = hw_data (me);
463
464 sim_io_printf (sd, "M68HC11 Timer:\n");
465
466 base = cpu_get_io_base (cpu);
467
468 val = cpu->ios[M6811_TMSK2];
469 print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2);
470 sim_io_printf (sd, "\n");
471
472 val = cpu->ios[M6811_TFLG2];
473 print_io_byte (sd, "TFLG2", tflg2_desc, val, base + M6811_TFLG2);
474 sim_io_printf (sd, "\n");
475
476 val = cpu->ios[M6811_PACTL];
477 print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL);
478 sim_io_printf (sd, "\n");
479
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);
485 }
486
487 static int
488 m68hc11tim_ioctl (struct hw *me,
489 hw_ioctl_request request,
490 va_list ap)
491 {
492 m68hc11tim_info (me);
493 return 0;
494 }
495
496 /* generic read/write */
497
498 static unsigned
499 m68hc11tim_io_read_buffer (struct hw *me,
500 void *dest,
501 int space,
502 unsigned_word base,
503 unsigned nr_bytes)
504 {
505 SIM_DESC sd;
506 struct m68hc11tim *controller;
507 sim_cpu *cpu;
508 unsigned8 val;
509 unsigned cnt = 0;
510
511 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
512
513 sd = hw_system (me);
514 cpu = STATE_CPU (sd, 0);
515 controller = hw_data (me);
516
517 while (nr_bytes)
518 {
519 switch (base)
520 {
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. */
524 case M6811_TCTN_H:
525 val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
526 / (controller->clock_prescaler * 256));
527 break;
528
529 case M6811_TCTN_L:
530 val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
531 / controller->clock_prescaler);
532 break;
533
534 default:
535 val = cpu->ios[base];
536 break;
537 }
538 *((unsigned8*) dest) = val;
539 dest++;
540 base++;
541 nr_bytes--;
542 cnt++;
543 }
544 return cnt;
545 }
546
547 static unsigned
548 m68hc11tim_io_write_buffer (struct hw *me,
549 const void *source,
550 int space,
551 unsigned_word base,
552 unsigned nr_bytes)
553 {
554 SIM_DESC sd;
555 struct m68hc11tim *controller;
556 sim_cpu *cpu;
557 unsigned8 val, n;
558 signed64 adj;
559 int reset_compare = 0;
560 int reset_overflow = 0;
561 int cnt = 0;
562
563 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
564
565 sd = hw_system (me);
566 cpu = STATE_CPU (sd, 0);
567 controller = hw_data (me);
568
569 while (nr_bytes)
570 {
571 val = *((const unsigned8*) source);
572 switch (base)
573 {
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. */
578 case M6811_TCTN_L:
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;
585 reset_compare = 1;
586 reset_overflow = 1;
587 break;
588
589 case M6811_TCTN_H:
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;
596 reset_compare = 1;
597 reset_overflow = 1;
598 break;
599
600 case M6811_TMSK2:
601
602 /* Timer prescaler cannot be changed after 64 bus cycles. */
603 if (cpu->cpu_absolute_cycle >= 64)
604 {
605 val &= ~(M6811_PR1 | M6811_PR0);
606 val |= cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0);
607 }
608 switch (val & (M6811_PR1 | M6811_PR0))
609 {
610 case 0:
611 n = 1;
612 break;
613 case M6811_PR0:
614 n = 4;
615 break;
616 case M6811_PR1:
617 n = 8;
618 break;
619 default:
620 case M6811_PR1 | M6811_PR0:
621 n = 16;
622 break;
623 }
624 if (cpu->cpu_absolute_cycle < 64)
625 {
626 reset_overflow = 1;
627 controller->clock_prescaler = n;
628 }
629 cpu->ios[base] = val;
630 interrupts_update_pending (&cpu->cpu_interrupts);
631 break;
632
633 case M6811_PACTL:
634 n = (1 << ((val & (M6811_RTR1 | M6811_RTR0))));
635 cpu->ios[base] = val;
636
637 controller->rti_delay = (long) (n) * 8192;
638 m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100));
639 break;
640
641 case M6811_TFLG2:
642 if (val & M6811_TOF)
643 val &= ~M6811_TOF;
644 else
645 val |= cpu->ios[M6811_TFLG2] & M6811_TOF;
646
647 /* Clear the Real Time interrupt flag. */
648 if (val & M6811_RTIF)
649 val &= ~M6811_RTIF;
650 else
651 val |= cpu->ios[M6811_TFLG2] & M6811_RTIF;
652
653 cpu->ios[base] = val;
654 interrupts_update_pending (&cpu->cpu_interrupts);
655 break;
656
657 case M6811_TOC1:
658 case M6811_TOC2:
659 case M6811_TOC3:
660 case M6811_TOC4:
661 case M6811_TOC5:
662 cpu->ios[base] = val;
663 reset_compare = 1;
664 break;
665
666 default:
667 break;
668 }
669
670 base++;
671 nr_bytes--;
672 cnt++;
673 source++;
674 }
675
676 /* Re-compute the next timer compare event. */
677 if (reset_compare)
678 {
679 m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT));
680 }
681 if (reset_overflow)
682 {
683 m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100));
684 }
685 return cnt;
686 }
687
688
689 const struct hw_descriptor dv_m68hc11tim_descriptor[] = {
690 { "m68hc11tim", m68hc11tim_finish },
691 { "m68hc12tim", m68hc11tim_finish },
692 { NULL },
693 };
694
This page took 0.044548 seconds and 4 git commands to generate.