Page 1 of 2
Flag to Mask Conversions
Posted: Tue Aug 30, 2022 1:32 am
by TheBrewThatIsTrue
Greetings,
I spent a couple of enjoyable hours reading through some of this boards threads last night. This is my first post.
I have recently returned to 65xx assembly after a very long hiatus (my last time was in the early 80s).
For the heck of it (and to keep my mind sharp), my first foray back is to cobble together an Atari 2600 4k game binary.
As I experiment and learn the 2600, I find myself wishing I had a set of fast constant-time 6507 flag to mask conversion snippets.
Before I wrack my brain reinventing the wheel, I thought I'd check if anyone on this board knows of an existing set.
What I'm looking for is a set of "bithacks" for converting processor flag states (or boolean combination of processor flag states) to canonical 8-bit masks in A, in the least number of cycles but in constant-time.
By canonical mask I mean -1/0 (all bits on or all bits off), similar to Forth flags.
By constant-time I mean either
branchless or using
"ballasted" branches, so that all conditional paths through the code end up taking exactly the same number of cycles.
I'm perfectly fine with using undocumented 6507 opcodes, as they seem to be commonly used in 2600 homebrews.
Here are a couple of examples (I have no idea if these are optimal or not).
~C -> -1/0:
Code: Select all
a900 lda #$00 (2)
e900 sbc #$00 (2)
C -> -1/0:
Code: Select all
a900 lda #$00 (2)
e900 sbc #$00 (2)
49ff eor #$ff (2)
... and so on and so forth, including useful boolean combinations of N, V, C, Z.
Cheers,
Mark
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 2:53 am
by Dr Jefyll
Welcome, Mark, and congratulations on ending your very long hiatus!
Here are two possible approaches. I'm pretty sure I understand what we're trying to achieve. But I'm less sure I've gotten all the details correct, as it's late and I'm getting sleepy! Maybe this will at least help you get started.
-- Jeff
Very fast but also very bulky:
Code: Select all
php
pla
tax
lda LookupTable,X ;each element of the table is either 0 or $FF
A bit slower but a great deal smaller:
Code: Select all
php
pla
eor #BitsToInvert
ora #BitsToIgnore ;now A= $FF or less than $FF
cmp #$FF ;if A=$FF then carry=1 (ie, the CMP didn't borrow) else carry=0
lda #$00
sbc #0
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 3:47 am
by TheBrewThatIsTrue
Welcome, Mark, and congratulations on ending your very long hiatus!
Here are two possible approaches. I'm pretty sure I understand what we're trying to achieve. But I'm less sure I've gotten all the details correct, as it's late and I'm getting sleepy! Maybe this will at least help you get started.
-- Jeff
Very fast but also very bulky:
Code: Select all
php
pla
tax
lda LookupTable,X ;each element of the table is either 0 or $FF
A bit slower but a great deal smaller:
Code: Select all
php
pla
eor #BitsToInvert
ora #BitsToIgnore ;now A= $FF or less than $FF
cmp #$FF ;if A=$FF then carry=1 (ie, the CMP didn't borrow) else carry=0
lda #$00
sbc #0
Thanks very much for the kind welcome and the code.
It's not exactly what I'm looking for, in the sense that I'm after the fastest routine per test rather than a generic approach.
For example if one is attempting to convert ~C to a mask, I'm guessing
lda #0 sbc #0 at 4mc may be the fastest constant-time option, and perhaps
lda #0 sbc #0 eor #$ff at 6mc is best for converting C to a mask, I don't really know. In summary, I'm after the best mask generator for each commonly useful SR flags test.
Cheers,
Mark
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 4:03 am
by GARTHWILSON
Welcome.
I always welcome new tricks, but I can't imagine you'll be able to do this quite the way you had hoped. C is the only flag you can do this kind of thing with, so without conditional branches or tables, you're probably confined to PHP, PLA, and shifting the desired position into the C flag position and then doing your add or subtract. I'd be glad to be proven wrong. If someone comes up with a way, we should put it in the wiki.
What's the 00/FF thing for? I do use Forth; but in every case I can think of, anything non-0 is fine for a "true" flag. In 65c02 work, setting a flag byte can consist of just decrementing the byte and later testing it with BIT followed by BMI or BPL, as long as you don't decrement so many times the byte becomes positive again; and for clearing it, I just use STZ. I realize you don't have STZ on the 6507, and would have to do LDA #0, STA.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 4:31 am
by TheBrewThatIsTrue
Welcome.
I always welcome new tricks, but I can't imagine you'll be able to do this quite the way you had hoped. C is the only flag you can do this kind of thing with, so without conditional branches or tables, you're probably confined to PHP, PLA, and shifting the desired position into the C flag position and then doing your add or subtract. I'd be glad to be proven wrong. If someone comes up with a way, we should put it in the wiki.
Thank you.
If it does turn out to be infeasible, then I'll at least try to reproduce some of the Bxx tests as mask producers to similar ends, e.g.
A = -(A>=0) [edited for correction (twice!)]
Code: Select all
0a asl (2)
a900 lda #$00 (2)
e900 sbc #$00 (2)
What's the 00/FF thing for? [...]
In Forth-83 test/query words returned -1/0, Forth-79 and Fig-Forth used 1/0.
Although I'm not a fan of the later ANS-Forth, I adopted some of the controversial changes of '83, particularly the -1/0 test results and the use of floored division.
As to why -1/0 is better, you can use a result directly as a mask.
Also, unlike C for example you don't need different operators for logical and bitwise operations, since they're the equivalent when using -1/0 as canonical flags.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 4:43 am
by TheBrewThatIsTrue
Below is an example where I'm using the result of a comparison as a mask for the subsequent AND.
Code: Select all
Preload Player Graphics.
98 tya (2)x3 @ dk.000*.090-095
N.B. clc rather than sec.
18 clc (2)x3 @ dk.000*.096-101
e587 sbc SRAM_P0_Y (3)x3 @ dk.000*.102-110
c5a7 cmp CRAM_P0_HEIGHT (3)x3 @ dk.000*.111-119
aa tax (2)x3 @ dk.000*.120-125
a900 lda #$00 (2)x3 @ dk.000*.126-131
e900 sbc #$00 (2)x3 @ dk.000*.132-137
35a9 and CRAM_GRP0_ROWS,X (4)x3 @ dk.000*.138-149
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 5:06 am
by GARTHWILSON
What's the 00/FF thing for? [...]
In Forth-83 test/query words returned -1/0, Forth-79 and Fig-Forth used 1/0.
Although I'm not a fan of the later ANS-Forth, I adopted some of the controversial changes of '83, particularly the -1/0 test results and the use of floored division.
As to why -1/0 is better, you can use a result directly as a mask.
Also, unlike C for example you don't need different operators for logical and bitwise operations, since they're the equivalent when using -1/0 as canonical flags.
Sorry—I didn't mean 1 versus -1 for a "true" flag, but that IF, WHILE, UNTIL, ABORT", ?DUP, ?EXIT, ?<anything> only look to see if it's 0 or not. Things that produce a flag, like 0=, >, etc. do produce a -1 as a true flag; but I've seldom found that it matters. In the rare case that it does matter, you can use 0<> to change any non-0 number into a -1.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 5:40 am
by TheBrewThatIsTrue
What's the 00/FF thing for? [...]
In Forth-83 test/query words returned -1/0, Forth-79 and Fig-Forth used 1/0.
Although I'm not a fan of the later ANS-Forth, I adopted some of the controversial changes of '83, particularly the -1/0 test results and the use of floored division.
As to why -1/0 is better, you can use a result directly as a mask.
Also, unlike C for example you don't need different operators for logical and bitwise operations, since they're the equivalent when using -1/0 as canonical flags.
Sorry—I didn't mean 1 versus -1 for a "true" flag, but that IF, WHILE, UNTIL, ABORT", ?DUP, ?EXIT, ?<anything> only look to see if it's 0 or not. Things that produce a flag, like 0=, >, etc. do produce a -1 as a true flag; but I've seldom found that it matters. In the rare case that it does matter, you can use 0<> to change any non-0 number into a -1.
Yes, in the grand scheme it's a very minor difference, sometimes a small convenience, other times a small inconvenience. Which you favor is more a question of personal coding style and taste than anything else.
And of course, with Forth you can always have it your way.

Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 5:53 am
by TheBrewThatIsTrue
The reason I'm keen on mask generators is that, in the display kernel of a 2600 game, I'd like to avoid branches wherever I can easily do so, since all control flow paths will need to be balanced to consume the exact same number of cycles, and ballasting branches is a pain.

Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 6:10 am
by GARTHWILSON
Which HP calc is your avatar of?
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 6:20 am
by TheBrewThatIsTrue
Which HP calc is your avatar of?
It's an HP-16C
Computer Scientist, bought it at Macy's in San Francisco in the early 80s.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 6:58 am
by GARTHWILSON
Nice! I use the HP-41cx regularly. It doesn't have as many computer-science functions as the 16c, but my Advantage module has the base conversions and boolean functions, 32-bit, which is adequate for me. There is another module that just came out in the last couple of years that does the 16c stuff with 64-bit numbers, using buffers it sets up for the extra bits. I don't have that module, but I have a lot of others loaded. Engineers are still introducing fantastic modules for it, even today. The 41CL and I believe the DM41x are a lot faster than the original HP product and come with over 300 modules pre-installed in flash. Unfortunately the DM41x does not have HP-IL, and HP-IL was the whole reason I got into the 41 in 1986. Actually my 41 controlled the Bytek Writer EPROM programmer with an RS-232 interface for my early 65c02 work, after a manual home-made programmer proved to be non-workable due to its slowness and vulnerability to human error. One of the interface converters I have for the 41 (and 71) is HP-IL to RS-232.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 8:04 am
by TheBrewThatIsTrue
Nice! I use the HP-41cx regularly. It doesn't have as many computer-science functions as the 16c, but my Advantage module has the base conversions and boolean functions, 32-bit, which is adequate for me. There is another module that just came out in the last couple of years that does the 16c stuff with 64-bit numbers, using buffers it sets up for the extra bits. I don't have that module, but I have a lot of others loaded. Engineers are still introducing fantastic modules for it, even today. The 41CL and I believe the DM41x are a lot faster than the original HP product and come with over 300 modules pre-installed in flash. Unfortunately the DM41x does not have HP-IL, and HP-IL was the whole reason I got into the 41 in 1986. Actually my 41 controlled the Bytek Writer EPROM programmer with an RS-232 interface for my early 65c02 work, after a manual home-made programmer proved to be non-workable due to its slowness and vulnerability to human error. One of the interface converters I have for the 41 (and 71) is HP-IL to RS-232.
Very very cool
I was just reading last night or this morning about your use of HP-IL on your workbench computers page.
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 8:40 am
by BigEd
Welcome, Mark! An interesting quest, to be sure. And rather jumping in at the deep end of deterministic runtime, to pick the 2600. But I look forward to seeing some ingenious ideas.
You might find the resources linked here useful, if any are new to you:
https://alienbill.com/2600/
And there's an in-browser IDE for the 2600 which might help when you want to test things:
https://8bitworkshop.com/v3.9.0/?file=e ... atform=vcs
Re: Flag to Mask Conversions
Posted: Tue Aug 30, 2022 9:08 am
by TheBrewThatIsTrue
Welcome, Mark! An interesting quest, to be sure. And rather jumping in at the deep end of deterministic runtime, to pick the 2600. But I look forward to seeing some ingenious ideas.
You might find the resources linked here useful, if any are new to you:
https://alienbill.com/2600/
And there's an in-browser IDE for the 2600 which might help when you want to test things:
https://8bitworkshop.com/v3.9.0/?file=e ... atform=vcs
Thanks for the welcome and the resources BigEd.
