Search
lxdream.org :: lxdream/src/sh4/intc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/intc.c
changeset 1:eea311cfd33e
next19:9da7a8e38f9d
author nkeynes
date Sat Mar 13 00:03:32 2004 +0000 (15 years ago)
permissions -rw-r--r--
last change This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches.
file annotate diff log raw
nkeynes@1
     1
#include <assert.h>
nkeynes@1
     2
#include "sh4mmio.h"
nkeynes@1
     3
#include "sh4core.h"
nkeynes@1
     4
#include "intc.h"
nkeynes@1
     5
nkeynes@1
     6
int priorities[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
nkeynes@1
     7
nkeynes@1
     8
struct intc_sources_t {
nkeynes@1
     9
    char *name;
nkeynes@1
    10
    uint32_t code;
nkeynes@1
    11
    int priority;
nkeynes@1
    12
};
nkeynes@1
    13
nkeynes@1
    14
#define PRIORITY(which) intc_sources[which].priority
nkeynes@1
    15
#define INTCODE(which) intc_sources[which].code
nkeynes@1
    16
nkeynes@1
    17
static struct intc_sources_t intc_sources[] = {
nkeynes@1
    18
    { "IRQ0", 0x200, 15 }, { "IRQ1", 0x220, 14 }, { "IRQ2", 0x240, 13 },
nkeynes@1
    19
    { "IRQ3", 0x260, 12 }, { "IRQ4", 0x280, 11 }, { "IRQ5", 0x2A0, 10 },
nkeynes@1
    20
    { "IRQ6", 0x2C0, 9 },  { "IRQ7", 0x2E0, 8 },  { "IRQ8", 0x300, 7 },
nkeynes@1
    21
    { "IRQ9", 0x320, 6 },  { "IRQ10",0x340, 5 },  { "IRQ11",0x360, 4 },
nkeynes@1
    22
    { "IRQ12",0x380, 3 },  { "IRQ13",0x3A0, 2 },  { "IRQ14",0x3C0, 1 },
nkeynes@1
    23
    { "NMI", 0x1C0, 16 },  { "H-UDI",0x600, 0 },  { "GPIOI",0x620, 0 },
nkeynes@1
    24
    { "DMTE0",0x640, 0 },  { "DMTE1",0x660, 0 },  { "DMTE2",0x680, 0 },
nkeynes@1
    25
    { "DMTE3",0x6A0, 0 },  { "DMTAE",0x6C0, 0 },  { "TUNI0",0x400, 0 },
nkeynes@1
    26
    { "TUNI1",0x420, 0 },  { "TUNI2",0x440, 0 },  { "TICPI2",0x460, 0 },
nkeynes@1
    27
    { "RTC_ATI",0x480, 0 },{ "RTC_PRI",0x4A0, 0 },{ "RTC_CUI",0x4C0, 0 },
nkeynes@1
    28
    { "SCI_ERI",0x4E0, 0 },{ "SCI_RXI",0x500, 0 },{ "SCI_TXI",0x520, 0 },
nkeynes@1
    29
    { "SCI_TEI",0x540, 0 },
nkeynes@1
    30
    { "SCIF_ERI",0x700, 0 },{ "SCIF_RXI",0x720, 0 },{ "SCIF_BRI",0x740, 0 },
nkeynes@1
    31
    { "SCIF_TXI",0x760, 0 },
nkeynes@1
    32
    { "WDT_ITI",0x560, 0 },{ "RCMI",0x580, 0 },   { "ROVI",0x5A0, 0 } };
nkeynes@1
    33
nkeynes@1
    34
int intc_pending[INT_NUM_SOURCES];
nkeynes@1
    35
int intc_num_pending = 0;
nkeynes@1
    36
nkeynes@1
    37
void mmio_region_INTC_write( uint32_t reg, uint32_t val )
nkeynes@1
    38
{
nkeynes@1
    39
    /* Well it saves having to use an intermediate table... */
nkeynes@1
    40
    switch( reg ) {
nkeynes@1
    41
        case ICR: /* care about this later */
nkeynes@1
    42
            break;
nkeynes@1
    43
        case IPRA:
nkeynes@1
    44
            PRIORITY(INT_TMU_TUNI0) = (val>>12)&0x000F;
nkeynes@1
    45
            PRIORITY(INT_TMU_TUNI1) = (val>>8)&0x000F;
nkeynes@1
    46
            PRIORITY(INT_TMU_TUNI2) =
nkeynes@1
    47
                PRIORITY(INT_TMU_TICPI2) = (val>>4)&0x000F;
nkeynes@1
    48
            PRIORITY(INT_RTC_ATI) =
nkeynes@1
    49
                PRIORITY(INT_RTC_PRI) =
nkeynes@1
    50
                PRIORITY(INT_RTC_CUI) = val&0x000F;
nkeynes@1
    51
            break;
nkeynes@1
    52
        case IPRB:
nkeynes@1
    53
            PRIORITY(INT_WDT_ITI) = (val>>12)&0x000F;
nkeynes@1
    54
            PRIORITY(INT_REF_RCMI) =
nkeynes@1
    55
                PRIORITY(INT_REF_ROVI) = (val>>8)&0x000F;
nkeynes@1
    56
            PRIORITY(INT_SCI_ERI) =
nkeynes@1
    57
                PRIORITY(INT_SCI_RXI) =
nkeynes@1
    58
                PRIORITY(INT_SCI_TXI) =
nkeynes@1
    59
                PRIORITY(INT_SCI_TEI) = (val>>4)&0x000F;
nkeynes@1
    60
            /* Bits 0-3 reserved */
nkeynes@1
    61
            break;
nkeynes@1
    62
        case IPRC:
nkeynes@1
    63
            PRIORITY(INT_GPIO) = (val>>12)&0x000F;
nkeynes@1
    64
            PRIORITY(INT_DMA_DMTE0) =
nkeynes@1
    65
                PRIORITY(INT_DMA_DMTE1) =
nkeynes@1
    66
                PRIORITY(INT_DMA_DMTE2) =
nkeynes@1
    67
                PRIORITY(INT_DMA_DMTE3) =
nkeynes@1
    68
                PRIORITY(INT_DMA_DMAE) = (val>>8)&0x000F;
nkeynes@1
    69
            PRIORITY(INT_SCIF_ERI) =
nkeynes@1
    70
                PRIORITY(INT_SCIF_RXI) =
nkeynes@1
    71
                PRIORITY(INT_SCIF_BRI) =
nkeynes@1
    72
                PRIORITY(INT_SCIF_TXI) = (val>>4)&0x000F;
nkeynes@1
    73
            PRIORITY(INT_HUDI) = val&0x000F;
nkeynes@1
    74
            break;
nkeynes@1
    75
    }
nkeynes@1
    76
    MMIO_WRITE( INTC, reg, val );
nkeynes@1
    77
}
nkeynes@1
    78
nkeynes@1
    79
int32_t mmio_region_INTC_read( uint32_t reg )
nkeynes@1
    80
{
nkeynes@1
    81
    return MMIO_READ( INTC, reg );
nkeynes@1
    82
}
nkeynes@1
    83
        
nkeynes@1
    84
/* We basically maintain a priority queue here, raise_interrupt adds an entry,
nkeynes@1
    85
 * accept_interrupt takes it off. At the moment this is does as a simple
nkeynes@1
    86
 * ordered array, on the basis that in practice there's unlikely to be more
nkeynes@1
    87
 * than one at a time. There are lots of ways to optimize this if it turns out
nkeynes@1
    88
 * to be necessary, but I'd doubt it will be...
nkeynes@1
    89
 */
nkeynes@1
    90
nkeynes@1
    91
void intc_raise_interrupt( int which )
nkeynes@1
    92
{
nkeynes@1
    93
    int i, j, pri;
nkeynes@1
    94
    
nkeynes@1
    95
    pri = PRIORITY(which);
nkeynes@1
    96
    if( pri == 0 ) return; /* masked off */
nkeynes@1
    97
    
nkeynes@1
    98
    for( i=0; i<intc_num_pending; i++ ) {
nkeynes@1
    99
        if( intc_pending[i] == which ) return; /* Don't queue more than once */
nkeynes@1
   100
        if( PRIORITY(intc_pending[i]) > pri ||
nkeynes@1
   101
            (PRIORITY(intc_pending[i]) == pri &&
nkeynes@1
   102
             intc_pending[i] < which))
nkeynes@1
   103
            break;
nkeynes@1
   104
    }
nkeynes@1
   105
    /* i == insertion point */
nkeynes@1
   106
    for( j=intc_num_pending; j > i; j-- )
nkeynes@1
   107
        intc_pending[j] = intc_pending[j-1];
nkeynes@1
   108
    intc_pending[i] = which;
nkeynes@1
   109
nkeynes@1
   110
    if( i == intc_num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri )
nkeynes@1
   111
        sh4r.int_pending = 1;
nkeynes@1
   112
nkeynes@1
   113
    intc_num_pending++;
nkeynes@1
   114
}
nkeynes@1
   115
nkeynes@1
   116
uint32_t intc_accept_interrupt( void )
nkeynes@1
   117
{
nkeynes@1
   118
    assert(intc_num_pending > 0);
nkeynes@1
   119
    intc_num_pending--;
nkeynes@1
   120
    if( intc_num_pending > 0 )
nkeynes@1
   121
        sh4r.int_pending = PRIORITY(intc_pending[intc_num_pending-1]);
nkeynes@1
   122
    else
nkeynes@1
   123
        sh4r.int_pending = 0;
nkeynes@1
   124
    return INTCODE(intc_pending[intc_num_pending]);
nkeynes@1
   125
}
nkeynes@1
   126
nkeynes@1
   127
void intc_mask_changed( void )
nkeynes@1
   128
{   
nkeynes@1
   129
    if( intc_num_pending > 0 && (sh4r.sr&SR_BL)==0 &&
nkeynes@1
   130
        SH4_INTMASK() < PRIORITY(intc_pending[intc_num_pending-1]) )
nkeynes@1
   131
        sh4r.int_pending = 1;
nkeynes@1
   132
    else sh4r.int_pending = 0;
nkeynes@1
   133
}
nkeynes@1
   134
    
nkeynes@1
   135
nkeynes@1
   136
char *intc_get_interrupt_name( int code )
nkeynes@1
   137
{
nkeynes@1
   138
    return intc_sources[code].name;
nkeynes@1
   139
}
nkeynes@1
   140
nkeynes@1
   141
void intc_reset( void )
nkeynes@1
   142
{
nkeynes@1
   143
    intc_num_pending = 0;
nkeynes@1
   144
    sh4r.int_pending = 0;
nkeynes@1
   145
}
.