| View previous topic :: View next topic |
| Author |
Message |
UncleSporky
Joined: 17 Nov 2007 Posts: 274
|
Posted: Mon Jan 19, 2009 6:11 pm Post subject: Efficiency: reading joypad data into a byte of RAM |
|
|
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 |
|
 |
Celius

Joined: 05 Jun 2005 Posts: 1934 Location: Minneapolis, Minnesota, United States
|
Posted: Mon Jan 19, 2009 6:19 pm Post subject: |
|
|
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 .
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 |
|
 |
Disch

Joined: 10 Nov 2004 Posts: 1585
|
Posted: Mon Jan 19, 2009 6:22 pm Post subject: |
|
|
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 |
|
 |
Celius

Joined: 05 Jun 2005 Posts: 1934 Location: Minneapolis, Minnesota, United States
|
Posted: Mon Jan 19, 2009 6:26 pm Post subject: |
|
|
| Woah, ldx #9? And what's the deal with bit 0 and 1? |
|
| Back to top |
|
 |
Disch

Joined: 10 Nov 2004 Posts: 1585
|
Posted: Mon Jan 19, 2009 6:28 pm Post subject: |
|
|
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 |
|
 |
UncleSporky
Joined: 17 Nov 2007 Posts: 274
|
Posted: Mon Jan 19, 2009 6:33 pm Post subject: |
|
|
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 . | 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 |
|
 |
blargg

Joined: 27 Sep 2004 Posts: 2412
|
Posted: Mon Jan 19, 2009 7:18 pm Post subject: |
|
|
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 |
|
 |
MetalSlime

Joined: 19 Aug 2008 Posts: 143 Location: Japan
|
Posted: Tue Jan 20, 2009 1:11 am Post subject: |
|
|
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 |
|
 |
Bregalad

Joined: 12 Nov 2004 Posts: 4040 Location: Jongny, VD, Switzerland
|
Posted: Tue Jan 20, 2009 7:17 am Post subject: |
|
|
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 |
|
 |
tepples

Joined: 19 Sep 2004 Posts: 5824 Location: NE Indiana, USA (NTSC)
|
Posted: Tue Jan 20, 2009 7:41 am Post subject: |
|
|
| 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 |
|
 |
UncleSporky
Joined: 17 Nov 2007 Posts: 274
|
Posted: Tue Jan 20, 2009 10:29 am Post subject: |
|
|
| 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?  |
|
| Back to top |
|
 |
Bregalad

Joined: 12 Nov 2004 Posts: 4040 Location: Jongny, VD, Switzerland
|
Posted: Tue Jan 20, 2009 10:33 am Post subject: |
|
|
| 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 |
|
 |
Disch

Joined: 10 Nov 2004 Posts: 1585
|
Posted: Tue Jan 20, 2009 11:42 am Post subject: |
|
|
| 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 |
|
 |
blargg

Joined: 27 Sep 2004 Posts: 2412
|
|
| Back to top |
|
 |
|