Search
lxdream.org :: lxdream/src/sh4/intc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/intc.c
changeset 157:fbe03268ad8a
prev114:1cc849575bc7
next265:5daf59b7f31b
author nkeynes
date Thu Jun 15 10:27:10 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Add preliminary call-stack tracing ability
Fix INTC state save/load/reset
view annotate diff log raw
     1 /**
     2  * $Id: intc.c,v 1.6 2006-06-15 10:27:10 nkeynes Exp $
     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"
    24 struct intc_sources_t {
    25     char *name;
    26     uint32_t code;
    27 } intc_sources[INT_NUM_SOURCES] = {
    28     { "IRQ0", 0x200 },  { "IRQ1", 0x220 },  { "IRQ2", 0x240 },
    29     { "IRQ3", 0x260 },  { "IRQ4", 0x280 },  { "IRQ5", 0x2A0 },
    30     { "IRQ6", 0x2C0 },  { "IRQ7", 0x2E0 },  { "IRQ8", 0x300 },
    31     { "IRQ9", 0x320 },  { "IRQ10",0x340 },  { "IRQ11",0x360 },
    32     { "IRQ12",0x380 },  { "IRQ13",0x3A0 },  { "IRQ14",0x3C0 },
    33     { "NMI", 0x1C0 },   { "H-UDI",0x600 },  { "GPIOI",0x620 },
    34     { "DMTE0",0x640 },  { "DMTE1",0x660 },  { "DMTE2",0x680 },
    35     { "DMTE3",0x6A0 },  { "DMTAE",0x6C0 },  { "TUNI0",0x400 },
    36     { "TUNI1",0x420 },  { "TUNI2",0x440 },  { "TICPI2",0x460 },
    37     { "RTC_ATI",0x480 },{ "RTC_PRI",0x4A0 },{ "RTC_CUI",0x4C0 },
    38     { "SCI_ERI",0x4E0 },{ "SCI_RXI",0x500 },{ "SCI_TXI",0x520 },
    39     { "SCI_TEI",0x540 },
    40     { "SCIF_ERI",0x700 },{ "SCIF_RXI",0x720, 0 },{ "SCIF_BRI",0x740 },
    41     { "SCIF_TXI",0x760 },
    42     { "WDT_ITI",0x560 },{ "RCMI",0x580 },   { "ROVI",0x5A0 } };
    44 static int intc_default_priority[INT_NUM_SOURCES] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 16 };
    46 #define PRIORITY(which) intc_state.priority[which]
    47 #define INTCODE(which) intc_sources[which].code
    49 static struct intc_state {
    50     int num_pending;
    51     int pending[INT_NUM_SOURCES];
    52     int priority[INT_NUM_SOURCES];
    53 } intc_state;
    55 void mmio_region_INTC_write( uint32_t reg, uint32_t val )
    56 {
    57     /* Well it saves having to use an intermediate table... */
    58     switch( reg ) {
    59         case ICR: /* care about this later */
    60             break;
    61         case IPRA:
    62             PRIORITY(INT_TMU_TUNI0) = (val>>12)&0x000F;
    63             PRIORITY(INT_TMU_TUNI1) = (val>>8)&0x000F;
    64             PRIORITY(INT_TMU_TUNI2) =
    65                 PRIORITY(INT_TMU_TICPI2) = (val>>4)&0x000F;
    66             PRIORITY(INT_RTC_ATI) =
    67                 PRIORITY(INT_RTC_PRI) =
    68                 PRIORITY(INT_RTC_CUI) = val&0x000F;
    69             break;
    70         case IPRB:
    71             PRIORITY(INT_WDT_ITI) = (val>>12)&0x000F;
    72             PRIORITY(INT_REF_RCMI) =
    73                 PRIORITY(INT_REF_ROVI) = (val>>8)&0x000F;
    74             PRIORITY(INT_SCI_ERI) =
    75                 PRIORITY(INT_SCI_RXI) =
    76                 PRIORITY(INT_SCI_TXI) =
    77                 PRIORITY(INT_SCI_TEI) = (val>>4)&0x000F;
    78             /* Bits 0-3 reserved */
    79             break;
    80         case IPRC:
    81             PRIORITY(INT_GPIO) = (val>>12)&0x000F;
    82             PRIORITY(INT_DMA_DMTE0) =
    83                 PRIORITY(INT_DMA_DMTE1) =
    84                 PRIORITY(INT_DMA_DMTE2) =
    85                 PRIORITY(INT_DMA_DMTE3) =
    86                 PRIORITY(INT_DMA_DMAE) = (val>>8)&0x000F;
    87             PRIORITY(INT_SCIF_ERI) =
    88                 PRIORITY(INT_SCIF_RXI) =
    89                 PRIORITY(INT_SCIF_BRI) =
    90                 PRIORITY(INT_SCIF_TXI) = (val>>4)&0x000F;
    91             PRIORITY(INT_HUDI) = val&0x000F;
    92             break;
    93     }
    94     MMIO_WRITE( INTC, reg, val );
    95 }
    97 int32_t mmio_region_INTC_read( uint32_t reg )
    98 {
    99     return MMIO_READ( INTC, reg );
   100 }
   102 void INTC_reset()
   103 {
   104     int i;
   106     intc_state.num_pending = 0;
   107     for( i=0; i<INT_NUM_SOURCES; i++ )
   108 	intc_state.priority[i] = intc_default_priority[i];
   109     sh4r.int_pending = 0;
   110 }
   113 void INTC_save_state( FILE *f )
   114 {
   115     fwrite( &intc_state, sizeof(intc_state), 1, f );
   116 }
   118 int INTC_load_state( FILE *f )
   119 {
   120     if( fread(&intc_state, sizeof(intc_state), 1, f) != 1 )
   121 	return -1;
   122     return 0;
   123 }
   125 /* We basically maintain a priority queue here, raise_interrupt adds an entry,
   126  * accept_interrupt takes it off. At the moment this is does as a simple
   127  * ordered array, on the basis that in practice there's unlikely to be more
   128  * than one at a time. There are lots of ways to optimize this if it turns out
   129  * to be necessary, but I'd doubt it will be...
   130  */
   132 void intc_raise_interrupt( int which )
   133 {
   134     int i, j, pri;
   136     pri = PRIORITY(which);
   137     if( pri == 0 ) return; /* masked off */
   139     for( i=0; i<intc_state.num_pending; i++ ) {
   140         if( intc_state.pending[i] == which ) return; /* Don't queue more than once */
   141         if( PRIORITY(intc_state.pending[i]) > pri ||
   142             (PRIORITY(intc_state.pending[i]) == pri &&
   143              intc_state.pending[i] < which))
   144             break;
   145     }
   146     /* i == insertion point */
   147     for( j=intc_state.num_pending; j > i; j-- )
   148         intc_state.pending[j] = intc_state.pending[j-1];
   149     intc_state.pending[i] = which;
   151     if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri )
   152         sh4r.int_pending = 1;
   154     intc_state.num_pending++;
   155 }
   157 void intc_clear_interrupt( int which )
   158 {
   159     int i;
   160     for( i=intc_state.num_pending-1; i>=0; i-- ) {
   161 	if( intc_state.pending[i] == which ) {
   162 	    /* Shift array contents down */
   163 	    while( i < intc_state.num_pending-1 ) {
   164 		intc_state.pending[i] = intc_state.pending[++i];
   165 	    }
   166 	    intc_state.num_pending--;
   167 	    intc_mask_changed();
   168 	    break;
   169 	}
   170     }
   172 }
   174 uint32_t intc_accept_interrupt( void )
   175 {
   176     assert(intc_state.num_pending > 0);
   177     return INTCODE(intc_state.pending[intc_state.num_pending-1]);
   178 }
   180 void intc_mask_changed( void )
   181 {   
   182     if( intc_state.num_pending > 0 && (sh4r.sr&SR_BL)==0 &&
   183         SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) )
   184         sh4r.int_pending = 1;
   185     else sh4r.int_pending = 0;
   186 }
   189 char *intc_get_interrupt_name( int code )
   190 {
   191     return intc_sources[code].name;
   192 }
.