BizHawk/waterbox/vb/input.cpp

197 lines
4.6 KiB
C++

/******************************************************************************/
/* Mednafen Virtual Boy Emulation Module */
/******************************************************************************/
/* input.cpp:
** Copyright (C) 2010-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 "vb.h"
#include "input.h"
namespace MDFN_IEN_VB
{
static bool InstantReadHack;
static bool IntPending;
static uint16 PadData;
static uint16 PadLatched;
static uint8 SCR;
static uint16 SDR;
#define SCR_S_ABT_DIS 0x01
#define SCR_SI_STAT 0x02
#define SCR_HW_SI 0x04
#define SCR_SOFT_CLK 0x10
#define SCR_PARA_SI 0x20
#define SCR_K_INT_INH 0x80
static uint32 ReadBitPos;
static int32 ReadCounter;
static v810_timestamp_t last_ts;
void VBINPUT_Init(void)
{
InstantReadHack = true;
}
void VBINPUT_SetInstantReadHack(bool enabled)
{
InstantReadHack = enabled;
}
uint8 VBINPUT_Read(v810_timestamp_t &timestamp, uint32 A)
{
uint8 ret = 0;
VBINPUT_Update(timestamp);
//if(((A & 0xFF) == 0x10 || (A & 0xFF) == 0x14))
// printf("Read %d\n", timestamp);
//if(((A & 0xFF) == 0x10 || (A & 0xFF) == 0x14) && ReadCounter > 0)
//{
// printf("Input port read during hardware transfer: %08x %d\n", A, timestamp);
//}
switch (A & 0xFF)
{
case 0x10:
if (InstantReadHack)
ret = PadData;
else
ret = SDR & 0xFF;
break;
case 0x14:
if (InstantReadHack)
ret = PadData >> 8;
else
ret = SDR >> 8;
break;
case 0x28:
ret = SCR | (0x40 | 0x08 | SCR_HW_SI);
if (ReadCounter > 0)
ret |= SCR_SI_STAT;
break;
}
// printf("Input Read: %08x %02x\n", A, ret);
VB_SetEvent(VB_EVENT_INPUT, (ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
return (ret);
}
void VBINPUT_Write(v810_timestamp_t &timestamp, uint32 A, uint8 V)
{
VBINPUT_Update(timestamp);
//printf("Input write: %d, %08x %02x\n", timestamp, A, V);
switch (A & 0xFF)
{
case 0x28:
if ((V & SCR_HW_SI) && !(SCR & SCR_S_ABT_DIS) && ReadCounter <= 0)
{
//printf("Start Read: %d\n", timestamp);
PadLatched = PadData;
ReadBitPos = 0;
ReadCounter = 640;
}
if (V & SCR_S_ABT_DIS)
{
ReadCounter = 0;
ReadBitPos = 0;
}
if (V & SCR_K_INT_INH)
{
IntPending = false;
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, IntPending);
}
SCR = V & (0x80 | 0x20 | 0x10 | 1);
break;
}
VB_SetEvent(VB_EVENT_INPUT, (ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
}
void VBINPUT_Frame(const void* ptr)
{
PadData = (MDFN_de16lsb(ptr) << 2) | 0x2;
}
v810_timestamp_t VBINPUT_Update(const v810_timestamp_t timestamp)
{
int32 clocks = timestamp - last_ts;
if (ReadCounter > 0)
{
ReadCounter -= clocks;
while (ReadCounter <= 0)
{
SDR &= ~(1 << ReadBitPos);
SDR |= PadLatched & (1 << ReadBitPos);
ReadBitPos++;
if (ReadBitPos < 16)
ReadCounter += 640;
else
{
//printf("Read End: %d\n", timestamp);
if (!(SCR & SCR_K_INT_INH))
{
//printf("Input IRQ: %d\n", timestamp);
IntPending = true;
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, IntPending);
}
break;
}
}
}
last_ts = timestamp;
return ((ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
}
void VBINPUT_ResetTS(void)
{
last_ts = 0;
}
void VBINPUT_Power(void)
{
last_ts = 0;
PadData = 0;
PadLatched = 0;
SDR = 0;
SCR = 0;
ReadBitPos = 0;
ReadCounter = 0;
IntPending = false;
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, 0);
}
}