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