Quote:
I know you basically said the same thing as the tut but I got your way more. Thanks ill keep you posted if I have more trouble.
Glad I could help, and it sounds like you're doing some exploring which is nice to do.
Re: Controller Reading.
I'll explain the other way. He's mentioned C, so I assume he's done some stuff in it. Bit shifts may already be in his repertoire, and if not it may not be as huge a leap for him as others.
We've got the benefit of being a forum, so we can tailor our teaching to the person.
Tokumaru, I actually wouldn't mind seeing a tutorial by you. You know this stuff better than I do AND provide shorter (and easier to understand) explanations than I do. Else one day I really will write my own. And I'll teach things in a different order than this post, I guess.
Camronas, this way is worth reading about even if you have already got the other way working. Also this turned into a long post (I warned of this!), and it may help to read a little at a time to let it sink in.
A quick note about this post: I haven't had time to thoroughly check it for errors. I promise I'll come back and fix it if I find some later, but just be aware there may be parts where there are nine bits in an LDA instruction or something. Hopefully nothing more serious than that, but I wrote this all in one go with not a lot of proofreading...
Edit: Also, shoot, I just realized I never mentioned how to USE the buttons variable once this code is finished. I'll add a quick note at the end.
Quote:
I cant see the difference between the two function to be able to see what needs to change, this code works though.
That is correct. There is no difference between how you get the bit for each new button.
$4016 is a special address for interfacing with NES hardware. Every time you read from it, its value is updated to the state of the next button. So even in this string of code that looks like it would be redundant:
Code:
lda $4016
lda $4016
The accumulator can actually be given a different value each time because it is moving to different buttons upon read.
The order is always:
A
B
Select
Start
Up
Down
Left
Right
What this code does:
Code:
LDA #$01
STA $4016
LDA #$00
STA $4016 ; tell both the controllers to latch buttons
is resets the button state you will get from a $4016 read back to the first button. (A)
I will now pause on controller reading to review some things about the 6502 that are important to understand for the other controller method.
There is a byte internal to the 6502 CPU. Each bit represents a different thing that is either true (1) or false (0). These bits are called the processor status flags.
Code:
From Assembly in One Step
bit -> 7 0
+---+---+---+---+---+---+---+---+
| N | V | | B | D | I | Z | C | <-- flag, 0/1 = reset/set
+---+---+---+---+---+---+---+---+
When the CPU does anything, the individual bits of that byte are set (to 1) or cleared (to 0) based on the result of the last instruction. We will only care about Z and C right now. (By the way, the order of the bits in this byte is not important to us at all right now. You just need to know that they exist and a little about how they update)
The easy one to explain is Z. It is set if the result of the last instruction was zero, and cleared if the result was not zero.
Code:
lda #$00; Z is set.
lda #$FF; Z is cleared.
lda #$XX;where XX is anything but 00. Z is cleared
Here is something a little more tricky that will set Z.
Code:
lda #$01
sec;We set the carry before a subtract
sbc #$01;1-1=0.
;The result of the last operation was 0. Z is set.
One more:
Code:
ldx #$01;X is another register that holds a value like A. There is also Y.
dex;Subtracts one from X.
1-1 = 0; Z is set.
Now I will teach a few more instructions that shift the bits in A. The easy two are ROR, and ROL. ROR ROtates all the bits in a byte to the Right. ROL ROtates them to the Left.
As you know a byte is eight bits. But ROR and ROL actually work on NINE bits. Say, WHAT?
The ninth bit is C in the processor status byte. So let's say we have a this byte in A: #%10000000
It looks like this to ROL and ROR:
Code:
C = The carry bit. If cleared, it is zero. If set it is 1.
C10000000C
When you ROR, C goes to the left bit of A, that bit that was where C just moved goes one bit to the right, etc until the right most bit in A moves into C.
Let's look at this code:
Code:
clc; Clears the carry flag. C is 0.
lda #%1000000R;(R is 0. I have marked it R for a reason)
ROR a;Rotates the bits in A to the right.
;A now has this byte: #%01000000
;What about the carry? It gets the bit that was on the very right of A. (marked R in the example).
;R was 0. C is now 0.
;The carry is now clear.
Sort of interesting. Let's look at this code:
Code:
sec;Sets the carry flag. C is 1.
lda #%10000000;No need to mark R now, right?
ROR a
;A now has this byte: #%11000000
;The carry was set instead of cleared when we started, so a 1 was moved into A's leftmost bit instead of a zero.
;Because a zero was in A's rightmost bit, the carry is now clear.
If you get ROR, ROL is not any different except it moves left. Here is a quick example anyway:
Code:
clc
lda #%10000000
rol a
;A = #%00000000
;Carry is set.
Got it? Cool.
Now for two that are a little different. LSR and ASL. LSR shifts bits right, but puts a ZERO into the left most bit of the byte instead of what was in C. The right most bit of A is still moved into C, however.
ASL shifts bits left but puts a ZERO in the right most bit of the byte instead of what was in C. The left most bit of A is still moved into C.
Similar enough, right? Here are some examples just in case.
Code:
sec
lda #%10000000
ASL a
;A now has #%00000000. The zero flag was set! Don't forget about that.
;C has 1.
Another quick one.
Code:
clc
lda #%10000000
ASL a
;A now has #%00000000.
;C has 1.
So as you can see, the state of the carry flag before ASL actually doesn't matter, unlike with ROL.
LSR is similar.
Code:
;State of carry doesn't matter
lda #%00000010
lsr a
;A is #%00000001
;Carry is clear.
Code:
;State of carry doesn't matter
lda #%00000001
lsr a
;A is #%00000000
;Carry is set.
You now know almost everything you need to know to understand the "standard" joypad reading code. Except the bitwise operators and branching (which you may know from Nerdy Nights by now). If you already know & (AND), |(ORA) and ^(EOR) from C, you're good on the bitwise operators. If not,
please read this post.Let's construct a simple endless loop using a branch.
Code:
label:
lda #$00
beq label;This jmps to label if Z is set. It continues down if Z is clear.
And another using a different branch.
Code:
label:
lda #$FF
bne label;This jmps to label if Z is clear. It continues down if Z is set.
That was pretty concise, but it should make sense if you think about it.
Now let's construct a regular loop. Sort of like the for loop in C.
Code:
ldx #$02
label:
lda $4016
dex
bne label
clc;Just extra code.
What will this do? Read from $4016 twice. We start with 2 in X. We read from $4016. We subtract 1 from X. 2-1 is not equal to 0, so we branch back to label. 1 is in X. We read $4016. We subtract 1 from X. 1-1 is equal to 0. We continue to where the clc is.
From the explanation earlier, you may realize we actually read two button states just now. But we didn't store them anyplace we could use them later.
Code:
LatchController:
LDA #$01
STA $4016
LDA #$00
STA $4016 ; tell both the controllers to latch buttons
sta buttons;A variable in RAM. All buttons are now unpressed.
ldx #$08;Why not read 8 button states?
buttonreadloop:
asl buttons;We can ASL bytes other than A. It works the same just using RAM instead of A.
lda $4016
and #%00000001;We only care about this one bit.
ora buttons
sta buttons
dex
bne buttonreadloop
So the first run through the loop reads $4016. It gets the bit that contains the button state. We isolate that bit with the AND. We ora it with #$00. (Since we set buttons to that before the loop started.) We store it in buttons. buttons now contains the state of A in its rightmost bit.
We loop again. We shift buttons so that the state of the A button is now in the part of the bit marked A. #%000000A0. It puts a 0 in place for the next button to set if pressed because of how asl works. We load the state of the button through $4016. We isolate the bit. We ora, so now A contains the state of both buttons. Then we store A in buttons so the actual buttons variable contains the state of both buttons.
We keep looping until we have all eight buttons.
If that was hyper confusing, give it some time to digest. If you need an alternate explanation on an instruction (ROR, ASL, ETC), let me know. Once you get those, the controller code should "click" after a little thought, but if not ask away! As always, sorry for writing so much.
Edit: To use the buttons variable: Load it, AND out the bits you don't want to check. and #%1000000 would give you the A button, because all the others will end up zero.
Then you can use BEQ to branch passed the code that requires A, because if A was pressed the result of the beq would not be zero.