a1e3ddbefd2d67fc2ebe44d0d8346bbe714e409d
[external/binutils.git] / sim / mips / dv-tx3904sio.c
1 /*  This file is part of the program GDB, the GNU debugger.
2     
3     Copyright (C) 1998 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 2 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, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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_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_SET_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 };