197 lines
4.6 KiB
C++
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 ×tamp, 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 ×tamp, 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);
|
|
}
|
|
}
|