TylerBarnes 183 Member · Posted December 6, 2019 Share Posted December 6, 2019 Not sure if it has already been discussed elsewhere, but was wondering.... Simple projects on the NES are going certainly going to have plenty of slots in RAM to use for various flags, values, and buffer space. However, I could see certain cases where a project gets very large or large ram buffers are used. Anyone ever use a single byte in RAM for up to status 8 flags? I was thinking about this in that having tons of bytes in RAM that only ever toggle from 0 to 1 all the time is wasteful. Also I could see it used as a sort of organisation system if one byte did many related flags. Too convoluted or no? Setting flags in this way could look like this (in my head at least): PlayerState = $A0 IsStunned = 1 IsJumping = 2 HasPowerUp = 4 IsDead = 8 GameState = $A1 Paused = 1 GameOver = 2 Credits = 4 Jump: LDA PlayerState ORA #IsJumping STA PlayerState [Do jump stuff] RTS Physics: [Do gravity stuff] [Do floor detection] BEQ Landed RTS Landed: LDA PlayerState EOR #$FF ORA #IsJumping EOR #$FF STA PlayerState RTS Link to comment Share on other sites More sharing options...
RH 4,053 Member · Posted December 6, 2019 Share Posted December 6, 2019 What, exactly are you asking? I've never dug to deep in NES dev, but a lot of flags are bits, packed within specific bytes. I'm unfamiliar with the ASM syntax, but usually you do an AND mask of some form to check a bit, and then branch accordingly. To be clear, this is the right way to save space and not waste bytes. 1 Link to comment Share on other sites More sharing options...
KHAN Games 147 Member · Posted December 6, 2019 Share Posted December 6, 2019 I've done this many times. In my Fishing Challenge I use one bit per fish to keep track if I have it or not. Similarly in NEScape! I use a single bit to keep track of if a book is pushed in/pulled out or a piano key is pressed or not. 1 1 Link to comment Share on other sites More sharing options...
Sumez 2,218 Member · Posted December 6, 2019 Share Posted December 6, 2019 (edited) For NES development I do this constantly. It's very simpe to check towards a single bit/flag, it's just a single AND. So I don't really see why you shouldn't. I store a lot of data in bitmasks also, and enemy/object spawning/destroying uses a bitmask too, just using an 8-byte LUT to get the correct mask value. For SNES development, I don't really bother. In fact, I frequently even reserve two bytes for tiny numbers, just so I don't have to worry about not having registers the correct size when I address it.. That system just has an infinite supply of RAM. Edited December 6, 2019 by Sumez 1 Link to comment Share on other sites More sharing options...
TylerBarnes 183 Member · Posted December 7, 2019 Author Share Posted December 7, 2019 6 hours ago, RH said: What, exactly are you asking? The main inquiry was are people bothering with the extra logic involved when using every bit for flags and masking all the time, or if it is more rare to want/need to use all bits of a byte for flags. 6 hours ago, RH said: but usually you do an AND mask of some form to check a bit, and then branch accordingly. Indeed. I forgot to include that sort of section in my example. Jump: LDA PlayerState ; Load Player Flags AND #IsJumping ; Examine Only Jump Flag BNE Skip ; Skip if flag is set LDA PlayerState ; Load Player Flags ORA #IsJumping ; Set Jump Flag STA PlayerState ; Save Flags [Do jump stuff] Skip: RTS 5 hours ago, Sumez said: using an 8-byte LUT to get the correct mask value. Do you have a small digestible example of this lookup table setup? I don't think I can picture what you mean. Link to comment Share on other sites More sharing options...
0xDEAFC0DE 1,270 Member · Posted December 7, 2019 Share Posted December 7, 2019 33 minutes ago, TylerBarnes said: Do you have a small digestible example of this lookup table setup? I don't think I can picture what you mean. MaskLUT: .hex 01 02 04 08 10 20 40 80 I think they're referring to something like the table above. Then if you want to get the 'i'th bit you and with 'MaskLUT + i'. 1 Link to comment Share on other sites More sharing options...
TylerBarnes 183 Member · Posted December 7, 2019 Author Share Posted December 7, 2019 Ah, I see now. I was over thinking in that it was something more specific than that. I personally like the readability of declaring constants with labels. Seeing too many instances of MaskLUT+1, MaskLUT+3, etc in the code would throw me off in the context I am thinking of. Other contexts I'm sure would be great with the above. Link to comment Share on other sites More sharing options...
treed 1 Member · Posted December 7, 2019 Share Posted December 7, 2019 Seems entirely reasonable to me. I'm working my way through Nerdy Nights and took a similar approach for flags. Although I wonder why I haven't seen other people using BIT for this: LDA #8 BIT buttons1 BEQ MovePaddleDown As far as I can tell, it's identical in cycles and bytes, so is it just a matter of taste or is there a drawback there? I guess the only benefit I see with using BIT over AND is that A is left alone, in case you wanted to use the same bitmask right away. With the game states though, I probably wouldn't represent it at a bitfield, since the states are actually mutually exclusive. You won't ever have a state which is GameOver & Credits & Paused, for instance. The approach I'm planning to use in my NN Pong is that "State" is just an address and then I do an Indirect JMP once per frame to do the updates. Sadly there's no indirect JSR. You also couldn't do a jumptable of states, since there's not even indexed JMP. Could be some drawback to this plan, but I guess that's what this whole phase of learning is for. Link to comment Share on other sites More sharing options...
Sumez 2,218 Member · Posted December 7, 2019 Share Posted December 7, 2019 (edited) 6 hours ago, TylerBarnes said: Ah, I see now. I was over thinking in that it was something more specific than that. I personally like the readability of declaring constants with labels. Seeing too many instances of MaskLUT+1, MaskLUT+3, etc in the code would throw me off in the context I am thinking of. Other contexts I'm sure would be great with the above. If you're working with constants there's no reason to use data space at all, and of course "MaskLUT+3" doesn't make any sense - that's not the purpose of a look-up table. My example was in the context of accessing a dynamic index into a byte with 8 flags in it, for example because you have 8 on-screen enemy slots with indexes from 0 to 7, and need to access one of them. LDY CurrentEnemy ; Let's say this is enemy index 3, so Y is now = #3 LDA EnemyFlags ; A byte with 8 flags, one for each enemy. We are looking for bit 3, but our code doesn't know that so we can't use a constant AND MaskLUT, Y ; This will AND the byte with %00001000 (8) to check for the flag state in index #3 BEQ WhateverBranch ; Branches based on enemy 3's flag Edited December 7, 2019 by Sumez Link to comment Share on other sites More sharing options...
Sumez 2,218 Member · Posted December 7, 2019 Share Posted December 7, 2019 2 hours ago, treed said: As far as I can tell, it's identical in cycles and bytes, so is it just a matter of taste or is there a drawback there? I guess the only benefit I see with using BIT over AND is that A is left alone, in case you wanted to use the same bitmask right away. Though of course BIT has other usages, that's the primary reason to use BIT over AND when you are only interested in the Zero flag. Though in your example it would probably make more sense to load "buttons1" into A and then BIT with the bitmask, allowing you to use the button states again, immediately after your branch. 1 Link to comment Share on other sites More sharing options...
Orab Games 97 Member · Posted December 7, 2019 Share Posted December 7, 2019 Yeah, I do this. Tailgate Party's achievements are handled this way. I'm sure there are many more times I have done this as well. Link to comment Share on other sites More sharing options...
TylerBarnes 183 Member · Posted December 7, 2019 Author Share Posted December 7, 2019 9 hours ago, treed said: Although I wonder why I haven't seen other people using BIT for this: Never thought to use BIT. Being able to BIT through multiple states in a row on the same button state without additional LDAs would be helpful. 7 hours ago, Sumez said: and of course "MaskLUT+3" doesn't make any sense You are right. Brain fart. Of course MaskLUT, y would be to index. I somehow understood deafcode's example and then proceeded to act like I didn't know how to index a table. lol. Thank you for the example. That definitely shows the advantage of a table vs using the bits for different states. Link to comment Share on other sites More sharing options...
treed 1 Member · Posted December 8, 2019 Share Posted December 8, 2019 12 hours ago, Sumez said: Though of course BIT has other usages, that's the primary reason to use BIT over AND when you are only interested in the Zero flag. Though in your example it would probably make more sense to load "buttons1" into A and then BIT with the bitmask, allowing you to use the button states again, immediately after your branch. Yeah, I originally thought about that, but BIT has no immediate mode. It's only got ZP and Absolute. Link to comment Share on other sites More sharing options...
0xDEAFC0DE 1,270 Member · Posted December 8, 2019 Share Posted December 8, 2019 6 hours ago, TylerBarnes said: You are right. Brain fart. Of course MaskLUT, y would be to index. I somehow understood deafcode's example and then proceeded to act like I didn't know how to index a table. lol. Thank you for the example. That definitely shows the advantage of a table vs using the bits for different states. Ah, sorry. It's been a little while since I've programmed 6502, so I forgot what the indexing syntax was. Link to comment Share on other sites More sharing options...
Sumez 2,218 Member · Posted December 8, 2019 Share Posted December 8, 2019 X/Y indexing is the bread and butter of the 6502 along with quick zeropage access It's not very C friendly, but it's very effective when your code and data structure is optimized towards it. Link to comment Share on other sites More sharing options...
TylerBarnes 183 Member · Posted December 9, 2019 Author Share Posted December 9, 2019 On 12/8/2019 at 11:58 AM, Sumez said: X/Y indexing is the bread and butter of the 6502 along with quick zeropage access It's not very C friendly, but it's very effective when your code and data structure is optimized towards it. Very true; Indexing makes many things soooo much easier. My favorite thing to do for code re usability is add pointer support to functions that could be used for multiple tables. Lets say you have different palettes for different levels. ;---------------Variables----------- data = $C2 dataH = $C3 ;----------------Setup-------------- LoadLevel1Palettes: LDA #<Lev1Pal ; Load Level1 Palette's LDX #>Lev1Pal ; location into a pointer. STA data STX dataH JSR LoadPalette ; Run the load palette routine Forever: JMP Forever ;---------------Subroutines---------- LoadPalette: LDA #$3F ; Load PPU location to write LDY #$00 ; $3F00 is for Palettes STA $2006 STY $2006 PalLoop: LDA (data), y ; Index into loacation in Pointer (data) STA $2007 ; Write Byte INY ; Incriment Index CPY #$20 ; Takes 32 writes to complete BNE PalLoop ; Keeps looping till done RTS ;----------------Data---------------- Lev1Pal: .incbin "Level1.pal" Link to comment Share on other sites More sharing options...
gauauu 79 Member · Posted December 9, 2019 Share Posted December 9, 2019 My answer: I've definitely used it. When to use it is a tradeoff of how often you access something vs the space required for it. For a flag that gets used multiple times in a frame in a loop, and isn't part of a giant array of flags, I'd just waste a byte for it. It's so much faster, and what's 1 byte of out 2K? Example: In my current game Halcyon, there's a flag for whether the player is in the tank or out of it. I just waste a byte. No point in packing that for something that simple. But for something that's a big array, particularly if it's not accessed often, then bit-packing is the way to go. In Halcyon, for storing where a player has been (for the minimap), I use a bit per screen. And a bit per item picked up in the global game status. It's a little slower, but for storing that much state, it would be really wasteful to have a byte per item. 1 Link to comment Share on other sites More sharing options...
TylerBarnes 183 Member · Posted December 9, 2019 Author Share Posted December 9, 2019 I see, that definitely makes a lot of sense. When the space saving starts to impede on performance of a commonly checked bit, it starts become more of a con than a pro. 1 Link to comment Share on other sites More sharing options...
gauauu 79 Member · Posted December 11, 2019 Share Posted December 11, 2019 On 12/9/2019 at 3:07 PM, TylerBarnes said: I see, that definitely makes a lot of sense. When the space saving starts to impede on performance of a commonly checked bit, it starts become more of a con than a pro. Oh, and performance isn't the only tradeoff -- the other is in readability/maintainability. If you're skimming through your code 6 months later, trying to figure out what's going, simpler is better. My mantra: I ALWAYS optimize my code. But the first optimization priority is for readability. Only when performance or space becomes an issue do you shift and optimize for one of them instead. Link to comment Share on other sites More sharing options...
Recommended Posts