Page 1 of 1
isolate the high bit of a byte
Posted: Tue Jul 31, 2012 4:34 am
by bogax
I need a routine to isolate the high bit of a byte.
so eg 80-FF should return 80, 40-7F should return 40, etc
Even 32 bytes for nibble wise LUTs seems excessive,
but I wouldn't rule it out if it there was enough of a
speed advantage.
this is the best I've come up with
Code: Select all
HIBIT
lda num
and #$F0
bne SKIP1
eor num
SKIP1
sta temp
and #$CC
bne SKIP2
eor temp
SKIP2
sta temp
and #$AA
bne SKIP3
eor temp
SKIP3
rts
Any better ideas?
Re: isolate the high bit of a byte
Posted: Tue Jul 31, 2012 5:57 am
by BigEd
Warren's "
Hacker's Delight" suggests
Code: Select all
x=x | (x >> 1)
x=x | (x >> 2)
x=x | (x >> 4)
which would be
Code: Select all
HIBIT
lda num
lsr
ora num
sta num
lsr
lsr
ora num
sta num
lsr
lsr
lsr
lsr
ora num
I haven't fully tested this.
I thought I might find something in
HAKMEM but no.
Cheers
Ed
Edit: oops, that only makes a mask. To reduce to top bit set we must also do
Re: isolate the high bit of a byte
Posted: Tue Jul 31, 2012 6:22 am
by GARTHWILSON
How about:
Code: Select all
HIBIT: LDA #0
SEC
BEGIN
ROR A
ASL INPUT
UNTIL_C_SET
or the same thing, non-structured:
Code: Select all
HIBIT: LDA #0
SEC
hb1: ROR A
ASL INPUT
BCC hb1
Re: isolate the high bit of a byte
Posted: Tue Jul 31, 2012 6:25 am
by Dr Jefyll
Nice work, Bogax. It's a delightfully tidy algorithm -- not to be improved upon! (at least not by me).
The implementation can be tightened up a bit, though. A few of the instructions are eligible for substitution on a one-for-one basis, as follows:
Code: Select all
HIBIT
lda num
and #$F0
bne SKIP1
lda num ;was: eor num
SKIP1
sta temp
and #$CC
bne SKIP2
lda temp ;was: eor temp
SKIP2
sta temp
and #$AA
bne SKIP3
lda temp ;was: eor temp
SKIP3
rts
Using
lda as a substitute for
eor may seem odd but it's acceptable simply because A is known to be zero, owing to the immediately preceding bne instruction. (The substitution improves readability, IMO. But that's not the primary benefit.)
Now the value
temp has nothing happening to it except simple move operations. It becomes feasible to keep the value in a register rather than a zero-page location (see below). This saves 4 bytes and up to 4 cycles.
Code: Select all
HIBIT
lda num
and #$F0
bne SKIP1
lda num ;was: eor num
SKIP1
tay ;was: sta temp
and #$CC
bne SKIP2
tya ;was: lda temp ;was: eor temp
SKIP2
tay ;was: sta temp
and #$AA
bne SKIP3
tya ;was: lda temp ;was: eor temp
SKIP3
rts
I haven't fully tested this.
And I haven't fully
wrapped my brain around this! Good one, Ed! But I won't be able to give it full concentration until tomorrow. It's past bedtime on this side of the pond, and I'm sleepy (whereas I'm guessing
you just got up!)
cheers
Jeff
Re: isolate the high bit of a byte
Posted: Tue Jul 31, 2012 5:31 pm
by BigEd
Agreed, Bogax' code is very nice - and mine was wrong (is now updated)
Re: isolate the high bit of a byte
Posted: Fri Oct 23, 2015 3:55 pm
by BigEd
Resurrecting an old thread, because it's the only mention of Hacker's Delight I could find. And I wanted to add a link to a related site, called Bit Twiddling, as recently noted over at the HP Museum:
https://graphics.stanford.edu/~seander/bithacks.html
via
http://www.hpmuseum.org/forum/thread-49 ... 44284.html
which mentions some other books which might be of interest.
Re: isolate the high bit of a byte
Posted: Sat Oct 24, 2015 7:27 am
by Omegamatrix
In addition to Dr Jefyll's saving with using TAY and TYA, you can shave 1 cycle off worse case execution in the first part of the routine.
Change this:
Code: Select all
lda num
and #$F0
bne SKIP1
eor num
SKIP1
To this:
Code: Select all
lda num
cmp #$10
bcc SKIP1
and #$F0
SKIP1
Re: isolate the high bit of a byte
Posted: Sun Oct 25, 2015 2:54 pm
by BitWise
How about removing rightmost bits until you reach the last. NUM must be non-zero at the start and will contain the last bit at the end.
Code: Select all
lda NUM
Loop:
dec a
and NUM
beq Done
sta NUM
bra Loop
Done:
Utterly untested
Re: isolate the high bit of a byte
Posted: Sun Oct 25, 2015 3:10 pm
by nyef
How about removing rightmost bits until you reach the last. NUM must be non-zero at the start and will contain the last bit at the end.
Code: Select all
lda NUM
Loop:
dec a
and NUM
beq Done
sta NUM
bra Loop
Done:
Utterly untested
I see no requirement for NUM being non-zero here. If NUM is zero on entry, it will also be so on exit.
Re: isolate the high bit of a byte
Posted: Sun Oct 25, 2015 3:22 pm
by BitWise
I see no requirement for NUM being non-zero here. If NUM is zero on entry, it will also be so on exit.
Agreed. I was playing safe.
Slightly smaller if you shuffle the instructions and put the initial value in A. Result still in NUM.
Code: Select all
Loop:
sta NUM
dec A
and NUM
bne Loop
Re: isolate the high bit of a byte
Posted: Sun Oct 25, 2015 4:32 pm
by Dr Jefyll
Slightly smaller if you shuffle the instructions and put the initial value in A.
Nice, if memory economy is the goal. Of course the other potential priority is speed, which, judging from the lead post, is what Bogax was interested in. His algorithm has a very fast worst-case execution because there's
no looping.
In addition to Dr Jefyll's saving with using TAY and TYA, you can shave 1 cycle off worse case execution in the first part of the routine.
Good spot, Omegamatrix -- I missed that! The 2nd instruction tests the high 4 bits, but the test needn't be destructive as in my previous version. CMP and BIT are both capable of doing the test while at the same time preserving the contents of A. I've adopted your suggestion (below) but I prefer to use BIT since it's just as fast as CMP and IMO is slightly more readable.
Code: Select all
HIBIT: ;previous version
lda num
and #$F0 ; <- destructive test
bne SKIP1
lda num
; [etc ]
Code: Select all
HIBIT: ;improved version
lda num
bit #$F0 ; <- non-destructive test
beq SKIP1
and #$F0
SKIP1: ;if any of bits 7,6,5,4 is set then bits 3,2,1,0 have now been cleared
tay
and #$CC
bne SKIP2
tya
SKIP2: ;if any of bits 7,6,3,2 is set then bits 5,4,1,0 have now been cleared
tay
and #$AA
bne SKIP3
tya
SKIP3: ;if any of bits 7,5,3,1 is set then bits 6,4,2,0 have now been cleared
rts
-- Jeff
Re: isolate the high bit of a byte
Posted: Sun Oct 25, 2015 6:29 pm
by Omegamatrix
Good spot, Omegamatrix -- I missed that! The 2nd instruction tests the high 4 bits, but the test needn't be destructive as in my previous version. CMP and BIT are both capable of doing the test while at the same time preserving the contents of A.
I have only programmed for the 6502, and there's no BIT #IMM instruction for it. Looking at the 65C02 and 65816 I see there is.
