xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/m68hc11/dv-m68hc11sio.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /*  dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
2     Copyright (C) 1999-2023 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 
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 
66 enum
67 {
68   RESET_PORT
69 };
70 
71 
72 static const struct hw_port_descriptor m68hc11sio_ports[] =
73 {
74   { "reset", RESET_PORT, 0, input_port, },
75   { NULL, },
76 };
77 
78 
79 /* Serial Controller information.  */
80 struct 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 
109 static hw_io_read_buffer_method m68hc11sio_io_read_buffer;
110 static hw_io_write_buffer_method m68hc11sio_io_write_buffer;
111 static hw_port_event_method m68hc11sio_port_event;
112 static hw_ioctl_method m68hc11sio_ioctl;
113 
114 #define M6811_SCI_FIRST_REG (M6811_BAUD)
115 #define M6811_SCI_LAST_REG  (M6811_SCDR)
116 
117 
118 static void
119 attach_m68hc11sio_regs (struct hw *me,
120                         struct m68hc11sio *controller)
121 {
122   hw_attach_address (hw_parent (me), M6811_IO_LEVEL, io_map,
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 
141 static void
142 m68hc11sio_finish (struct hw *me)
143 {
144   struct m68hc11sio *controller;
145 
146   controller = HW_ZALLOC (me, struct m68hc11sio);
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 
177 static void
178 m68hc11sio_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   uint8_t 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 
245 static void
246 m68hc11sio_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 
318 static void
319 m68hc11sio_tx_poll (struct hw *me, void *data)
320 {
321   SIM_DESC sd;
322   struct m68hc11sio *controller;
323   sim_cpu *cpu;
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 
332   /* Transmitter is enabled and we have something to send.  */
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;
338       switch (controller->backend)
339         {
340         case sio_tcp:
341           dv_sockser_write (sd, controller->tx_char);
342           break;
343 
344         case sio_stdio:
345           sim_io_write_stdout (sd, (const char *)&controller->tx_char, 1);
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 
373   interrupts_update_pending (&cpu->cpu_interrupts);
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.  */
378 io_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 
390 io_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 
398 io_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 
409 io_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 
420 static void
421 m68hc11sio_info (struct hw *me)
422 {
423   SIM_DESC sd;
424   uint16_t base = 0;
425   sim_cpu *cpu;
426   struct m68hc11sio *controller;
427   uint8_t 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       int64_t 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;
466       sim_io_printf (sd, "  Transmit finished in %s (%d bit%s)\n",
467 		     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE),
468                      n, (n > 1 ? "s" : ""));
469     }
470   if (controller->rx_poll_event)
471     {
472       int64_t t;
473 
474       t = hw_event_remain_time (me, controller->rx_poll_event);
475       sim_io_printf (sd, "  Receive finished in %s\n",
476 		     cycle_to_string (cpu, t, PRINT_TIME | PRINT_CYCLE));
477     }
478 
479 }
480 
481 static int
482 m68hc11sio_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 
492 static unsigned
493 m68hc11sio_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   uint8_t 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   *((uint8_t*) dest) = val;
534   return 1;
535 }
536 
537 static unsigned
538 m68hc11sio_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   uint8_t 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 uint8_t*) 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 
658 const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
659   { "m68hc11sio", m68hc11sio_finish },
660   { "m68hc12sio", m68hc11sio_finish },
661   { NULL },
662 };
663 
664