]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11sio.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11sio.c
CommitLineData
e0709f50 1/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
6aba47ca 2 Copyright (C) 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
e0709f50
AC
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 version 2 of the License, or
11 (at your option) any later version.
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 "dv-sockser.h"
28#include "sim-assert.h"
29
30
31/* DEVICE
32
33 m68hc11sio - m68hc11 serial I/O
34
35
36 DESCRIPTION
37
38 Implements the m68hc11 serial I/O controller described in the m68hc11
39 user guide. The serial I/O controller is directly connected to the CPU
40 interrupt. The simulator implements:
41
42 - baud rate emulation
43 - 8-bits transfers
44
45 PROPERTIES
46
47 backend {tcp | stdio}
48
49 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
50
51
52 PORTS
53
54 reset (input)
55
56 Reset port. This port is only used to simulate a reset of the serial
57 I/O controller. It should be connected to the RESET output of the cpu.
58
59 */
60
61
62
63/* port ID's */
64
65enum
66{
67 RESET_PORT
68};
69
70
71static const struct hw_port_descriptor m68hc11sio_ports[] =
72{
73 { "reset", RESET_PORT, 0, input_port, },
74 { NULL, },
75};
76
77
78/* Serial Controller information. */
79struct m68hc11sio
80{
81 enum {sio_tcp, sio_stdio} backend; /* backend */
82
83 /* Number of cpu cycles to send a bit on the wire. */
84 unsigned long baud_cycle;
85
86 /* Length in bits of characters sent, this includes the
87 start/stop and parity bits. Together with baud_cycle, this
88 is used to find the number of cpu cycles to send/receive a data. */
89 unsigned int data_length;
90
91 /* Information about next character to be transmited. */
92 unsigned char tx_has_char;
93 unsigned char tx_char;
94
95 unsigned char rx_char;
96 unsigned char rx_clear_scsr;
97
98 /* Periodic I/O polling. */
99 struct hw_event* tx_poll_event;
100 struct hw_event* rx_poll_event;
101};
102
103
104
105/* Finish off the partially created hw device. Attach our local
106 callbacks. Wire up our port names etc. */
107
108static hw_io_read_buffer_method m68hc11sio_io_read_buffer;
109static hw_io_write_buffer_method m68hc11sio_io_write_buffer;
110static hw_port_event_method m68hc11sio_port_event;
111static hw_ioctl_method m68hc11sio_ioctl;
112
113#define M6811_SCI_FIRST_REG (M6811_BAUD)
114#define M6811_SCI_LAST_REG (M6811_SCDR)
115
116
117static void
118attach_m68hc11sio_regs (struct hw *me,
119 struct m68hc11sio *controller)
120{
63348d04 121 hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
e0709f50
AC
122 M6811_SCI_FIRST_REG,
123 M6811_SCI_LAST_REG - M6811_SCI_FIRST_REG + 1,
124 me);
125
126 if (hw_find_property(me, "backend") != NULL)
127 {
128 const char *value = hw_find_string_property(me, "backend");
129 if(! strcmp(value, "tcp"))
130 controller->backend = sio_tcp;
131 else if(! strcmp(value, "stdio"))
132 controller->backend = sio_stdio;
133 else
134 hw_abort (me, "illegal value for backend parameter `%s':"
135 "use tcp or stdio", value);
136 }
137}
138
139
140static void
141m68hc11sio_finish (struct hw *me)
142{
143 struct m68hc11sio *controller;
144
145 controller = HW_ZALLOC (me, struct m68hc11sio);
e0709f50
AC
146 set_hw_data (me, controller);
147 set_hw_io_read_buffer (me, m68hc11sio_io_read_buffer);
148 set_hw_io_write_buffer (me, m68hc11sio_io_write_buffer);
149 set_hw_ports (me, m68hc11sio_ports);
150 set_hw_port_event (me, m68hc11sio_port_event);
151#ifdef set_hw_ioctl
152 set_hw_ioctl (me, m68hc11sio_ioctl);
153#else
154 me->to_ioctl = m68hc11sio_ioctl;
155#endif
156
157 /* Preset defaults. */
158 controller->backend = sio_stdio;
159
160 /* Attach ourself to our parent bus. */
161 attach_m68hc11sio_regs (me, controller);
162
163 /* Initialize to reset state. */
164 controller->tx_poll_event = NULL;
165 controller->rx_poll_event = NULL;
166 controller->tx_char = 0;
167 controller->tx_has_char = 0;
168 controller->rx_clear_scsr = 0;
169 controller->rx_char = 0;
170}
171
172
173
174/* An event arrives on an interrupt port. */
175
176static void
177m68hc11sio_port_event (struct hw *me,
178 int my_port,
179 struct hw *source,
180 int source_port,
181 int level)
182{
183 SIM_DESC sd;
184 struct m68hc11sio *controller;
185 sim_cpu *cpu;
186 unsigned8 val;
187
188 controller = hw_data (me);
189 sd = hw_system (me);
190 cpu = STATE_CPU (sd, 0);
191 switch (my_port)
192 {
193 case RESET_PORT:
194 {
195 HW_TRACE ((me, "SCI reset"));
196
197 /* Reset the state of SCI registers. */
198 val = 0;
199 m68hc11sio_io_write_buffer (me, &val, io_map,
200 (unsigned_word) M6811_BAUD, 1);
201 m68hc11sio_io_write_buffer (me, &val, io_map,
202 (unsigned_word) M6811_SCCR1, 1);
203 m68hc11sio_io_write_buffer (me, &val, io_map,
204 (unsigned_word) M6811_SCCR2, 1);
205
206 cpu->ios[M6811_SCSR] = M6811_TC | M6811_TDRE;
207 controller->rx_char = 0;
208 controller->tx_char = 0;
209 controller->tx_has_char = 0;
210 controller->rx_clear_scsr = 0;
211 if (controller->rx_poll_event)
212 {
213 hw_event_queue_deschedule (me, controller->rx_poll_event);
214 controller->rx_poll_event = 0;
215 }
216 if (controller->tx_poll_event)
217 {
218 hw_event_queue_deschedule (me, controller->tx_poll_event);
219 controller->tx_poll_event = 0;
220 }
221
222 /* In bootstrap mode, initialize the SCI to 1200 bauds to
223 simulate some initial setup by the internal rom. */
224 if (((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA)) == M6811_SMOD)
225 {
226 unsigned char val = 0x33;
227
228 m68hc11sio_io_write_buffer (me, &val, io_map,
229 (unsigned_word) M6811_BAUD, 1);
230 val = 0x12;
231 m68hc11sio_io_write_buffer (me, &val, io_map,
232 (unsigned_word) M6811_SCCR2, 1);
233 }
234 break;
235 }
236
237 default:
238 hw_abort (me, "Event on unknown port %d", my_port);
239 break;
240 }
241}
242
243
244void
245m68hc11sio_rx_poll (struct hw *me, void *data)
246{
247 SIM_DESC sd;
248 struct m68hc11sio *controller;
249 sim_cpu *cpu;
250 char cc;
251 int cnt;
252 int check_interrupt = 0;
253
254 controller = hw_data (me);
255 sd = hw_system (me);
256 cpu = STATE_CPU (sd, 0);
257 switch (controller->backend)
258 {
259 case sio_tcp:
260 cnt = dv_sockser_read (sd);
261 if (cnt != -1)
262 {
263 cc = (char) cnt;
264 cnt = 1;
265 }
266 break;
267
268 case sio_stdio:
269 cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1);
270 break;
271
272 default:
273 cnt = 0;
274 break;
275 }
276
277 if (cnt == 1)
278 {
279 /* Raise the overrun flag if the previous character was not read. */
280 if (cpu->ios[M6811_SCSR] & M6811_RDRF)
281 cpu->ios[M6811_SCSR] |= M6811_OR;
282
283 cpu->ios[M6811_SCSR] |= M6811_RDRF;
284 controller->rx_char = cc;
285 controller->rx_clear_scsr = 0;
286 check_interrupt = 1;
287 }
288 else
289 {
290 /* handle idle line detect here. */
291 ;
292 }
293
294 if (controller->rx_poll_event)
295 {
296 hw_event_queue_deschedule (me, controller->rx_poll_event);
297 controller->rx_poll_event = 0;
298 }
299
300 if (cpu->ios[M6811_SCCR2] & M6811_RE)
301 {
302 unsigned long clock_cycle;
303
304 /* Compute CPU clock cycles to wait for the next character. */
305 clock_cycle = controller->data_length * controller->baud_cycle;
306
307 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
308 m68hc11sio_rx_poll,
309 NULL);
310 }
311
312 if (check_interrupt)
313 interrupts_update_pending (&cpu->cpu_interrupts);
314}
315
316
317void
318m68hc11sio_tx_poll (struct hw *me, void *data)
319{
320 SIM_DESC sd;
321 struct m68hc11sio *controller;
322 sim_cpu *cpu;
e0709f50
AC
323
324 controller = hw_data (me);
325 sd = hw_system (me);
326 cpu = STATE_CPU (sd, 0);
327
328 cpu->ios[M6811_SCSR] |= M6811_TDRE;
329 cpu->ios[M6811_SCSR] |= M6811_TC;
330
11115521 331 /* Transmitter is enabled and we have something to send. */
e0709f50
AC
332 if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
333 {
334 cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
335 cpu->ios[M6811_SCSR] &= ~M6811_TC;
336 controller->tx_has_char = 0;
e0709f50
AC
337 switch (controller->backend)
338 {
339 case sio_tcp:
340 dv_sockser_write (sd, controller->tx_char);
341 break;
342
343 case sio_stdio:
344 sim_io_write_stdout (sd, &controller->tx_char, 1);
345 sim_io_flush_stdout (sd);
346 break;
347
348 default:
349 break;
350 }
351 }
352
353 if (controller->tx_poll_event)
354 {
355 hw_event_queue_deschedule (me, controller->tx_poll_event);
356 controller->tx_poll_event = 0;
357 }
358
359 if ((cpu->ios[M6811_SCCR2] & M6811_TE)
360 && ((cpu->ios[M6811_SCSR] & M6811_TC) == 0))
361 {
362 unsigned long clock_cycle;
363
364 /* Compute CPU clock cycles to wait for the next character. */
365 clock_cycle = controller->data_length * controller->baud_cycle;
366
367 controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
368 m68hc11sio_tx_poll,
369 NULL);
370 }
371
11115521 372 interrupts_update_pending (&cpu->cpu_interrupts);
e0709f50
AC
373}
374
375/* Descriptions of the SIO I/O ports. These descriptions are only used to
376 give information of the SIO device under GDB. */
377io_reg_desc sccr2_desc[] = {
378 { M6811_TIE, "TIE ", "Transmit Interrupt Enable" },
379 { M6811_TCIE, "TCIE ", "Transmit Complete Interrupt Enable" },
380 { M6811_RIE, "RIE ", "Receive Interrupt Enable" },
381 { M6811_ILIE, "ILIE ", "Idle Line Interrupt Enable" },
382 { M6811_TE, "TE ", "Transmit Enable" },
383 { M6811_RE, "RE ", "Receive Enable" },
384 { M6811_RWU, "RWU ", "Receiver Wake Up" },
385 { M6811_SBK, "SBRK ", "Send Break" },
386 { 0, 0, 0 }
387};
388
389io_reg_desc sccr1_desc[] = {
390 { M6811_R8, "R8 ", "Receive Data bit 8" },
391 { M6811_T8, "T8 ", "Transmit Data bit 8" },
392 { M6811_M, "M ", "SCI Character length (0=8-bits, 1=9-bits)" },
393 { M6811_WAKE, "WAKE ", "Wake up method select (0=idle, 1=addr mark" },
394 { 0, 0, 0 }
395};
396
397io_reg_desc scsr_desc[] = {
398 { M6811_TDRE, "TDRE ", "Transmit Data Register Empty" },
399 { M6811_TC, "TC ", "Transmit Complete" },
400 { M6811_RDRF, "RDRF ", "Receive Data Register Full" },
401 { M6811_IDLE, "IDLE ", "Idle Line Detect" },
402 { M6811_OR, "OR ", "Overrun Error" },
403 { M6811_NF, "NF ", "Noise Flag" },
404 { M6811_FE, "FE ", "Framing Error" },
405 { 0, 0, 0 }
406};
407
408io_reg_desc baud_desc[] = {
409 { M6811_TCLR, "TCLR ", "Clear baud rate (test mode)" },
410 { M6811_SCP1, "SCP1 ", "SCI baud rate prescaler select (SCP1)" },
411 { M6811_SCP0, "SCP0 ", "SCI baud rate prescaler select (SCP0)" },
412 { M6811_RCKB, "RCKB ", "Baur Rate Clock Check (test mode)" },
413 { M6811_SCR2, "SCR2 ", "SCI Baud rate select (SCR2)" },
414 { M6811_SCR1, "SCR1 ", "SCI Baud rate select (SCR1)" },
415 { M6811_SCR0, "SCR0 ", "SCI Baud rate select (SCR0)" },
416 { 0, 0, 0 }
417};
418
419static void
420m68hc11sio_info (struct hw *me)
421{
422 SIM_DESC sd;
423 uint16 base = 0;
424 sim_cpu *cpu;
425 struct m68hc11sio *controller;
426 uint8 val;
427 long clock_cycle;
428
429 sd = hw_system (me);
430 cpu = STATE_CPU (sd, 0);
431 controller = hw_data (me);
432
433 sim_io_printf (sd, "M68HC11 SIO:\n");
434
435 base = cpu_get_io_base (cpu);
436
437 val = cpu->ios[M6811_BAUD];
438 print_io_byte (sd, "BAUD ", baud_desc, val, base + M6811_BAUD);
439 sim_io_printf (sd, " (%ld baud)\n",
440 (cpu->cpu_frequency / 4) / controller->baud_cycle);
441
442 val = cpu->ios[M6811_SCCR1];
443 print_io_byte (sd, "SCCR1", sccr1_desc, val, base + M6811_SCCR1);
444 sim_io_printf (sd, " (%d bits) (%dN1)\n",
445 controller->data_length, controller->data_length - 2);
446
447 val = cpu->ios[M6811_SCCR2];
448 print_io_byte (sd, "SCCR2", sccr2_desc, val, base + M6811_SCCR2);
449 sim_io_printf (sd, "\n");
450
451 val = cpu->ios[M6811_SCSR];
452 print_io_byte (sd, "SCSR ", scsr_desc, val, base + M6811_SCSR);
453 sim_io_printf (sd, "\n");
454
455 clock_cycle = controller->data_length * controller->baud_cycle;
456
457 if (controller->tx_poll_event)
458 {
459 signed64 t;
460 int n;
461
462 t = hw_event_remain_time (me, controller->tx_poll_event);
463 n = (clock_cycle - t) / controller->baud_cycle;
464 n = controller->data_length - n;
2990a9f4 465 sim_io_printf (sd, " Transmit finished in %s (%d bit%s)\n",
a685700c
SC
466 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
467 n, (n > 1 ? "s" : ""));
e0709f50
AC
468 }
469 if (controller->rx_poll_event)
470 {
471 signed64 t;
472
473 t = hw_event_remain_time (me, controller->rx_poll_event);
2990a9f4 474 sim_io_printf (sd, " Receive finished in %s\n",
a685700c 475 cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
e0709f50
AC
476 }
477
478}
479
480static int
481m68hc11sio_ioctl (struct hw *me,
482 hw_ioctl_request request,
483 va_list ap)
484{
485 m68hc11sio_info (me);
486 return 0;
487}
488
489/* generic read/write */
490
491static unsigned
492m68hc11sio_io_read_buffer (struct hw *me,
493 void *dest,
494 int space,
495 unsigned_word base,
496 unsigned nr_bytes)
497{
498 SIM_DESC sd;
499 struct m68hc11sio *controller;
500 sim_cpu *cpu;
501 unsigned8 val;
502
503 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
504
505 sd = hw_system (me);
506 cpu = STATE_CPU (sd, 0);
507 controller = hw_data (me);
508
509 switch (base)
510 {
511 case M6811_SCSR:
512 controller->rx_clear_scsr = cpu->ios[M6811_SCSR]
513 & (M6811_RDRF | M6811_IDLE | M6811_OR | M6811_NF | M6811_FE);
514
515 case M6811_BAUD:
516 case M6811_SCCR1:
517 case M6811_SCCR2:
518 val = cpu->ios[base];
519 break;
520
521 case M6811_SCDR:
522 if (controller->rx_clear_scsr)
523 {
524 cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
525 }
526 val = controller->rx_char;
527 break;
528
529 default:
530 return 0;
531 }
532 *((unsigned8*) dest) = val;
533 return 1;
534}
535
536static unsigned
537m68hc11sio_io_write_buffer (struct hw *me,
538 const void *source,
539 int space,
540 unsigned_word base,
541 unsigned nr_bytes)
542{
543 SIM_DESC sd;
544 struct m68hc11sio *controller;
545 sim_cpu *cpu;
546 unsigned8 val;
547
548 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
549
550 sd = hw_system (me);
551 cpu = STATE_CPU (sd, 0);
552 controller = hw_data (me);
553
554 val = *((const unsigned8*) source);
555 switch (base)
556 {
557 case M6811_BAUD:
558 {
559 long divisor;
560 long baud;
561
562 cpu->ios[M6811_BAUD] = val;
563 switch (val & (M6811_SCP1|M6811_SCP0))
564 {
565 case M6811_BAUD_DIV_1:
566 divisor = 1 * 16;
567 break;
568
569 case M6811_BAUD_DIV_3:
570 divisor = 3 * 16;
571 break;
572
573 case M6811_BAUD_DIV_4:
574 divisor = 4 * 16;
575 break;
576
577 default:
578 case M6811_BAUD_DIV_13:
579 divisor = 13 * 16;
580 break;
581 }
582 val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
583 divisor *= (1 << val);
584
585 baud = (cpu->cpu_frequency / 4) / divisor;
586
587 HW_TRACE ((me, "divide rate %ld, baud rate %ld",
588 divisor, baud));
589
590 controller->baud_cycle = divisor;
591 }
592 break;
593
594 case M6811_SCCR1:
595 {
596 if (val & M6811_M)
597 controller->data_length = 11;
598 else
599 controller->data_length = 10;
600
601 cpu->ios[M6811_SCCR1] = val;
602 }
603 break;
604
605 case M6811_SCCR2:
606 if ((val & M6811_RE) == 0)
607 {
608 val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
609 val |= (cpu->ios[M6811_SCCR2]
610 & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
611 cpu->ios[M6811_SCCR2] = val;
612 break;
613 }
614
615 /* Activate reception. */
616 if (controller->rx_poll_event == 0)
617 {
618 long clock_cycle;
619
620 /* Compute CPU clock cycles to wait for the next character. */
621 clock_cycle = controller->data_length * controller->baud_cycle;
622
623 controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
624 m68hc11sio_rx_poll,
625 NULL);
626 }
627 cpu->ios[M6811_SCCR2] = val;
628 interrupts_update_pending (&cpu->cpu_interrupts);
629 break;
630
631 /* No effect. */
632 case M6811_SCSR:
633 return 1;
634
635 case M6811_SCDR:
636 if (!(cpu->ios[M6811_SCSR] & M6811_TDRE))
637 {
638 return 0;
639 }
640
641 controller->tx_char = val;
642 controller->tx_has_char = 1;
643 if ((cpu->ios[M6811_SCCR2] & M6811_TE)
644 && controller->tx_poll_event == 0)
645 {
646 m68hc11sio_tx_poll (me, NULL);
647 }
648 return 1;
649
650 default:
651 return 0;
652 }
653 return nr_bytes;
654}
655
656
657const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
b93775f5
SC
658 { "m68hc11sio", m68hc11sio_finish },
659 { "m68hc12sio", m68hc11sio_finish },
e0709f50
AC
660 { NULL },
661};
662