Could you explain why you shift bits and push the accumulator to the stack? I don't know much about shifting bits and pushing and pulling the stack. I know how to count in binary. Is that what shifting bits is? Just a glorified increment? Isn't the stack what remembers the address of the command It's executing?

Read the controller state into $00.Load $00 and save it on the stack.Read the controller state into $00 again.Load the value saved on the stack, which is the first controller state.Compare it to the value in $00, which is the second controller state.

It's trying to read the controller twice, compare the results, and accept the result only if the two reads match. This avoids a bug in the 2A03 CPU, used in the Famicom, NTSC NES, and RGB systems, that causes misreads during DPCM playback.

In general, reading the controllers need not involve the stack. The routine in the file I linked, pads.s, reads the controllers to $0000 and $0001 and saves the first read to $0002 and $0003 instead of the stack.

But the use of the stack to save a temporary value is a common idiom in assembly language programming. We can only speculate why the stack was used instead of a variable on zero page in this particular instance. One possibility is saving code size, as PHA and PLA are one byte shorter than STA to zero page or LDA from zero page. Another is overwriting fewer local variables so as not to disturb variables in use by the caller.

Okay, I understand bit shifting. what about pushing and pulling from the stack? Why do we need that in reading the controllers?

Just to be clear, you don't need to use the stack to read the controllers, it's just that one specific implementation used it. Everything in programming can be done a thousand different ways.

Anyway, that routine is just saving a copy of the button states to the stack, so it can read the controllers again (which overwrites the variable) and compare both values. There's a glitch in the NES that sometimes corrupts controller reads when DPCM samples are playing, so one solution to avoid that problem is to read the controller repeatedly until 2 consecutive reads match.

You can use PHA and PLA to store things in the stack temporarily, but you have to be careful to always execute the same number of PHAs and PLAs, otherwise the program can easily crash due to stack overflows or underflows.

Variables are actually just definitions (labels) of RAM registers so you could use the = or .equ directive in ASM6 like:

Code:

var0 = $0000 ;general purpose variablevar1 = $0001;...

But that would make it not possible to insert new variables in between the ones you wrote earlier. So assemblers has directives that automatically increments an internal counter of the assembler for definition purposes. In ASM6 it's the .dsb (define storage byte) and .dsw (define storage word) directives together with .enum (enumerate) and .ende (end enumerate).

Here var0 will be defined as $0000 and var1 will be $0001. The number after the .dsb directive is how many bytes you reserve for the label. I used two byte for con_stat, that way you can have controller I button states in con_stat+0 and controller II button states in con_stat+1. Zero Page should only be used for often accessed variables and for your pointers (as they require the ZP). Bigger things like arrays may be put in later pages so they don't take up too much of your Zero Page space. Page 1 is used by the hardware stack, but you can use part of it if you run out of RAM and don't use a ton of stack. The stack builds from $01FF and down, so use the first part of this page for variables in that case. Page 2 is usually used for shadow OAM, it's not necessary to use this page, but you have to use one whole RAM page for that if you are going to use OAM DMA, so you might as well use page 2 since that's what everyone does. Commercial games as well as homebrew normally uses it.Dividing the RAM in pages like this you must of course make sure that your variables doesn't spill out of the page and into the next one.

I think you can make RAM definitions about anywhere in the source file (I'm not sure), but it makes sense to put them in the beginning like in the templates.

LDA joypad1_last_frame AND #b_button ;check if b still held from last frame BNE b_exit LDA joypad1 AND #b_button ;check if new b press BEQ b_exit JSR Whatever_B_Doesb_exit: ;check some other button now

the AND here does a bit mask...removing all the other buttons from the Accumulator, so that we are only concerned with just that bit. If the result is zero (because the button is not pressed) it will set the z flag, and we can BEQ / BNE away from the subroutine.

_________________nesdoug.com -- blog/tutorial on programming for the NES

Last edited by dougeff on Tue Mar 21, 2017 11:21 am, edited 2 times in total.

Who is online

Users browsing this forum: Bing [Bot] and 5 guests

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum