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