filename | src/sh4/intc.c |
changeset | 929:fd8cb0c82f5f |
prev | 736:a02d1475ccfd |
next | 975:007bf7eb944f |
author | nkeynes |
date | Sat Dec 27 02:59:35 2008 +0000 (15 years ago) |
branch | lxdream-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 }
.