The HLA Standard Library provides the bits.hhf
module that provides several bit-related functions, including built-in functions for many of the algorithms we've studied in this chapter. This section describes some of the functions available in the HLA Standard Library.
procedure bits.cnt( b:dword ); @returns( "eax" );
This procedure returns the number of 1 bits present in the b
parameter. It returns the count in the EAX register. To count the number of 0 bits in the parameter value, invert the value of the parameter before passing it to bits.cnt
. If you want to count the number of bits in a 16-bit operand, simply zero extend it to 32 bits prior to calling this function. Here are a couple of examples:
// Compute the number of bits in a 16-bit register:
pushw( 0 );
push( ax );
call bits.cnt;
// If you prefer to use a higher-level syntax, try the following:
bits.cnt( #{ pushw(0); push(ax); }# );
// Compute the number of bits in a 16-bit memory location:
pushw( 0 );
push( mem16
);
call bits.cnt;
If you want to compute the number of bits in an 8-bit operand, it's probably faster to write a simple loop that rotates all the bits in the source operand and adds the carry into the accumulating sum. Of course, if performance isn't an issue, you can zero extend the byte to 32 bits and call the bits.cnt
procedure.
procedure bits.distribute( source:dword; mask:dword; dest:dword ); @returns( "eax" );
This function takes the L.O. n bits of source
, where n is the number of 1 bits in mask
, and inserts these bits into dest
at the bit positions specified by the 1 bits in mask
(that is, the same as the distribute algorithm appearing earlier in this chapter). This function does not change the bits in dest
that correspond to the zeros in the mask
value. This function does not affect the value of the actual dest
parameter; it returns the new value in the EAX register.
procedure bits.coalesce( source:dword; mask:dword ); @returns( "eax" );
This function is the converse of bits.distribute
. It extracts all the bits in source whose corresponding positions in mask
contain a 1. This function coalesces (right justifies) these bits in the L.O. bit positions of the result and returns the result in EAX.
procedure bits.extract( var d:dword ); @returns( "eax" ); // Really a macro.
This function extracts the first set bit in d
searching from bit 0 and returns the index of this bit in the EAX register; the function also returns the zero flag clear in this case. This function also clears that bit in the operand. If d
contains 0, then this function returns the zero flag set and EAX will contain −1.
Note that HLA actually implements this function as a macro, not a procedure. This means that you can pass any double-word operand as a parameter (a memory or a register operand). However, the results are undefined if you pass EAX as the parameter (because this function computes the bit number in EAX).
procedure bits.reverse32( d:dword ); @returns( "eax" ); procedure bits.reverse16( w:word ); @returns( "ax" ); procedure bits.reverse8( b:byte ); @returns( "al" );
These three routines return their parameter value with its bits reversed in the accumulator register (AL/AX/EAX). Call the routine appropriate for your data size.
procedure bits.merge32( even:dword; odd:dword ); @returns( "edx:eax" ); procedure bits.merge16( even:word; odd:word ); @returns( "eax" ); procedure bits.merge8( even:byte; odd:byte ); @returns( "ax" );
These routines merge two streams of bits to produce a value whose size is the combination of the two parameters. The bits from the even
parameter occupy the even bit positions in the result; the bits from the odd
parameter occupy the odd bit positions in the result. Notice that these functions return 16, 32, or 64 bits based on byte, word, and double-word parameter values.
procedure bits.nibbles32( d:dword ); @returns( "edx:eax" ); procedure bits.nibbles16( w:word ); @returns( "eax" ); procedure bits.nibbles8( b:byte ); @returns( "ax" );
These routines extract each nibble from the parameter and place those nibbles into individual bytes. The bits.nibbles8
function extracts the two nibbles from the b
parameter and places the L.O. nibble in AL and the H.O. nibble in AH. The bits.nibbles16
function extracts the four nibbles in w
and places them in each of the 4 bytes of EAX. You can use the bswap
or rox instructions to gain access to the nibbles in the H.O. word of EAX. The bits.nibbles32
function extracts the eight nibbles in EAX and distributes them through the 8 bytes in EDX:EAX. Nibble 0 winds up in AL and nibble 7 winds up in the H.O. byte of EDX. Again, you can use bswap
or the rotate instructions to access the upper bytes of EAX and EDX.