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