Search
lxdream.org :: lxdream/src/sh4/intc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/intc.c
changeset 929:fd8cb0c82f5f
prev736:a02d1475ccfd
next975:007bf7eb944f
author nkeynes
date Sat Dec 27 02:59:35 2008 +0000 (15 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode,
which tracks the field of the same name in sh4r - actually a little faster this way.
Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR
flag yet).

Also fixed the failure to check the flags in the common case (code address returned
by previous block) which took away the performance benefits, but oh well.
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 void INTC_reset()
   105 {
   106     int i;
   108     intc_state.num_pending = 0;
   109     for( i=0; i<INT_NUM_SOURCES; i++ )
   110         intc_state.priority[i] = intc_default_priority[i];
   111     sh4r.event_pending = event_get_next_time();
   112     sh4r.event_types &= (~PENDING_IRQ);
   113 }
   116 void INTC_save_state( FILE *f )
   117 {
   118     fwrite( &intc_state, sizeof(intc_state), 1, f );
   119 }
   121 int INTC_load_state( FILE *f )
   122 {
   123     if( fread(&intc_state, sizeof(intc_state), 1, f) != 1 )
   124         return -1;
   125     return 0;
   126 }
   128 /* We basically maintain a priority queue here, raise_interrupt adds an entry,
   129  * accept_interrupt takes it off. At the moment this is done as a simple
   130  * ordered array, on the basis that in practice there's unlikely to be more
   131  * than one at a time. There are lots of ways to optimize this if it turns out
   132  * to be necessary, but I'd doubt it will be...
   133  */
   135 void intc_raise_interrupt( int which )
   136 {
   137     int i, j, pri;
   139     pri = PRIORITY(which);
   140     if( pri == 0 ) return; /* masked off */
   142     for( i=0; i<intc_state.num_pending; i++ ) {
   143         if( intc_state.pending[i] == which ) return; /* Don't queue more than once */
   144         if( PRIORITY(intc_state.pending[i]) > pri ||
   145                 (PRIORITY(intc_state.pending[i]) == pri &&
   146                         intc_state.pending[i] < which))
   147             break;
   148     }
   149     /* i == insertion point */
   150     for( j=intc_state.num_pending; j > i; j-- )
   151         intc_state.pending[j] = intc_state.pending[j-1];
   152     intc_state.pending[i] = which;
   154     if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri ) {
   155         sh4r.event_pending = 0;
   156         sh4r.event_types |= PENDING_IRQ;
   157     }
   159     intc_state.num_pending++;
   160 }
   162 void intc_clear_interrupt( int which )
   163 {
   164     int i;
   165     for( i=intc_state.num_pending-1; i>=0; i-- ) {
   166         if( intc_state.pending[i] == which ) {
   167             /* Shift array contents down */
   168             while( i < intc_state.num_pending-1 ) {
   169                 intc_state.pending[i] = intc_state.pending[i+1];
   170                 i++;
   171             }
   172             intc_state.num_pending--;
   173             intc_mask_changed();
   174             break;
   175         }
   176     }
   178 }
   180 uint32_t intc_accept_interrupt( void )
   181 {
   182     assert(intc_state.num_pending > 0);
   183     return INTCODE(intc_state.pending[intc_state.num_pending-1]);
   184 }
   186 void intc_mask_changed( void )
   187 {   
   188     if( intc_state.num_pending > 0 && (sh4r.sr&SR_BL)==0 &&
   189             SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) ) {
   190         sh4r.event_pending = 0;
   191         sh4r.event_types |= PENDING_IRQ ;
   192     }
   193     else {
   194         sh4r.event_pending = event_get_next_time();
   195         sh4r.event_types &= (~PENDING_IRQ);
   196     }
   197 }
   200 char *intc_get_interrupt_name( int code )
   201 {
   202     return intc_sources[code].name;
   203 }
.