filename | src/sh4/intc.c |
changeset | 929:fd8cb0c82f5f |
prev | 736:a02d1475ccfd |
next | 975:007bf7eb944f |
author | nkeynes |
date | Sat Jan 03 03:30:26 2009 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | MMU work-in-progress * Move SDRAM out into separate sdram.c * Move all page-table management into mmu.c * Convert UTLB management to use the new page-tables * Rip out all calls to mmu_vma_to_phys_* and replace with direct access |
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 }
.