Read & Assign specific bits in a byte

BlitzMax Forums/BlitzMax Programming/Read & Assign specific bits in a byte

Pineapple(Posted 2009) [#1]
I have pursued for hours working functions to read & write bits to a single byte.

I need a function that can retreive a value from any number of bits from the byte, so I wrote this:
Function GetBits:Int(num:Int,start:Byte,length:Byte=1,isbyte:Byte=1)
	Local ret:Int=0,pos:Byte,pos2:Byte=0
	If isbyte=True Then start=start+23
	For pos=start+1 To start+length+1
		ret=ret+Int(Mid(Bin$(num),pos,1))*(2^(length-pos2))
		pos2=pos2+1
	Next
	Return ret
End Function


I needed to set the value of an individual bit in a byte, so I made this:
Function SetBit:Byte(byt:Byte,pos:Byte,tobit:Byte)
	Local ret:Byte=0
	For Local modret:Byte=0 To 7
		If modret<>pos Then
			ret:+ (2^modret)*Int(Mid(Right(Bin(byt),8),modret+1,1))
		ElseIf tobit=1
			ret:+ (2^modret)
		EndIf
	Next
	Return ret
End Function


And they don't seem to work.


I don't exactly care if they write bits backwards or something, but it is mandatory that when I set a bit to a byte, when I try to read the same position, I get what I wrote.

And don't go telling me bytes for everything isn't that much worse; I'm writing an engine that requires miniscule amounts of information requiring only a few bits each, but there's far too many of these little bits to waste space.

I don't know what I'm doing wrong, but it is become very upsetting. Please help, and thanks in advance.


Brucey(Posted 2009) [#2]
Small example :
SuperStrict

Local b:Byte = $00

Print Bin(b)

b :| $04 ' set the 3rd bit

Print Bin(b)

' shifts are 0 indexed ...

b :| 1 Shl 0 ' set the 1st bit

Print Bin(b)

b :| 1 Shl 4 ' set the 5th bit

Print Bin(b)

b :~ 1 Shl 4 ' toggle the 5th bit off

Print Bin(b)

b :~ 1 Shl 4 ' toggle the 5th bit on

Print Bin(b)

' reading bits

' is 5th bit set?

Print b & $10 ' > 0 is true

b :~ 1 Shl 4 ' toggle the 5th bit off

Print b & $10

' and with shifting

Print b & 1 Shl 4 ' = 0 is false

b :~ 1 Shl 4 ' toggle the 5th bit on

Print b & 1 Shl 4


Don't mind the long results from Bin(), it shows 32-bits with of bits by default.


Pineapple(Posted 2009) [#3]
Thanks, but I'm looking for something along the lines of functions.


N(Posted 2009) [#4]
What, you mean like this?
Strict

Import Brl.Retro

Function SetBit(in:Int, position:Int)
    Return (in|(%1 Shl (position-1)))
End Function

Function UnsetBit(in:Int, position:Int)
    Return (in&(~(%1 Shl (position-1))))
End Function

Function BitRange:Int(in:Int, start:Int, length:Int)
	in :Shr start
	in :& $FFFFFFFF Shr length
	Return in
End Function

Local bitbot:Byte = 0

bitbot = SetBit(bitbot,1)
bitbot = SetBit(bitbot,8)

Print Bin(bitbot)[24..]

bitbot = $FF

bitbot = UnsetBit(bitbot, 1)
bitbot = UnsetBit(bitbot, 8)

Print Bin(bitbot)[24..]

SeedRnd(Millisecs())
Local random:Int = Rand(-1000000, 1000000)

Print "Bin(random) = "+Bin(random)
Print "Bin(random)[12..20] = "+Bin(random)[12..20]
Print Bin(BitRange(random, 12, 8))[24..]


I just wonder if you'll understand how these work, considering you spent a bunch of time, for some reason, trying to do this with strings...


Pineapple(Posted 2009) [#5]
I was using strings because I first tried bit shifting and couldn't get that to work the way I wanted, either.

And thanks very much, these functions should do the trick.


Pineapple(Posted 2009) [#6]
Oi, I've got one more problem. (I renamed BitRange to GetBits for the sake of convenience)

why does this line of code:

GetBits(PeekByte(tile.bank,fx),bitpos*2,2)

return 22, when PeekByte(tile.bank,fx) is 22 and bitpos is 0?

EDIT: After further investigation, it seems the function's length is somehow automatically equal to 8 - start..
AUGH all this bitshifting is beyond me


N(Posted 2009) [#7]
That one there's a brainfart.

Function BitRange:Int(in:Int, start:Int, length:Int)
	Return ((in Shr start) & (~($FFFFFFFF Shl length)))
End Function



Pineapple(Posted 2009) [#8]
thanks much, works like a charm.