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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [mips/] [dv-tx3904sio.c] - Blame information for rev 298

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

Line No. Rev Author Line
1 24 jeremybenn
/*  This file is part of the program GDB, the GNU debugger.
2
 
3
    Copyright (C) 1998, 1999, 2007, 2008 Free Software Foundation, Inc.
4
    Contributed by Cygnus Solutions.
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
19
    */
20
 
21
 
22
#include "sim-main.h"
23
#include "hw-main.h"
24
#include "dv-sockser.h"
25
#include "sim-assert.h"
26
 
27
 
28
/* DEVICE
29
 
30
 
31
   tx3904sio - tx3904 serial I/O
32
 
33
 
34
   DESCRIPTION
35
 
36
 
37
   Implements one tx3904 serial I/O controller described in the tx3904
38
   user guide.  Three instances are required for SIO0 and SIO1 within
39
   the tx3904, at different base addresses.
40
 
41
   Both internal and system clocks are synthesized as divided versions
42
   of the simulator clock.
43
 
44
   There is no support for:
45
    - CTS/RTS flow control
46
    - baud rate emulation - use infinite speed instead
47
    - general frame format - use 8N1
48
    - multi-controller system
49
    - DMA - use interrupt-driven or polled-I/O instead
50
 
51
 
52
   PROPERTIES
53
 
54
 
55
   reg <base> <length>
56
 
57
   Base of SIO control register bank.  <length> must equal 0x100.
58
   Register offsets:       0: SLCR: line control register
59
                           4: SLSR: line status register
60
                           8: SDICR: DMA/interrupt control register
61
                          12: SDISR: DMA/interrupt status register
62
                          16: SFCR: FIFO control register
63
                          20: SBGR: baud rate control register
64
                          32: transfer FIFO buffer
65
                          48: transfer FIFO buffer
66
 
67
   backend {tcp | stdio}
68
 
69
   Use dv-sockser TCP-port backend or stdio for backend.  Default: stdio.
70
 
71
 
72
 
73
   PORTS
74
 
75
 
76
   int (output)
77
 
78
   Interrupt port.  An event is generated when a timer interrupt
79
   occurs.
80
 
81
 
82
   reset (input)
83
 
84
   Reset port.
85
 
86
   */
87
 
88
 
89
 
90
/* static functions */
91
 
92
struct tx3904sio_fifo;
93
 
94
static void tx3904sio_tickle(struct hw*);
95
static int tx3904sio_fifo_nonempty(struct hw*, struct tx3904sio_fifo*);
96
static char tx3904sio_fifo_pop(struct hw*, struct tx3904sio_fifo*);
97
static void tx3904sio_fifo_push(struct hw*, struct tx3904sio_fifo*, char);
98
static void tx3904sio_fifo_reset(struct hw*, struct tx3904sio_fifo*);
99
static void tx3904sio_poll(struct hw*, void* data);
100
 
101
 
102
/* register numbers; each is one word long */
103
enum
104
{
105
  SLCR_REG = 0,
106
  SLSR_REG = 1,
107
  SDICR_REG = 2,
108
  SDISR_REG = 3,
109
  SFCR_REG = 4,
110
  SBGR_REG = 5,
111
  TFIFO_REG = 8,
112
  SFIFO_REG = 12,
113
};
114
 
115
 
116
 
117
/* port ID's */
118
 
119
enum
120
 {
121
  RESET_PORT,
122
  INT_PORT,
123
};
124
 
125
 
126
static const struct hw_port_descriptor tx3904sio_ports[] =
127
{
128
  { "int", INT_PORT, 0, output_port, },
129
  { "reset", RESET_PORT, 0, input_port, },
130
  { NULL, },
131
};
132
 
133
 
134
 
135
/* Generic FIFO */
136
struct tx3904sio_fifo
137
{
138
  int size, used;
139
  unsigned_1 *buffer;
140
};
141
 
142
 
143
 
144
/* The timer/counter register internal state.  Note that we store
145
   state using the control register images, in host endian order. */
146
 
147
struct tx3904sio
148
{
149
  address_word base_address; /* control register base */
150
  enum {sio_tcp, sio_stdio} backend; /* backend */
151
 
152
  struct tx3904sio_fifo rx_fifo, tx_fifo; /* FIFOs */
153
 
154
  unsigned_4 slcr;
155
#define SLCR_WR_MASK        0xe17f0000U
156
#define SLCR_SET_BYTE(c,o,b) ((c)->slcr = SLCR_WR_MASK & (((c)->slcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
157
  unsigned_4 slsr;
158
#define SLSR_WR_MASK        0x00000000 /* UFER/UPER/UOER unimplemented */
159
  unsigned_4 sdicr;
160
#define SDICR_WR_MASK       0x000f0000U
161
#define SDICR_SET_BYTE(c,o,b) ((c)->sdicr = SDICR_WR_MASK & (((c)->sdicr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
162
#define SDICR_GET_SDMAE(c)  ((c)->sdicr & 0x00080000)
163
#define SDICR_GET_ERIE(c)   ((c)->sdicr & 0x00040000)
164
#define SDICR_GET_TDIE(c)   ((c)->sdicr & 0x00020000)
165
#define SDICR_GET_RDIE(c)   ((c)->sdicr & 0x00010000)
166
  unsigned_4 sdisr;
167
#define SDISR_WR_MASK       0x00070000U
168
#define SDISR_SET_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
169
#define SDISR_CLEAR_FLAG_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) & ((b)<< (o)*8)))
170
#define SDISR_GET_TDIS(c)   ((c)->sdisr & 0x00020000)
171
#define SDISR_SET_TDIS(c)   ((c)->sdisr |= 0x00020000)
172
#define SDISR_GET_RDIS(c)   ((c)->sdisr & 0x00010000)
173
#define SDISR_SET_RDIS(c)   ((c)->sdisr |= 0x00010000)
174
  unsigned_4 sfcr;
175
#define SFCR_WR_MASK       0x001f0000U
176
#define SFCR_SET_BYTE(c,o,b) ((c)->sfcr = SFCR_WR_MASK & (((c)->sfcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
177
#define SFCR_GET_TFRST(c)   ((c)->sfcr & 0x00040000)
178
#define SFCR_GET_RFRST(c)   ((c)->sfcr & 0x00020000)
179
#define SFCR_GET_FRSTE(c)   ((c)->sfcr & 0x00010000)
180
  unsigned_4 sbgr;
181
#define SBGR_WR_MASK       0x03ff0000U
182
#define SBGR_SET_BYTE(c,o,b) ((c)->sbgr = SBGR_WR_MASK & (((c)->sbgr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
183
 
184
  /* Periodic I/O polling */
185
  struct hw_event* poll_event;
186
};
187
 
188
 
189
 
190
/* Finish off the partially created hw device.  Attach our local
191
   callbacks.  Wire up our port names etc */
192
 
193
static hw_io_read_buffer_method tx3904sio_io_read_buffer;
194
static hw_io_write_buffer_method tx3904sio_io_write_buffer;
195
static hw_port_event_method tx3904sio_port_event;
196
 
197
 
198
static void
199
attach_tx3904sio_regs (struct hw *me,
200
                      struct tx3904sio *controller)
201
{
202
  unsigned_word attach_address;
203
  int attach_space;
204
  unsigned attach_size;
205
  reg_property_spec reg;
206
 
207
  if (hw_find_property (me, "reg") == NULL)
208
    hw_abort (me, "Missing \"reg\" property");
209
 
210
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
211
    hw_abort (me, "\"reg\" property must contain one addr/size entry");
212
 
213
  hw_unit_address_to_attach_address (hw_parent (me),
214
                                     &reg.address,
215
                                     &attach_space,
216
                                     &attach_address,
217
                                     me);
218
  hw_unit_size_to_attach_size (hw_parent (me),
219
                               &reg.size,
220
                               &attach_size, me);
221
 
222
  hw_attach_address (hw_parent (me), 0,
223
                     attach_space, attach_address, attach_size,
224
                     me);
225
 
226
  if(hw_find_property(me, "backend") != NULL)
227
    {
228
      const char* value = hw_find_string_property(me, "backend");
229
      if(! strcmp(value, "tcp"))
230
        controller->backend = sio_tcp;
231
      else if(! strcmp(value, "stdio"))
232
        controller->backend = sio_stdio;
233
      else
234
        hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value);
235
    }
236
 
237
  controller->base_address = attach_address;
238
}
239
 
240
 
241
static void
242
tx3904sio_finish (struct hw *me)
243
{
244
  struct tx3904sio *controller;
245
 
246
  controller = HW_ZALLOC (me, struct tx3904sio);
247
  set_hw_data (me, controller);
248
  set_hw_io_read_buffer (me, tx3904sio_io_read_buffer);
249
  set_hw_io_write_buffer (me, tx3904sio_io_write_buffer);
250
  set_hw_ports (me, tx3904sio_ports);
251
  set_hw_port_event (me, tx3904sio_port_event);
252
 
253
  /* Preset defaults */
254
  controller->backend = sio_stdio;
255
 
256
  /* Attach ourself to our parent bus */
257
  attach_tx3904sio_regs (me, controller);
258
 
259
  /* Initialize to reset state */
260
  tx3904sio_fifo_reset(me, & controller->rx_fifo);
261
  tx3904sio_fifo_reset(me, & controller->tx_fifo);
262
  controller->slsr = controller->sdicr
263
    = controller->sdisr = controller->sfcr
264
    = controller->sbgr = 0;
265
  controller->slcr = 0x40000000; /* set TWUB */
266
  controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
267
  controller->poll_event = NULL;
268
}
269
 
270
 
271
 
272
/* An event arrives on an interrupt port */
273
 
274
static void
275
tx3904sio_port_event (struct hw *me,
276
                     int my_port,
277
                     struct hw *source,
278
                     int source_port,
279
                     int level)
280
{
281
  struct tx3904sio *controller = hw_data (me);
282
 
283
  switch (my_port)
284
    {
285
    case RESET_PORT:
286
      {
287
        HW_TRACE ((me, "reset"));
288
 
289
        tx3904sio_fifo_reset(me, & controller->rx_fifo);
290
        tx3904sio_fifo_reset(me, & controller->tx_fifo);
291
        controller->slsr = controller->sdicr
292
          = controller->sdisr = controller->sfcr
293
          = controller->sbgr = 0;
294
        controller->slcr = 0x40000000; /* set TWUB */
295
        controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
296
        /* Don't interfere with I/O poller. */
297
        break;
298
      }
299
 
300
    default:
301
      hw_abort (me, "Event on unknown port %d", my_port);
302
      break;
303
    }
304
}
305
 
306
 
307
/* generic read/write */
308
 
309
static unsigned
310
tx3904sio_io_read_buffer (struct hw *me,
311
                         void *dest,
312
                         int space,
313
                         unsigned_word base,
314
                         unsigned nr_bytes)
315
{
316
  struct tx3904sio *controller = hw_data (me);
317
  unsigned byte;
318
 
319
  HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
320
 
321
  /* tickle fifos */
322
  tx3904sio_tickle(me);
323
 
324
  for (byte = 0; byte < nr_bytes; byte++)
325
    {
326
      address_word address = base + byte;
327
      int reg_number = (address - controller->base_address) / 4;
328
      int reg_offset = (address - controller->base_address) % 4;
329
      unsigned_4 register_value; /* in target byte order */
330
 
331
      /* fill in entire register_value word */
332
      switch (reg_number)
333
        {
334
        case SLCR_REG: register_value = controller->slcr; break;
335
        case SLSR_REG: register_value = controller->slsr; break;
336
        case SDICR_REG: register_value = controller->sdicr; break;
337
        case SDISR_REG: register_value = controller->sdisr; break;
338
        case SFCR_REG: register_value = controller->sfcr; break;
339
        case SBGR_REG: register_value = controller->sbgr; break;
340
        case TFIFO_REG: register_value = 0; break;
341
        case SFIFO_REG:
342
          /* consume rx fifo for MS byte */
343
          if(reg_offset == 0 && tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
344
            register_value = (tx3904sio_fifo_pop(me, & controller->rx_fifo) << 24);
345
          else
346
            register_value = 0;
347
          break;
348
        default: register_value = 0;
349
        }
350
 
351
      /* write requested byte out */
352
      register_value = H2T_4(register_value);
353
      /* HW_TRACE ((me, "byte %d %02x", reg_offset, ((char*)& register_value)[reg_offset])); */
354
      memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
355
    }
356
 
357
  return nr_bytes;
358
}
359
 
360
 
361
 
362
static unsigned
363
tx3904sio_io_write_buffer (struct hw *me,
364
                          const void *source,
365
                          int space,
366
                          unsigned_word base,
367
                          unsigned nr_bytes)
368
{
369
  struct tx3904sio *controller = hw_data (me);
370
  unsigned byte;
371
 
372
  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
373
  for (byte = 0; byte < nr_bytes; byte++)
374
    {
375
      address_word address = base + byte;
376
      unsigned_1 write_byte = ((const unsigned char*) source)[byte];
377
      int reg_number = (address - controller->base_address) / 4;
378
      int reg_offset = 3 - (address - controller->base_address) % 4;
379
 
380
      /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */
381
 
382
      /* fill in entire register_value word */
383
      switch (reg_number)
384
        {
385
        case SLCR_REG:
386
          SLCR_SET_BYTE(controller, reg_offset, write_byte);
387
          break;
388
 
389
        case SLSR_REG: /* unwriteable */ break;
390
 
391
        case SDICR_REG:
392
          {
393
            unsigned_4 last_int, next_int;
394
 
395
            /* deassert interrupt upon clear */
396
            last_int = controller->sdisr & controller->sdicr;
397
            /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x",
398
               controller->sdisr, controller->sdicr)); */
399
            SDICR_SET_BYTE(controller, reg_offset, write_byte);
400
            /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x",
401
               controller->sdisr, controller->sdicr)); */
402
            next_int = controller->sdisr & controller->sdicr;
403
 
404
            if(SDICR_GET_SDMAE(controller))
405
              hw_abort(me, "Cannot support DMA-driven sio.");
406
 
407
            if(~last_int & next_int) /* any bits set? */
408
              hw_port_event(me, INT_PORT, 1);
409
            if(last_int & ~next_int) /* any bits cleared? */
410
              hw_port_event(me, INT_PORT, 0);
411
          }
412
        break;
413
 
414
        case SDISR_REG:
415
          {
416
            unsigned_4 last_int, next_int;
417
 
418
            /* deassert interrupt upon clear */
419
            last_int = controller->sdisr & controller->sdicr;
420
            /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x",
421
               controller->sdisr, controller->sdicr)); */
422
            SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte);
423
            /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x",
424
               controller->sdisr, controller->sdicr)); */
425
            next_int = controller->sdisr & controller->sdicr;
426
 
427
            if(~last_int & next_int) /* any bits set? */
428
              hw_port_event(me, INT_PORT, 1);
429
            if(last_int & ~next_int) /* any bits cleared? */
430
              hw_port_event(me, INT_PORT, 0);
431
          }
432
        break;
433
 
434
        case SFCR_REG:
435
          SFCR_SET_BYTE(controller, reg_offset, write_byte);
436
          if(SFCR_GET_FRSTE(controller))
437
            {
438
              if(SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo);
439
              if(SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo);
440
            }
441
          break;
442
 
443
        case SBGR_REG:
444
          SBGR_SET_BYTE(controller, reg_offset, write_byte);
445
          break;
446
 
447
        case SFIFO_REG: /* unwriteable */ break;
448
 
449
        case TFIFO_REG:
450
          if(reg_offset == 3) /* first byte */
451
            tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte);
452
          break;
453
 
454
        default:
455
          HW_TRACE ((me, "write to illegal register %d", reg_number));
456
        }
457
    } /* loop over bytes */
458
 
459
  /* tickle fifos */
460
  tx3904sio_tickle(me);
461
 
462
  return nr_bytes;
463
}
464
 
465
 
466
 
467
 
468
 
469
 
470
/* Send enqueued characters from tx_fifo and trigger TX interrupt.
471
Receive characters into rx_fifo and trigger RX interrupt. */
472
void
473
tx3904sio_tickle(struct hw *me)
474
{
475
  struct tx3904sio* controller = hw_data(me);
476
  int c;
477
  char cc;
478
  unsigned_4 last_int, next_int;
479
 
480
  /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
481
  switch(controller->backend)
482
    {
483
    case sio_tcp:
484
 
485
      while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
486
        {
487
          cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
488
          dv_sockser_write(hw_system(me), cc);
489
          HW_TRACE ((me, "tcp output: %02x", cc));
490
        }
491
 
492
      c = dv_sockser_read(hw_system(me));
493
      while(c != -1)
494
        {
495
          cc = (char) c;
496
          HW_TRACE ((me, "tcp input: %02x", cc));
497
          tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
498
          c = dv_sockser_read(hw_system(me));
499
        }
500
      break;
501
 
502
    case sio_stdio:
503
 
504
      while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
505
        {
506
          cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
507
          sim_io_write_stdout(hw_system(me), & cc, 1);
508
          sim_io_flush_stdout(hw_system(me));
509
          HW_TRACE ((me, "stdio output: %02x", cc));
510
        }
511
 
512
      c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
513
      while(c == 1)
514
        {
515
          HW_TRACE ((me, "stdio input: %02x", cc));
516
          tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
517
          c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
518
        }
519
 
520
      break;
521
 
522
    default:
523
      hw_abort(me, "Illegal backend mode: %d", controller->backend);
524
    }
525
 
526
  /* Update RDIS / TDIS flags */
527
  last_int = controller->sdisr & controller->sdicr;
528
  /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
529
  if(tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
530
    SDISR_SET_RDIS(controller);
531
  if(! tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
532
    SDISR_SET_TDIS(controller);
533
  next_int = controller->sdisr & controller->sdicr;
534
  /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
535
 
536
  if(~last_int & next_int) /* any bits set? */
537
    hw_port_event(me, INT_PORT, 1);
538
  if(last_int & ~next_int) /* any bits cleared? */
539
    hw_port_event(me, INT_PORT, 0);
540
 
541
  /* Add periodic polling for this port, if it's not already going. */
542
  if(controller->poll_event == NULL)
543
    {
544
      controller->poll_event = hw_event_queue_schedule (me, 1000,
545
                                                        tx3904sio_poll, NULL);
546
 
547
    }
548
}
549
 
550
 
551
 
552
 
553
int
554
tx3904sio_fifo_nonempty(struct hw* me, struct tx3904sio_fifo* fifo)
555
{
556
  /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */
557
  return(fifo->used > 0);
558
}
559
 
560
 
561
char
562
tx3904sio_fifo_pop(struct hw* me, struct tx3904sio_fifo* fifo)
563
{
564
  char it;
565
  ASSERT(fifo->used > 0);
566
  ASSERT(fifo->buffer != NULL);
567
  it = fifo->buffer[0];
568
  memcpy(& fifo->buffer[0], & fifo->buffer[1], fifo->used - 1);
569
  fifo->used --;
570
  /* HW_TRACE ((me, "pop fifo -> %02x", it)); */
571
  return it;
572
}
573
 
574
 
575
void
576
tx3904sio_fifo_push(struct hw* me, struct tx3904sio_fifo* fifo, char it)
577
{
578
  /* HW_TRACE ((me, "push %02x -> fifo", it)); */
579
  if(fifo->size == fifo->used) /* full */
580
    {
581
      int next_size = fifo->size * 2 + 16;
582
      char* next_buf = zalloc(next_size);
583
      memcpy(next_buf, fifo->buffer, fifo->used);
584
 
585
      if(fifo->buffer != NULL) zfree(fifo->buffer);
586
      fifo->buffer = next_buf;
587
      fifo->size = next_size;
588
    }
589
 
590
  fifo->buffer[fifo->used] = it;
591
  fifo->used ++;
592
}
593
 
594
 
595
void
596
tx3904sio_fifo_reset(struct hw* me, struct tx3904sio_fifo* fifo)
597
{
598
  /* HW_TRACE ((me, "reset fifo")); */
599
  fifo->used = 0;
600
  fifo->size = 0;
601
  zfree(fifo->buffer);
602
  fifo->buffer = 0;
603
}
604
 
605
 
606
void
607
tx3904sio_poll(struct hw* me, void* ignored)
608
{
609
  struct tx3904sio* controller = hw_data (me);
610
  tx3904sio_tickle (me);
611
  hw_event_queue_deschedule (me, controller->poll_event);
612
  controller->poll_event = hw_event_queue_schedule (me, 1000,
613
                                                    tx3904sio_poll, NULL);
614
}
615
 
616
 
617
 
618
const struct hw_descriptor dv_tx3904sio_descriptor[] = {
619
  { "tx3904sio", tx3904sio_finish, },
620
  { NULL },
621
};

powered by: WebSVN 2.1.0

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