Bits manipulation

Share your advanced PureBasic knowledge/code with the community.
Poshu
Enthusiast
Enthusiast
Posts: 459
Joined: Tue Jan 25, 2005 7:01 pm
Location: Canada

Bits manipulation

Post by Poshu »

Heya!
I needed a few macro to manipulate bits, because of a big fat array that was eating memory away.

Code: Select all

EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
	
	Macro SetBit(Integer,bit)
		MOV eax, Integer
		MOV ebx, bit
		BTS eax, ebx
		MOV Integer,eax
	EndMacro
	
	Macro ResetBit(Integer,bit)
		MOV eax, Integer
		MOV ebx, bit
		BTR eax, ebx
		MOV Integer,eax
	EndMacro
	
	Macro ToggleBit(Integer,bit)
		MOV eax, Integer
		MOV ebx, bit
		BTC eax,ebx
		MOV Integer, eax
	EndMacro
	
	Procedure.b GetBit(Integer, bit)
		MOV ebx, bit
		BT Integer, ebx
		SETC al
		ProcedureReturn
	EndProcedure
	
	Macro ReadBit(Integer, bit,Result)
		MOV ebx, bit
		BT Integer, ebx
		SETC al
		MOV Result,al
	EndMacro
	
CompilerElse
	
	Macro SetBit(Integer,bit)
		MOV rax, Integer
		MOV rbx, bit
		BTS rax, rbx
		MOV Integer,rax
	EndMacro
	
	Macro ResetBit(Integer,bit)
		MOV rax, Integer
		MOV rbx, bit
		BTR rax, rbx
		MOV Integer,rax
	EndMacro
	
	Macro ToggleBit(Integer,bit)
		MOV rax, Integer
		MOV rbx, bit
		BTC rax,rbx
		MOV Integer, rax
	EndMacro
			
	Macro ReadBit(Integer, bit,Result)
		MOV rbx, bit
		BT Integer, rbx
		SETC al
		MOV Result,al
	EndMacro
	
	Procedure.b GetBit(Integer, bit)
		MOV rbx, bit
		BT Integer, rbx
		SETC al
		ProcedureReturn
	EndProcedure
	
CompilerEndIf
Self explanatory, except maybe ReadBit and GetBit which are basically the same function in different flavor (depending on your coding style, the macro is faster but the procedure is more readable).
User avatar
thyphoon
Enthusiast
Enthusiast
Posts: 345
Joined: Sat Dec 25, 2004 2:37 pm

Re: Bits manipulation

Post by thyphoon »

Merci ! c'est plus pratique que ce que je faisais !! :P
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Bits manipulation

Post by davido »

Very nice! Thank you for sharing. :D

I'll learn a lot, too.
DE AA EB
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Bits manipulation

Post by rsts »

Nice. Thanks for sharing.
Kelebrindae
Enthusiast
Enthusiast
Posts: 151
Joined: Tue Apr 01, 2008 3:23 pm

Re: Bits manipulation

Post by Kelebrindae »

Most useful indeed. :D

Thank you very much, Poshu!
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: Bits manipulation

Post by Helle »

For the 'Procedure.b GetBit(Integer, bit)' use e.g. for 64-bit

Code: Select all

   Procedure.b GetBit(Integer, bit)
      MOV rbx, bit
      XOR rax,rax    ;set RAX to zero
      BT Integer, rbx
      SETC al
      ProcedureReturn
   EndProcedure
'SETC al' set only AL and in the return-value (EAX/RAX) is only AL 0 or 1. PB ignored '.b'.
BTW: With

Code: Select all

ProcedureReturn al
makes PB nonsense.
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Bits manipulation

Post by skywalk »

BitGet() Macro without ASM...

Code: Select all

Macro BinX(x, nBits=16)
  "%" + RSet(Bin(x), nBits, "0")
EndMacro

Macro HexX(x, nBits=16)
  "$" + RSet(Hex(x), nBits, "0")
EndMacro

Macro ML_BITGET(x, bit)  ; x.i, 0-based bit position
  ; Returns val of binary at bit pos, instead of ProcedureReturn 0 or 1
  ; Debug ML_BITGET(33,6) ; = 0:  ; Debug ML_BITGET(33,0) ; = 1:  ; Debug ML_BITGET(33,5) ; = 32
  ((x) & (1 << (bit)))
EndMacro

Define x.i = 225
Debug "225           Dec = " + RSet(Str(x),9)
Debug "BinX(225)     Bin = " + BinX(x             ,8)
Debug "BitGet(225,5) Bin = " + BinX(ML_BITGET(x,5),8)
Debug "BitGet(225,5) Hex = " + HexX(ML_BITGET(x,5),8)
Debug "BitGet(225,5) Dec = " + RSet(Str(ML_BITGET(x,5)),9)
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Harry0
User
User
Posts: 13
Joined: Sun Mar 02, 2008 4:28 pm
Location: Palatine

Re: Bits manipulation

Post by Harry0 »

First post in a long time!
I have an issue with trying to convert this code to use ASM in different fashion.
Probably due to something stupid I am doing (or not doing) BUT I can't see it.

Given the above code I have been trying to use the alternative calling nomenclature (code example below):

Code: Select all

;
; from URL: http://www.purebasic.fr/english/viewtopic.php?f=12&t=54608
;

Define TargetByte.i = 225

EnableASM

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
   
   
CompilerElse
   
;
;Test code below, first comment out this section then
;

  
   Macro _M_ToggleBit(ByteTarget, bit)
      mov rax, ByteTarget
      mov rbx, BIT
      btc rax, rbx
      mov ByteTarget, rax
   EndMacro
        
;
; Put this code in to play (take out the ';')
;
   
;   Macro _M_ToggleBit(ByteTarget, bit)
;      !mov rax, [p.v_#ByteTarget]                    ;(line of error)
;      !mov rbx, [p.v_#BIT]
;      !btc rax, rbx
;      !mov [p.v_#ByteTarget], rax
;   EndMacro
    
        
CompilerEndIf

Macro _M_BinX(x, nBits=(SizeOf(Integer)*8))
  "%" + RSet(Bin(x), nBits, "0")
EndMacro

Macro _M_HexX(x, nBits=(SizeOf(Integer)*8))
  "$" + RSet(Hex(x), nBits, "0")
EndMacro

Macro _M_ML_BITGET(x, bit)  ; x.i, 0-based bit position
  ; Returns val of binary at bit pos, instead of ProcedureReturn 0 or 1
  ; Debug ML_BITGET(33,6) ; = 0:  ; Debug ML_BITGET(33,0) ; = 1:  ; Debug ML_BITGET(33,5) ; = 32
  ((x) & (1 << (bit)))
EndMacro

;Define TargetByte.i = 225
Debug "TargetByte = 225           Dec = " + RSet(Str(TargetByte),9)
Debug "_M_BinX(225)     Bin = " + _M_BinX(TargetByte             ,8)
Debug "_M_BitGet(225,5) Bin = " + _M_BinX(_M_ML_BITGET(TargetByte,5),8)
Debug "_M_BitGet(225,5) Hex = " + _M_HexX(_M_ML_BITGET(TargetByte,5),8)
Debug "_M_BitGet(225,5) Dec = " + RSet(Str(_M_ML_BITGET(TargetByte,5)),9)

Debug "Other tests"
TargetByte = 245
Debug "TargetByte = 245                 Dec = " + RSet(Str(TargetByte),9)
Debug "_M_BinX(TargetByte)            Bin = " + _M_BinX(TargetByte             ,8)
Debug "_M_ToggleBit(TargetByte,6):"
_M_ToggleBit(TargetByte,6)
Debug "_M_BinX(TargetByte)            Bin = " + _M_BinX(TargetByte             ,8)
Debug "Value of TargetByte              Dec = " + RSet(Str(TargetByte),9)


The code as is work fine.

But when I try to put the second version in to play I get an error "undefined symbol" at the Line of error noted above.

What am I doing wrong?

Harry0
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Bits manipulation

Post by jassing »

maybe because the constant isn't defined?
Harry0
User
User
Posts: 13
Joined: Sun Mar 02, 2008 4:28 pm
Location: Palatine

Re: Bits manipulation

Post by Harry0 »

Jassing,

The line of code '[p.v_#ByteTarget]' is not defining a constant but the nomenclature for how to use concatenation in a Macro ([p.v_#ByteTarget] turns in to [p.v_<PB Var>] instead of [p.v_ByteTarget]).
This is how you pass a PB variable to in-line assembler when using the ! directive (direct call of an ASM directive).

It is described in the docs/help file under 'ASM'.

I have used this method in my other programs without a problem, so I know the technique is valid (but have issues in this one case!?!?!?!?).

Hope that clarifies things!

Harry0
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Bits manipulation

Post by jassing »

thank you for explaining it.
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Bits manipulation

Post by Demivec »

Harry0 wrote:Probably due to something stupid I am doing (or not doing) BUT I can't see it.
Harry0 wrote:;      !mov rax, [p.v_#ByteTarget]                    ;(line of error)
IMHO, the variable being referenced in the macro must be a parameter ('p.v_') of a procedure. You are using it with a variable local to the main block of code. I think that would be require it to be !mov rax, [v_#ByteTarget].
Harry0
User
User
Posts: 13
Joined: Sun Mar 02, 2008 4:28 pm
Location: Palatine

Re: Bits manipulation

Post by Harry0 »

Demivec,

WOW, learn something new everyday!!!!

So..... What did I learn from this?

1. When using ASM the following must be used:
1.a. The nomenclature of '[v.<PB_VAR>] is used for variables defined/used in the main section of code (not in a procedure)
1.b. The nomenclature of '[p_v.<PB_VAR>] is used for variables defined/used in a procedure section of code
1.c. The name of the variable must match the case of the variable when defined/first used
1.d. You can not pass a value to ASM code when it is expecting a variable

Thank you Demivec for the help and have a great day!

Harry0
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Bits manipulation

Post by Demivec »

Harry0 wrote:Thank you Demivec for the help and have a great day!
Your welcome. :)
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Bits manipulation

Post by Psychophanta »

I use these, in 2 flavours for your choose; Procedure or Macro:
Procedures:

Code: Select all

Procedure Setbit(n.l,*addr.byte)
  *addr+n/8:*addr\b|1<<(n%8)
EndProcedure
Procedure Resbit(n.l,*addr.byte)
  *addr+n/8:*addr\b&((1<<(n%8))!$FF)
EndProcedure
Procedure.b Getbit(n.l,*addr.byte)
  *addr+n/8:If *addr\b&1<<(n%8):ProcedureReturn 1:EndIf:ProcedureReturn 0
EndProcedure
Macros:

Code: Select all

Macro SetbitMacro(n,a)
  PokeB(a#+n#/8,PeekB(a#+n#/8)|1<<(n#%8))
EndMacro
Macro ResbitMacro(n,a)
  PokeB(a#+n#/8,PeekB(a#+n#/8)&((1<<(n#%8))!$FF))
EndMacro
Macro GetbitMacro(n,a)
  (1&Val(Trim(Bin(PeekB(a#+n#/8)&1<<(n#%8),#PB_Byte),"0")))
EndMacro
By the way:
With these functions and macros you can Set, Reset, or Get the 'n'th bit (starting by 0), counting from the memory address passed in the 2nd parameter.
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply