Home | History | Annotate | Line # | Download | only in mips
      1 /*  This file is part of the program GDB, the GNU debugger.
      2 
      3     Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4     Contributed by Cygnus Solutions.
      5 
      6     This program is free software; you can redistribute it and/or modify
      7     it under the terms of the GNU General Public License as published by
      8     the Free Software Foundation; either version 3 of the License, or
      9     (at your option) any later version.
     10 
     11     This program is distributed in the hope that it will be useful,
     12     but WITHOUT ANY WARRANTY; without even the implied warranty of
     13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14     GNU General Public License for more details.
     15 
     16     You should have received a copy of the GNU General Public License
     17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 
     19     */
     20 
     21 /* This must come before any other includes.  */
     22 #include "defs.h"
     23 
     24 #include "sim-main.h"
     25 #include "hw-main.h"
     26 
     27 
     28 /* DEVICE
     29 
     30 
     31    tx3904irc - tx3904 interrupt controller
     32 
     33 
     34    DESCRIPTION
     35 
     36 
     37    Implements the tx3904 interrupt controller described in the tx3904
     38    user guide.  It does not include the interrupt detection circuit
     39    that preprocesses the eight external interrupts, so assumes that
     40    each event on an input interrupt port signals a new interrupt.
     41    That is, it implements edge- rather than level-triggered
     42    interrupts.
     43 
     44    This implementation does not support multiple concurrent
     45    interrupts.
     46 
     47 
     48    PROPERTIES
     49 
     50 
     51    reg <base> <length>
     52 
     53    Base of IRC control register bank.  <length> must equal 0x20.
     54    Registers offsets:       0: ISR: interrupt status register
     55                             4: IMR: interrupt mask register
     56                            16: ILR0: interrupt level register 3..0
     57                            20: ILR1: interrupt level register 7..4
     58                            24: ILR2: interrupt level register 11..8
     59                            28: ILR3: interrupt level register 15..12
     60 
     61 
     62 
     63    PORTS
     64 
     65 
     66    ip (output)
     67 
     68    Interrupt priority port.  An event is generated when an interrupt
     69    of a sufficient priority is passed through the IRC.  The value
     70    associated with the event is the interrupt level (16-31), as given
     71    for bits IP[5:0] in the book TMPR3904F Rev. 2.0, pg. 11-3.  Note
     72    that even though INT[0] is tied externally to IP[5], we simulate
     73    it as passing through the controller.
     74 
     75    An output level of zero signals the clearing of a level interrupt.
     76 
     77 
     78    int0-7 (input)
     79 
     80    External interrupts.  Level = 0 -> level interrupt cleared.
     81 
     82 
     83    dmac0-3 (input)
     84 
     85    DMA internal interrupts, correspond to DMA channels 0-3.  Level = 0 -> level interrupt cleared.
     86 
     87 
     88    sio0-1 (input)
     89 
     90    SIO internal interrupts.  Level = 0 -> level interrupt cleared.
     91 
     92 
     93    tmr0-2 (input)
     94 
     95    Timer internal interrupts.  Level = 0 -> level interrupt cleared.
     96 
     97    */
     98 
     99 
    100 
    101 
    102 
    103 /* register numbers; each is one word long */
    104 enum
    105 {
    106   ISR_REG = 0,
    107   IMR_REG = 1,
    108   ILR0_REG = 4,
    109   ILR1_REG = 5,
    110   ILR2_REG = 6,
    111   ILR3_REG = 7,
    112 };
    113 
    114 
    115 /* port ID's */
    116 
    117 enum
    118 {
    119   /* inputs, ordered to correspond to interrupt sources 0..15 */
    120   INT1_PORT = 0, INT2_PORT, INT3_PORT, INT4_PORT, INT5_PORT, INT6_PORT, INT7_PORT,
    121   DMAC3_PORT, DMAC2_PORT, DMAC1_PORT, DMAC0_PORT, SIO0_PORT, SIO1_PORT,
    122   TMR0_PORT, TMR1_PORT, TMR2_PORT,
    123 
    124   /* special INT[0] port */
    125   INT0_PORT,
    126 
    127   /* reset */
    128   RESET_PORT,
    129 
    130   /* output */
    131   IP_PORT
    132 };
    133 
    134 
    135 static const struct hw_port_descriptor tx3904irc_ports[] = {
    136 
    137   /* interrupt output */
    138 
    139   { "ip", IP_PORT, 0, output_port, },
    140 
    141   /* interrupt inputs (as names) */
    142   /* in increasing order of level number */
    143 
    144   { "int1", INT1_PORT, 0, input_port, },
    145   { "int2", INT2_PORT, 0, input_port, },
    146   { "int3", INT3_PORT, 0, input_port, },
    147   { "int4", INT4_PORT, 0, input_port, },
    148   { "int5", INT5_PORT, 0, input_port, },
    149   { "int6", INT6_PORT, 0, input_port, },
    150   { "int7", INT7_PORT, 0, input_port, },
    151 
    152   { "dmac3", DMAC3_PORT, 0, input_port, },
    153   { "dmac2", DMAC2_PORT, 0, input_port, },
    154   { "dmac1", DMAC1_PORT, 0, input_port, },
    155   { "dmac0", DMAC0_PORT, 0, input_port, },
    156 
    157   { "sio0", SIO0_PORT, 0, input_port, },
    158   { "sio1", SIO1_PORT, 0, input_port, },
    159 
    160   { "tmr0", TMR0_PORT, 0, input_port, },
    161   { "tmr1", TMR1_PORT, 0, input_port, },
    162   { "tmr2", TMR2_PORT, 0, input_port, },
    163 
    164   { "reset", RESET_PORT, 0, input_port, },
    165   { "int0", INT0_PORT, 0, input_port, },
    166 
    167   { NULL, },
    168 };
    169 
    170 
    171 #define NR_SOURCES (TMR3_PORT - INT1_PORT + 1) /* 16: number of interrupt sources */
    172 
    173 
    174 /* The interrupt controller register internal state.  Note that we
    175    store state using the control register images, in host endian
    176    order. */
    177 
    178 struct tx3904irc {
    179   address_word base_address; /* control register base */
    180   unsigned_4 isr;
    181 #define ISR_SET(c, s) ((c)->isr &= ~(1 << (s)))
    182   unsigned_4 imr;
    183 #define IMR_GET(c) ((c)->imr)
    184   unsigned_4 ilr[4];
    185 #define ILR_GET(c, s) LSEXTRACTED32((c)->ilr[(s) / 4], (s) % 4 * 8 + 2, (s) % 4 * 8)
    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 tx3904irc_io_read_buffer;
    194 static hw_io_write_buffer_method tx3904irc_io_write_buffer;
    195 static hw_port_event_method tx3904irc_port_event;
    196 
    197 static void
    198 attach_tx3904irc_regs (struct hw *me,
    199 		      struct tx3904irc *controller)
    200 {
    201   unsigned_word attach_address;
    202   int attach_space;
    203   unsigned attach_size;
    204   reg_property_spec reg;
    205 
    206   if (hw_find_property (me, "reg") == NULL)
    207     hw_abort (me, "Missing \"reg\" property");
    208 
    209   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    210     hw_abort (me, "\"reg\" property must contain one addr/size entry");
    211 
    212   hw_unit_address_to_attach_address (hw_parent (me),
    213 				     &reg.address,
    214 				     &attach_space,
    215 				     &attach_address,
    216 				     me);
    217   hw_unit_size_to_attach_size (hw_parent (me),
    218 			       &reg.size,
    219 			       &attach_size, me);
    220 
    221   hw_attach_address (hw_parent (me), 0,
    222 		     attach_space, attach_address, attach_size,
    223 		     me);
    224 
    225   controller->base_address = attach_address;
    226 }
    227 
    228 
    229 static void
    230 tx3904irc_finish (struct hw *me)
    231 {
    232   struct tx3904irc *controller;
    233 
    234   controller = HW_ZALLOC (me, struct tx3904irc);
    235   set_hw_data (me, controller);
    236   set_hw_io_read_buffer (me, tx3904irc_io_read_buffer);
    237   set_hw_io_write_buffer (me, tx3904irc_io_write_buffer);
    238   set_hw_ports (me, tx3904irc_ports);
    239   set_hw_port_event (me, tx3904irc_port_event);
    240 
    241   /* Attach ourself to our parent bus */
    242   attach_tx3904irc_regs (me, controller);
    243 
    244   /* Initialize to reset state */
    245   controller->isr = 0x0000ffff;
    246   controller->imr = 0;
    247   controller->ilr[0] =
    248     controller->ilr[1] =
    249     controller->ilr[2] =
    250     controller->ilr[3] = 0;
    251 }
    252 
    253 
    254 
    255 /* An event arrives on an interrupt port */
    256 
    257 static void
    258 tx3904irc_port_event (struct hw *me,
    259 		     int my_port,
    260 		     struct hw *source_dev,
    261 		     int source_port,
    262 		     int level)
    263 {
    264   struct tx3904irc *controller = hw_data (me);
    265 
    266   /* handle deactivated interrupt */
    267   if (level == 0)
    268     {
    269       HW_TRACE ((me, "interrupt cleared on port %d", my_port));
    270       hw_port_event(me, IP_PORT, 0);
    271       return;
    272     }
    273 
    274   switch (my_port)
    275     {
    276     case INT0_PORT:
    277       {
    278 	int ip_number = 32; /* compute IP[5:0] */
    279 	HW_TRACE ((me, "port-event INT[0]"));
    280 	hw_port_event(me, IP_PORT, ip_number);
    281 	break;
    282       }
    283 
    284     case INT1_PORT: case INT2_PORT: case INT3_PORT: case INT4_PORT:
    285     case INT5_PORT: case INT6_PORT: case INT7_PORT: case DMAC3_PORT:
    286     case DMAC2_PORT: case DMAC1_PORT: case DMAC0_PORT: case SIO0_PORT:
    287     case SIO1_PORT: case TMR0_PORT: case TMR1_PORT: case TMR2_PORT:
    288       {
    289 	int source = my_port - INT1_PORT;
    290 
    291 	HW_TRACE ((me, "interrupt asserted on port %d", source));
    292 	ISR_SET(controller, source);
    293 	if (ILR_GET(controller, source) > IMR_GET(controller))
    294 	  {
    295 	    int ip_number = 16 + source; /* compute IP[4:0] */
    296 	    HW_TRACE ((me, "interrupt level %d", ILR_GET(controller, source)));
    297 	    hw_port_event(me, IP_PORT, ip_number);
    298 	  }
    299 	break;
    300       }
    301 
    302     case RESET_PORT:
    303       {
    304 	HW_TRACE ((me, "reset"));
    305 	controller->isr = 0x0000ffff;
    306 	controller->imr = 0;
    307 	controller->ilr[0] =
    308 	  controller->ilr[1] =
    309 	  controller->ilr[2] =
    310 	  controller->ilr[3] = 0;
    311 	break;
    312       }
    313 
    314     case IP_PORT:
    315       hw_abort (me, "Event on output port %d", my_port);
    316       break;
    317 
    318     default:
    319       hw_abort (me, "Event on unknown port %d", my_port);
    320       break;
    321     }
    322 }
    323 
    324 
    325 /* generic read/write */
    326 
    327 static unsigned
    328 tx3904irc_io_read_buffer (struct hw *me,
    329 			 void *dest,
    330 			 int space,
    331 			 unsigned_word base,
    332 			 unsigned nr_bytes)
    333 {
    334   struct tx3904irc *controller = hw_data (me);
    335   unsigned byte;
    336 
    337   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
    338   for (byte = 0; byte < nr_bytes; byte++)
    339     {
    340       address_word address = base + byte;
    341       int reg_number = (address - controller->base_address) / 4;
    342       int reg_offset = (address - controller->base_address) % 4;
    343       unsigned_4 register_value; /* in target byte order */
    344 
    345       /* fill in entire register_value word */
    346       switch (reg_number)
    347 	{
    348 	case ISR_REG: register_value = controller->isr; break;
    349 	case IMR_REG: register_value = controller->imr; break;
    350 	case ILR0_REG: register_value = controller->ilr[0]; break;
    351 	case ILR1_REG: register_value = controller->ilr[1]; break;
    352 	case ILR2_REG: register_value = controller->ilr[2]; break;
    353 	case ILR3_REG: register_value = controller->ilr[3]; break;
    354 	default: register_value = 0;
    355 	}
    356 
    357       /* write requested byte out */
    358       register_value = H2T_4(register_value);
    359       memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
    360     }
    361 
    362   return nr_bytes;
    363 }
    364 
    365 
    366 
    367 static unsigned
    368 tx3904irc_io_write_buffer (struct hw *me,
    369 			  const void *source,
    370 			  int space,
    371 			  unsigned_word base,
    372 			  unsigned nr_bytes)
    373 {
    374   struct tx3904irc *controller = hw_data (me);
    375   unsigned byte;
    376 
    377   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
    378   for (byte = 0; byte < nr_bytes; byte++)
    379     {
    380       address_word address = base + byte;
    381       int reg_number = (address - controller->base_address) / 4;
    382       int reg_offset = (address - controller->base_address) % 4;
    383       unsigned_4* register_ptr;
    384       unsigned_4 register_value = 0;
    385 
    386       /* fill in entire register_value word */
    387       switch (reg_number)
    388 	{
    389 	case ISR_REG: register_ptr = & controller->isr; break;
    390 	case IMR_REG: register_ptr = & controller->imr; break;
    391 	case ILR0_REG: register_ptr = & controller->ilr[0]; break;
    392 	case ILR1_REG: register_ptr = & controller->ilr[1]; break;
    393 	case ILR2_REG: register_ptr = & controller->ilr[2]; break;
    394 	case ILR3_REG: register_ptr = & controller->ilr[3]; break;
    395 	default: register_ptr = & register_value; /* used as a dummy */
    396 	}
    397 
    398       /* HW_TRACE ((me, "reg %d pre: %08lx", reg_number, (long) *register_ptr)); */
    399 
    400       /* overwrite requested byte */
    401       register_value = H2T_4(* register_ptr);
    402       memcpy (((char*)&register_value)+reg_offset, (const char*)source + byte, 1);
    403       * register_ptr = T2H_4(register_value);
    404 
    405       /* HW_TRACE ((me, "post: %08lx", (long) *register_ptr)); */
    406     }
    407   return nr_bytes;
    408 }
    409 
    410 
    411 const struct hw_descriptor dv_tx3904irc_descriptor[] = {
    412   { "tx3904irc", tx3904irc_finish, },
    413   { NULL },
    414 };
    415