in reply to Re: Modifying multiple bits in a byte - bitwise operators
in thread Modifying multiple bits in a byte - bitwise operators

Hi stevieb!

Yes, the generic set of HLL operations to set a field of bits is to do a bit-wise AND with a one's complement of a "mask" to make sure the bits are all unset, then do a bit-wise OR operation to set those bits to however you want them.

The difference between the HLL version and an actual Assembly language implementation is that there is some uncertainty in how big a "natural integer" is with the HLL. With assembly, I know exactly whether I've got 8, 16, 32, or 64 bits. Typically with HLL, you only know something like size >= 32 bits for an int.

So, with ASM, the "negate the MASK" step would not be there. The ~MASK value would have been compiled in as a "load immediate" constant. With HLL, we want to actually calculate this "flipping of bits" mask. When we calculate ~0x3, we get 2 bits of zeroes and as as many leading one bits as needed to make up the "native int". Design for a min size int, but allow bigger ints.

Here is some code with a couple of things I like to do:

use strict; use warnings; use constant {UP => 0x0<<3, DOWN => 0x1<<3, LEFT => 0x3<<3, RIGHT => 0x2<<3, MASK => 0x3<<3}; printf "direction Mask: "; print8bits (MASK); #Prints: direction Mask: 0001 1000 my $register8b=0; #set direction left $register8b = $register8b & ~MASK | LEFT; print8bits ($register8b); #Prints: 0001 1000 #set direction down $register8b = $register8b & ~MASK | DOWN; print8bits ($register8b); #Prints: 0000 1000 sub print8bits { my $int = shift; print map{s/(\d{4})/$1 /g;$_;}sprintf "%08b\n", $int; }
  1. Consider the use of the constant feature. Make a constant block for each of the fields in the 16 bit register. Naming convention to your satisfation. Maybe DIRECT_UP or DIRECTION_UP instead of just UP or whatever. Consider the naming convention in whatever documentation that you are working from.
  2. I prefer "0x3" notation over just decimal 3 for these things. Although they code to exactly the same bits, use of 0x notation alerts me to the fact that this is some hardware bit thing and not a "normal" variable.
  3. For debugging, I find something like my sub print8bits() to be useful. Space the bits out into 4 bit hex compatible groups. The %b format spec in Perl is very nice (doesn't exist in std C.. have to "roll your own").
  4. Consider a naming convention to indicate how many of the bits are "significant". $register8bit , $r8bit_control or whatever. Design the code that it will still work with native int sizes greater than what current platform is.
  5. While manipulating the 16 or 8 bit register, I just keep the internal representation as a native int, whatever that size is, rather than splitting this into say $lsB and $msB like you did. Or mucking around prematurely with pack/unpack. BTW, your code could confuse a hardware guy. Use lower case "b" for bit and upper case "B" for byte, e.g. $msB instead of $msb.
  6. If you do a lot of bit twiddling, you will find that the inability to access the hardware carry bit is a real hassle. There are various techniques around that, but not in the scope of this post.
Hope this helps.
I have written most of my bit fiddling code in C as I am emulating say a hardware ECC algorithm or whatever and sometimes "fast" is important. But Perl can do bit manipulation amazingly well and I have used Perl to decode some complex binary formats.

Replies are listed 'Best First'.
Re^3: Modifying multiple bits in a byte - bitwise operators
by stevieb (Canon) on Jan 11, 2017 at 14:11 UTC

    This is a great breakdown and explanation. Thanks Marshall!