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