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