So, I'm trying to read controller data. I have written a little function thing to handle all this, but uhh... I get problems when I try to program responses for buttons other than the directional buttons.
This is what I've got:
1 | controller equ $4016 ; controller 1 is at register $4016 |
2 | |
3 | ; ----- reads the controller ------------ |
4 | |
5 | readController: |
6 | ; this bit is required, just ignore if you wish |
7 | lda #1 ; strobe controller |
8 | sta controller |
9 | lda #0 ; reset controller |
10 | sta controller |
11 | ; end that bit |
12 | |
13 | |
14 | jsr buttonA ; check buttons by jumping to the sub-routine |
15 | jsr buttonB |
16 | jsr buttonSelect |
17 | jsr buttonStart |
18 | jsr buttonUp |
19 | jsr buttonDown |
20 | jsr buttonLeft |
21 | jsr buttonRight |
22 | |
23 | rts ; return from sub-routine |
24 | |
25 | ; ------------------------------------ |
The buttons on the NES controller are read one a time, in that order. And then the button* sub-routines are all basically the same, like this:
button*: ; check if button * is pressed lda controller ; load button state into register A and #1 ; bitwise AND with 1 beq callbackReturn ; if the AND was true, branch to callbackReturn ; callbackReturn jumps to an "rts" command ; in other words, it's equivalent to a return in C ; do whatever rts ; return
Now, whenever that ; do whatever (besides the four directional buttons) involves the loading of a non-immediate value (ie- from a label or from a specific register) or the storing of a value, it sort of freezes the game (or at least prevents the working input from happening).
Umm.. your method looks overcomplicated but before i can figure out what might be wrong i need some more details.
So.. you say that controller is register-mapped to address $4016. I assume that each button is a 'bit' (how is the signal stored) 8 buttons = 8-bits?
Otherwise i don't see anything inherently wrong. You don't touch the stack, and you have a simple branch..
Actually.. how far is the branch (in memory distance)? Relative addressing is only 8-bit IIRC.
It may be overly complicated, but I don't currently know of any better ways to do it. I've seen some examples of a loop that reads all 8 buttons, but I have no idea how it works, so I'm staying away from it for now.
So.. you say that controller is register-mapped to address $4016. I assume that each button is a 'bit' (how is the signal stored) 8 buttons = 8-bits?
As far as I understand, yes that's how it works. It seems to only read one bit at a time, each time that register is read. I've tried bitwise ANDing it, having only read it once, using an 8 bit binary number, but it doesn't work, so it has to be read 8 times.
how far is the branch (in memory distance)?
I'm new to assembly, so let me know if this was not what you meant. It's not very deep, it's within the "main loop", so it only goes 2 branches deep when running.
gameLoop: ; check if in VBlank ; draw sprite jsr readController jmp gameLoop
I can't recall the 6502 ISA off the top of my head but why not something like this
1 | ;possibly the wrong numbers |
2 | ;masks for each button |
3 | buttonA equ #1 |
4 | buttonB equ #2 |
5 | buttonSt equ #4 |
6 | buttonSe equ #8 |
7 | buttonUp equ #16 |
8 | buttonDo equ #32 |
9 | buttonLe equ #64 |
10 | buttonRi equ #128 |
11 | |
12 | |
13 | readController: |
14 | |
15 | ;read value from controller (make sure these are right!) |
16 | lda #1 ; strobe controller |
17 | sta controller |
18 | lda #0 ; reset controller |
19 | sta controller |
20 | ; end that bit |
21 | |
22 | ;read value from controller |
23 | lda controller |
24 | |
25 | ;store this value somewhere convenient. |
26 | sta controller_status |
27 | |
28 | ;check if button A pushed |
29 | lda controller_status |
30 | and buttonA |
31 | beq butB ;if button a is not pressed.. and will return 0. beq jumps when z flag is zero.. correct!? |
32 | jsr buttonA_action |
33 | butB: |
34 | lda controller_status |
35 | and buttonB |
36 | beq butC |
37 | jsr buttonB_action |
38 | butC: ;.. and so on |
39 | |
40 | rts ;end of function! |
That's what I was talking about by only reading the controller once and then ANDing it with a single binary number. Unfortunately, it does not work.
If it doesn't work then maybe you should read the documents and open up your debugger. Test the simplest of cases.. track the stack. check out what happens when you hit that instruction. It is quite possibly you are overwriting your own instructions or perhaps your stack is screwed up.
ah 6502, takes me back, like Goalie Ca said, it may be your branch distance.
I think that you can branch back 127 bytes and forward 128.
To keep jumps small it may be better doing it like this :-
bne dontreturn rts dontreturn: ...
like Goalie Ca said, it may be your branch distance.
I think that you can branch back 127 bytes and forward 128.
That's JR (jump relative), not JSR (jump to subroutine). JSR takes an absolute, 16bit, address.
I think the problem is most likely that you've misunderstood the NES specs, but I don't know them off hand. Maybe I can help more at lunchtime...
eh, bne is a branch which is 8 bit, jump is 16 bit yes, but the potential problem is that there is a "beq callbackReturn", callbackReturn isn't listed and could easily be beyond 128 bytes away from the branch.
eh, bne is a branch which is 8 bit, jump is 16 bit yes, but the potential problem is that there is a "beq callbackReturn"
I didn't spot the BEQ. I was looking at the JSRs.
Besides that, your code seems to be compliant to the docs here. Does it work if you change it to the code below?
button*: ; check if button * is pressed lda controller ; load button state into register A and #1 ; bitwise AND with 1 bne .noReturnNow ; if the AND was true, avoid the rts that comes next rts .noReturnNow ; do whatever rts ; return
I'm not sure if it's a universal trait of 6502 assemblers, but the 65SC02 assembler I used to use treated labels with a dot at the start of their name as local labels, i.e. they're accessible only between one real label (such as buttonA) and the next (presumably buttonB). So it's safe to use them in macros, and have a different .noReturnNow for each of your button functions.
Also, if you want to save a cycle, try this:
button*: ; check if button * is pressed lda controller ; load button state into register A lsr ; shift lowest bit into the carry register bcs .noReturnNow ; if the AND was true, branch to callbackReturn ; callbackReturn jumps to an "rts" command ; in other words, it's equivalent to a return in C rts .noReturnNow ; do whatever rts ; return
It's not very helpful here, but if you had an 8bit byte and wanted to do different things depending on the status of individual bits then often the fastest way to decompose it is to shift each bit in turn into carry.