Home | History | Annotate | Line # | Download | only in mips
dv-tx3904cpu.c revision 1.3
      1  1.1  christos /*  This file is part of the program GDB, the GNU debugger.
      2  1.1  christos 
      3  1.3  christos     Copyright (C) 1998-2015 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 
     25  1.1  christos /* DEVICE
     26  1.1  christos 
     27  1.1  christos 
     28  1.1  christos    tx3904cpu - tx3904 cpu virtual device
     29  1.1  christos 
     30  1.1  christos 
     31  1.1  christos    DESCRIPTION
     32  1.1  christos 
     33  1.1  christos 
     34  1.1  christos    Implements the external tx3904 functionality.  This includes the
     35  1.1  christos    delivery of of interrupts generated from other devices and the
     36  1.1  christos    handling of device specific registers.
     37  1.1  christos 
     38  1.1  christos 
     39  1.1  christos    PROPERTIES
     40  1.1  christos 
     41  1.1  christos    none
     42  1.1  christos 
     43  1.1  christos 
     44  1.1  christos    PORTS
     45  1.1  christos 
     46  1.1  christos 
     47  1.1  christos    reset (input)
     48  1.1  christos 
     49  1.1  christos    Currently ignored.
     50  1.1  christos 
     51  1.1  christos 
     52  1.1  christos    nmi (input)
     53  1.1  christos 
     54  1.1  christos    Deliver a non-maskable interrupt to the processor.
     55  1.1  christos 
     56  1.1  christos 
     57  1.1  christos    level (input)
     58  1.1  christos 
     59  1.1  christos    Deliver a maskable interrupt of given level, corresponding to
     60  1.1  christos    IP[5:0], to processor.
     61  1.1  christos 
     62  1.1  christos 
     63  1.1  christos 
     64  1.1  christos    BUGS
     65  1.1  christos 
     66  1.1  christos 
     67  1.1  christos    When delivering an interrupt, this code assumes that there is only
     68  1.1  christos    one processor (number 0).
     69  1.1  christos 
     70  1.1  christos    This code does not attempt to be efficient at handling pending
     71  1.1  christos    interrupts.  It simply schedules the interrupt delivery handler
     72  1.1  christos    every instruction cycle until all pending interrupts go away.  An
     73  1.1  christos    alternative implementation might modify instructions that change
     74  1.1  christos    the PSW and have them check to see if the change makes an interrupt
     75  1.1  christos    delivery possible.
     76  1.1  christos 
     77  1.1  christos    */
     78  1.1  christos 
     79  1.1  christos 
     80  1.1  christos 
     81  1.1  christos struct tx3904cpu {
     82  1.1  christos   /* Pending interrupts for delivery by event handler */
     83  1.1  christos   int pending_reset, pending_nmi, pending_level;
     84  1.1  christos   struct hw_event* event;
     85  1.1  christos };
     86  1.1  christos 
     87  1.1  christos 
     88  1.1  christos 
     89  1.1  christos /* input port ID's */
     90  1.1  christos 
     91  1.1  christos enum {
     92  1.1  christos   RESET_PORT,
     93  1.1  christos   NMI_PORT,
     94  1.1  christos   LEVEL_PORT,
     95  1.1  christos };
     96  1.1  christos 
     97  1.1  christos 
     98  1.1  christos static const struct hw_port_descriptor tx3904cpu_ports[] = {
     99  1.1  christos 
    100  1.1  christos   /* interrupt inputs */
    101  1.1  christos   { "reset", RESET_PORT, 0, input_port, },
    102  1.1  christos   { "nmi", NMI_PORT, 0, input_port, },
    103  1.1  christos   { "level", LEVEL_PORT, 0, input_port, },
    104  1.1  christos 
    105  1.1  christos   { NULL, },
    106  1.1  christos };
    107  1.1  christos 
    108  1.1  christos 
    109  1.1  christos /* Finish off the partially created hw device.  Attach our local
    110  1.1  christos    callbacks.  Wire up our port names etc */
    111  1.1  christos 
    112  1.1  christos static hw_port_event_method tx3904cpu_port_event;
    113  1.1  christos 
    114  1.1  christos 
    115  1.1  christos 
    116  1.1  christos static void
    117  1.1  christos tx3904cpu_finish (struct hw *me)
    118  1.1  christos {
    119  1.1  christos   struct tx3904cpu *controller;
    120  1.1  christos 
    121  1.1  christos   controller = HW_ZALLOC (me, struct tx3904cpu);
    122  1.1  christos   set_hw_data (me, controller);
    123  1.1  christos   set_hw_ports (me, tx3904cpu_ports);
    124  1.1  christos   set_hw_port_event (me, tx3904cpu_port_event);
    125  1.1  christos 
    126  1.1  christos   /* Initialize the pending interrupt flags */
    127  1.1  christos   controller->pending_level = 0;
    128  1.1  christos   controller->pending_reset = 0;
    129  1.1  christos   controller->pending_nmi = 0;
    130  1.1  christos   controller->event = NULL;
    131  1.1  christos }
    132  1.1  christos 
    133  1.1  christos 
    134  1.1  christos 
    135  1.1  christos /* An event arrives on an interrupt port */
    136  1.1  christos 
    137  1.1  christos static void
    138  1.1  christos deliver_tx3904cpu_interrupt (struct hw *me,
    139  1.1  christos 			    void *data)
    140  1.1  christos {
    141  1.1  christos   struct tx3904cpu *controller = hw_data (me);
    142  1.1  christos   SIM_DESC sd = hw_system (me);
    143  1.1  christos   sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
    144  1.1  christos   address_word cia = CIA_GET (cpu);
    145  1.1  christos 
    146  1.1  christos #define CPU cpu
    147  1.1  christos #define SD current_state
    148  1.1  christos 
    149  1.1  christos   if (controller->pending_reset)
    150  1.1  christos     {
    151  1.1  christos       controller->pending_reset = 0;
    152  1.1  christos       HW_TRACE ((me, "reset pc=0x%08lx", (long) CIA_GET (cpu)));
    153  1.1  christos       SignalExceptionNMIReset();
    154  1.1  christos     }
    155  1.1  christos   else if (controller->pending_nmi)
    156  1.1  christos     {
    157  1.1  christos       controller->pending_nmi = 0;
    158  1.1  christos       HW_TRACE ((me, "nmi pc=0x%08lx", (long) CIA_GET (cpu)));
    159  1.1  christos       SignalExceptionNMIReset();
    160  1.1  christos     }
    161  1.1  christos   else if (controller->pending_level)
    162  1.1  christos     {
    163  1.1  christos       HW_TRACE ((me, "interrupt level=%d pc=0x%08lx sr=0x%08lx",
    164  1.1  christos 		 controller->pending_level,
    165  1.1  christos 		 (long) CIA_GET (cpu), (long) SR));
    166  1.1  christos 
    167  1.1  christos       /* Clear CAUSE register.  It may stay this way if the interrupt
    168  1.1  christos 	 was cleared with a negative pending_level. */
    169  1.1  christos       CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
    170  1.1  christos 
    171  1.1  christos       if(controller->pending_level > 0) /* interrupt set */
    172  1.1  christos 	{
    173  1.1  christos 	  /* set hardware-interrupt subfields of CAUSE register */
    174  1.1  christos 	  CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift;
    175  1.1  christos 
    176  1.1  christos 	  /* check for enabled / unmasked interrupts */
    177  1.1  christos 	  if((SR & status_IEc) &&
    178  1.1  christos 	     (controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
    179  1.1  christos 	    {
    180  1.1  christos 	      controller->pending_level = 0;
    181  1.1  christos 	      SignalExceptionInterrupt(0 /* dummy value */);
    182  1.1  christos 	    }
    183  1.1  christos 	  else
    184  1.1  christos 	    {
    185  1.1  christos 	      /* reschedule soon */
    186  1.1  christos 	      if(controller->event != NULL)
    187  1.1  christos 		hw_event_queue_deschedule(me, controller->event);
    188  1.1  christos 	      controller->event =
    189  1.1  christos 		hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
    190  1.1  christos 	    }
    191  1.1  christos 	} /* interrupt set */
    192  1.1  christos     }
    193  1.1  christos #undef CPU cpu
    194  1.1  christos #undef SD current_state
    195  1.1  christos }
    196  1.1  christos 
    197  1.1  christos 
    198  1.1  christos static void
    199  1.1  christos tx3904cpu_port_event (struct hw *me,
    200  1.1  christos 		     int my_port,
    201  1.1  christos 		     struct hw *source,
    202  1.1  christos 		     int source_port,
    203  1.1  christos 		     int level)
    204  1.1  christos {
    205  1.1  christos   struct tx3904cpu *controller = hw_data (me);
    206  1.1  christos 
    207  1.1  christos   switch (my_port)
    208  1.1  christos     {
    209  1.1  christos     case RESET_PORT:
    210  1.1  christos       controller->pending_reset = 1;
    211  1.1  christos       HW_TRACE ((me, "port-in reset"));
    212  1.1  christos       break;
    213  1.1  christos 
    214  1.1  christos     case NMI_PORT:
    215  1.1  christos       controller->pending_nmi = 1;
    216  1.1  christos       HW_TRACE ((me, "port-in nmi"));
    217  1.1  christos       break;
    218  1.1  christos 
    219  1.1  christos     case LEVEL_PORT:
    220  1.1  christos       /* level == 0 means that the interrupt was cleared */
    221  1.1  christos       if(level == 0)
    222  1.1  christos 	controller->pending_level = -1; /* signal end of interrupt */
    223  1.1  christos       else
    224  1.1  christos 	controller->pending_level = level;
    225  1.1  christos       HW_TRACE ((me, "port-in level=%d", level));
    226  1.1  christos       break;
    227  1.1  christos 
    228  1.1  christos     default:
    229  1.1  christos       hw_abort (me, "bad switch");
    230  1.1  christos       break;
    231  1.1  christos     }
    232  1.1  christos 
    233  1.1  christos   /* Schedule an event to be delivered immediately after current
    234  1.1  christos      instruction. */
    235  1.1  christos   if(controller->event != NULL)
    236  1.1  christos     hw_event_queue_deschedule(me, controller->event);
    237  1.1  christos   controller->event =
    238  1.1  christos     hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
    239  1.1  christos }
    240  1.1  christos 
    241  1.1  christos 
    242  1.1  christos const struct hw_descriptor dv_tx3904cpu_descriptor[] = {
    243  1.1  christos   { "tx3904cpu", tx3904cpu_finish, },
    244  1.1  christos   { NULL },
    245  1.1  christos };
    246