_BIT OPERATIONS WITH C MACROS_ by John Rogers Listing One /* BitOps.h - bit operation macros. Copyright (c) 1987-1994 by JR * (John Rogers). All rights reserved. CompuServe: 72634,2402 * Permission is granted to use these macros in compiled code without payment * of royalties or inclusion of a copyright notice. This source file * may not be sold without written permission from the author. * * The following macros are inspired by the FORTRAN bit operation routines in * MIL-STD-1753. Except for MVBITS, all return values rather than modifying * parameters. MVBITS updates a parameter and does not return anything. The * leading "I" in most of these names means that they return some kind of * integer result. * BTEST(value,bitnum,type) * IAND(m,n,type) * IBCLR(value,bitnum,type) * IBITS(value,bitnum,len,type) * IBSET(value,bitnum,type) * IEOR(m,n,type) * IOR(m,n,type) * ISHFT(value,shifts,type) * ISHFTC(value,shifts,len,type) * MVBITS(src,srcindex,len,destptr,destindex,type) * NOT(value,type) * The following C macros were invented by me (JR) or various other C * programmers; all return values rather than modifying parameters: * ALL_ONE_BITS(type) * ALL_ZERO_BITS(type) * BIT_NUM_AND_LEN_TO_MASK(bitnum,len,type) * BIT_NUM_TO_MASK(bitnum,type) * CLEAR_BITS_USING_MASK(value,mask,type) * FLIP_BITS_USING_MASK(value,mask,type) * LEFT_CIRCULAR_SHIFT_BITS(value,shifts,len,type) * LEFT_SHIFT_BITS(value,shifts,len,type) * NAND_BITS(m,n,type) * NOR_BITS(m,n,type) * RIGHT_CIRCULAR_SHIFT_BITS(value,shifts,len,type) * RIGHT_SHIFT_BITS(value,shifts,len,type) * SET_BITS_USING_MASK(value,mask,type) * TEST_BITS_USING_MASK(value,mask,type) * TYPE_SIZE_IN_BITS(type) * XNOR_BITS(m,n,type) * Beware of side effects: many macros in this file evaluate their arguments * more than once. These are marked with EVALTWICE comments. */ /* Gracefully allow multiple includes of this file. */ #ifndef BITOPS_H #define BITOPS_H /******************* I N C L U D E S *****************/ /*lint -efile(766,limits.h) */ #include /* CHAR_BIT. */ /*********************** M A C R O S ****************/ /* ALL_ONE_BITS(type): Generate a value of type "type" with all bits set to * 1. "type" must be an unsigned integral type. */ #define ALL_ONE_BITS(type) ( (type) ~((type)0) ) /* ALL_ZERO_BITS(type): Generate a value of type "type" with all bits set to * 0. "type" must be an unsigned integral type. */ #define ALL_ZERO_BITS(type) ( (type) 0 ) /* BIT_NUM_AND_LEN_TO_MASK(bitnum,len,type): Return a mask of type "type", * with "len" bits on, starting at "bitnum". Bit 0 is LSB, bits start at * "bitnum" and are turned on in the mask starting at "bitnum" and going to * the left. "type" must be an unsigned integral type. */ /*EVALTWICE*/ #define BIT_NUM_AND_LEN_TO_MASK(bitnum,len,type) \ /*CONSTCOND*/ \ /*lint -save -e506 -e572 -e778 */ \ ( (type) \ ( \ ( (ALL_ONE_BITS(type)) \ >> ((TYPE_SIZE_IN_BITS(type)) \ - ((bitnum)+(type)(len)) ) ) \ & ( \ ((bitnum)>0) \ ? ~( ALL_ONE_BITS(type) \ >> ( (TYPE_SIZE_IN_BITS(type)) \ - (bitnum) ) ) \ : ALL_ONE_BITS(type) ) \ ) \ ) \ /*lint -restore */ /* BIT_NUM_TO_MASK(bitnum,type): Convert bit number "bitnum" to mask of type * "type". Bits are numbered from right to left, with bit 0 being the least * significant bit (LSB). "type" must be an unsigned integral type. * This is my (JR's) modification of something posted to Usenet by Bill * Shannon (shannon@sun.uucp) many years ago. */ #define BIT_NUM_TO_MASK(bitnum,type) \ ( (type) ( ((type)1) << ((type)(bitnum)) ) ) /* BTEST(value,bitnum,type): Test bit numbered "bitnum" in "value", which must * be of type "type". If the tested bit is on, return a Boolean true value * (1); otherwise, return a Boolean false (0). "type" must be an unsigned * integral type. */ #define BTEST(value,bitnum,type) \ ( ( (value) & (BIT_NUM_TO_MASK((bitnum),type)) ) \ ? 1 : 0 \ ) /* CLEAR_BITS_USING_MASK(value,mask,type): Return "value", except that any bits * which are turned on in "mask" will be turned off in the return value. * "type" must be an unsigned integral type. */ #define CLEAR_BITS_USING_MASK(value,mask,type) \ ( (type) ( (value) & ~(mask) ) ) /* FLIP_BITS_USING_MASK(value,mask,type): Return "value", except that any bits * which are turned on in "mask" will be flipped (toggled) in the return * value. "type" must be an unsigned integral type. */ #define FLIP_BITS_USING_MASK(value,mask,type) \ ( (type) ( (value) ^ (mask) ) ) /* IAND(m.n,type): Return the bitwise "and" of the integral values "m" and "n". * "type" must be an unsigned integral type. */ #define IAND(m,n,type) \ ( (type) ( (m) & (n) ) ) /* IBCLR(value,bitnum,type): Return "value" with bit at "bitnum" cleared * (zeroed). "type" must be an unsigned integral type. */ #define IBCLR(value,bitnum,type) \ ( \ (type) CLEAR_BITS_USING_MASK( \ (value), \ BIT_NUM_TO_MASK( (bitnum), type ), \ type) \ ) /* IBITS(value,bitnum,len,type): Extract bits from "value", starting at bit * "bitnum", for "len" bits. The result will be right justified. "type" must be * an unsigned integral type. */ /*EVALTWICE*/ #define IBITS(value,bitnum,len,type) \ /*CONSTCOND*/ \ /*lint -save */ /* Preserve PC-LINT options. */ \ /*lint -e572 */ /* Ignore excessive shift val */ \ /*lint -e778 */ /* Ignore const expr eval to 0 */ \ ( (type) \ ( \ ( (value) & \ (BIT_NUM_AND_LEN_TO_MASK( \ (bitnum), (len), type )) ) \ >> (bitnum) \ ) \ ) \ /*lint -restore */ /* IBSET(value,bitnum,type): Return "value" with bit at "bitnum" set to true. * "type" must be an unsigned integral type. */ #define IBSET(value,bitnum,type) \ ( (type) \ ( \ SET_BITS_USING_MASK( \ (value), \ BIT_NUM_TO_MASK( (bitnum), type ), \ type) \ ) \ ) /* IEOR(m.n,type): Return the bitwise exclusive-or of the integral values "m" * and "n". "type" must be an unsigned integral type. */ #define IEOR(m,n,type) \ ( (type) ( (m) ^ (n) ) ) /* IOR(m.n,type): Return the bitwise "or" of the integral values "m" and "n". * "type" must be an unsigned integral type. */ #define IOR(m,n,type) \ ( (type) ( (m) | (n) ) ) /* ISHFT(value,shifts,type): Return "value" with bits logically shifted as * specified by "shifts". Zeros will be shifted-in as applicable. A positive * amount for "shifts" causes a left shift; a negative amount causes a right * shift; a zero amount causes no shift. Note that the absolute value of * "shifts" must be less than or equal to TYPE_SIZE_IN_BITS("type"). Also note * that "value" must be of type "type", and "type" must be an unsigned * integral type. */ /*EVALTWICE*/ #define ISHFT(value,shifts,type) \ /*CONSTCOND*/ \ /*lint -save */ /* Preserve PC-LINT settings. */ \ /*lint -e504 */ /* Ignore unusual shift value */ \ /*lint -e778 */ /* Ignore const expr eval to 0 */ \ ( (type) \ ( ((shifts)>0) \ ? ( (value) << (shifts) ) \ : ( ( (shifts)<0 ) \ ? ( (value) >> (-(shifts)) ) \ : (value) \ ) \ ) \ ) \ /*lint -restore */ /* ISHFTC(value,shifts,len,type): Return "value" with bits circularly shifted * (as specified by "shifts") within the lower "len" bits of "value". A * positive amount for "shifts" causes a left shift; a negative amount causes * a right shift; a zero amount causes no shift. Note that the absolute value * of "shifts" must be less than or equal to "len". Also note that "value" * must be of type "type", and "type" must be an unsigned integral type. "len" * must be greater than 0 and less than or equal to TYPE_SIZE_IN_BITS("type"). */ /*EVALTWICE*/ #define ISHFTC(value,shifts,len,type) \ /*lint -save -e501 */ \ ( (type) ( \ ( ((shifts) == 0) \ || ((len) == (type) (shifts)) \ || ((len) == - (type) (shifts)) ) \ ? ((type)(value)) \ : ( \ ( (shifts) > 0 ) \ ? (RIGHT_CIRCULAR_SHIFT_BITS( \ (value), (shifts), (len), type) ) \ : (LEFT_CIRCULAR_SHIFT_BITS( \ (value), (type) (- (shifts)), \ (len), type) ) ) \ ) \ ) /*lint -restore */ /* LEFT_CIRCULAR_SHIFT_BITS(value,shifts,len,type): Return "value" with bits * circularly shifted left "shifts" bits within the lower "len" bits of * "value". A zero amount for "shifts" causes no shift. Note that "shifts" * must be less than or equal to "len". Also note that "value" must be of type * "type", and "type" must be an unsigned integral type. "len" must also be * greater than zero and less than or equal to TYPE_SIZE_IN_BITS("type"). */ /*EVALTWICE*/ #define LEFT_CIRCULAR_SHIFT_BITS( \ value,shifts,len,type) \ /*lint -save -e504 */ \ ( (type) ( \ ((shifts)==0) || ((len)==(type) (shifts)) \ ? (value) \ : ( ( (value) & \ ~BIT_NUM_AND_LEN_TO_MASK(0,(len),type) ) \ | ( ( (value) & (BIT_NUM_AND_LEN_TO_MASK( \ 0, (len), type )) ) \ >> (shifts) ) \ | ( ( (value) & (BIT_NUM_AND_LEN_TO_MASK( \ 0, (shifts), type )) ) \ << ((len)-(type)(shifts)) ) ) ) \ ) /*lint -restore */ /* LEFT_SHIFT_BITS(value,shifts,len,type): Return "value" with bits logically * shifted left "shifts" bits within the lower "len" bits of "value". If * necessary, zero bits are added on the right. A zero amount for "shifts" * causes no shift. Note that "shifts" must be less than or equal to "len". * Also note that "value" must be of type "type", and "type" must be an * unsigned integral type. "len" must also be greater than zero and less than * or equal to TYPE_SIZE_IN_BITS("type"). */ /*EVALTWICE*/ #define LEFT_SHIFT_BITS(value,shifts,len,type) \ /*lint -save -e504 */ \ ( (type) ( \ ( ((shifts)==0) || ((len)==(type) (shifts)) ) \ ? (value) \ : ( ( (value) & \ ~BIT_NUM_AND_LEN_TO_MASK(0,(len),type) ) \ | ( ( (value) << (shifts) ) \ & (BIT_NUM_AND_LEN_TO_MASK( \ 0, (len), type )) ) ) \ ) \ ) /*lint -restore */ /* MVBITS(src,srcindex,len,destptr,destindex,type): Update the value that * "destptr" points to, using bits extracted from "src" starting at bit * "srcindex" for "len" bits. "destindex" indicates the bit number in the * destination to begin updates. "type" must be an unsigned integral type. */ /*EVALTWICE*/ #define MVBITS( \ src,srcindex,len,destptr,destindex,type) \ /*CONSTCOND*/ /*lint -save -e506 */ \ { \ type srcbits = \ (src) & BIT_NUM_AND_LEN_TO_MASK( \ (srcindex), (len), type ); \ type destmask = BIT_NUM_AND_LEN_TO_MASK( \ (destindex), (len), type ); \ *(destptr) &= ~destmask; \ *(destptr) |= ISHFT( \ srcbits, \ (int) ((destindex)-(srcindex)), \ type ); \ } /*lint -restore */ /* NAND_BITS(m.n,type): Return the bitwise "nand" of the integral values * "m" and "n". "type" must be an unsigned integral type. */ #define NAND_BITS(m,n,type) \ ( (type) ~ ( IAND((m),(n),type) ) ) /* NOR_BITS(m.n,type): Return the bitwise "nor" of the integral values "m" and * "n". "type" must be an unsigned integral type. */ #define NOR_BITS(m,n,type) \ ( (type) ~ ( IOR((m),(n),type) ) ) /* NOT(value,type): Return all bits of "value" flipped. Note that "value" must * be of type "type", which must be an unsigned integral type. */ #define NOT(value,type) ( (type) ~((type)(value)) ) /* RIGHT_CIRCULAR_SHIFT_BITS(value,shifts,len,type). Return "value" with bits * circularly shifted right "shifts" bits within the lower "len" bits of * "value". A zero amount for "shifts" causes no shift. Note that "shifts" * must be less than or equal to "len". Also note that "value" must be of type * "type", and "type" must be an unsigned integral type. "len" must also be * greater than zero and less than or equal to TYPE_SIZE_IN_BITS("type"). */ /*EVALTWICE*/ #define RIGHT_CIRCULAR_SHIFT_BITS( \ value,shifts,len,type) \ /*lint -save -e504 */ \ ( (type) ( \ ((shifts)==0) || ((len)==(type) (shifts)) \ ? (value) \ : ( ( (value) & \ ~BIT_NUM_AND_LEN_TO_MASK(0,(len),type) ) \ | ( ( (value) & (BIT_NUM_AND_LEN_TO_MASK( \ 0, ((len)-(type)(shifts)),type)) ) \ <<(shifts)) \ | ( ((value)&(BIT_NUM_AND_LEN_TO_MASK( \ ((len)-(type)(shifts)),(shifts),type))) \ >> ((len)-(type)(shifts)) ) ) ) \ ) /*lint -restore*/ /* RIGHT_SHIFT_BITS(value,shifts,len,type): Return "value" with bits logically * shifted right "shifts" bits within the lower "len" bits of "value". If * necessary, zero bits are added on the left. A zero amount for "shifts" * causes no shift. Note that "shifts" must be less than or equal to "len". * Also note that "value" must be of type "type", and "type" must be an * unsigned integral type. "len" must also be greater than zero and * less than or equal to TYPE_SIZE_IN_BITS("type"). */ /*EVALTWICE*/ #define RIGHT_SHIFT_BITS(value,shifts,len,type) \ /*lint -save -e504 */ \ ( (type) ( \ ( ((shifts)==0) || ((len)==(type) (shifts)) ) \ ? (value) \ : ( ( (value) & \ ~BIT_NUM_AND_LEN_TO_MASK(0,(len),type) ) \ | ( ( (value) & (BIT_NUM_AND_LEN_TO_MASK( \ 0, (len), type )) ) >> (shifts) ) ) \ ) \ ) /*lint -restore */ /* SET_BITS_USING_MASK(value,mask,type): Return "value", except that any bits * which are turned on in "mask" will also be turned on in the return * value. "type" must be an unsigned integral type. */ #define SET_BITS_USING_MASK(value,mask,type) \ ( (type) ( (value) | (mask) ) ) /* TEST_BITS_USING_MASK(value,mask,type): Return "value", except that only bits * which are turned on in "mask" will be returned. "type" must be an * unsigned integral type. */ #define TEST_BITS_USING_MASK(value,mask,type) \ ( (type) ( (value) & (mask) ) ) /* TYPE_SIZE_IN_BITS(type): Return the number of bits required for type "type". */ #define TYPE_SIZE_IN_BITS(type) \ ( (type) ( sizeof(type) * CHAR_BIT ) ) /* XNOR_BITS(m.n,type): Return the bitwise exclusive "nor" of the integral * values "m" and "n". "type" must be an unsigned integral type. */ #define XNOR_BITS(m,n,type) \ ( (type) ~ ( IEOR((m),(n),type) ) ) #endif /* BITOPS_H */ Listing Two /* mmixcom.h-- MMIX common defns. Copyright (c) 1994 by JR (John Rogers). * All rights reserved. CompuServe: 72634,2402 * FUNCTION - mmixcom.h contains types and equates used for defining MMIX * instructions in object code format. * We take advantage of the implicit ANSI C requirement that unsigned char be 8 * bits or larger. Similarly, we can assume unsigned long is 32 bits or larger. */ #ifndef MMIXCOM_H #define MMIXCOM_H /* Define a type for one instruction. Note that this will be at least 32 bits, * depending on the compiler. */ typedef unsigned long MMIX_Instr_T; /* We also need to deal with single words in MMIX. These are currently 32 bits * wide, although Knuth is likely to change them to 64 bits soon. */ typedef unsigned long MMIX_Word_T; #define MMIX_WORD_LEN 32 /* Many parts of MMIX words are in bytes. In MMIX, a byte is 8 bits long. In C, * this might be larger. */ typedef unsigned char MMIX_Byte_T; /* Even if "char" is more than 8 bits, leave this. */ #define MMIX_BYTE_BIT_LEN 8 /* Define a type for an opcode. */ typedef MMIX_Byte_T MMIX_Opcode_T; /* Define equates for each part of MMIX_Instr_T. Use bit numbering convention * of 0=least significant bit (LSB). */ #define MMIX_INSTR_OPCODE_START 24 #define MMIX_INSTR_OPCODE_LEN MMIX_BYTE_BIT_LEN #define MMIX_INSTR_X_START 16 #define MMIX_INSTR_X_LEN MMIX_BYTE_BIT_LEN #define MMIX_INSTR_Y_START 8 #define MMIX_INSTR_Y_LEN MMIX_BYTE_BIT_LEN #define MMIX_INSTR_Z_START 0 #define MMIX_INSTR_Z_LEN MMIX_BYTE_BIT_LEN #endif /* MMIXCOM_H */ Example 1: unsigned short x; x = ALL_ZERO_BITS(unsigned short); Example 2: #include "mmixcom.h" /* MMIX_Opcode_T, etc. */ MMIX_Instr_T Current_Instruction; MMIX_Opcode_T Current_Opcode; ... /* Assume Current_Instruction has already been set. */ /* IBITS right-justifies result, so use it to extract opcode. */ Current_Opcode = (MMIX_Opcode_T) IBITS( Current_Instruction, /* value */ MMIX_INSTR_OPCODE_START, /* start bit num */ MMIX_INSTR_OPCODE_LEN, /* len */ MMIX_Instr_T); /* type */ Example 3: MMIX_Instr_T New_Instr = ALL_ZERO_BITS(MMIX_Instr_T); /* Set opcode. */ MVBITS( 0xC2, /* ADDU opcode */ /* src */ 0, /* src index: src bit 0. */ MMIX_INSTR_OPCODE_LEN, /* len */ &New_Instr, /* dest ptr */ MMIX_INSTR_OPCODE_START, /* dest index */ MMIX_Instr_T); /* type */ /* Set X (target) field to say r40. */ MVBITS( 40, /* register 40 */ /* src */ 0, /* src index: src bit 0. */ MMIX_INSTR_X_LEN, /* len */ &New_Instr, /* dest ptr */ MMIX_INSTR_X_START, /* dest index */ MMIX_Instr_T); /* type */ /* Set Y (a source field) to r41. */ MVBITS( 41, /* register 41 */ /* src */ 0, /* src index: src bit 0. */ MMIX_INSTR_Y_LEN, /* len */ &New_Instr, /* dest ptr */ MMIX_INSTR_Y_START, /* dest index */ MMIX_Instr_T); /* type */ /* Set Z (the other source field) to r42. */ MVBITS( 42, /* register 42 */ /* src */ 0, /* src index: src bit 0. */ MMIX_INSTR_Z_LEN, /* len */ &New_Instr, /* dest ptr */ MMIX_INSTR_Z_START, /* dest index */ MMIX_Instr_T); /* type */ Example 4: #include "mmixcom.h" /* MMIX_Word_T, MMIX_WORD_LEN, etc. */ MMIX_Word_T Sim_SRU( /* Simulate shift right unsigned instr. */ MMIX_Word_T Source_Reg, MMIX_Word_T Shift_Count_Reg) { if (Shift_Count_Reg >= MMIX_WORD_LEN) return (0); return (RIGHT_SHIFT_BITS( Source_Reg, /* value */ Shift_Count_Reg, /* shifts */ MMIX_WORD_LEN, /* len */ MMIX_Word_T)); /* type */ } Example 5: MMIX_Word_T Sim_XOR( /* Simulate exclusive-OR bits instr. */ MMIX_Word_T Some_Bits, MMIX_Word_T Other_Bits) { return (IEOR( Some_Bits, Other_Bits, MMIX_Word_T)); /* type */ } Example 6: MMIX_Word_T Sim_NOR( /* Simulate NOR bits instr. */ MMIX_Word_T Some_Bits, MMIX_Word_T Other_Bits) { return (NOR_BITS( Some_Bits, Other_Bits, MMIX_Word_T)); /* type */ }