xref: /netbsd-src/external/gpl3/gdb/dist/sim/mips/dv-tx3904sio.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*  This file is part of the program GDB, the GNU debugger.
2 
3     Copyright (C) 1998, 1999, 2007, 2008, 2009, 2010, 2011
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) free(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   free(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 };
623