Flag to Mask Conversions

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Flag to Mask Conversions

Post 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
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Flag to Mask Conversions

Post 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
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

Dr Jefyll wrote:
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. 8)

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
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Flag to Mask Conversions

Post 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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

GARTHWILSON wrote:
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. 8)

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)
GARTHWILSON wrote:

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.
Last edited by TheBrewThatIsTrue on Tue Aug 30, 2022 9:14 am, edited 3 times in total.
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post 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
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Flag to Mask Conversions

Post by GARTHWILSON »

TheBrewThatIsTrue wrote:
GARTHWILSON wrote:

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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

GARTHWILSON wrote:
TheBrewThatIsTrue wrote:
GARTHWILSON wrote:

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. :)
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post 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. :)
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Flag to Mask Conversions

Post by GARTHWILSON »

Which HP calc is your avatar of?
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

GARTHWILSON wrote:
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.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Flag to Mask Conversions

Post 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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

GARTHWILSON wrote:
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 8)
I was just reading last night or this morning about your use of HP-IL on your workbench computers page.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Flag to Mask Conversions

Post 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
User avatar
TheBrewThatIsTrue
Posts: 12
Joined: 26 Aug 2022
Location: Manila, Philippines

Re: Flag to Mask Conversions

Post by TheBrewThatIsTrue »

BigEd wrote:
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. :D
Post Reply