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