Local variables in C and C++ are allocated on the stack (a sliding window of RAM used just for locals and function parameters). On a 6502 you don't have such a thing.

In 6502 ASM a "local" variable is one that is only used by one particular subroutine. Assemblers that support scoping can make this easier by making access to labels from the outside harder. This does not support recursion, so if your subroutine calls itself it will stomp on the local variables, unlike C and C++.

What Tokumaru was describing was something different. I will try to explain in more round terms:

Hypothetical Man wrote:

I have a routine that handles the title screen. It needs 500 bytes of RAM, which I allocate starting at $0300.

I have another routine that implements my game. It needs 1500 bytes of RAM. Because I know that the game and the title screen will never be running at the same time, I also start allocating RAM at $0300.

So now I have two routines that use the same memory locations for variables, but because they never run at the same time (and do not care what is in RAM when they start) they do not step on each other's toes.

I think this approach is fine when you are dealing with distinct modes of operation, like our title screen / game example. If your game is a series of mini games (like Pirates!), each mini-game might reuse the same area of RAM for variables, and then you might have a small protected segment to keep game state variables.

Personally I do not like doing this within a game mode. It's true, my sprite generator never runs at the same time as my object updates, but this type of data interleaving over-complicates your code. Only if I were very desperate for RAM would this be an option for me.

So that means we could declare a variable... and then, later on, since the previous variable was local... and we are in a different area of code, we could declare another variable in the same spot!?

That's the idea. Since not all variables must exist at all times, many variables can share memory locations, and the code I wrote before is the most organized way I can think of doing that.

Quote:

Just like local variables in C++?

Kinda... In the sample code I wrote they aren't exactly local, because technically you could still use them anywhere in the program (i.e. the labels are global). Of course you wouldn't want to use one module's variables in another module, because that would crash the program. You could probably use ASM6's local labels (they start with a period, I think) though, and they would be more like local variables. Something like this:

Code:

SomeFunction:

.enum LocalVariables3

.LocalVariable1 .dsb 1.LocalVariable2 .dsb 1.LocalPointer .dsb 2

.ende

;the variables declared above can only be seen here

;return rts

Quote:

If all of the files combine in to one single .asm file then how does this work when there is just one file?

There's really no difference between 1 file vs. multiple files... When you include a file, it's the same as if you were copying and pasting its contents directly into the first file. The only reason to separate the source into multiple files and use includes is organization. Scrolling through a 20,000 line program looking for a piece of code is hell.

Personally I do not like doing this within a game mode. It's true, my sprite generator never runs at the same time as my object updates, but this type of data interleaving over-complicates your code. Only if I were very desperate for RAM would this be an option for me.

I wouldn't be able to make my game without this. The main engine uses every last byte of RAM, so I can't afford to have memory allocated for a bunch of stuff that just isn't running during gameplay (title screen, menus, bonus stages, etc). The main systems, like the ones dealing with music, sprites, etc. use global variables, because those are used by all program modes. It's not a difficult thing to manage at all: whatever is used by multiple program modes is global.

Warning: don't forget that active DMC conflicts with $2002 and controllers polling, read docs to learn how to avoid it (generally don't use $2002 polling and poll controllers three times in a row, then use matching result).

What is active DMC? I know $2002 is in the first group of I/O registers... I guess it allows interaction with the controllers. In my code I'm using $4016 to read the controller... $4016 is from the second and last group of I/O registers. When I read the controller from $4016 is that called 'polling' too?

Any reading that has side effects may screw up, because DMC adds one extra read. Examples of reads with side effects include reading the controller or reading bytes from PPU Data. Reading PPU status is okay, since one extra read won't hurt anything.

Any reading that has side effects may screw up... Examples of reads with side effects include reading the controller

Yes, I agree, now (after reading some more about reading). : ) My song wont play for me. And so I'm wondering if it has something to do with the way I've worked the callling code into the controller reading part. Here is what i've got (the famitone code is between the ---\/-- and the ---^---):

First off, you need to read the controller and store it into a variable. Doing it right off of the read is a terrible way to make an engine. Do a LSR and ROL it into a variable, then use that variable to see what needs to happen.

3gengames, I relpaced my code with your code and put this right after it

Code:

jsr high_c .if ControllerButtons != 0 .error "need help" .endif

And while running my program it never ever stops and says need help no matther what I'm pressing on the controller. The controller works fine in other programs. It is continuealy reaching this code cause I can hear a high pitch C noise over and over.

In your code you've got

Code:

Loop: LDA $4016 LSR A ROL ControllerButtons DEX BNE Loop

That lsr a writes its answer back into the accumulator right? And rol ControllerButtons writes its answer back into ControllerButtons right? So how is ControllerButtons updated? (These questions are for yall too.)

"LDA $4016" puts the state of the current button into the accumulator; "LSR A" (or simply "LSR", depending on the assembler) shifts the bit out of the accumulator and into the carry flag; "ROL ControllerButtons" shifts the carry flag into ControllerButtons. Do this 8 times in a row and each bit of "ControllerButtons" will indicate the state of a buttom.

the .rsset and Controller variable is any piece of RAM you want to point it at, here's a commented and better version:

Code:

LDX #$01 ;X=1STX $4016 ;Write high latch value to controller port.DEX ;X=0STX $4016 ;4016=0 now, can be read back.LDX #$08 ;X=8Loop: LDA $4016; Put the player 1 controller value into the accumulator. This will hold the value of ONE button.LSR A ;Put DataLine1 [Controller] onto the Carry.ROL ControllerButtons ;Shift ControllerButtons RAM one bit left with the carry. When done 8 times, will be updated with button statuses for each button. One bit will represent one button. The MSB will be first read, LSB last read. 1=Pressed, 0=Not pressed.DEX ;X=X-1BNE Loop;If X!=0 then loop.RTS ;Return from subroutine. New controller status for Player 1 will be in the RAM byte ControllerButtons.

Does this make sense on how it works? Any qustions just ask. This program should work.

ETA: NINJA'D!

Last edited by 3gengames on Thu Jun 16, 2011 12:19 pm, edited 1 time in total.

Who is online

Users browsing this forum: No registered users and 9 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