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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [m68hc11/] [dv-m68hc11sio.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/*  dv-m68hc11sio.c -- Simulation of the 68HC11 serial device.
2
    Copyright (C) 1999, 2000, 2001, 2007, 2008 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
 

powered by: WebSVN 2.1.0

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