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