6Button reading routine, C code and a glitch!.

For anything related to IO (joypad, serial, XE...)

Moderator: BigEvilCorporation

Post Reply
Fonzie
Genny lover
Posts: 323
Joined: Tue Aug 29, 2006 11:17 am
Contact:

6Button reading routine, C code and a glitch!.

Post by Fonzie » Fri Aug 21, 2009 7:38 am

Hi Guys,

I've been trying to edit the classic 3button reading function so it can handle 6buttons as well.

The idea is to always read twice the joypad (even if its 3button), and look if the second read is different than the first (if so, its 6button joypad, ORRRRR bad contacts!).
That sounds like a horrible idea, heh? :P

My idea was to get the stuff done as fast as possible (without the trick to query the joypad).

It works, but it has some glitches time to time (like once every 10 minutes of play).

Is there anyway to improve it without loosing too much speed?
C, still.
Since I'm not relying on Vint, it would be awesome to have workaround for the famous "bad result if read more than once per frame" syndrome.

Bellow is my current code.
I'm storing result in WORDS, instead of the good old BYTE of Kaneda's routines :)

I'm never really fresh when it comes to such stuff ^^ And programming in general, seems :P

Code: Select all


          pb = (uchar *) 0xa10003;
          *pb = 0x40;
          asm("nop");
          asm("nop");
          asm("nop");
           i = *pb & 0x3f; //6 lower bits
          *pb = 0;
          asm("nop");
          asm("nop");
          asm("nop");
          j = (*pb & 0x30) << 2; //2 top bits
          fvr_joypad_result[1]=(i|j); /*p1*/

          //Other read
          *pb = 0x40;
          asm("nop");
          asm("nop");

          *pb = 0;
          asm("nop");
          asm("nop");

          //Other read to enable 6 button
          *pb = 0x40;
          asm("nop");
          asm("nop");
          j=(*pb);
          *pb = 0;

          if((fvr_joypad_result[1]&0xF)!=(j&0xF))//6 button pad :)
            {
              j<<=8;//Shift J result
              fvr_joypad_result[1]|=j;
              fvr_joypad_result[1]=~fvr_joypad_result[1];
              fvr_joypad_result[1]=fvr_joypad_result[1]&0xFFF;
            }
          else
            {
              fvr_joypad_result[1]=~fvr_joypad_result[1];
              fvr_joypad_result[1]=fvr_joypad_result[1]&0xFF;
            }



Thanks for your help.

Fonzie

HardWareMan
Very interested
Posts: 745
Joined: Sat Dec 15, 2007 7:49 am
Location: Kazakhstan, Pavlodar

Post by HardWareMan » Fri Aug 21, 2009 8:48 am

My 6-button routine:

Code: Select all

*Buttons map
JoyUp           equ    $0001
JoyDown         equ    $0002
JoyUpDown       equ    $0003
JoyLeft         equ    $0004
JoyRight        equ    $0008
JoyLeftRight    equ    $000C
JoyCursor       equ    $000F
JoyB            equ    $0010
JoyC            equ    $0020
JoyA            equ    $0040
JoyABC          equ    $0070
JoyStart        equ    $0080
JoyABCS         equ    $00F0
JoyZ            equ    $0100
JoyY            equ    $0200
JoyX            equ    $0400
JoyMode         equ    $0800
JoyMS           equ    $0880
JoyXYZM         equ    $0F00
JoyAnyButton    equ    $0FF0
JoyAnyKey       equ    $0FFF

*Joypad polling
	clr.l	d0			*Clear d0
	clr.l	d1			*Clear d1
	move.b	#$40,$A10003		*SYN = 1
	nop				*Delay
	nop				*Delay
	move.b	$A10003,d1		*Reading first 6 buttons
	andi.b	#$3F,d1			*Mask it
	move.b	#$00,$A10003		*SYN = 0
	nop				*Delay
	nop				*Delay
	move.b	$A10003,d0		*Read second 2 buttons
	and.b	#$30,d0			*Mask it
	rol.b	#2,d0			*Shift by 2 bits
	or.b	d0,d1			*Combine basic 8 buttons and store it to d1
	move.b	#$40,$A10003		*SYN = 1
	nop				*Delay
	nop				*Delay
	move.b	#$00,$A10003		*SYN = 0
	nop				*Delay
	nop				*Delay
	move.b	#$40,$A10003		*SYN = 1
	nop				*Delay
	nop				*Delay
	move.b	#$00,$A10003		*SYN = 0
	nop				*Delay
	nop				*Delay
	move.b	#$40,$A10003		*SYN = 1
	nop				*Delay
	nop				*All this for unlock extra buttons (XYZM)
	move.b	$A10003,d0		*Read extra buttons
	andi.b	#$0F,d0			*Mask it
	eor.b	#$0F,d0			*Invert it
	rol.l	#8,d0			*Shift it by 8 bits
	or.w	d1,d0			*Combine it with basic buttons
	not.b	d0			*Invert basic buttons
	move.b	#$40,$A10003		*SYN = 1
	move.w	d0,KeyState			*Save joystick state
And I think, that second byte (when first time you set SYN=0) contains in LRUD field an ID, wich will different for each hardware, and 0xF for unattached open port. At least Comix Zone, using this field, recognize 3 or 6 button pads.
I wish to get full ID table of Genesis/MD peripheral hardware.
And one more thing: 6 button joypad, when you set it to extra button mode for reading them, needs some time to reset own state. So, you can't read twice 6 button joypad so fast.

GManiac
Very interested
Posts: 92
Joined: Thu Jan 29, 2009 2:05 am
Location: Russia

Post by GManiac » Fri Aug 21, 2009 9:50 am

You can borrow 6-button routine from any original game, for example, from Comix Zone. I did so :) It even detects 3/6 button joypad after reading.

up: oh, I'm inattentive. Never mind.

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Post by Eke » Fri Aug 21, 2009 9:56 am

I wish to get full ID table of Genesis/MD peripheral hardware.
is that what you want ?

Image


Image

HardWareMan
Very interested
Posts: 745
Joined: Sat Dec 15, 2007 7:49 am
Location: Kazakhstan, Pavlodar

Post by HardWareMan » Fri Aug 21, 2009 11:47 am

Eke wrote:
I wish to get full ID table of Genesis/MD peripheral hardware.
is that what you want ?
Yes. But this is incomplete information, isn't it?
PS {img} tags not working. But URLs is works fine.

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Post by Eke » Fri Aug 21, 2009 1:03 pm

Yes. But this is incomplete information, isn't it?
what other peripheral hardware are they ?
Justifier,Menacer, EA 4-Way-Play ?

From game disassembling, I know Justifier lightguns should return 0x01 and it seems Menacer returns 0x00

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Aug 21, 2009 4:05 pm

Here's the code I use to read 3/6 button controllers. Anyone who wishes to use it is free to do so.

Code: Select all

| get current pad value
| entry: a0 = pad control port
| exit:  d2 = pad value (0 0 0 1 M X Y Z S A C B R L D U) or (0 0 0 0 0 0 0 0 S A C B R L D U)
get_pad:
        bsr.b   get_input       /* - 0 s a 0 0 d u - 1 c b r l d u */
        move.w  d0,d1
        andi.w  #0x0C00,d0
        bne.b   no_pad
        bsr.b   get_input       /* - 0 s a 0 0 d u - 1 c b r l d u */
        bsr.b   get_input       /* - 0 s a 0 0 0 0 - 1 c b m x y z */
        move.w  d0,d2
        bsr.b   get_input       /* - 0 s a 1 1 1 1 - 1 c b r l d u */
        andi.w  #0x0F00,d0      /* 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 */
        cmpi.w  #0x0F00,d0
        beq.b   common          /* six button pad */
        move.w  #0x010F,d2      /* three button pad */
common:
        lsl.b   #4,d2           /* - 0 s a 0 0 0 0 m x y z 0 0 0 0 */
        lsl.w   #4,d2           /* 0 0 0 0 m x y z 0 0 0 0 0 0 0 0 */
        andi.w  #0x303F,d1      /* 0 0 s a 0 0 0 0 0 0 c b r l d u */
        move.b  d1,d2           /* 0 0 0 0 m x y z 0 0 c b r l d u */
        lsr.w   #6,d1           /* 0 0 0 0 0 0 0 0 s a 0 0 0 0 0 0 */
        or.w    d1,d2           /* 0 0 0 0 m x y z s a c b r l d u */
        eori.w  #0x1FFF,d2      /* 0 0 0 1 M X Y Z S A C B R L D U */
        rts

no_pad:
        move.w  #0xF000,d2
        rts

| read single phase from controller
get_input:
        move.b  #0x00,(a0)
        nop
        nop
        move.b  (a0),d0
        move.b  #0x40,(a0)
        lsl.w   #8,d0
        move.b  (a0),d0
        rts

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Fri Aug 21, 2009 9:13 pm

You can read 6button pad few times a frame, but its best if you read things only once, and since frame is the smallest time unit in a typical frame based game engine(not taking Hints into account), you don't really need to read things more.

I'd just have a controller type detection routine and do a single IF when reading controllers... its highly unlikely someone changes controllers while playing, and when it happens, the one must suffer the possible consequences :P
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

HardWareMan
Very interested
Posts: 745
Joined: Sat Dec 15, 2007 7:49 am
Location: Kazakhstan, Pavlodar

Post by HardWareMan » Sat Aug 22, 2009 5:51 am

Eke wrote:...EA 4-Way-Play ?
This schematic was developed at 1994-1995.
Image
It was tested on all AE Sports (i'm problably a spammer, NHL, NBA) and works fine with "Street Racer" too. Don't surely remeber, but it works with "General Chaos" too, I guess. As you can see, EA 4Way Play use first port for ID. And it must be 0x3 (I guess it just test D3 and D2 =0, D1 and D0 don't care. And this status must be all time, except joypad reading. And this was start point for development this device for me (I accidentally connect D0-D3 to GND, and "Street Racer" unblocked menus for 4 players mode). In middle 90s I don't had PC and internet, so I don't use dissassembler.
PS Zero Tolerance link cable was developed by me too, just analyzing port pin activity. ;)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Aug 22, 2009 6:20 am

TmEE co.(TM) wrote:You can read 6button pad few times a frame, but its best if you read things only once, and since frame is the smallest time unit in a typical frame based game engine(not taking Hints into account), you don't really need to read things more.

I'd just have a controller type detection routine and do a single IF when reading controllers... its highly unlikely someone changes controllers while playing, and when it happens, the one must suffer the possible consequences :P
I call my pad routines during the vertical blank, and only if the last call didn't return 0xF000 (which meant there was no pad there). If you call it during the vertical blank regardless of the previous return, it allows you to sense controllers being changed on the fly.

8bitwizard
Very interested
Posts: 159
Joined: Sat Feb 24, 2007 11:35 pm
Location: San Antonio, TX

Post by 8bitwizard » Mon Aug 24, 2009 3:25 am

Did you declare pb as volatile?

Fonzie
Genny lover
Posts: 323
Joined: Tue Aug 29, 2006 11:17 am
Contact:

Post by Fonzie » Tue Aug 25, 2009 3:01 am

pb as volatile?
Yep I did sir! :)

Thank you all for posting.

>HardWareMan
Seeing your code. I was wondering... Lets say there is a 3button joypad plugged, how would you be sure that X/Y/Z/Mode wouldn't reflect UP/DOWN/LEFT/RIGHT ?
I dont see any test in your code (I'm newbie at asm!).
At least Comix Zone, using this field, recognize 3 or 6 button pads.
Umm ok, but then it means that 6button joypad have a specific ID compared to 3buttons one :P And given the doc posted by Eke, they share same id (0xd?)


>Chilly Willy
Ok, so from what I understood, you suppose its 6 buttons IF next reads return 1111 bits on the X's read.
"
bsr.b get_input /* - 0 s a 1 1 1 1 - 1 c b r l d u */
andi.w #0x0F00,d0 /* 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 */
cmpi.w #0x0F00,d0
"
Ok, so after many toggling, it finaly returns 1111...

I think I got the logic, i'll try to improve my C code! :D
Thanks guys!

Post Reply