1 /* Mednafen - Multi-system Emulator
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "pcfx.h"
19 #include "interrupt.h"
20
21 static uint16 InterruptAsserted;
22 static uint16 InterruptMask;
23 static uint16 InterruptPriority[2];
24
BuildInterruptCache(void)25 static void BuildInterruptCache(void)
26 {
27 uint32 iwithmask = InterruptAsserted &~ InterruptMask;
28 int InterruptCache = -1;
29 int last_prio = -1;
30
31 for(int level = 8; level < 16; level++)
32 if(iwithmask & (1 << (15 - level)))
33 {
34 int tmp_prio;
35
36 if(level >= 12)
37 tmp_prio = (InterruptPriority[0] >> ((15 - level) * 3)) & 0x7;
38 else
39 tmp_prio = (InterruptPriority[1] >> ((11 - level) * 3)) & 0x7;
40
41 if(tmp_prio >= last_prio)
42 {
43 if(tmp_prio == last_prio)
44 {
45 FXDBG("Undefined IRQ behavior: %d, %d\n", level, tmp_prio);
46 }
47 InterruptCache = 8 + tmp_prio;
48 last_prio = tmp_prio;
49 }
50 }
51
52 PCFX_V810.SetInt(InterruptCache);
53 }
54
PCFXIRQ_Assert(int source,bool assert)55 void PCFXIRQ_Assert(int source, bool assert)
56 {
57 assert(source >= 0 && source <= 7);
58
59 InterruptAsserted &= ~(1 << (7 - source));
60
61 if(assert)
62 InterruptAsserted |= (1 << (7 - source));
63
64 BuildInterruptCache();
65 }
66
67
PCFXIRQ_Read16(uint32 A)68 uint16 PCFXIRQ_Read16(uint32 A)
69 {
70 switch(A & 0xC0)
71 {
72 case 0x00:
73 return InterruptAsserted;
74 case 0x40:
75 return InterruptMask;
76 case 0x80:
77 return InterruptPriority[0];
78 case 0xC0:
79 return InterruptPriority[1];
80 }
81
82 return 0;
83 }
84
PCFXIRQ_Read8(uint32 A)85 uint8 PCFXIRQ_Read8(uint32 A)
86 {
87 return(PCFXIRQ_Read16(A&~1) >> ((A & 1) * 8));
88 }
89
PCFXIRQ_Write16(uint32 A,uint16 V)90 void PCFXIRQ_Write16(uint32 A, uint16 V)
91 {
92 // printf("IRQ Controller Write: %08x %04x\n", A, V);
93 //
94 switch(A & 0xC0)
95 {
96 case 0x00:
97 puts("Address error clear");
98 break;
99 case 0x40:
100 InterruptMask = V & 0x7F;
101 BuildInterruptCache();
102 break;
103
104 case 0x80:
105 if(InterruptMask == 0x7F)
106 {
107 InterruptPriority[0] = V & 0xFFF;
108 BuildInterruptCache();
109 }
110 break;
111
112 case 0xC0:
113 if(InterruptMask == 0x7F)
114 {
115 InterruptPriority[1] = V & 0x1FF;
116 BuildInterruptCache();
117 }
118 break;
119 }
120 }
121
PCFXIRQ_StateAction(StateMem * sm,int load,int data_only)122 int PCFXIRQ_StateAction(StateMem *sm, int load, int data_only)
123 {
124 SFORMAT StateRegs[] =
125 {
126 SFVAR(InterruptAsserted),
127 SFVAR(InterruptMask),
128 SFARRAY16(InterruptPriority, 2),
129 SFEND
130 };
131
132 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "IRQ", false);
133
134 if(load)
135 BuildInterruptCache();
136
137 return(ret);
138 }
139
PCFXIRQ_SetRegister(const std::string & name,uint32 value)140 bool PCFXIRQ_SetRegister(const std::string &name, uint32 value)
141 {
142 if(name == "IMASK")
143 {
144 InterruptMask = value & 0x7F;
145 BuildInterruptCache();
146 }
147 else if(name == "IPRIO0")
148 {
149 InterruptPriority[0] = value & 0xFFF;
150 BuildInterruptCache();
151 }
152 else if(name == "IPRIO1")
153 {
154 InterruptPriority[1] = value & 0x1FF;
155 BuildInterruptCache();
156 }
157 else if(name == "IPEND")
158 {
159 InterruptAsserted = value;
160 BuildInterruptCache();
161 }
162 return(FALSE);
163 }
164
PCFXIRQ_GetRegister(const std::string & name,uint32 & value,std::string * special)165 bool PCFXIRQ_GetRegister(const std::string &name, uint32 &value, std::string *special)
166 {
167 if(name == "IMASK")
168 {
169 value = InterruptMask;
170 if(special)
171 {
172 char buf[256];
173 snprintf(buf, 256, "IRQ Allowed; HuC6273: %s, HuC6270-B: %s, HuC6272: %s, HuC6270-A: %s, Pad: %s, Timer: %s, Reset: %s",
174 (InterruptMask & (1 << 0)) ? "No" : "Yes", (InterruptMask & (1 << 1)) ? "No" : "Yes",
175 (InterruptMask & (1 << 2)) ? "No" : "Yes", (InterruptMask & (1 << 3)) ? "No" : "Yes",
176 (InterruptMask & (1 << 4)) ? "No" : "Yes", (InterruptMask & (1 << 6)) ? "No" : "Yes",
177 (InterruptMask & (1 << 7)) ? "No" : "Yes");
178 *special = std::string(buf);
179 }
180 return(TRUE);
181 }
182 else if(name == "IPRIO0")
183 {
184 value = InterruptPriority[0];
185 if(special)
186 {
187 char buf[256];
188 snprintf(buf, 256, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d",
189 (InterruptPriority[0] >> 0) & 0x7, (InterruptPriority[0] >> 3) & 0x7,
190 (InterruptPriority[0] >> 6) & 0x7, (InterruptPriority[0] >> 9) & 0x7);
191 *special = std::string(buf);
192 }
193 return(TRUE);
194 }
195 else if(name == "IPRIO1")
196 {
197 value = InterruptPriority[1];
198 if(special)
199 {
200 char buf[256];
201 snprintf(buf, 256, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
202 (InterruptPriority[1] >> 0) & 0x7, (InterruptPriority[1] >> 3) & 0x7,
203 (InterruptPriority[1] >> 6) & 0x7, (InterruptPriority[1] >> 9) & 0x7);
204 *special = std::string(buf);
205 }
206 return(TRUE);
207 }
208 else if(name == "IPEND")
209 {
210 value = InterruptAsserted;
211 if(special)
212 {
213 char buf[256];
214 snprintf(buf, 256, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d, Pad: %d, ??: %d, Timer: %d, Reset: %d", (int)(bool)(value & 0x01), (int)(bool)(value & 0x02),
215 (int)(bool)(value & 0x04), (int)(bool)(value & 0x08), (int)(bool)(value & 0x10), (int)(bool)(value & 0x20),
216 (int)(bool)(value & 0x40), (int)(bool)(value & 0x80));
217 *special = std::string(buf);
218 }
219 return(TRUE);
220 }
221 else
222 return(FALSE);
223 }
224
PCFXIRQ_Reset(void)225 void PCFXIRQ_Reset(void)
226 {
227 InterruptAsserted = 0;
228 InterruptMask = 0xFFFF;
229
230 InterruptPriority[0] = 0;
231 InterruptPriority[1] = 0;
232
233 BuildInterruptCache();
234 }
235
236