Minor formatting fixes.
[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
81 /* Periodic timers. */
82 struct hw_event *rti_timer_event;
83 struct hw_event *cop_timer_event;
84 struct hw_event *tof_timer_event;
85 struct hw_event *cmp_timer_event;
86 };
87
88
89
90 /* Finish off the partially created hw device. Attach our local
91 callbacks. Wire up our port names etc. */
92
93 static hw_io_read_buffer_method m68hc11tim_io_read_buffer;
94 static hw_io_write_buffer_method m68hc11tim_io_write_buffer;
95 static hw_port_event_method m68hc11tim_port_event;
96 static hw_ioctl_method m68hc11tim_ioctl;
97
98 #define M6811_TIMER_FIRST_REG (M6811_TCTN)
99 #define M6811_TIMER_LAST_REG (M6811_PACNT)
100
101
102 static void
103 attach_m68hc11tim_regs (struct hw *me,
104 struct m68hc11tim *controller)
105 {
106 hw_attach_address (hw_parent (me), 0, io_map,
107 M6811_TIMER_FIRST_REG,
108 M6811_TIMER_LAST_REG - M6811_TIMER_FIRST_REG + 1,
109 me);
110 }
111
112
113 static void
114 m68hc11tim_finish (struct hw *me)
115 {
116 struct m68hc11tim *controller;
117
118 controller = HW_ZALLOC (me, struct m68hc11tim);
119 me->overlap_mode_hw = 1;
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 }
170 if (controller->cop_timer_event)
171 {
172 hw_event_queue_deschedule (me, controller->cop_timer_event);
173 controller->cop_timer_event = 0;
174 }
175 if (controller->tof_timer_event)
176 {
177 hw_event_queue_deschedule (me, controller->tof_timer_event);
178 controller->tof_timer_event = 0;
179 }
180 if (controller->cmp_timer_event)
181 {
182 hw_event_queue_deschedule (me, controller->cmp_timer_event);
183 controller->cmp_timer_event = 0;
184 }
185
186 /* Reset the state of Timer registers. This also restarts
187 the timer events (overflow and RTI clock). */
188 val = 0;
189 m68hc11tim_io_write_buffer (me, &val, io_map,
190 (unsigned_word) M6811_TMSK2, 1);
191 m68hc11tim_io_write_buffer (me, &val, io_map,
192 (unsigned_word) M6811_TFLG2, 1);
193 m68hc11tim_io_write_buffer (me, &val, io_map,
194 (unsigned_word) M6811_PACTL, 1);
195 break;
196 }
197
198 default:
199 hw_abort (me, "Event on unknown port %d", my_port);
200 break;
201 }
202 }
203
204 enum event_type
205 {
206 COP_EVENT,
207 RTI_EVENT,
208 OVERFLOW_EVENT,
209 COMPARE_EVENT
210 };
211
212 void
213 m68hc11tim_timer_event (struct hw *me, void *data)
214 {
215 SIM_DESC sd;
216 struct m68hc11tim *controller;
217 sim_cpu *cpu;
218 enum event_type type;
219 unsigned long delay;
220 struct hw_event **eventp;
221 int check_interrupt = 0;
222 unsigned mask;
223 unsigned flags;
224 unsigned long tcnt;
225 int i;
226
227 controller = hw_data (me);
228 sd = hw_system (me);
229 cpu = STATE_CPU (sd, 0);
230 type = (enum event_type) ((long) data) & 0x0FF;
231
232 delay = 0;
233 switch (type)
234 {
235 case COP_EVENT:
236 eventp = &controller->cop_timer_event;
237 delay = controller->cop_delay;
238 check_interrupt = 1;
239 break;
240
241 case RTI_EVENT:
242 eventp = &controller->rti_timer_event;
243 delay = controller->rti_delay;
244 if (((long) (data) & 0x0100) == 0)
245 {
246 cpu->ios[M6811_TFLG2] |= M6811_RTIF;
247 check_interrupt = 1;
248 }
249 break;
250
251 case OVERFLOW_EVENT:
252 eventp = &controller->tof_timer_event;
253 delay = controller->ovf_delay;
254 cpu->ios[M6811_TFLG2] |= M6811_TOF;
255 break;
256
257 case COMPARE_EVENT:
258 eventp = &controller->cmp_timer_event;
259
260 /* Get current free running counter. */
261 tcnt = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
262 / controller->clock_prescaler);
263 tcnt &= 0x0ffffL;
264
265 flags = cpu->ios[M6811_TMSK1];
266 mask = 0x80;
267 delay = 65536;
268
269 /* Scan each output compare register to see if one matches
270 the free running counter. Set the corresponding OCi flag
271 if the output compare is enabled. */
272 for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1)
273 {
274 unsigned short compare;
275
276 compare = (cpu->ios[i] << 8) + cpu->ios[i+1];
277 if (compare == tcnt && (flags & mask))
278 {
279 cpu->ios[M6811_TFLG1] |= mask;
280 check_interrupt++;
281 }
282
283 /* Compute how many times for the next match. */
284 if (compare > tcnt)
285 compare = compare - tcnt;
286 else
287 compare = compare - tcnt + 65536;
288
289 if (compare < delay)
290 delay = compare;
291 }
292 delay = delay * controller->clock_prescaler;
293
294 /* Deactivate the compare timer if no output compare is enabled. */
295 if ((flags & 0xF0) == 0)
296 delay = 0;
297 break;
298
299 default:
300 eventp = 0;
301 break;
302 }
303
304 if (*eventp)
305 {
306 hw_event_queue_deschedule (me, *eventp);
307 *eventp = 0;
308 }
309
310 if (delay != 0)
311 {
312 *eventp = hw_event_queue_schedule (me, delay,
313 m68hc11tim_timer_event,
314 (void*) type);
315 }
316
317 if (check_interrupt)
318 interrupts_update_pending (&cpu->cpu_interrupts);
319 }
320
321
322 /* Descriptions of the Timer I/O ports. These descriptions are only used to
323 give information of the Timer device under GDB. */
324 io_reg_desc tmsk2_desc[] = {
325 { M6811_TOI, "TOI ", "Timer Overflow Interrupt Enable" },
326 { M6811_RTII, "RTII ", "RTI Interrupt Enable" },
327 { M6811_PAOVI, "PAOVI ", "Pulse Accumulator Overflow Interrupt Enable" },
328 { M6811_PAII, "PAII ", "Pulse Accumulator Interrupt Enable" },
329 { M6811_PR1, "PR1 ", "Timer prescaler (PR1)" },
330 { M6811_PR0, "PR0 ", "Timer prescaler (PR0)" },
331 { M6811_TPR_1, "TPR_1 ", "Timer prescaler div 1" },
332 { M6811_TPR_4, "TPR_4 ", "Timer prescaler div 4" },
333 { M6811_TPR_8, "TPR_8 ", "Timer prescaler div 8" },
334 { M6811_TPR_16, "TPR_16", "Timer prescaler div 16" },
335 { 0, 0, 0 }
336 };
337
338 io_reg_desc tflg2_desc[] = {
339 { M6811_TOF, "TOF ", "Timer Overflow Bit" },
340 { M6811_RTIF, "RTIF ", "Read Time Interrupt Flag" },
341 { M6811_PAOVF, "PAOVF ", "Pulse Accumulator Overflow Interrupt Flag" },
342 { M6811_PAIF, "PAIF ", "Pulse Accumulator Input Edge" },
343 { 0, 0, 0 }
344 };
345
346 io_reg_desc pactl_desc[] = {
347 { M6811_DDRA7, "DDRA7 ", "Data Direction for Port A bit-7" },
348 { M6811_PAEN, "PAEN ", "Pulse Accumulator System Enable" },
349 { M6811_PAMOD, "PAMOD ", "Pulse Accumulator Mode" },
350 { M6811_PEDGE, "PEDGE ", "Pulse Accumulator Edge Control" },
351 { M6811_RTR1, "RTR1 ", "RTI Interrupt rate select (RTR1)" },
352 { M6811_RTR0, "RTR0 ", "RTI Interrupt rate select (RTR0)" },
353 { 0, 0, 0 }
354 };
355
356 static double
357 to_realtime (sim_cpu *cpu, signed64 t)
358 {
359 return (double) (t) / (double) (cpu->cpu_frequency / 4);
360 }
361
362 static void
363 m68hc11tim_print_timer (struct hw *me, const char *name,
364 struct hw_event *event)
365 {
366 SIM_DESC sd;
367
368 sd = hw_system (me);
369 if (event == 0)
370 {
371 sim_io_printf (sd, " No %s interrupt will be raised.\n", name);
372 }
373 else
374 {
375 signed64 t;
376 double dt;
377 sim_cpu* cpu;
378
379 cpu = STATE_CPU (sd, 0);
380
381 t = hw_event_remain_time (me, event);
382 dt = to_realtime (cpu, t) * 1000.0;
383 sim_io_printf (sd, " Next %s interrupt in %ld cycles (%3.3f ms)\n",
384 name, (long) t, dt);
385 }
386 }
387
388 static void
389 m68hc11tim_info (struct hw *me)
390 {
391 SIM_DESC sd;
392 uint16 base = 0;
393 sim_cpu *cpu;
394 struct m68hc11tim *controller;
395 uint8 val;
396
397 sd = hw_system (me);
398 cpu = STATE_CPU (sd, 0);
399 controller = hw_data (me);
400
401 sim_io_printf (sd, "M68HC11 Timer:\n");
402
403 base = cpu_get_io_base (cpu);
404
405 val = cpu->ios[M6811_TMSK2];
406 print_io_byte (sd, "TMSK2 ", tmsk2_desc, val, base + M6811_TMSK2);
407 sim_io_printf (sd, "\n");
408
409 val = cpu->ios[M6811_TFLG2];
410 print_io_byte (sd, "TFLG2", tflg2_desc, val, base + M6811_TFLG2);
411 sim_io_printf (sd, "\n");
412
413 val = cpu->ios[M6811_PACTL];
414 print_io_byte (sd, "PACTL", pactl_desc, val, base + M6811_PACTL);
415 sim_io_printf (sd, "\n");
416
417 /* Give info about the next timer interrupts. */
418 m68hc11tim_print_timer (me, "RTI", controller->rti_timer_event);
419 m68hc11tim_print_timer (me, "COP", controller->cop_timer_event);
420 m68hc11tim_print_timer (me, "OVERFLOW", controller->tof_timer_event);
421 m68hc11tim_print_timer (me, "COMPARE", controller->cmp_timer_event);
422 }
423
424 static int
425 m68hc11tim_ioctl (struct hw *me,
426 hw_ioctl_request request,
427 va_list ap)
428 {
429 m68hc11tim_info (me);
430 return 0;
431 }
432
433 /* generic read/write */
434
435 static unsigned
436 m68hc11tim_io_read_buffer (struct hw *me,
437 void *dest,
438 int space,
439 unsigned_word base,
440 unsigned nr_bytes)
441 {
442 SIM_DESC sd;
443 struct m68hc11tim *controller;
444 sim_cpu *cpu;
445 unsigned8 val;
446
447 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
448
449 sd = hw_system (me);
450 cpu = STATE_CPU (sd, 0);
451 controller = hw_data (me);
452
453 switch (base)
454 {
455 /* The cpu_absolute_cycle is updated after each instruction.
456 Reading in a 16-bit register will be split in two accesses
457 but this will be atomic within the simulator. */
458 case M6811_TCTN_H:
459 val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
460 / (controller->clock_prescaler * 256));
461 break;
462
463 case M6811_TCTN_L:
464 val = (uint8) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
465 / controller->clock_prescaler);
466 break;
467
468 default:
469 val = cpu->ios[base];
470 break;
471 }
472 *((unsigned8*) dest) = val;
473 return 1;
474 }
475
476 static unsigned
477 m68hc11tim_io_write_buffer (struct hw *me,
478 const void *source,
479 int space,
480 unsigned_word base,
481 unsigned nr_bytes)
482 {
483 SIM_DESC sd;
484 struct m68hc11tim *controller;
485 sim_cpu *cpu;
486 unsigned8 val, n;
487 signed64 adj;
488 int reset_compare = 0;
489
490 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
491
492 sd = hw_system (me);
493 cpu = STATE_CPU (sd, 0);
494 controller = hw_data (me);
495
496 val = *((const unsigned8*) source);
497 switch (base)
498 {
499 /* Set the timer counter low part, trying to preserve the low part.
500 We compute the absolute cycle adjustment that we have to apply
501 to obtain the timer current value. Computation must be made
502 in 64-bit to avoid overflow problems. */
503 case M6811_TCTN_L:
504 adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
505 / (controller->clock_prescaler * (signed64) 256)) & 0x0FF;
506 adj = cpu->cpu_absolute_cycle
507 - (adj * controller->clock_prescaler * (signed64) 256)
508 - ((signed64) adj * controller->clock_prescaler);
509 controller->tcnt_adjust = adj;
510 reset_compare = 1;
511 break;
512
513 case M6811_TCTN_H:
514 adj = ((cpu->cpu_absolute_cycle - controller->tcnt_adjust)
515 / controller->clock_prescaler) & 0x0ff;
516 adj = cpu->cpu_absolute_cycle
517 - ((signed64) val * controller->clock_prescaler * (signed64) 256)
518 - (adj * controller->clock_prescaler);
519 controller->tcnt_adjust = adj;
520 reset_compare = 1;
521 break;
522
523 case M6811_TMSK2:
524
525 /* Timer prescaler cannot be changed after 64 bus cycles. */
526 if (cpu->cpu_absolute_cycle >= 64)
527 {
528 val &= ~(M6811_PR1 | M6811_PR0);
529 val |= cpu->ios[M6811_TMSK2] & (M6811_PR1 | M6811_PR0);
530 }
531 switch (val & (M6811_PR1 | M6811_PR0))
532 {
533 case 0:
534 n = 1;
535 break;
536 case M6811_PR0:
537 n = 4;
538 break;
539 case M6811_PR1:
540 n = 8;
541 break;
542 default:
543 case M6811_PR1 | M6811_PR0:
544 n = 16;
545 break;
546 }
547 if (controller->clock_prescaler != n)
548 {
549 controller->clock_prescaler = n;
550 controller->ovf_delay = n * 65536;
551 m68hc11tim_timer_event (me, (void*) (OVERFLOW_EVENT| 0x100));
552 }
553 cpu->ios[base] = val;
554 interrupts_update_pending (&cpu->cpu_interrupts);
555 break;
556
557 case M6811_PACTL:
558 n = (1 << ((val & (M6811_RTR1 | M6811_RTR0))));
559 cpu->ios[base] = val;
560
561 controller->rti_delay = (long) (n) * 8192;
562 m68hc11tim_timer_event (me, (void*) (RTI_EVENT| 0x100));
563 break;
564
565 case M6811_TFLG2:
566 if (val & M6811_TOF)
567 val &= ~M6811_TOF;
568 else
569 val |= cpu->ios[M6811_TFLG2] & M6811_TOF;
570
571 /* Clear the Real Time interrupt flag. */
572 if (val & M6811_RTIF)
573 val &= ~M6811_RTIF;
574 else
575 val |= cpu->ios[M6811_TFLG2] & M6811_RTIF;
576
577 cpu->ios[base] = val;
578 interrupts_update_pending (&cpu->cpu_interrupts);
579 break;
580
581 case M6811_TOC1:
582 case M6811_TOC2:
583 case M6811_TOC3:
584 case M6811_TOC4:
585 case M6811_TOC5:
586 cpu->ios[base] = val;
587 reset_compare = 1;
588 break;
589
590 default:
591 return 0;
592 }
593
594 /* Re-compute the next timer compare event. */
595 if (reset_compare)
596 {
597 m68hc11tim_timer_event (me, (void*) (COMPARE_EVENT));
598 }
599 return nr_bytes;
600 }
601
602
603 const struct hw_descriptor dv_m68hc11tim_descriptor[] = {
604 { "m68hc11tim", m68hc11tim_finish, },
605 { NULL },
606 };
607
This page took 0.046635 seconds and 4 git commands to generate.