dv-tx3904sio.c revision 1.1.1.3
1/*  This file is part of the program GDB, the GNU debugger.
2
3    Copyright (C) 1998-2014 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
92struct tx3904sio_fifo;
93
94static void tx3904sio_tickle(struct hw*);
95static int tx3904sio_fifo_nonempty(struct hw*, struct tx3904sio_fifo*);
96static char tx3904sio_fifo_pop(struct hw*, struct tx3904sio_fifo*);
97static void tx3904sio_fifo_push(struct hw*, struct tx3904sio_fifo*, char);
98static void tx3904sio_fifo_reset(struct hw*, struct tx3904sio_fifo*);
99static void tx3904sio_poll(struct hw*, void* data);
100
101
102/* register numbers; each is one word long */
103enum
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
119enum
120 {
121  RESET_PORT,
122  INT_PORT,
123};
124
125
126static 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 */
136struct 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
147struct 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
193static hw_io_read_buffer_method tx3904sio_io_read_buffer;
194static hw_io_write_buffer_method tx3904sio_io_write_buffer;
195static hw_port_event_method tx3904sio_port_event;
196
197
198static void
199attach_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
241static void
242tx3904sio_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
274static void
275tx3904sio_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
309static unsigned
310tx3904sio_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
362static unsigned
363tx3904sio_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.
471Receive characters into rx_fifo and trigger RX interrupt. */
472void
473tx3904sio_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
553int
554tx3904sio_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
561char
562tx3904sio_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
575void
576tx3904sio_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) free(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
595void
596tx3904sio_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  free(fifo->buffer);
602  fifo->buffer = 0;
603}
604
605
606void
607tx3904sio_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
618const struct hw_descriptor dv_tx3904sio_descriptor[] = {
619  { "tx3904sio", tx3904sio_finish, },
620  { NULL },
621};
622