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