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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [mips/] [dv-tx3904sio.c] - Blame information for rev 868

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

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

powered by: WebSVN 2.1.0

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