xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/dv-m68hc11sio.c (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
1 /*  dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
2     Copyright (C) 1999-2024 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             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       ATTRIBUTE_FALLTHROUGH;
527 
528     case M6811_BAUD:
529     case M6811_SCCR1:
530     case M6811_SCCR2:
531       val = m68hc11_cpu->ios[base];
532       break;
533 
534     case M6811_SCDR:
535       if (controller->rx_clear_scsr)
536         {
537           m68hc11_cpu->ios[M6811_SCSR] &= ~controller->rx_clear_scsr;
538         }
539       val = controller->rx_char;
540       break;
541 
542     default:
543       return 0;
544     }
545   *((uint8_t*) dest) = val;
546   return 1;
547 }
548 
549 static unsigned
550 m68hc11sio_io_write_buffer (struct hw *me,
551                             const void *source,
552                             int space,
553                             unsigned_word base,
554                             unsigned nr_bytes)
555 {
556   SIM_DESC sd;
557   struct m68hc11sio *controller;
558   sim_cpu *cpu;
559   struct m68hc11_sim_cpu *m68hc11_cpu;
560   uint8_t val;
561 
562   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
563 
564   sd  = hw_system (me);
565   cpu = STATE_CPU (sd, 0);
566   m68hc11_cpu = M68HC11_SIM_CPU (cpu);
567   controller = hw_data (me);
568 
569   val = *((const uint8_t*) source);
570   switch (base)
571     {
572     case M6811_BAUD:
573       {
574         long divisor;
575         long baud;
576 
577         m68hc11_cpu->ios[M6811_BAUD] = val;
578         switch (val & (M6811_SCP1|M6811_SCP0))
579           {
580           case M6811_BAUD_DIV_1:
581             divisor = 1 * 16;
582             break;
583 
584           case M6811_BAUD_DIV_3:
585             divisor = 3 * 16;
586             break;
587 
588           case M6811_BAUD_DIV_4:
589             divisor = 4 * 16;
590             break;
591 
592           default:
593           case M6811_BAUD_DIV_13:
594             divisor = 13 * 16;
595             break;
596           }
597         val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
598         divisor *= (1 << val);
599 
600         baud = (m68hc11_cpu->cpu_frequency / 4) / divisor;
601 
602         HW_TRACE ((me, "divide rate %ld, baud rate %ld",
603                    divisor, baud));
604 
605         controller->baud_cycle = divisor;
606       }
607       break;
608 
609     case M6811_SCCR1:
610       {
611         if (val & M6811_M)
612           controller->data_length = 11;
613         else
614           controller->data_length = 10;
615 
616         m68hc11_cpu->ios[M6811_SCCR1] = val;
617       }
618       break;
619 
620     case M6811_SCCR2:
621       if ((val & M6811_RE) == 0)
622         {
623           val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
624           val |= (m68hc11_cpu->ios[M6811_SCCR2]
625                   & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
626           m68hc11_cpu->ios[M6811_SCCR2] = val;
627           break;
628         }
629 
630       /* Activate reception.  */
631       if (controller->rx_poll_event == 0)
632         {
633           long clock_cycle;
634 
635           /* Compute CPU clock cycles to wait for the next character.  */
636           clock_cycle = controller->data_length * controller->baud_cycle;
637 
638           controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
639                                                                m68hc11sio_rx_poll,
640                                                                NULL);
641         }
642       m68hc11_cpu->ios[M6811_SCCR2] = val;
643       interrupts_update_pending (&m68hc11_cpu->cpu_interrupts);
644       break;
645 
646       /* No effect.  */
647     case M6811_SCSR:
648       return 1;
649 
650     case M6811_SCDR:
651       if (!(m68hc11_cpu->ios[M6811_SCSR] & M6811_TDRE))
652         {
653           return 0;
654         }
655 
656       controller->tx_char     = val;
657       controller->tx_has_char = 1;
658       if ((m68hc11_cpu->ios[M6811_SCCR2] & M6811_TE)
659           && controller->tx_poll_event == 0)
660         {
661           m68hc11sio_tx_poll (me, NULL);
662         }
663       return 1;
664 
665     default:
666       return 0;
667     }
668   return nr_bytes;
669 }
670 
671 
672 const struct hw_descriptor dv_m68hc11sio_descriptor[] = {
673   { "m68hc11sio", m68hc11sio_finish },
674   { "m68hc12sio", m68hc11sio_finish },
675   { NULL },
676 };
677 
678