OSDN Git Service

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