English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 30 April 2021, 08:49   #1
Auscoder
Registered User
 
Join Date: Jan 2019
Location: Brisbane
Posts: 99
Bits set

Hi folks,

Just wondering if there is a better/tricker/hidden/black book approach to testing if some bit combo is set. I am trying to replace a cases of multiple compares against word variables in my code. So I planned to change to use a 32bit var to hold bits as flags for various state, like (0)enabled, (1)visible, (2)etc, and have them enumerated as such. I need all 32 bits and the code is a little bit generic so using longs.

Old code had - Stuff like this just for example...

Code:
cmp.b #1,obj_visible(ax)
bne .exit
cmp.b #1,obj_enabled(ax)
bne .exit
; update and draw
Most often I need to test only one state (say enabled), sometimes I have 2 like listed here (enabled and visible), and sometimes more. It seems in cases of only 1 & 2 tests, its faster to wear the individual compare costs, and 3 or more tests use the following. But can it be faster?

The
Code:
cmp.l #(1<<0)|(1<<1),d0
just pushes cycle count too high for regular usage.

Code:
        ; Test bit flags
        ;moveq.l #0,d0 ; No bits are set (works)
        ;move.l #(1<<0),d0 ; Set bit 0 (works)
        ;move.l #(1<<1),d0 ; Set bit 1 (works)
        ;move.l #(1<<0)|(1<<1),d0 ; Set bit 0 and 1 (works)
        move.l #(1<<0)|(1<<1)|(1<<2),d0 ; Set bit 0 and 1 and 2 (works)

        ; Test if these bits 0 and 1 are set
        andi.l #(1<<0)|(1<<1),d0
        cmp.l #(1<<0)|(1<<1),d0
        sub.l #(1<<0)|(1<<1),d0 ; replace cmp.l with sub.l saves 8 cycles. Making it slightly faster than two individual compares.
        beq .theseBitsAreSet
        
        ; Both bits are not set
        move.l #-100,d0
        rts

.theseBitsAreSet
        move.l #100,d0
        rts

Last edited by Auscoder; 30 April 2021 at 09:11.
Auscoder is offline  
Old 30 April 2021, 09:51   #2
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
In your specific case (3 bits), could be as simple as:

Code:
    btst    d0,#%11111110
    bne     .theseBitsAreSet
        
    ; bits 1 or 2 or 3 are not set
    move.l #-100,d0
    rts

.theseBitsAreSet
    move.l #100,d0
    rts
It can be extended up to 5 bits using a register instead of a constant, but beyond that you have to complicate the code a bit.
ross is offline  
Old 30 April 2021, 09:54   #3
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,322
For your first example, you can just have these two bits in same byte.
And instead of having to check if these are both set, compare them with 0 by reversing their meaning :
Code:
 tst.b obj_state(ax)
 bne .exit
Generally, it's easier to check for 0 than check for 1 so reverse them where you can.

If you only have 2 bits and not all possible combinations need to be checked, you can use the following method (use sign bit and any other like b0, keeping all other bits =0) :
Code:
 tst.b obj_state(ax)
 bne .xx         ; $01, $80, $81
 beq .xx         ; $00
 bpl .xx         ; $00, $01
 bmi .xx         ; $80, $81
 bgt .xx         ; $01
 ble .xx         ; $00, $80

Quote:
Originally Posted by Auscoder View Post
I need all 32 bits and the code is a little bit generic so using longs.
That may be a big part of the problem...
meynaf is online now  
Old 30 April 2021, 10:17   #4
DanScott
Lemon. / Core Design
 
DanScott's Avatar
 
Join Date: Mar 2016
Location: Tier 5
Posts: 1,209
You just need to do this:

Code:
        ; Test if these bits 0 and 1 are set
        andi.l #(1<<0)|(1<<1),d0
        beq .theseBitsAreNotSet
no need for a "cmp" or "sub", as the "and" will set the condition codes
DanScott is offline  
Old 30 April 2021, 10:23   #5
Auscoder
Registered User
 
Join Date: Jan 2019
Location: Brisbane
Posts: 99
Quote:
Originally Posted by DanScott View Post
You just need to do this:

Code:
        ; Test if these bits 0 and 1 are set
        andi.l #(1<<0)|(1<<1),d0
        beq .theseBitsAreNotSet
no need for a "cmp" or "sub", as the "and" will set the condition codes
What if other bits are set in d0?
Auscoder is offline  
Old 30 April 2021, 10:25   #6
JoeJoe
Registered User
 
Join Date: Feb 2020
Location: Germany
Posts: 177
I found the following interesting article.
Attached Thumbnails
Click image for larger version

Name:	bitset.png
Views:	105
Size:	141.6 KB
ID:	71762  
JoeJoe is offline  
Old 30 April 2021, 10:52   #7
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,038
If you are testing for multiple bits, as pointed out, it's better to use reverse logic (0 = flag is set) and test for a zero.
One way to optimize and simplify this is to use macros instead, and there you can do all kind of stuff: check if all the flags of interest are in the lower or the upper byte/word and only do an 8/16-bit check, maybe use moveq if they fit in 7 bits, check if it's only a single flag and do a btst, ...
For example, I use macros to set/clear/test for a single bit in a 32-bit mask, so I don't have to bother thinking which byte of the 4 is it (mem ops are 8-bit). Multi-bits would of course be more complex, it depends how much important is the cycle count.
a/b is offline  
Old 30 April 2021, 10:54   #8
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
Quote:
Originally Posted by Auscoder View Post
What if other bits are set in d0?
Just move to a spare register
Something like this:

Code:
    moveq   #%111,d1
    and.l   d0,d1
    bne     .theseBitsAreSet
In this case, speed is the same as btst version (which does not use extra registers and is fast).

EDIT: or even faster on vanilla 68k:
and.w   d0,d1


Of course this also has its limits.
You have to adapt your code to your needs.

Last edited by ross; 30 April 2021 at 11:27. Reason: reversed d1 and d0 :)
ross is offline  
Old 02 May 2021, 10:03   #9
Auscoder
Registered User
 
Join Date: Jan 2019
Location: Brisbane
Posts: 99
Z will be cleared if any of tested bits is set. I want to confirm all bits of interest are set. Others can be set or not, not a problem. But src bits all must be set. So I ended up explaining it very badly I think. I hope this clears it up.

Code:
      ; Any bits could be set (example 7 and 15 or more...)
      move.l #(1<<7)|(1<<15),d0
      andi.l #(1<<1)|(1<<2),d0  ; z set if none of the bits 1|2 are set (dest == 0)
        
      move.l #(1<<7)|(1<<15),d0
      andi.l #(1<<2)|(1<<7),d0  ; z cleared if *any* bits 2|7 are set (dest != 0)
      sub.l #(1<<2)|(1<<7),d0   ; validates both are set if dest == 0
        
      move.l #(1<<7)|(1<<15)|(1<<18),d0 ; must handle arbitrary bits set
      andi.l #(1<<7)|(1<<18),d0   ; z cleared when both are set (good)

Quote:
Originally Posted by ross View Post

Code:
    moveq   #%111,d1
    and.l   d0,d1
    bne     .theseBitsAreSet
EDIT: or even faster on vanilla 68k:
and.w   d0,d1
Quote:
Originally Posted by DanScott View Post
You just need to do this:

Code:
        ; Test if these bits 0 and 1 are set
        andi.l #(1<<0)|(1<<1),d0
        beq .theseBitsAreNotSet
no need for a "cmp" or "sub", as the "and" will set the condition codes

Last edited by Auscoder; 02 May 2021 at 10:13. Reason: Explain 3rd case better
Auscoder is offline  
Old 02 May 2021, 10:39   #10
saimo
Registered User
 
saimo's Avatar
 
Join Date: Aug 2010
Location: Italy
Posts: 787
If, as suggested, you can use reverse logic:
andi.l #<BitsToCheck>,d0
beq(.b) AllBitsOn

Otherwise:
move(q).l #<BitsToCheck>,d1
and.l d1,d0
cmp.l d1,d0
beq(.b) AllBitsOn
saimo is offline  
Old 02 May 2021, 10:48   #11
Auscoder
Registered User
 
Join Date: Jan 2019
Location: Brisbane
Posts: 99
Quote:
Originally Posted by saimo View Post
If, as suggested, you can use reverse logic:
andi.l #<BitsToCheck>,d0
beq(.b) AllBitsOn

Otherwise:
move(q).l #<BitsToCheck>,d1
and.l d1,d0
cmp.l d1,d0
beq(.b) AllBitsOn
Sounds like the trick I am looking for, thanks to all those that mentioned it. Also the bit set testing I’ll have a look at JoeJoe and others. Now just need to wrap my head around it. For reverse logic takes a bit of good old fashioned paper and pen for it to click with me.
Auscoder is offline  
Old 02 May 2021, 12:16   #12
Auscoder
Registered User
 
Join Date: Jan 2019
Location: Brisbane
Posts: 99
Code:
        move.l #$ffffffff,d0
        bclr.l #7,d0
        bclr.l #15,d0
        andi.l #(1<<7)|(1<<2),d0    ; z is clear
        
        move.l #$ffffffff,d0
        bclr.l #7,d0
        bclr.l #15,d0
        andi.l #(1<<7)|(1<<18),d0   ; z is clear
        
        move.l #-1,d0
        bclr.l #7,d0
        bclr.l #15,d0
        bclr.l #18,d0
        andi.l #(1<<7)|(1<<15),d0   ; z is set
Very good, thank you! I will wrap in some macros like suggested by a/b to achieve improvements under special cases.. Now makes sense. Thanks folks, good tricks here!
Auscoder is offline  
Old 02 May 2021, 14:05   #13
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,322
Quote:
Originally Posted by saimo View Post
move(q).l #<BitsToCheck>,d1
and.l d1,d0
cmp.l d1,d0
beq(.b) AllBitsOn
The above code destroys the contents of d0.
If this isn't acceptable, you can also do :
Code:
 move(q).l #~<BitsToCheck>,d1
 or.l d0,d1
 addq.l #1,d1
 beq(.b) AllBitsOn

Last edited by meynaf; 02 May 2021 at 14:30.
meynaf is online now  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Some very rare bits available Ricardo Coders. Asm / Hardware 1 18 March 2014 20:31
WinUAE 2.7.0 64 Bits freddy support.WinUAE 10 12 December 2013 22:40
Need a few bits - can anyone help? Rabbit80 MarketPlace 0 11 October 2008 22:16
BITS demos. SoLo2 support.Demos 64 19 September 2008 19:42
Old Bits wanted please ---> ElectroBlaster MarketPlace 0 06 September 2003 00:24

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:33.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.20750 seconds with 16 queries