nesdev.parodius.com Forum Index nesdev.parodius.com
NES Development and Strangulation Records message boards
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Efficiency: reading joypad data into a byte of RAM

 
Post new topic   Reply to topic    nesdev.parodius.com Forum Index -> Newbie Help Center
View previous topic :: View next topic  
Author Message
UncleSporky



Joined: 17 Nov 2007
Posts: 274

PostPosted: Mon Jan 19, 2009 6:11 pm    Post subject: Efficiency: reading joypad data into a byte of RAM Reply with quote

Forgive me for asking about something so simple, but I am paranoid about program efficiency. This is the best way I could come up with to read all the joypad data into one byte...is it decent? Anything you would do differently?

Code:
   lda #$01    ;strobe joypad
   sta $4016
   lda #$00
   sta $4016

   clc
   lda #0      ;clear pad 1 data
   stx #8      ;loop 8 times, once for every button
-  sta pad1
   lda $4016   ;get next button state
   adc pad1    ;add the 0 or 1 into pad data
   ror         ;rotate pad data right
   dex
   bne -
   sta pad1

It's really short and simple, but I want to make sure I'm doing this stuff right and not, for example, doing an adc when a cmp would suffice. I want to start off with good programming practices so I don't end up with a huge mess later.

Just before I posted it I already noticed one thing to fix, I was able to eliminate one extra load/store to pad1.
Back to top
View user's profile Send private message
Celius



Joined: 05 Jun 2005
Posts: 1934
Location: Minneapolis, Minnesota, United States

PostPosted: Mon Jan 19, 2009 6:19 pm    Post subject: Reply with quote

Here's how I'd do it:

Code:

ldx #1
stx $4016
dex
stx $4016

ldx #8
-
lda $4016
lsr a
rol NewJoyPad
dex
bne -



Also notice you don't have to clear "NewJoyPad', because it's shifted left 8 times, completely erasing every old bit in the byte. Oh, and just a tip for basically anything, remember that you don't have to use "adc" to add something like 1 and 2 together. You can just use "ora" if you're adding to cleared bits.

And also, I just noticed you do lda #0 two times in a row. Remember to look for things like that when optimizing code. Sorry, don't mean to be really picky or anything Smile .

Oh, also, stx #8 wouldn't do much for you. Ldx #8 I'm sure is what you meant.


Last edited by Celius on Mon Jan 19, 2009 6:28 pm; edited 2 times in total
Back to top
View user's profile Send private message Visit poster's website
Disch



Joined: 10 Nov 2004
Posts: 1585

PostPosted: Mon Jan 19, 2009 6:22 pm    Post subject: Reply with quote

For those of you who want to be Famicom compatible, you may want to consider checking both bits 0 and 1 for button presses with a CMP instruction:

Code:

ldx #9
stx $4016
dex
stx $4016

loop:
  lda $4016
  and #3
  cmp #1
  rol joy
  dex
  bne loop



EDIT:

Also @ UncleSporky, your method won't work because $4016 doesn't give you $00/$01 like you expect -- the high bits are open bus which means you'll most likely get $40/$41. You need to mask out the low bit(s) -- or shift them out, like Celius does. You shouldn't use the value you get from $4016 in full.
Back to top
View user's profile Send private message
Celius



Joined: 05 Jun 2005
Posts: 1934
Location: Minneapolis, Minnesota, United States

PostPosted: Mon Jan 19, 2009 6:26 pm    Post subject: Reply with quote

Woah, ldx #9? And what's the deal with bit 0 and 1?
Back to top
View user's profile Send private message Visit poster's website
Disch



Joined: 10 Nov 2004
Posts: 1585

PostPosted: Mon Jan 19, 2009 6:28 pm    Post subject: Reply with quote

Only bit 0 matters for strobing. So writing 9 has the same effect as writing 1, with the advantage of setting X to 8 after the dex, so you don't need another ldx to prep your loop.

Famicom controllers are build in to the system, they weren't seperate things you plug in like on the NES. This means that replacement controllers or special controllers (like ones with turbo) had to be plugged into the expansion port and data from them is read from bit 1 (not from bit 0, because bit 0 are the built-in controllers). Therefore checking both bits 0 and 1 makes your program more Famicom friendly.
Back to top
View user's profile Send private message
UncleSporky



Joined: 17 Nov 2007
Posts: 274

PostPosted: Mon Jan 19, 2009 6:33 pm    Post subject: Reply with quote

Wow, that was really fast.

Celius wrote:
Here's how I'd do it:

Code:

ldx #1
stx $4016
dex
stx $4016

ldx #8
-
lda $4016
lsr a
rol NewJoyPad
dex
bne -



Also notice you don't have to clear "NewJoyPad', because it's shifted left 8 times, completely erasing every old bit in the byte. Oh, and just a tip for basically anything, remember that you don't have to use "adc" to add something like 1 and 2 together. You can just use "ora" if you're adding to cleared bits.
Oh, that is brilliant, using the carry flag to put data right into the variable. I didn't catch that right away.

Quote:
And also, I just noticed you do lda #0 two times in a row. Remember to look for things like that when optimizing code. Sorry, don't mean to be really picky or anything Smile .
No, that is precisely what I need to learn. But I like your way better, just using dex.

Quote:
Oh, also, stx #8 wouldn't do much for you. Ldx #8 I'm sure is what you meant.
I was just coming back to fix that!

Quote:
Also @ UncleSporky, your method won't work because $4016 doesn't give you $00/$01 like you expect -- the high bits are open bus which means you'll most likely get $40/$41. You need to mask out the low bit(s) -- or shift them out, like Celius does. You shouldn't use the value you get from $4016 in full.
Yet another thing I didn't know, I was wondering why it wasn't working right. Suddenly I am really glad I posted about this.

I don't think I will bother with the Famicom for now, but that is good to know for future use.

Thanks a lot guys.
Back to top
View user's profile Send private message
blargg



Joined: 27 Sep 2004
Posts: 2412

PostPosted: Mon Jan 19, 2009 7:18 pm    Post subject: Reply with quote

There was another thread about this a while back: Joystick read without using temp RAM intermediate. The non-Famicom version there had a completely unrolled loop, making it about twice as fast as the others. If you want a rolled loop, you can use your shift register as a counter, leaving X and Y untouched:
Code:
    lda #%01111111
    sta NewJoyPad
    sta $4016
    asl a       ; A = %11111110
    sta $4016
loop:
    lda $4016
    lsr a
    ror NewJoyPad
    bcs loop

NewJoyPad starts out with %01111111 in it, so after the first 7 RORs at the end of the loop, carry is set, and the loop continues. After the 8th ROR, carry is clear, so the loop stops.
Back to top
View user's profile Send private message Visit poster's website
MetalSlime



Joined: 19 Aug 2008
Posts: 143
Location: Japan

PostPosted: Tue Jan 20, 2009 1:11 am    Post subject: Reply with quote

Awesome thread. I didn't know about the famicon thing, and was puzzled when I found them reading that other bit in some ROMs. Now I know.

And I love all of these sneaky tricks!
Back to top
View user's profile Send private message
Bregalad



Joined: 12 Nov 2004
Posts: 4040
Location: Jongny, VD, Switzerland

PostPosted: Tue Jan 20, 2009 7:17 am    Post subject: Reply with quote

I could just past the way I do it :
Code:
ReadJoy
   lda #$01
   sta $4016      ;Be sure to reset the shift counters
   sta JoyData.b
   lsr A         ;Simple trick to get a 0, heh
   sta $4016
_joyLoop
   lda $4016      ;Read the value of JoyPad 1
   and #$03
   cmp #$01
   rol JoyData.b
   bcc _joyLoop      ;Carry will be set when all 8 keys are read
   rts


I guess it's pretty much optimal if you want anything better you'd want to have an unrolled loop.

Also to detect only '0' to '1' transitions which is very usefull :
Code:
ReadLockJoys
   lda JoyData
   eor #$ff      ;Invert the old value
   pha
   jsr ReadJoy
   pla
   and JoyData      ;And AND it with the new one
   sta JoyLocked
   bit JoyLocked
   bvc +
   inc BButtonCounter   ;Increase button counter for combos
+   rts

It also have a counter that counts automatically '0' to '1' transitions of the B button, for some reason I needed that in my project.
I guess it's pretty much optimal, but maybe one could come with something better, anyway I'm going to use my own routines. Anyone is free to use them for any non-commercial project.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
tepples



Joined: 19 Sep 2004
Posts: 5824
Location: NE Indiana, USA (NTSC)

PostPosted: Tue Jan 20, 2009 7:41 am    Post subject: Reply with quote

Are you going to be playing sampled audio (using $4010-$4013) in your demo? If so, you need to keep in mind that the DMA unit causes "noise" on the controller ports' clock signal.
Back to top
View user's profile Send private message Visit poster's website AIM Address
UncleSporky



Joined: 17 Nov 2007
Posts: 274

PostPosted: Tue Jan 20, 2009 10:29 am    Post subject: Reply with quote

tepples wrote:
Are you going to be playing sampled audio (using $4010-$4013) in your demo? If so, you need to keep in mind that the DMA unit causes "noise" on the controller ports' clock signal.

By clock signal, you mean I might read out erroneous data from $4016? Is this why some games such as Mario 3 do multiple reads, and why most games don't have anything going on while the DMA is playing?

Is this particular quirk documented anywhere, or do I just need to be as knowledgeable as you? Smile
Back to top
View user's profile Send private message
Bregalad



Joined: 12 Nov 2004
Posts: 4040
Location: Jongny, VD, Switzerland

PostPosted: Tue Jan 20, 2009 10:33 am    Post subject: Reply with quote

Yes, it has been discovered recently that the DPCM can cause erronous $4016 reads in NTSC machines, so you have to read multiple times until you get two consecutive matches. This don't apply if you do not use DPCM or if you are on PAL machines.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Disch



Joined: 10 Nov 2004
Posts: 1585

PostPosted: Tue Jan 20, 2009 11:42 am    Post subject: Reply with quote

Bregalad wrote:
This don't apply if you do not use DPCM or if you are on PAL machines.


News to me. Do you have a source for this? I fail to see why PAL systems would be unaffected.
Back to top
View user's profile Send private message
blargg



Joined: 27 Sep 2004
Posts: 2412

PostPosted: Tue Jan 20, 2009 12:28 pm    Post subject: Reply with quote

UncleSporky wrote:
Is this particular quirk documented anywhere, or do I just need to be as knowledgeable as you? :)

See these threads: DPCM generates extra $4016 read pulse and DMC-fortified controller read routine.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    nesdev.parodius.com Forum Index -> Newbie Help Center All times are GMT - 7 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group