Search
lxdream.org :: lxdream/src/sh4/intc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/intc.c
changeset 736:a02d1475ccfd
prev561:533f6b478071
next929:fd8cb0c82f5f
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
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 void mmio_region_INTC_write( uint32_t reg, uint32_t val )
    57 {
    58     /* Well it saves having to use an intermediate table... */
    59     switch( reg ) {
    60     case ICR: /* care about this later */
    61         break;
    62     case IPRA:
    63         PRIORITY(INT_TMU_TUNI0) = (val>>12)&0x000F;
    64         PRIORITY(INT_TMU_TUNI1) = (val>>8)&0x000F;
    65         PRIORITY(INT_TMU_TUNI2) =
    66             PRIORITY(INT_TMU_TICPI2) = (val>>4)&0x000F;
    67         PRIORITY(INT_RTC_ATI) =
    68             PRIORITY(INT_RTC_PRI) =
    69                 PRIORITY(INT_RTC_CUI) = val&0x000F;
    70         break;
    71     case IPRB:
    72         PRIORITY(INT_WDT_ITI) = (val>>12)&0x000F;
    73         PRIORITY(INT_REF_RCMI) =
    74             PRIORITY(INT_REF_ROVI) = (val>>8)&0x000F;
    75         PRIORITY(INT_SCI_ERI) =
    76             PRIORITY(INT_SCI_RXI) =
    77                 PRIORITY(INT_SCI_TXI) =
    78                     PRIORITY(INT_SCI_TEI) = (val>>4)&0x000F;
    79         /* Bits 0-3 reserved */
    80         break;
    81     case IPRC:
    82         PRIORITY(INT_GPIO) = (val>>12)&0x000F;
    83         PRIORITY(INT_DMA_DMTE0) =
    84             PRIORITY(INT_DMA_DMTE1) =
    85                 PRIORITY(INT_DMA_DMTE2) =
    86                     PRIORITY(INT_DMA_DMTE3) =
    87                         PRIORITY(INT_DMA_DMAE) = (val>>8)&0x000F;
    88         PRIORITY(INT_SCIF_ERI) =
    89             PRIORITY(INT_SCIF_RXI) =
    90                 PRIORITY(INT_SCIF_BRI) =
    91                     PRIORITY(INT_SCIF_TXI) = (val>>4)&0x000F;
    92         PRIORITY(INT_HUDI) = val&0x000F;
    93         break;
    94     }
    95     MMIO_WRITE( INTC, reg, val );
    96 }
    98 int32_t mmio_region_INTC_read( uint32_t reg )
    99 {
   100     return MMIO_READ( INTC, reg );
   101 }
   103 void INTC_reset()
   104 {
   105     int i;
   107     intc_state.num_pending = 0;
   108     for( i=0; i<INT_NUM_SOURCES; i++ )
   109         intc_state.priority[i] = intc_default_priority[i];
   110     sh4r.event_pending = event_get_next_time();
   111     sh4r.event_types &= (~PENDING_IRQ);
   112 }
   115 void INTC_save_state( FILE *f )
   116 {
   117     fwrite( &intc_state, sizeof(intc_state), 1, f );
   118 }
   120 int INTC_load_state( FILE *f )
   121 {
   122     if( fread(&intc_state, sizeof(intc_state), 1, f) != 1 )
   123         return -1;
   124     return 0;
   125 }
   127 /* We basically maintain a priority queue here, raise_interrupt adds an entry,
   128  * accept_interrupt takes it off. At the moment this is done as a simple
   129  * ordered array, on the basis that in practice there's unlikely to be more
   130  * than one at a time. There are lots of ways to optimize this if it turns out
   131  * to be necessary, but I'd doubt it will be...
   132  */
   134 void intc_raise_interrupt( int which )
   135 {
   136     int i, j, pri;
   138     pri = PRIORITY(which);
   139     if( pri == 0 ) return; /* masked off */
   141     for( i=0; i<intc_state.num_pending; i++ ) {
   142         if( intc_state.pending[i] == which ) return; /* Don't queue more than once */
   143         if( PRIORITY(intc_state.pending[i]) > pri ||
   144                 (PRIORITY(intc_state.pending[i]) == pri &&
   145                         intc_state.pending[i] < which))
   146             break;
   147     }
   148     /* i == insertion point */
   149     for( j=intc_state.num_pending; j > i; j-- )
   150         intc_state.pending[j] = intc_state.pending[j-1];
   151     intc_state.pending[i] = which;
   153     if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri ) {
   154         sh4r.event_pending = 0;
   155         sh4r.event_types |= PENDING_IRQ;
   156     }
   158     intc_state.num_pending++;
   159 }
   161 void intc_clear_interrupt( int which )
   162 {
   163     int i;
   164     for( i=intc_state.num_pending-1; i>=0; i-- ) {
   165         if( intc_state.pending[i] == which ) {
   166             /* Shift array contents down */
   167             while( i < intc_state.num_pending-1 ) {
   168                 intc_state.pending[i] = intc_state.pending[i+1];
   169                 i++;
   170             }
   171             intc_state.num_pending--;
   172             intc_mask_changed();
   173             break;
   174         }
   175     }
   177 }
   179 uint32_t intc_accept_interrupt( void )
   180 {
   181     assert(intc_state.num_pending > 0);
   182     return INTCODE(intc_state.pending[intc_state.num_pending-1]);
   183 }
   185 void intc_mask_changed( void )
   186 {   
   187     if( intc_state.num_pending > 0 && (sh4r.sr&SR_BL)==0 &&
   188             SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) ) {
   189         sh4r.event_pending = 0;
   190         sh4r.event_types |= PENDING_IRQ ;
   191     }
   192     else {
   193         sh4r.event_pending = event_get_next_time();
   194         sh4r.event_types &= (~PENDING_IRQ);
   195     }
   196 }
   199 char *intc_get_interrupt_name( int code )
   200 {
   201     return intc_sources[code].name;
   202 }
.