x and y registers used as a "this" vs. "that" idiom.

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
x and y registers used as a "this" vs. "that" idiom.
by on (#201873)
For both my previous games, the "x" register always meant: "This entity" during my entity update loop. If I wanted to parameterize a child entity, I had to save the x register on the stack, set up the child entity, then restore the x register. For my new game, I now have my "entity_spawn" routine work entirely with the y register. Now it just feels a heck of a lot cleaner to spawn child entities, no stack required...I can just transfer straight from the parent entity, indexed by x being "this" entity, to the child entity, indexed by y being "that" entity.

This feels very idiomatic to me, like the "right way" to use 6502 in this particular instance. I.e. all previous ways I've designed this type of code were definitely clumsier in some fashion.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201874)
My native langauge do not have direct equivalents of words such as "this" or "that", so it makes no sense to me, but if it works for you then fine.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201875)
Bregalad wrote:
My native langauge do not have direct equivalents of words such as "this" or "that", so it makes no sense to me, but if it works for you then fine.


I would define "that" as "another this distinct from the original this."
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201877)
I too have used X and Y as "this" and "that". I also tend to use X as "this" and Y as an index into a table of properties of, say, each frame of animation of "this".

In The Curse of Possum Hollow, spawning a child entity in my engine is fairly heavyweight if has to be spawned immediately, as opposed to possibly several frames from now. (It may take a few frames for one of six slots in the active object table or one of two enemy CHR windows to become available.) So there's one routine that spawns an entity "whenever" by adding it to a queue that's checked every frame, quickly and using few registers. And there's another routine that spawns the enemy right effing nyeaaouw or returns an error code if there was a conflict keeping it from being spawned, so that the move routine can try again next frame. And there's a dedicated global variable for the index of the entity whose move routine is running, allowing move routines to restore X from that variable.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201880)
I use X and Y as this and that sometimes too.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201885)
Bregalad wrote:
My native langauge do not have direct equivalents of words such as "this" or "that", so it makes no sense to me, but if it works for you then fine.

«Ceci» et «cela», n'est pas?
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201891)
Unless it's German, where diese(r) means both "this" and "that", and jene(r) means only "that" but is rarely used in speech.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201930)
Swedish is pretty much like English in this case.

Adding Japanese into the mix might mess things up though. Japanese has: "kore" (this), "sore" (that) and "are" (that over there). The last one is used for things that isn't particularly close to neither the speaker nor the listener. I think I'd use A for kore, X for sore and Y for are maybe, messing things up.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201931)
I don't think either register should really get an exclusive semantic purpose like this. They aren't symmetrical so it doesn't make sense to me that one convention would fit every case.

e.g. X can be used with INC, but Y cannot, etc. Whether this asymmetry matters depends very specifically on what you're doing with either of the two things you're indexing. I'd generally suggest starting with X by "default" for indexing fixed arrays, because it's got more powerful operations for that. (Y on the other hand is more powerful for pointers.)

Once you have a pair of things to index, though, if it's as simple as a copy from one to another it doesn't really matter, and if it's not that simple there are situational advantages to both arrangements.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201933)
rainwarrior wrote:
I don't think either register should really get an exclusive semantic purpose like this. They aren't symmetrical so it doesn't make sense to me that one convention would fit every case.

e.g. X can be used with INC, but Y cannot, etc. Whether this asymmetry matters depends very specifically on what you're doing with either of the two things you're indexing. I'd generally suggest starting with X by "default" for indexing fixed arrays, because it's got more powerful operations for that. (Y on the other hand is more powerful for pointers.)

Once you have a pair of things to index, though, if it's as simple as a copy from one to another it doesn't really matter, and if it's not that simple there are situational advantages to both arrangements.

I don't think I took quite as hard line as that. I just said "in this particular instance," implying it was idiomatic in the case I'm applying it to. All I mean by that is I can't think of a neater or cleaner way to accomplish what I'm doing.

It feels natural partly because y follows x in the alphabet, and it further feels natural because most of the time, you'll be starting at some top level lookup table or array by addressing it directly, and then you might start picking addresses out of it and addressing those indirectly with y. Not saying that applies in all cases, but I'm wondering if that natural progression from "top level lookup table -> more detailed tables addressed indirectly" was in the mind of the creator of the 6502, or not. It seems to imply a natural hierarchical traversal of data starting at a table you know about, proceeding to other tables you don't yet know about til you read about them.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201936)
GradualGames wrote:
It seems to imply a natural hierarchical traversal of data starting at a table you know about, proceeding to other tables you don't yet know about til you read about them.

Well, I'd argue quite the opposite. Think of the very common case of unpacking from compressed data into your working structures. Compressed data comes in a stream, and pointers are usually the appropriate mechanism for reading serial data, so it has to be copying from a Y indexed pointer.

There is no logic to their alphabetical order. That's entirely irrelevant to what you actually need to do with these registers.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201944)
Pokun wrote:
Japanese has: "kore" (this), "sore" (that) and "are" (that over there)

Portuguese has these 3 as well: isto, isso, aquilo.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201957)
To put my point a different way, I think X and Y do have some strong and useful connections to various methods of data storage.

"Source" and "destination" are not types of data, though. Neither is "this", "that" or "the other". Even most copy operations are not copying between symmetrical equivalents, usually there is a transformation being done at the same time.

What I'm talking about are factors like:
  • serial vs random acesss
  • fixed or pointer
  • under or over 256 entries
  • read only or read and write
  • compressed or uncompressed
  • list or tree etc.
  • preserved after read or not

There's no general case for this. The source part of a "copy" has independent properties from the destination (though they can sometimes be the same). There's a lot of stuff that either X or Y can do, and several important things that only X or Y can do.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201963)
tokumaru wrote:
Portuguese has these 3 as well: isto, isso, aquilo.
I remember learning something similar back when I took Spanish, that there were 3.

So far I've only learned 2 in French, ce/ceci and ça/cela; so I don't understand what Bregalad's talking about when he said it wouldn't translate well. But I guess I can't really argue as he is a native speaker.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201966)
rainwarrior wrote:
To put my point a different way, I think X and Y do have some strong and useful connections to various methods of data storage.

"Source" and "destination" are not types of data, though. Neither is "this", "that" or "the other". Even most copy operations are not copying between symmetrical equivalents, usually there is a transformation being done at the same time.

What I'm talking about are factors like:
  • serial vs random acesss
  • fixed or pointer
  • under or over 256 entries
  • read only or read and write
  • compressed or uncompressed
  • list or tree etc.
  • preserved after read or not

There's no general case for this. The source part of a "copy" has independent properties from the destination (though they can sometimes be the same). There's a lot of stuff that either X or Y can do, and several important things that only X or Y can do.


Yeah I agree with all that. I guess what I'm really getting at is simply wondering what informed the design of the 6502. I suppose it perhaps mostly had to do with how expensive it was to design processors back then, but I wonder if they designed the instruction set with any particular use cases in mind. I.e. Were they informed by experience in any type of business related data processing for which their particular choices were particularly well suited? Or was it totally arbitrary and based only on : "What is actually possible to support given how few logic units we can use to design this thing?"

Regardless of that though, a more solid point I could really make is that when one is a beginner with assembly language, one does things in a clumsy fashion, over-using the stack or what not, but when one gains experience, it becomes more clear how to use registers in clearer or more consistent/persistent way. That's probably what I should have said to begin with. I definitely hadn't intended to say that this applied everywhere.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201986)
To me, X and Y registers (and also A register) is just whatever fits best with the instruction set for the most efficiency, and does not mean "this" and "that", it just means "X register" and "Y register".
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201987)
Of course, but in the specific case of dealing with game entities/actors/objects, most people have arrays of them, so you need some sort of indexing or pointers to access and manipulate them. When one entity/actor/object needs to talk to another, it makes sense to use X to index one of them, and Y to index the other. Using X for "this" entity makes sense to me because on the 6502 more operations are available with X indexing (e.g. ASL, LSR, ROL and ROR can only do indexed addressing using the X register), leaving Y to be used for "that" entity. If you use pointers though, Y becomes the more versatile register (but still not as versatile as X in absolute indexed mode).

Of course that even when we use X and Y to manipulate entities/actors/objects like this, the 6502 is so short on registers that you'll likely need to temporarily backup those indices so you can free the registers to do other tasks while manipulating the objects.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201988)
zzo38 wrote:
To me, X and Y registers (and also A register) is just whatever fits best with the instruction set for the most efficiency, and does not mean "this" and "that", it just means "X register" and "Y register".

My thoughts exactly.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201992)
In spanish, "this" is here, and "that" is there. "This tree" is close, within reach. "That tree" is far. I can get "this pencil" from the table, but I might have to leave my sit to reach "that one".

On the other hand, I've coded very little in assembly, but in my mindset, X=this and Y=that makes sense. I think I treated them that way.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201994)
For a more anecdotal example, in my game I used Y for "this entity" updates as a convention, and it was a mistake, largely because of how often it would be convenient to use it with INC. The "entities" are fixed arrays with fewer than 256 entries, so there's really no advantage to Y for them.

However, it doesn't really follow that I'd use X for "that entity". All cases of dealing with two at once are probably special. Sometimes I'll use X, sometimes I'll temporarily replace Y, sometimes I'll have switched "this" into the X position too. So... sometimes I would use X and Y to index two related things like that, but just as often I would do it some other way. Very situational. (For example: by temporarily replacing Y, I can reuse code that was written for the "this" case too, even when it's "that".)

And yeah, X should have been my primary convention for it, but hindsight is 20/20. In the end it's not really a big deal. After the entry to the entity's update code, I can transfer Y into X and use that instead if it's more convenient, etc. there's some inefficiency as a result, but not enough to make me want to refactor the whole thing. Even this wrong choice is good enough much of the time. ;)
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#201999)
All of my entity code uses the X register to refer to the current entity, and the entity routine is responsible for preserving X. Most of my entities need to read level data, and this is where indirect-indexed requiring Y comes in handy because it means I can directly use entity variables and level data together without needing to save and restore anything.

For entity spawning, I just have both a FindFreeObjectX and FindFreeObjectY because the routines are so small (21 bytes) and important that there's little reason not to just have both.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202001)
NovaSquirrel wrote:
All of my entity code uses the X register to refer to the current entity, and the entity routine is responsible for preserving X.

When an entity is called in my engines, X contains the index of the slot where the entity is, but this index is also stored in RAM. This allows the entity routines to quickly use X for other purposes and restore it easily afterwards.

Quote:
Most of my entities need to read level data, and this is where indirect-indexed requiring Y comes in handy because it means I can directly use enemy variables and level data together without needing to save and restore anything.

Yeah, Y then becomes the first choice for accessing data, but I can't always do everything using only Y, sometimes I need X too.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202007)
Of course I save and restore X if I need it for something else, it just means my STX is in the entity code itself rather than in the entity code caller (though it'd be a good idea to move it).

tokumaru wrote:
Yeah, Y then becomes the first choice for accessing data

I think it's the other way around. If you have large arrays involved (like my game's 4 KB level buffer) it stops being an arbitrary choice, because you're almost definitely going to need Y for that. X then becomes the first choice for anything else because Y is already taken.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202012)
Yeah, having the index redundantly in ZP somewhere is super convenient. (...sometimes not even X or Y is the right choice! We must not exclude other options.)

The other alternative to using Y, useful in some rare circumstances, is with self modifying code in RAM. You can roll your own pointer if you modify the address of the instruction directly.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202013)
NovaSquirrel wrote:
For entity spawning, I just have both a FindFreeObjectX and FindFreeObjectY because the routines are so small (21 bytes) and important that there's little reason not to just have both.

What sets up the health, initial animation frame, and other attributes of a newly spawned object, and ensures its cels are in CHR RAM?
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202015)
rainwarrior wrote:
And yeah, X should have been my primary convention for it, but hindsight is 20/20. In the end it's not really a big deal. After the entry to the entity's update code, I can transfer Y into X and use that instead if it's more convenient, etc. there's some inefficiency as a result, but not enough to make me want to refactor the whole thing. Even this wrong choice is good enough much of the time. ;)

It sounds like the choices you made concerning y vs. x are not as bad as the ones I had made previously to what I currently have. When I wanted one entity to talk to another with my current system, say transfer a bunch of 16 bit variables, AND use my 16 bit convenience macros, I'd have to transfer a bunch of data out of the current entity to ZP, then save the current index on the stack, then transfer those ZP variables into the other entity also indexed by x, then finally restore the old index from the stack. It was really ugly and hard to follow. Now it's literally just

Code:
ldy the_other_entity
move16 original_entity_variable, the_other_entity_variable, x, y


everywhere. (in other words, my macros only supported the x register at first, hence all that mess with zp transfer I mentioned above. once I added support for specifying registers it simplified a whole lot.)
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202021)
Something sort of related is that on 8080 based processors and their descendants (GBZ80, Z80, and x86), the different registers do carry some amount of semantic meaning in idiomatic code.
On the (GB)Z80, B/C/BC are typically used for counters, and DE is typically the first choice for a DEstination pointer for copies and writes and such - and that's despite the fact that the instruction set is almost entirely orthogonal w.r.t. these registers. And because HL is sort of a "16-bit accumulator", its constituent 8-bit registers are rarely wasted on storing independent 8-bit values unless necessary. These idioms do start to break down when you're writing "speed code" or facing lots of register pressure, though.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#202034)
adam_smasher wrote:
On the (GB)Z80, B/C/BC are typically used for counters, and DE is typically the first choice for a DEstination pointer for copies and writes and such - and that's despite the fact that the instruction set is almost entirely orthogonal w.r.t. these registers.

And then on the real z80 you've got instructions like "ldir" that do enforce DE as a destination, HL as a source, and BC as a counter, at least for the copy. "djnz" means that if you want to take advantage of it, the B register is already your loop counter.

tepples wrote:
What sets up the health, initial animation frame, and other attributes of a newly spawned object, and ensures its cels are in CHR RAM?

I've got a separate ObjectClearX and ObjectClearY that marks the entity as not coming from the level layout and also zeros out the entity's variables. I call that before overwriting whichever variables I want, but usually starting at zero is desired. I don't have variables specifically for things like health (almost all enemies die in one hit) or animation frame (based on timers) and in general my engine sounds simpler than yours are.
Re: x and y registers used as a "this" vs. "that" idiom.
by on (#203080)
I always use X for "this" entity and Y for other stuff like child entities, lookup tables (for entities that move in a sinusoidal way, like moving platforms in REKT).
As somebody else already mentioned, the use of X is great since it lets you use INCs and DECs with your entities, which is amazing for simple movements and animation.