213 lines
5.3 KiB
C++
213 lines
5.3 KiB
C++
/******************************************************************************/
|
|
/* Mednafen NEC PC-FX Emulation Module */
|
|
/******************************************************************************/
|
|
/* interrupt.cpp:
|
|
** Copyright (C) 2006-2016 Mednafen Team
|
|
**
|
|
** This program is free software; you can redistribute it and/or
|
|
** modify it under the terms of the GNU General Public License
|
|
** as published by the Free Software Foundation; either version 2
|
|
** of the License, or (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "pcfx.h"
|
|
#include "interrupt.h"
|
|
|
|
namespace MDFN_IEN_PCFX
|
|
{
|
|
|
|
static uint16 InterruptAsserted;
|
|
static uint16 InterruptMask;
|
|
static uint16 InterruptPriority[2];
|
|
|
|
static void BuildInterruptCache(void)
|
|
{
|
|
uint32 iwithmask = InterruptAsserted &~ InterruptMask;
|
|
int InterruptCache = -1;
|
|
int last_prio = -1;
|
|
|
|
for(int level = 8; level < 16; level++)
|
|
if(iwithmask & (1 << (15 - level)))
|
|
{
|
|
int tmp_prio;
|
|
|
|
if(level >= 12)
|
|
tmp_prio = (InterruptPriority[0] >> ((15 - level) * 3)) & 0x7;
|
|
else
|
|
tmp_prio = (InterruptPriority[1] >> ((11 - level) * 3)) & 0x7;
|
|
|
|
if(tmp_prio >= last_prio)
|
|
{
|
|
if(tmp_prio == last_prio)
|
|
{
|
|
FXDBG("Undefined IRQ behavior: %d, %d\n", level, tmp_prio);
|
|
}
|
|
InterruptCache = 8 + tmp_prio;
|
|
last_prio = tmp_prio;
|
|
}
|
|
}
|
|
|
|
PCFX_V810.SetInt(InterruptCache);
|
|
}
|
|
|
|
void PCFXIRQ_Assert(int source, bool assert)
|
|
{
|
|
assert(source >= 0 && source <= 7);
|
|
|
|
InterruptAsserted &= ~(1 << (7 - source));
|
|
|
|
if(assert)
|
|
InterruptAsserted |= (1 << (7 - source));
|
|
|
|
BuildInterruptCache();
|
|
}
|
|
|
|
|
|
uint16 PCFXIRQ_Read16(uint32 A)
|
|
{
|
|
uint32 ret = 0x00;
|
|
|
|
switch(A & 0xC0)
|
|
{
|
|
case 0x00: ret = InterruptAsserted; break;
|
|
case 0x40: ret = InterruptMask; break;
|
|
case 0x80: ret = InterruptPriority[0]; break;
|
|
case 0xC0: ret = InterruptPriority[1]; break;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
uint8 PCFXIRQ_Read8(uint32 A)
|
|
{
|
|
return(PCFXIRQ_Read16(A&~1) >> ((A & 1) * 8));
|
|
}
|
|
|
|
void PCFXIRQ_Write16(uint32 A, uint16 V)
|
|
{
|
|
// printf("IRQ Controller Write: %08x %04x\n", A, V);
|
|
switch(A & 0xC0)
|
|
{
|
|
case 0x00: puts("Address error clear");
|
|
break;
|
|
|
|
case 0x40: InterruptMask = V & 0x7F;
|
|
BuildInterruptCache();
|
|
break;
|
|
|
|
case 0x80: if(InterruptMask == 0x7F)
|
|
{
|
|
InterruptPriority[0] = V & 0xFFF;
|
|
BuildInterruptCache();
|
|
}
|
|
break;
|
|
|
|
case 0xC0: if(InterruptMask == 0x7F)
|
|
{
|
|
InterruptPriority[1] = V & 0x1FF;
|
|
BuildInterruptCache();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PCFXIRQ_SetRegister(const unsigned int id, uint32 value)
|
|
{
|
|
switch(id)
|
|
{
|
|
case PCFXIRQ_GSREG_IMASK:
|
|
InterruptMask = value & 0x7F;
|
|
BuildInterruptCache();
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPRIO0:
|
|
InterruptPriority[0] = value & 0xFFF;
|
|
BuildInterruptCache();
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPRIO1:
|
|
InterruptPriority[1] = value & 0x1FF;
|
|
BuildInterruptCache();
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPEND:
|
|
InterruptAsserted = value;
|
|
BuildInterruptCache();
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32 PCFXIRQ_GetRegister(const unsigned int id, char *special, const uint32 special_len)
|
|
{
|
|
uint32 value = 0xDEADBEEF;
|
|
|
|
switch(id)
|
|
{
|
|
case PCFXIRQ_GSREG_IMASK:
|
|
value = InterruptMask;
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "IRQ Allowed; HuC6273: %s, HuC6270-B: %s, HuC6272: %s, HuC6270-A: %s, Pad: %s, Timer: %s, Reset: %s",
|
|
(InterruptMask & (1 << 0)) ? "No" : "Yes", (InterruptMask & (1 << 1)) ? "No" : "Yes",
|
|
(InterruptMask & (1 << 2)) ? "No" : "Yes", (InterruptMask & (1 << 3)) ? "No" : "Yes",
|
|
(InterruptMask & (1 << 4)) ? "No" : "Yes", (InterruptMask & (1 << 6)) ? "No" : "Yes",
|
|
(InterruptMask & (1 << 7)) ? "No" : "Yes");
|
|
}
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPRIO0:
|
|
value = InterruptPriority[0];
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d",
|
|
(InterruptPriority[0] >> 0) & 0x7, (InterruptPriority[0] >> 3) & 0x7,
|
|
(InterruptPriority[0] >> 6) & 0x7, (InterruptPriority[0] >> 9) & 0x7);
|
|
}
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPRIO1:
|
|
value = InterruptPriority[1];
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
|
|
(InterruptPriority[1] >> 0) & 0x7, (InterruptPriority[1] >> 3) & 0x7,
|
|
(InterruptPriority[1] >> 6) & 0x7, (InterruptPriority[1] >> 9) & 0x7);
|
|
}
|
|
break;
|
|
|
|
case PCFXIRQ_GSREG_IPEND:
|
|
value = InterruptAsserted;
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "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),
|
|
(int)(bool)(value & 0x04), (int)(bool)(value & 0x08), (int)(bool)(value & 0x10), (int)(bool)(value & 0x20),
|
|
(int)(bool)(value & 0x40), (int)(bool)(value & 0x80));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void PCFXIRQ_Reset(void)
|
|
{
|
|
InterruptAsserted = 0;
|
|
InterruptMask = 0xFFFF;
|
|
|
|
InterruptPriority[0] = 0;
|
|
InterruptPriority[1] = 0;
|
|
|
|
BuildInterruptCache();
|
|
}
|
|
|
|
}
|