Not too long ago I created a
minimal NES emulator targeted at homebrew games.
After supporting 10+ games, I never implemented calculating the V flag after any add or subtract operation, only setting it after "bit," commonly used for vblank waits.
I've never used it, myself, after any add or subtract operation. Is it ever useful?
Grepping the cc65 source, it's used for 32-bit int handling, and some non-nes platform-specific things.
calima wrote:
Grepping the cc65 source, it's used for 32-bit int handling, and some non-nes platform-specific things.
I guess I'm mostly curious about whether it's ever useful for game development purposes. I've never used anything bigger than 24 bits when coding NES games, myself...
It's useful to detect signed overflows/underflows (while the carry is used for unsigned overflows/underflows). If you take 120 and add 10, you get 130, a perfectly valid unsigned result, but it's larger than 127, the largest signed value a byte can hold. So yeah, even with smaller 8-bit numbers the V flag might still be useful. I hardly use it though, but that's because I hardly ever have to bother about signed overflows.
I can't think of a very practical example, but the Vflag could be used to store one bit of branch info you'd like to hang onto through a chunk of code that doesn't contain ADC/SBC/BIT instructions.
EDIT: also to correct the topic, CMP doesn't affect V flag.
tokumaru wrote:
It's useful to detect signed overflows/underflows (while the carry is used for unsigned overflows/underflows). If you take 120 and add 10, you get 130, a perfectly valid unsigned result, but it's larger than 127, the largest signed value a byte can hold. So yeah, even with smaller 8-bit numbers the V flag might still be useful. I hardly use it though, but that's because I hardly ever have to bother about signed overflows.
I've used it for this reason before. Not often though.
GradualGames wrote:
After supporting 10+ games, I never implemented calculating the V flag after any add or subtract operation, only setting it after "bit," commonly used for vblank waits.
I've never used it, myself, after any add or subtract operation. Is it ever useful?
Yes. I use it to determine whether an addition or subtraction involving a signed number overflowed. This is useful for ensuring an entity's position doesn't leave the bounds of the screen or map and wrap to the other side, or that acceleration doesn't cause velocity to wrap past (say) +127 to -128.
Code:
clc
lda signed_velocity
adc signed_acceleration
bvc no_clamping_needed
; OMITTED: clamping code
no_clamping_needed:
sta signed_velocity
clc
lda unsigned_displacement
eor #$80
adc signed_velocity
eor #$80
bvc no_clamping_needed
; OMITTED: clamping code
no_clamping_needed:
sta unsigned_displacement
The effect of BIT is probably why I use it the most. The way I handle the math doesn't really need the V flag because most of the time I add signed 16-bit values to unsigned 16-bit values... so I still only ever need the carry for that (though I have to interpret the carry differently based on the sign of what I was adding to the unsigned value).
tepples wrote:
This is useful for ensuring an entity's position doesn't leave the bounds of the screen or map and wrap to the other side, or that acceleration doesn't cause velocity to wrap past (say) +127 to -128.
Yup, that's exactly where I've used it as well.
The V flag isn't affected by CMP (or CPX/CPY), but it's affected by ADC, SBC, BIT and of course CLV.
I just
asked about it myself and from what I understand it's used mostly for the following things:
* Signed comparisons
* Manual fixing in signed math (normally not needed)
* Simulation of a branch always instruction (for relocatable code and such)
* Used in a special feature of the BIT instruction
There's also a SET V pin on stock 6502 chips (though not on 65816) but I don't think the pin is available in the NES.
Also while it indicates a signed overflow, you don't use it in signed math like you use Carry in unsigned math as one might think, signed math is done the same way as unsigned math on the 6502. However signed comparisons won't work correctly just using CMP like with unsigned comparison. I learned how to do signed comparisons in
this article using SBC and the V flag, and I'm using it in my game to compare signed 16-bit numbers (for things like preventing the player from running faster than the allowed max speed).
So I guess my game (can be found somewhere in the above linked thread if you want to test it in your emulator) won't work in your emulator if it doesn't support the V flag after an SBC. I don't know how common it is to do things like I did it, but I imagine that using signed numbers is very common in action games, so signed comparisons can't be THAT uncommon.
Pokun wrote:
So I guess my game (can be found somewhere in the above linked thread if you want to test it in your emulator) won't work in your emulator if it doesn't support the V flag after an SBC. I don't know how common it is to do things like I did it, but I imagine that using signed numbers is very common in action games, so signed comparisons can't be THAT uncommon.
The scope of ggvm was intended to be insanely narrow and only support "one game at a time," so I just added features as I went. Adding support for the V flag would be pretty easy if someone needed it. That said though the scope of ggvm is so constrained the ppu doesn't even emulate scanline per scanline, which means things like status bars and the like have to be accomplished via special fake hardware registers that enable/disable features. Also there's no apu emulation either. (plays back mp3s instead) So as long as a game uses "mainly the basics" you can get it to where it's indistinguishable from a full emulator, for that specific game. But it'll never be a full emulator. I did it to get my games on something other than NES and it wound up helping out a few other people, which is cool. Didn't expect that to happen.
In my opinion this is an essential component of the CPU. I don't really understand any desire to leave out the V flag from instructions that are supposed to affect it. There is nothing to gain from that, and a lot of stuff will be broken without it. Why wouldn't you put it in???
This isn't like the illegal opcodes, every 6502 has this function and it's a standard part of signed computations! If you think it doesn't seem to be needed, the only thing I could say is you haven't used it very thoroughly. The stuff that breaks could be subtle, like in my game it would probably cause a lot of the enemy AI to make incorrect decisions about which way to move, but unless you know how they're supposed to move this would be a hard error to spot casually. Like, you've made a silent error condition here; if you really want to see for sure what it's breaking maybe put in a test condition on BVC to fire if the last V instruction was SBC, I'm sure you'd start to accumulate examples fairly quickly if you did that on a variety of games.
rainwarrior wrote:
In my opinion this is an essential component of the CPU. I don't really understand any desire to leave out the V flag from instructions that are supposed to affect it. There is nothing to gain from that, and a lot of stuff will be broken without it. Why wouldn't you put it in???
This isn't like the illegal opcodes, every 6502 has this function and it's a standard part of signed computations! If you think it doesn't seem to be needed, the only thing I could say is you haven't used it very thoroughly. The stuff that breaks could be subtle, like in my game it would probably cause a lot of the enemy AI to make incorrect decisions about which way to move, but unless you know how they're supposed to move this would be a hard error to spot casually. Like, you've made a silent error condition here; if you really want to see for sure what it's breaking maybe put in a test condition on BVC to fire if the last V instruction was SBC, I'm sure you'd start to accumulate examples fairly quickly if you did that on a variety of games.
I had no desire to leave it out, I just had no reason to implement it yet. My approach to developing ggvm is insanely amateurish if you haven't figured that out yet. To debug it, I typically need the full source code of a game, so that I can set breakpoints while ggvm runs and get an idea where I am in the running game's code. If I made it my 100% focus maybe I could write a series of tests or get some non homebrews working, but as it is I could not devote very much time to it. Just enough to get my games and a few homebrews working perfectly. *edit* I've actually grepped every single game's code that I've adapted to make sure it's not using bvs bvc except after bit.
I apologize for not being able to provide test cases at the moment. I made Thwaite in 2011 before I learned EOR-ADC-EOR-BVC, though there were several places that could have used it. By the time I programmed Haunted: Halloween '85, I knew the trick, but its source code is a trade secret. I forget whether I used it in Zap Ruder or RHDE; I haven't cloned them since my other laptop's battery died a couple weeks ago.
GradualGames wrote:
I've actually grepped every single game's code that I've adapted to make sure it's not using bvs bvc except after bit.
That... sounds like a lot more effort than it would take to just implement V. O_o
From...
http://www.6502.org/tutorials/vflag.html"CLV clears V. Simple enough. It is most frequently used in conjunction with a BVC to simulate a forced branch (a.k.a a branch always) in relocatable routines. The 65C02 has a branch always instruction (BRA), but the 6502 does not."
Once you are sure V is clear, you can use BVC repeatedly, as long as there are no ADC,SBC,or BIT instructions. Is 1 byte shorter than JMP
Also, I've used the V flag in signed math, but I prefer not to (unsigned math is easier). I've mostly seen it for sprite zero checking, after BIT.
Edit - I couldn't find any example code where I used bvc or bvs for math. I retract that statement.
tepples wrote:
I learned EOR-ADC-EOR-BVC, though there were several places that could have used it.
What does the EOR-ADC-EOR-BVC trick achieve?
I wanna know too.
rainwarrior wrote:
GradualGames wrote:
I've actually grepped every single game's code that I've adapted to make sure it's not using bvs bvc except after bit.
That... sounds like a lot more effort than it would take to just implement V. O_o
Yeah just implement it already! lol
This thread is interesting to see how people use V, but other than that, it's not much to discuss whether or not to implement it I think.
Oziphantom wrote:
tepples wrote:
I learned EOR-ADC-EOR-BVC, though there were several places that could have used it.
What does the EOR-ADC-EOR-BVC trick achieve?
From
my previous post: "I use it to determine whether an addition or subtraction involving a signed number overflowed. This is useful for ensuring an entity's position doesn't leave the bounds of the screen or map and wrap to the other side."
It distinguishes 129 + (-2) = 127, which in this context is desirable, from 1 + (-2) = 255, which in this context needs to be clamped to 0.
cc65 uses bvc in both icmp.s and lcmp.s for signed comparisons.
https://github.com/cc65/cc65/tree/master/libsrc/runtime
Pokun wrote:
I wanna know too.
rainwarrior wrote:
GradualGames wrote:
I've actually grepped every single game's code that I've adapted to make sure it's not using bvs bvc except after bit.
That... sounds like a lot more effort than it would take to just implement V. O_o
Yeah just implement it already! lol
This thread is interesting to see how people use V, but other than that, it's not much to discuss whether or not to implement it I think.
In most cases I simply asked the developer of the game I was adapting whether they ever used bvc or bvs and delegated the task of answering that question to them, so it didn't feel like much work. I did try to implement V initially, but couldn't figure it out at that time. Plus I had no games which were exercising it anyway, and didn't feel like writing a test rom for something which I didn't know would necessarily be used. Like I said I have a lot of other things I do with my time, like making games, music, my full time job, walking for an hour every day, playing games, watching tv, etc. ggvm was something I got done over winter when I had slightly fewer things occupying my time, now I barely have any time for it. You're welcome to add support for V to the
github project if you want to help out
It has turned out to be useful to a number of folks. That reminds me actually, I don't think I ever finished implementation of indexed indirect instructions either, I never use them and again, neither did the 10+ games I've adapted...
GradualGames wrote:
I don't think I ever finished implementation of indexed indirect instructions either, I never use them and again, neither did the 10+ games I've adapted...
I've read different explanations of good uses of indexed indirect instructions...but I've never once used them.
The only use (for (zp,x)) I've found so far is to dereference some address when X already happens to be 0 or I don't want to destroy Y (required for (zp),y) for some reason.
thefox wrote:
The only use (for (zp,x)) I've found so far is to dereference some address when X already happens to be 0 or I don't want to destroy Y (required for (zp),y) for some reason.
It's so rarely used too bad we can't go back in time and tell the chip designers to get rid of indexed indirect and instead make the rest of the instruction set symmetrical. Haha. I don't know how many times I've tried to use
sty blahblah,x
thinking I could because I also did
ldy blahblah,x
...
*edit* Wait, now I'm confused. Out of curiosity I checked my printed out 6502 reference. It says zp,x is available for sty. But I'm pretty sure ca65 yells at me when I try it. Oh wait....it's ABS,x that I'm trying..that's what isn't supported.
I once started a music engine where the streams for the different channels were accessed by consecutive pointers in ZP, and X was used to select one of them.
tokumaru wrote:
I once started a music engine where the streams for the different channels were accessed by consecutive pointers in ZP, and X was used to select one of them.
Same here. The only time I remember having actually used
(dd,X) has been in my music engine Pently, where X equals 0, 4, 8, 12, or 16 for the five logical tracks (pulse 1, pulse 2, triangle, drum, attack) or the four APU PSG channels (pulse 1, pulse 2, triangle, noise). But GGVM's sampler is completely different from the 2A03's APU anyway.
I imagine that there are other uses of a pointer table on zero page. But 6502 coders who learned on Commodore 64 or Apple II won't have a lot of experience with it because Microsoft BASIC in ROM ate so much of zero page for itself.
tepples wrote:
But 6502 coders who learned on Commodore 64 or Apple II won't have a lot of experience with it because Microsoft BASIC in ROM ate so much of zero page for itself.
And I guess they didn't even need ZP that much, since any absolute reference can be used as a pointer when code is running from RAM.
I suppose you could use (zp,x) as pointers to pointers. (Or rather, to get the starting offset within a pointer table). But I would still prefer to use (zp), y or some other mode for that.
I made it pretty clear on my blog that I don't like (zp, x) mode, and don't use it.
tokumaru wrote:
tepples wrote:
But 6502 coders who learned on Commodore 64 or Apple II won't have a lot of experience with it because Microsoft BASIC in ROM ate so much of zero page for itself.
And I guess they didn't even need ZP that much, since any absolute reference can be used as a pointer when code is running from RAM.
Well, in the case of (zp,X) the point is to be able to loop through or random-access a table of pointers. Self-modifying code doesn't do that very well (requires unrolled code, altering the pointers by index no longer possible, etc.)
tepples' canonical example for something that is convenient with a table of pointers is per-channel data streams in a music engine, and that's primarily where I've used it too.
thefox wrote:
The only use (for (zp,x)) I've found so far is to dereference some address when X already happens to be 0 or I don't want to destroy Y (required for (zp),y) for some reason.
Well I use (zp,X) as a way to do a multi-channel music engine, and I also do this for a bytecode interpreter (basically improved SWEET-16). So I may use the instruction twice in the whole game code, but that particular instruction can be executed potentially hundreds of times per frame.
Quote:
I made it pretty clear on my blog that I don't like (zp, x) mode, and don't use it.
It's up to you to like it or not, but refusing to use it in one of the rare cases where it could be handful it's not very bright.
As for BVS/BVC, I use it
mainly exclusively in combination with BIT, but not only with $2002. BIT is an amazing instruction when it comes to read the top two bits of any variable, I do that all the time. It's also common I have routines which returns two boolean values, one in C and one in V.
BIT $2002, BIT $BUTTON_STATE for B in V; a few "branch always" or otherwise wanting a flag that doesn't need a refresh instruction through some routine. Not used much signed arithmetic yet for the other purpose.
I am very, very glad (zp,X) is there. It is used
all the time in situations where you have a data stack in ZP, as stack cells may contain addresses (often calculated) to use as pointers. This is done constantly in the Forth programming language, but you can do the same kind of thing in assembly too, and some other HLLs use it as well. X becomes the data stack pointer. Anticipating a couple of objections: It may initially seem like that's too big of an expense; but when you do it this way, many of the usual needs for X go away. The few times it is needed for something else, it can be saved and restored. Taking space in ZP for a data stack may also seem unrealistic when ZP space is in such high demand; but when you do it this way, many of the ZP variables will no longer be needed. It really does work out well. I discuss it in chapters 4 through 8 of my
6502 stacks treatise.
Oziphantom wrote:
tepples wrote:
I learned EOR-ADC-EOR-BVC, though there were several places that could have used it.
What does the EOR-ADC-EOR-BVC trick achieve?
I wrote a blog post about this explaining its usefulness in detail:
http://www.dustmop.io/blog/2015/05/20/s ... detection/
tepples wrote:
tokumaru wrote:
I imagine that there are other uses of a pointer table on zero page. But 6502 coders who learned on Commodore 64 or Apple II won't have a lot of experience with it because Microsoft BASIC in ROM ate so much of zero page for itself.
Maybe on the Apple ][ but on the C64 only beginner programmers would suffer the issue. You can bank out all ROM, or just BASIC on a C64 allowing you to get all 64K of RAM and all of ZP ( minus 0,1) for your own uses. Most early games for the C64 keep the KERNAL in but not the BASIC ROM, later games tend to ditch both for the most part.
For other uses of (zp,x) see
http://csdb.dk/forums/index.php?roomid= ... allposts=1 kefren bars seems to be common use case, as does Audio Engines, Ray casters and Forth.