]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/m68hc11/dv-m68hc11sio.c
Update the copyright notice of some of the files I missed
[thirdparty/binutils-gdb.git] / sim / m68hc11 / dv-m68hc11sio.c
CommitLineData
e0709f50 1/* dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
e4d013fc
JB
2 Copyright (C) 1999, 2000, 2001, 2007, 2008, 2009
3 Free Software Foundation, Inc.
e0709f50
AC
4 Written by Stephane Carrez (stcarrez@worldnet.fr)
5 (From a driver model Contributed by Cygnus Solutions.)
6
7 This file is part of the program GDB, the GNU debugger.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
4744ac1b 11 the Free Software Foundation; either version 3 of the License, or
e0709f50 12 (at your option) any later version.
4744ac1b 13
e0709f50
AC
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
4744ac1b 18
e0709f50 19 You should have received a copy of the GNU General Public License
4744ac1b 20 along with this program. If not, see <http://www.gnu.org/licenses/>.
e0709f50
AC
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