Dealing with Variables in Ram That Are Only Used in One Area

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Dealing with Variables in Ram That Are Only Used in One Area
by on (#164591)
This is something that's been bugging me, because I don't know how you guys handle everything, but I usually reserve some ram (because I've run out of registers) for a variable in a routine that is only being used for that particular routine and is never used again. For example, "ObjectOffset" is used when I'm going through the code for all the objects (it offsets the object table to say what object you're on) and "SpriteCount" says how many sprites are currently being used, and this is used in the metasprite routine, which happens after all the objects have been processed. So really, I could have both of them be the same thing, but then I'd have to name it "ObjectOffset/SpriteCount" or something like that. Do you guys do this, or are you just not as careful about ram? Maybe it would be wiser to just name it "GeneralPurpose1" or something like that.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164593)
I use the first few bytes of RAM for general purpose stuff like this, and I redefine variables in that area all the time. It's labeled "Scratchpad", and I shamelessly use .org to redefine temporary variables in that space over and over:

Code:
.segment "DUMMY" ;<- dummy segment where I can pile variables
.org Scratchpad
   SomeVariable: .res 2
   AnotherVariable: .res 4
.reloc

Sometimes I need to use new temporary variables without overwriting others that are still in use, such as when one subroutine calls another and I need the temporary variables of both to share the scratchpad space. In this case so I just reserve a large enough unnamed space in the second block of variables, or I end the first block with a label marking its end and use that label in the .org statement of the second block, so it starts right after the variables it isn't supposed to overwrite.

If you don't like the idea of using .org, you can always declare these variables in a more old school way:

Code:
SomeVariable := Scratchpad + 0
AnotherVariable := Scratchpad + 2

If you know which specific variables can share the same byte, as in your ObjectOffset/SpriteCount example, you can always give 2 names to the same memory location like this:

Code:
ObjectOffset:
SpriteCount: .res 1

That is, only reserve the space after the last name you'll be using to refer to that location. You cal obviously also create aliases like this: SpriteCount := ObjectOffset

Another option is to go the "virtual registers" way, where you give each byte/word generic numbered names, like in your "GeneralPurpose1" idea, and either use those as is or create aliases for them as needed: ObjectOffset := GeneralPurpose4

There are many options, but the one thing that all these methods have in common is that you have to be extra careful with how you use this shared memory. When you have multiple names for the same memory locations it's easy to get confused and overwrite values you shouldn't.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164597)
Is there a 65816 equivalent to 68000's RS?
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164621)
Sik wrote:
Is there a 65816 equivalent to 68000's RS?

I've now skimmed two Motorola 68000 manuals and I can't find any definition of this, other than "register select" backed by either no description or an incredibly vague one. Can you shed some light on what this is?
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164622)
Or is it just an assembler directive that reserves memory, in which case it's not really a 68000 thing?

This is a Nintendo development forum, you shouldn't expect many of us to know much about 68000 coding. :wink:
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164646)
Currently I am reusing temporary variables with a module's routines but not globally like tokumaru.

The variables are word sized, named tmp1 to tmpN, and are declared at the start of a module. Inside the routine (which is encased in a proc) I rename them to tmp_<name>, so I can easily scan to see which routine uses which tmp variable.

These variables are declared at the module scope and not globally because I am generally unsure as to how I will be calling the routine and I want to prevent variable collisions.

As I code with DB=$7E I'm not worried about running out of RAM just yet.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164648)
Yeah, I think I'm just going to name it something that tells me it's not specific to anything, like the name I said earlier. I'll probably just put a comment at the beginning of the code that says what the different variables are being used for. The reason I don't want to name them is because I'll probably screw it up later by editing the code to were one of the variables does carry over past the routine and is jacked up. The best solution would be if you could name it whatever you want to, but you'd make the assembler spit out an error if you accessed that part of ram by a name not being used there. Were you talking about something like this, UnDisbeliever?
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164653)
Espozo wrote:
The reason I don't want to name them is because I'll probably screw it up later by editing the code to were one of the variables does carry over past the routine and is jacked up. The best solution would be if you could name it whatever you want to, but you'd make the assembler spit out an error if you accessed that part of ram by a name not being used there.

I always create the aliases inside the scope of the function that's using said aliases, so they can't normally be used outside of the function they were meant for. I do need to access them from the outside sometimes though, like for passing parameters to functions, so I created a macro to "export" symbols to the outer scope, but prefixed by the function's name, so that there's no doubt who those variables belong to when I use them from the outside.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#164656)
Espozo wrote:
Yeah, I think I'm just going to name it something that tells me it's not specific to anything, like the name I said earlier. I'll probably just put a comment at the beginning of the code that says what the different variables are being used for. The reason I don't want to name them is because I'll probably screw it up later by editing the code to were one of the variables does carry over past the routine and is jacked up. The best solution would be if you could name it whatever you want to, but you'd make the assembler spit out an error if you accessed that part of ram by a name not being used there. Were you talking about something like this, UnDisbeliever?

Yeah, that's the main reason I started doing it my way.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#168577)
I also use temporary variables, $10 for variables and 10 others for the function (in / out).
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#169378)
You could always reserve some stack area that would function as a local variable store to the routine. If you also move the DP register to the top of your stack frame you have a large number of instructions available (not only the ones that are able to operate stack relative).
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#169382)
Coming to 6502 straight from GameMaker, I'm used to dealing with scripts and arguments, so I reserved the first six of my ram as arg0-arg5, and at the beginning of each routine that uses those bytes I leave a comment line denoting the way each argument is used and whether the routine clobbers them. This is probably not the best (least confusing) way to do this, and I'm probably dedicating way too many bytes to these arguments, but I'm still on my first game here so take my example as an option and not a solution.

I have also had some luck with getting more temporary bytes by pushing the accumulator onto the stack at the start of a routine and pulling it as needed, but I'm nervous about using too much stack memory for fear of the NMI triggering at a bad time and causing an overflow. It hasn't happened to me yet but I feel like it's a danger to be aware of.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#169396)
I used to take the stack-based approach before I realized that a simple sta and lda on the DP is faster (and more flexible). So far I haven't run out of space in the DP so I'm using separate variables for different things instead of reusing the same scratch space.

Edit: For protecting the caller from side effects, I still push stuff I don't need to the stack where I'm going to use something in that register.
Re: Dealing with Variables in Ram That Are Only Used in One
by on (#169938)
HihiDanni wrote:
I used to take the stack-based approach before I realized that a simple sta and lda on the DP is faster (and more flexible). So far I haven't run out of space in the DP so I'm using separate variables for different things instead of reusing the same scratch space.

Edit: For protecting the caller from side effects, I still push stuff I don't need to the stack where I'm going to use something in that register.


Well, you could use the DP as an object slot pointer, if you can fit everything in the first 8kB.