mirror of
https://github.com/raphnet/4nes4snes
synced 2024-11-14 21:15:06 -05:00
SNES multitap support
This commit is contained in:
parent
fd19b71d38
commit
efe9d049d3
203
fournsnes.c
203
fournsnes.c
@ -35,6 +35,11 @@
|
|||||||
#define SNES_DATA_BIT3 (1<<1) /* controller 3 */
|
#define SNES_DATA_BIT3 (1<<1) /* controller 3 */
|
||||||
#define SNES_DATA_BIT4 (1<<0) /* controller 4 */
|
#define SNES_DATA_BIT4 (1<<0) /* controller 4 */
|
||||||
|
|
||||||
|
#define MULTITAP_SELECT_PORT PORTB
|
||||||
|
#define MULTITAP_SELECT_DDR DDRB
|
||||||
|
#define MULTITAP_SELECT_PIN PINB
|
||||||
|
#define MULTITAP_SELECT_BIT (1<<5)
|
||||||
|
|
||||||
/********* IO port manipulation macros **********/
|
/********* IO port manipulation macros **********/
|
||||||
#define SNES_LATCH_LOW() do { SNES_LATCH_PORT &= ~(SNES_LATCH_BIT); } while(0)
|
#define SNES_LATCH_LOW() do { SNES_LATCH_PORT &= ~(SNES_LATCH_BIT); } while(0)
|
||||||
#define SNES_LATCH_HIGH() do { SNES_LATCH_PORT |= SNES_LATCH_BIT; } while(0)
|
#define SNES_LATCH_HIGH() do { SNES_LATCH_PORT |= SNES_LATCH_BIT; } while(0)
|
||||||
@ -46,6 +51,9 @@
|
|||||||
#define SNES_GET_DATA3() (SNES_DATA_PIN & SNES_DATA_BIT3)
|
#define SNES_GET_DATA3() (SNES_DATA_PIN & SNES_DATA_BIT3)
|
||||||
#define SNES_GET_DATA4() (SNES_DATA_PIN & SNES_DATA_BIT4)
|
#define SNES_GET_DATA4() (SNES_DATA_PIN & SNES_DATA_BIT4)
|
||||||
|
|
||||||
|
#define MTAP_SELECT_HIGH() do { MULTITAP_SELECT_PORT |= MULTITAP_SELECT_BIT; } while(0)
|
||||||
|
#define MTAP_SELECT_LOW() do { MULTITAP_SELECT_PORT &= ~MULTITAP_SELECT_BIT; } while(0)
|
||||||
|
|
||||||
/*********** prototypes *************/
|
/*********** prototypes *************/
|
||||||
static void fournsnesInit(void);
|
static void fournsnesInit(void);
|
||||||
static void fournsnesUpdate(void);
|
static void fournsnesUpdate(void);
|
||||||
@ -62,6 +70,7 @@ static unsigned char last_reported_controller_bytes[GAMEPAD_BYTES];
|
|||||||
// indicates if a controller is in NES mode
|
// indicates if a controller is in NES mode
|
||||||
static unsigned char nesMode=0; /* Bit0: controller 1, Bit1: controller 2...*/
|
static unsigned char nesMode=0; /* Bit0: controller 1, Bit1: controller 2...*/
|
||||||
static unsigned char fourscore_mode = 0;
|
static unsigned char fourscore_mode = 0;
|
||||||
|
static unsigned char multitap_mode = 0; // SNES
|
||||||
static unsigned char live_autodetect = 1;
|
static unsigned char live_autodetect = 1;
|
||||||
|
|
||||||
void disableLiveAutodetect(void)
|
void disableLiveAutodetect(void)
|
||||||
@ -69,6 +78,45 @@ void disableLiveAutodetect(void)
|
|||||||
live_autodetect = 0;
|
live_autodetect = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void autoDetectSNESMultiTap(void)
|
||||||
|
{
|
||||||
|
// Detection is done by observing that DATA2 becomes
|
||||||
|
// low when LATCH is high.
|
||||||
|
//
|
||||||
|
// Not sure which state of MTAP_SELECT_HIGH is reliable
|
||||||
|
// so I'm simply trying with both states.
|
||||||
|
|
||||||
|
MTAP_SELECT_LOW();
|
||||||
|
|
||||||
|
if (SNES_GET_DATA2()) {
|
||||||
|
SNES_LATCH_HIGH();
|
||||||
|
_delay_us(12);
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA2()) {
|
||||||
|
SNES_LATCH_LOW();
|
||||||
|
_delay_us(12);
|
||||||
|
if (SNES_GET_DATA2()) {
|
||||||
|
multitap_mode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MTAP_SELECT_HIGH();
|
||||||
|
|
||||||
|
if (SNES_GET_DATA2()) {
|
||||||
|
SNES_LATCH_HIGH();
|
||||||
|
_delay_us(12);
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA2()) {
|
||||||
|
SNES_LATCH_LOW();
|
||||||
|
_delay_us(12);
|
||||||
|
if (SNES_GET_DATA2()) {
|
||||||
|
multitap_mode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void autoDetectFourScore(void)
|
static void autoDetectFourScore(void)
|
||||||
{
|
{
|
||||||
unsigned char dat18th_low = 0;
|
unsigned char dat18th_low = 0;
|
||||||
@ -129,6 +177,11 @@ static void fournsnesInit(void)
|
|||||||
// LATCH is Active HIGH
|
// LATCH is Active HIGH
|
||||||
SNES_LATCH_PORT &= ~(SNES_LATCH_BIT);
|
SNES_LATCH_PORT &= ~(SNES_LATCH_BIT);
|
||||||
|
|
||||||
|
|
||||||
|
MULTITAP_SELECT_DDR |= MULTITAP_SELECT_BIT;
|
||||||
|
MULTITAP_SELECT_PORT |= MULTITAP_SELECT_BIT;
|
||||||
|
|
||||||
|
|
||||||
nesMode = 0;
|
nesMode = 0;
|
||||||
fournsnesUpdate();
|
fournsnesUpdate();
|
||||||
|
|
||||||
@ -160,35 +213,13 @@ static void fournsnesInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
autoDetectFourScore();
|
autoDetectFourScore();
|
||||||
|
autoDetectSNESMultiTap();
|
||||||
|
|
||||||
SREG = sreg;
|
SREG = sreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
static void fournsnesUpdate_fourscore(void)
|
||||||
*
|
|
||||||
Clock Cycle Button Reported
|
|
||||||
=========== ===============
|
|
||||||
1 B
|
|
||||||
2 Y
|
|
||||||
3 Select
|
|
||||||
4 Start
|
|
||||||
5 Up on joypad
|
|
||||||
6 Down on joypad
|
|
||||||
7 Left on joypad
|
|
||||||
8 Right on joypad
|
|
||||||
9 A
|
|
||||||
10 X
|
|
||||||
11 L
|
|
||||||
12 R
|
|
||||||
13 none (always high)
|
|
||||||
14 none (always high)
|
|
||||||
15 none (always high)
|
|
||||||
16 none (always high)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void fournsnesUpdate(void)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char tmp1=0;
|
unsigned char tmp1=0;
|
||||||
@ -200,8 +231,6 @@ static void fournsnesUpdate(void)
|
|||||||
_delay_us(12);
|
_delay_us(12);
|
||||||
SNES_LATCH_LOW();
|
SNES_LATCH_LOW();
|
||||||
|
|
||||||
if (fourscore_mode)
|
|
||||||
{
|
|
||||||
/* Nes controller buttons are sent in this order:
|
/* Nes controller buttons are sent in this order:
|
||||||
* One byte: A B SEL START UP DOWN LEFT RIGHT */
|
* One byte: A B SEL START UP DOWN LEFT RIGHT */
|
||||||
|
|
||||||
@ -249,9 +278,130 @@ static void fournsnesUpdate(void)
|
|||||||
last_read_controller_bytes[3] = tmp4;
|
last_read_controller_bytes[3] = tmp4;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
Clock Cycle Button Reported
|
||||||
|
=========== ===============
|
||||||
|
1 B
|
||||||
|
2 Y
|
||||||
|
3 Select
|
||||||
|
4 Start
|
||||||
|
5 Up on joypad
|
||||||
|
6 Down on joypad
|
||||||
|
7 Left on joypad
|
||||||
|
8 Right on joypad
|
||||||
|
9 A
|
||||||
|
10 X
|
||||||
|
11 L
|
||||||
|
12 R
|
||||||
|
13 none (always high)
|
||||||
|
14 none (always high)
|
||||||
|
15 none (always high)
|
||||||
|
16 none (always high)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void fournsnesUpdate(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char tmp1=0;
|
||||||
|
unsigned char tmp2=0;
|
||||||
|
unsigned char tmp3=0;
|
||||||
|
unsigned char tmp4=0;
|
||||||
|
|
||||||
|
if (fourscore_mode)
|
||||||
|
{
|
||||||
|
fournsnesUpdate_fourscore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (multitap_mode)
|
||||||
|
{
|
||||||
|
SNES_LATCH_HIGH();
|
||||||
|
_delay_us(12);
|
||||||
|
SNES_LATCH_LOW();
|
||||||
|
_delay_us(12);
|
||||||
|
|
||||||
|
MTAP_SELECT_HIGH();
|
||||||
|
_delay_us(6);
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
SNES_CLOCK_LOW();
|
||||||
|
_delay_us(6);
|
||||||
|
|
||||||
|
tmp1 <<= 1;
|
||||||
|
tmp2 <<= 1;
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA1()) { tmp1 |= 1; }
|
||||||
|
if (!SNES_GET_DATA2()) { tmp2 |= 1; }
|
||||||
|
|
||||||
|
SNES_CLOCK_HIGH();
|
||||||
|
_delay_us(6);
|
||||||
|
}
|
||||||
|
last_read_controller_bytes[0] = tmp1;
|
||||||
|
last_read_controller_bytes[2] = tmp2;
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
SNES_CLOCK_LOW();
|
||||||
|
_delay_us(6);
|
||||||
|
|
||||||
|
tmp1 >>= 1;
|
||||||
|
tmp2 >>= 1;
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA1()) { tmp1 |= 0x80; }
|
||||||
|
if (!SNES_GET_DATA2()) { tmp2 |= 0x80; }
|
||||||
|
|
||||||
|
SNES_CLOCK_HIGH();
|
||||||
|
_delay_us(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MTAP_SELECT_LOW();
|
||||||
|
_delay_us(6);
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
SNES_CLOCK_LOW();
|
||||||
|
_delay_us(6);
|
||||||
|
|
||||||
|
tmp3 <<= 1;
|
||||||
|
tmp4 <<= 1;
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA1()) { tmp3 |= 1; }
|
||||||
|
if (!SNES_GET_DATA2()) { tmp4 |= 1; }
|
||||||
|
|
||||||
|
SNES_CLOCK_HIGH();
|
||||||
|
_delay_us(6);
|
||||||
|
}
|
||||||
|
last_read_controller_bytes[4] = tmp3;
|
||||||
|
last_read_controller_bytes[6] = tmp4;
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
SNES_CLOCK_LOW();
|
||||||
|
_delay_us(6);
|
||||||
|
|
||||||
|
tmp3 >>= 1;
|
||||||
|
tmp4 >>= 1;
|
||||||
|
|
||||||
|
if (!SNES_GET_DATA1()) { tmp3 |= 0x80; }
|
||||||
|
if (!SNES_GET_DATA2()) { tmp4 |= 0x80; }
|
||||||
|
|
||||||
|
SNES_CLOCK_HIGH();
|
||||||
|
_delay_us(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else // standard mode (not multitap)
|
||||||
|
{
|
||||||
|
SNES_LATCH_HIGH();
|
||||||
|
_delay_us(12);
|
||||||
|
SNES_LATCH_LOW();
|
||||||
|
|
||||||
for (i=0; i<8; i++)
|
for (i=0; i<8; i++)
|
||||||
{
|
{
|
||||||
_delay_us(6);
|
_delay_us(6);
|
||||||
@ -294,6 +444,7 @@ static void fournsnesUpdate(void)
|
|||||||
_delay_us(6);
|
_delay_us(6);
|
||||||
SNES_CLOCK_HIGH();
|
SNES_CLOCK_HIGH();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (live_autodetect) {
|
if (live_autodetect) {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: usbconfig.h,v 1.7 2009-05-02 13:55:11 cvs Exp $
|
* This Revision: $Id: usbconfig.h,v 1.8 2012-04-09 04:05:43 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __usbconfig_h_included__
|
#ifndef __usbconfig_h_included__
|
||||||
@ -143,7 +143,7 @@ rename it to "usbconfig.h". Then edit it accordingly.
|
|||||||
#define USB_CFG_DEVICE_ID 0x9d, 0x0a
|
#define USB_CFG_DEVICE_ID 0x9d, 0x0a
|
||||||
|
|
||||||
|
|
||||||
#define USB_CFG_DEVICE_VERSION 0x02, 0x01
|
#define USB_CFG_DEVICE_VERSION 0x03, 0x01
|
||||||
/* Version number of the device: Minor number first, then major number.
|
/* Version number of the device: Minor number first, then major number.
|
||||||
*/
|
*/
|
||||||
#define USB_CFG_VENDOR_NAME 'r', 'a', 'p', 'h', 'n', 'e', 't', '.', 'n', 'e', 't'
|
#define USB_CFG_VENDOR_NAME 'r', 'a', 'p', 'h', 'n', 'e', 't', '.', 'n', 'e', 't'
|
||||||
|
Loading…
Reference in New Issue
Block a user