OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [sim/] [m68hc11/] [dv-m68hc11sio.c] - Blame information for rev 866

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 330 jeremybenn
/*  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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.