Search
lxdream.org :: lxdream/src/sh4/intc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/intc.c
changeset 1187:266e7a1bae90
prev975:007bf7eb944f
author nkeynes
date Fri Dec 02 18:14:27 2011 +1000 (12 years ago)
permissions -rw-r--r--
last change Handle calls to sh4_disasm_instruction when the memory isn't mapped
(as can happen if we try to print a translated block that's been unmapped)
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * SH4 onboard interrupt controller (INTC) implementation
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <assert.h>
    20 #include "sh4mmio.h"
    21 #include "sh4core.h"
    22 #include "intc.h"
    23 #include "eventq.h"
    25 struct intc_sources_t {
    26     char *name;
    27     uint32_t code;
    28 } intc_sources[INT_NUM_SOURCES] = {
    29         { "IRQ0", 0x200 },  { "IRQ1", 0x220 },  { "IRQ2", 0x240 },
    30         { "IRQ3", 0x260 },  { "IRQ4", 0x280 },  { "IRQ5", 0x2A0 },
    31         { "IRQ6", 0x2C0 },  { "IRQ7", 0x2E0 },  { "IRQ8", 0x300 },
    32         { "IRQ9", 0x320 },  { "IRQ10",0x340 },  { "IRQ11",0x360 },
    33         { "IRQ12",0x380 },  { "IRQ13",0x3A0 },  { "IRQ14",0x3C0 },
    34         { "NMI", 0x1C0 },   { "H-UDI",0x600 },  { "GPIOI",0x620 },
    35         { "DMTE0",0x640 },  { "DMTE1",0x660 },  { "DMTE2",0x680 },
    36         { "DMTE3",0x6A0 },  { "DMTAE",0x6C0 },  { "TUNI0",0x400 },
    37         { "TUNI1",0x420 },  { "TUNI2",0x440 },  { "TICPI2",0x460 },
    38         { "RTC_ATI",0x480 },{ "RTC_PRI",0x4A0 },{ "RTC_CUI",0x4C0 },
    39         { "SCI_ERI",0x4E0 },{ "SCI_RXI",0x500 },{ "SCI_TXI",0x520 },
    40         { "SCI_TEI",0x540 },
    41         { "SCIF_ERI",0x700 },{ "SCIF_RXI",0x720 },{ "SCIF_BRI",0x740 },
    42         { "SCIF_TXI",0x760 },
    43         { "WDT_ITI",0x560 },{ "RCMI",0x580 },   { "ROVI",0x5A0 } };
    45 static int intc_default_priority[INT_NUM_SOURCES] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 16 };
    47 #define PRIORITY(which) intc_state.priority[which]
    48 #define INTCODE(which) intc_sources[which].code
    50 static struct intc_state {
    51     int num_pending;
    52     int pending[INT_NUM_SOURCES];
    53     int priority[INT_NUM_SOURCES];
    54 } intc_state;
    56 MMIO_REGION_WRITE_FN( INTC, reg, val )
    57 {
    58     reg &= 0xFFF;
    59     /* Well it saves having to use an intermediate table... */
    60     switch( reg ) {
    61     case ICR: /* care about this later */
    62         break;
    63     case IPRA:
    64         PRIORITY(INT_TMU_TUNI0) = (val>>12)&0x000F;
    65         PRIORITY(INT_TMU_TUNI1) = (val>>8)&0x000F;
    66         PRIORITY(INT_TMU_TUNI2) =
    67             PRIORITY(INT_TMU_TICPI2) = (val>>4)&0x000F;
    68         PRIORITY(INT_RTC_ATI) =
    69             PRIORITY(INT_RTC_PRI) =
    70                 PRIORITY(INT_RTC_CUI) = val&0x000F;
    71         break;
    72     case IPRB:
    73         PRIORITY(INT_WDT_ITI) = (val>>12)&0x000F;
    74         PRIORITY(INT_REF_RCMI) =
    75             PRIORITY(INT_REF_ROVI) = (val>>8)&0x000F;
    76         PRIORITY(INT_SCI_ERI) =
    77             PRIORITY(INT_SCI_RXI) =
    78                 PRIORITY(INT_SCI_TXI) =
    79                     PRIORITY(INT_SCI_TEI) = (val>>4)&0x000F;
    80         /* Bits 0-3 reserved */
    81         break;
    82     case IPRC:
    83         PRIORITY(INT_GPIO) = (val>>12)&0x000F;
    84         PRIORITY(INT_DMA_DMTE0) =
    85             PRIORITY(INT_DMA_DMTE1) =
    86                 PRIORITY(INT_DMA_DMTE2) =
    87                     PRIORITY(INT_DMA_DMTE3) =
    88                         PRIORITY(INT_DMA_DMAE) = (val>>8)&0x000F;
    89         PRIORITY(INT_SCIF_ERI) =
    90             PRIORITY(INT_SCIF_RXI) =
    91                 PRIORITY(INT_SCIF_BRI) =
    92                     PRIORITY(INT_SCIF_TXI) = (val>>4)&0x000F;
    93         PRIORITY(INT_HUDI) = val&0x000F;
    94         break;
    95     }
    96     MMIO_WRITE( INTC, reg, val );
    97 }
    99 MMIO_REGION_READ_FN( INTC, reg )
   100 {
   101     return MMIO_READ( INTC, reg & 0xFFF );
   102 }
   104 MMIO_REGION_READ_DEFSUBFNS(INTC)
   106 void INTC_reset()
   107 {
   108     int i;
   110     intc_state.num_pending = 0;
   111     for( i=0; i<INT_NUM_SOURCES; i++ )
   112         intc_state.priority[i] = intc_default_priority[i];
   113     sh4_set_event_pending( event_get_next_time() );
   114     sh4r.event_types &= (~PENDING_IRQ);
   115 }
   118 void INTC_save_state( FILE *f )
   119 {
   120     fwrite( &intc_state, sizeof(intc_state), 1, f );
   121 }
   123 int INTC_load_state( FILE *f )
   124 {
   125     if( fread(&intc_state, sizeof(intc_state), 1, f) != 1 )
   126         return -1;
   127     return 0;
   128 }
   130 /* We basically maintain a priority queue here, raise_interrupt adds an entry,
   131  * accept_interrupt takes it off. At the moment this is done as a simple
   132  * ordered array, on the basis that in practice there's unlikely to be more
   133  * than one at a time. There are lots of ways to optimize this if it turns out
   134  * to be necessary, but I'd doubt it will be...
   135  */
   137 void intc_raise_interrupt( int which )
   138 {
   139     int i, j, pri;
   141     pri = PRIORITY(which);
   142     if( pri == 0 ) return; /* masked off */
   144     for( i=0; i<intc_state.num_pending; i++ ) {
   145         if( intc_state.pending[i] == which ) return; /* Don't queue more than once */
   146         if( PRIORITY(intc_state.pending[i]) > pri ||
   147                 (PRIORITY(intc_state.pending[i]) == pri &&
   148                         intc_state.pending[i] < which))
   149             break;
   150     }
   151     /* i == insertion point */
   152     for( j=intc_state.num_pending; j > i; j-- )
   153         intc_state.pending[j] = intc_state.pending[j-1];
   154     intc_state.pending[i] = which;
   156     if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri ) {
   157         sh4_set_event_pending(0);
   158         sh4r.event_types |= PENDING_IRQ;
   159     }
   161     intc_state.num_pending++;
   162 }
   164 void intc_clear_interrupt( int which )
   165 {
   166     int i;
   167     for( i=intc_state.num_pending-1; i>=0; i-- ) {
   168         if( intc_state.pending[i] == which ) {
   169             /* Shift array contents down */
   170             while( i < intc_state.num_pending-1 ) {
   171                 intc_state.pending[i] = intc_state.pending[i+1];
   172                 i++;
   173             }
   174             intc_state.num_pending--;
   175             intc_mask_changed();
   176             break;
   177         }
   178     }
   180 }
   182 uint32_t intc_accept_interrupt( void )
   183 {
   184     assert(intc_state.num_pending > 0);
   185     return INTCODE(intc_state.pending[intc_state.num_pending-1]);
   186 }
   188 void intc_mask_changed( void )
   189 {   
   190     if( intc_state.num_pending > 0 && (sh4r.sr&SR_BL)==0 &&
   191             SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) ) {
   192         sh4_set_event_pending(0);
   193         sh4r.event_types |= PENDING_IRQ ;
   194     }
   195     else {
   196         sh4_set_event_pending(event_get_next_time());
   197         sh4r.event_types &= (~PENDING_IRQ);
   198     }
   199 }
   202 char *intc_get_interrupt_name( int code )
   203 {
   204     return intc_sources[code].name;
   205 }
.