/*
 * bf.h --
 *
 *	Macros to manipulate bits in an array of bytes, shorts, or words,
 *	simulating the effect of bit fields.
 *
 * Copyright 1990 Regents of the University of California
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies.  The University of California
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 *
 * $Header: /sprite/src/kernel/utils/RCS/bf.h,v 1.1 90/10/01 21:40:51 jhh Exp $ SPRITE (Berkeley)
 */

#ifndef _BF
#define _BF

/*
 * There are a number of formulas that are used to compute which bits
 * within the array are to be manipulated. The following definitions
 * and formulas are used throughout the bf macro package. In the 
 * definitions "left" refers to lower addresses when it refers to array
 * elements, and to the high order bit when it refers to bits within a
 * byte (element).
 *
 *	d = left offset of bit field within the array, in bits.
 *	s = size of the bit field, in bits.
 *	u = size of array elements, in bits.
 *	v = value to assign to or test the bit field with.
 *	x = index of current element of array that is being manipulated,
 *		where x = 0 is the index for the left-most element that
 *		contains part of the bit field.
 *	Dx = left offset of bit field within array element x.
 *	Sx = size of bit field in array element x.
 *	Rx = number of bits in bit field that are to the right of element
 *		x.
 *	Qx = number of bits in element x that are to the right of the
 *		bit field.
 *	Vx = the value of v associated with the bit field within element
 *		x.
 *	Ix = index of element x within the entire array of elements.
 *	Zx = the value of the bit field within element x.
 *
 * For example, consider the following array of bytes, where '|' denotes
 * byte boundaries, '#' denotes the bits of the bit field, and '_' denotes
 * bits that are not in the bit field:
 *
 *	|________|____####|##______| 	(high memory ->)
 *
 * which contains the following values:
 *
 *	|00000000|00001111|11000000|	(binary)
 *
 * Further more let v (the value we want to assign to the bit field) be
 * 101010 binary.  Then we have the following for the variables.  All
 * values are decimal except where noted.
 *	
 *	d = 12
 *	s = 6
 *	u = 8
 *	v = 101010 (binary)
 *	D0 = 4
 *	D1 = 0
 *	S0 = 4
 *	S1 = 2
 *	R0 = 2
 *	R1 = 0
 *	Q0 = 0
 *	Q1 = 6
 *	V0 = 1010 (binary)
 *	V1 = 10000000 (binary)
 *	I0 = 1
 *	I2 = 2
 *	Z0 = 1111 (binary)
 *	Z1 = 11 (binary)
 *
 * The values for d, s, u, and v, are dependent on the format of the
 * bit field.  The values of the other variables can be computed from
 * the following equations.
 *
 * 	D0 = d % u
 *	D1, D2, ... = 0
 *	Sx = min(u - Dx, s - (S0 + S1 + ... + S(x-1)))
 *	Qx = u - (Dx + Sx)
 *	Rx = s - (S0 + S1 + ... + Sx)
 *	Vx = ((v >> Rx) & mask(Sx)) << Qx
 *	Zx = array[Ix] & Vx  (v = the biggest mask in this case)
 *
 * where
 *	min(a,b) computes the minimum of a and b
 *	mask(k) produces a number consisting of x bits set to 1
 *	% is the remainder function.
 */


/*
 *----------------------------------------------------------------------
 *
 * BfMin --
 *
 *	Compute the minimum of two numbers.
 *
 * Results:
 *	The minimum of the two parameters.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfMin(a, b)    ((a) < (b) ? (a) : (b))


/*
 *----------------------------------------------------------------------
 *
 * BfMask --
 *
 *	Creates a mask (all bits are 1) with the number of bits indicated
 *	by the size parameter.
 *
 * Results:
 *	The mask value.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfMask(size)   ((1 << (size)) - 1)


/*
 *----------------------------------------------------------------------
 *
 * BfDx --
 *
 *	Computes the value Dx
 *
 * Results:
 *	Dx
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfDx(u, x, d)  (((x) == 0) ? ((d) % (u)) : 0)


/*
 *----------------------------------------------------------------------
 *
 * BfS0, BfS1, BfS2, BfS3, BfS4 --
 *
 *	Computes the values S0, S1, S2, S3, and S4.
 *
 * Results:
 *	S0 or S1 or S2 or S3 or S4.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfS0(u, d, s)     (BfMin(u - BfDx(u, 0, d), s))

#define BfS1(u, d, s)     (BfMin(u - BfDx(u, 1, d), (s) - BfSumS0(u, d, s)))

#define BfS2(u, d, s)     (BfMin(u - BfDx(u, 2, d), (s) - BfSumS1(u, d, s)))

#define BfS3(u, d, s)     (BfMin(u - BfDx(u, 3, d), (s) - BfSumS2(u, d, s)))

#define BfS4(u, d, s)     (BfMin(u - BfDx(u, 4, d), (s) - BfSumS3(u, d, s)))

/*
 *----------------------------------------------------------------------
 *
 * BfByteSx, BfHalfwordSx, BfWordSx --
 *
 *	Computes Sx. There are three routines for the three possible
 *	values of u.
 *
 * Results:
 *	Sx.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteSx(x, d, s) 	\
    (((x) == 0) ? BfS0(8, d, s) : (((x) == 1) ? BfS1(8, d, s) : BfS2(8, d, s)))

#define BfHalfwordSx(x, d, s) 	\
    (((x) == 0) ? BfS0(16, d, s) : BfS1(16, d, s))

#define BfWordSx(x, d, s)  \
    (((x) == 0) ? BfS0(32, d, s) : BfS1(32, d, s))


/*
 *----------------------------------------------------------------------
 *
 * BfSumS0, BfSumS1, BfSumS2, BfSumS3,  BfSumS4 --
 *
 *	Computes S0 + S1 + ... SN for some N.
 *
 * Results:
 *	The sum from 0 to N of Si.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */


#define BfSumS0(u, d, s)  (BfS0(u, d, s))


#define BfSumS1(u, d, s)  (BfS0(u, d, s) + BfS1(u, d, s))


#define BfSumS2(u, d, s)  (BfSumS1(u, d, s) + BfS2(u, d, s))


#define BfSumS3(u, d, s)  (BfSumS2(u, d, s) + BfS3(u, d, s))


#define BfSumS4(u, d, s)  (BfSumS3(u, d, s) + BfS4(u, d, s))


/*
 *----------------------------------------------------------------------
 *
 * BfSumByteSx, BfSumHalfwordSx, BfSumWordSx --
 *
 *	Computes the sum of S0 + S1 + ... + Sx.  There is one routine for 
 *	each value of u.
 *
 * Results:
 *	The sum.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfSumByteSx(x, d, s) \
    (((x) == 0) ? BfSumS0(8, d, s) : (((x) == 1) ? BfSumS1(8, d, s) : \
	BfSumS2(8, d, s)))


#define BfSumHalfwordSx(x, d, s) \
    (((x) == 0) ? BfSumS0(16, d, s) : BfSumS1(16, d, s))


#define BfSumWordSx(x, d, s)  \
    (((x) == 0) ? BfSumS0(32, d, s) : BfSumS1(32, d, s))


/*
 *----------------------------------------------------------------------
 *
 *  BfByteRx, BfHalfwordRx, BfWordRx--
 *
 *	Computes Rx.
 *
 * Results:
 *	Rx
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteRx(x, d, s)   ((s) - BfSumByteSx(x, d, s))
#define BfHalfwordRx(x, d, s)   ((s) - BfSumHalfwordSx(x, d, s))
#define BfWordRx(x, d, s)   ((s) - BfSumWordSx(x, d, s))


/*
 *----------------------------------------------------------------------
 *
 * BfByteQx, BfHalfwordQx, BfWordQx --
 *
 *	Computes Qx.
 *
 * Results:
 *	Qx.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteQx(x, d, s) (8 - (BfDx(8, x, d) + BfByteSx(x, d, s)))
#define BfHalfwordQx(x, d, s) (16 - (BfDx(16, x, d) + BfHalfwordSx(x, d, s)))
#define BfWordQx(x, d, s) (32 - (BfDx(32, x, d) + BfWordSx(x, d, s)))


/*
 *----------------------------------------------------------------------
 *
 * BfByteVx, BfHalfwordVx, BfWordVx --
 *
 *	Computes Vx
 *
 * Results:
 *	Vx.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteVx(x, d, s, v) \
    ((((v) >> BfByteRx(x, d, s)) & BfMask(BfByteSx(x, d, s))) << \
	BfByteQx(x, d, s))

#define BfHalfwordVx(x, d, s, v) \
    ((((v) >> BfHalfwordRx(x, d, s)) & BfMask(BfHalfwordSx(x, d, s))) << \
	BfHalfwordQx(x, d, s))

#define BfWordVx(x, d, s, v) \
    ((((v) >> BfWordRx(x, d, s)) & BfMask(BfWordSx(x, d, s))) << \
	BfWordQx(x, d, s))


/*
 *----------------------------------------------------------------------
 *
 * BfIx --
 *
 *	Computes Ix
 *
 * Results:
 *	Ix
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfIx(u, x, d) (((d) / (u)) + (x))


/*
 *----------------------------------------------------------------------
 *
 * BfByteZx, BfHalfwordZx, BfWordZx --
 *
 *	Computes Zx.
 *
 * Results:
 *	Zx.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteZx(ptr, x, d, s) \
    ((ptr)[BfIx(8, x, d)] & BfByteVx(x, d, s, 0xffffffff))

#define BfHalfwordZx(ptr, x, d, s) \
    ((ptr)[BfIx(16, x, d)] & BfHalfwordVx(x, d, s, 0xffffffff))

#define BfWordZx(ptr, x, d, s) \
    ((ptr)[BfIx(32, x, d)] & BfWordVx(x, d, s, 0xffffffff))


/*
 *----------------------------------------------------------------------
 *
 * BfByteSetx, BfHalfwordSetx, BfWordSetx --
 *
 *	Stores the value Vx into the xth element containing the bit field.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define BfByteSetx(ptr, x, d, s, v)  {					\
    if ((v) != BfMask(s)) {						\
	(ptr)[BfIx(8, x, d)] &= ~BfByteVx(x, d, s, 0xffffffff); 	\
    }									\
    (ptr)[BfIx(8, x, d)] |= BfByteVx(x, d, s, v); 			\
}

#define BfHalfwordSetx(ptr, x, d, s, v)  {				\
    if ((v) != BfMask(s)) {						\
	(ptr)[BfIx(16, x, d)] &= ~BfHalfwordVx(x, d, s, 0xffffffff); 	\
    }									\
    (ptr)[BfIx(16, x, d)] |= BfHalfwordVx(x, d, s, v);			\
}

#define BfWordSetx(ptr, x, d, s, v)  {					\
    if ((v) != BfMask(s)) {						\
	((ptr)[BfIx(32, x, d)]) &= ~BfWordVx(x, d, s, 0xffffffff); 	\
    }									\
    ((ptr)[BfIx(32, x, d)]) |= BfWordVx(x, d, s, v); 			\
}


/*
 *----------------------------------------------------------------------
 *
 * BfByteTestx, BfHalfwordTestx, BfWordTestx --
 *
 *	Tests the xth element containing the bit field against the value
 *	Vx.
 *
 * Results:
 *	1 if Zx == Vx, 0 otherwise
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */


#define BfByteTestx(ptr, x, d, s, v) \
    (BfByteZx(ptr, x, d, s) == BfByteVx(x, d, s, v))

#define BfHalfwordTestx(ptr, x, d, s, v) \
    (BfHalfwordZx(ptr, x, d, s) == BfHalfwordVx(x, d, s, v))

#define BfWordTestx(ptr, x, d, s, v) \
    (BfWordZx(ptr, x, d, s) == BfWordVx(x, d, s, v))


/*
 *----------------------------------------------------------------------
 *
 * Bf_ByteSet, Bf_HalfwordSet, Bf_WordSet --
 *
 *	Set the bit field defined by ptr, d and s with the value v.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define Bf_ByteSet(ptr, d, s, v)  {				\
    BfByteSetx(ptr, 0, d, s, v);				\
    if (BfByteRx(0, d, s) > 0) {				\
	BfByteSetx(ptr, 1, d, s, v);				\
	if (BfByteRx(1, d, s) > 0) {				\
	    BfByteSetx(ptr, 2, d, s, v);			\
	}							\
    }								\
}

#define Bf_HalfwordSet(ptr, d, s, v)  {				\
    BfHalfwordSetx(ptr, 0, d, s, v);				\
    if (BfHalfwordRx(0, d, s) > 0) {				\
	BfHalfwordSetx(ptr, 1, d, s, v);			\
    }								\
}

#define Bf_WordSet(ptr, d, s, v)  {				\
    BfWordSetx(ptr, 0, d, s, v);				\
    if (BfWordRx(0, d, s) > 0) {				\
	BfWordSetx(ptr, 1, d, s, v);				\
    }								\
}


/*
 *----------------------------------------------------------------------
 *
 * Bf_ByteTest, Bf_HalfwordTest, Bf_WordTest --
 *
 *	Compare the bitfield defined by ptr, d, and s with the value v.
 *
 * Results:
 *	1 if the value in the bitfield equals v, 0 otherwise
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define Bf_ByteTest(ptr, d, s, v) 				\
    ((BfByteRx(0, d, s) <= 0) ? 				\
	(BfByteTestx(ptr, 0, d, s, v)) : 			\
	((BfByteRx(1, d, s) <= 0) ?				\
	    (BfByteTestx(ptr, 0, d, s, v) &&			\
	    BfByteTestx(ptr, 1, d, s, v)) :			\
	    (BfByteTestx(ptr, 0, d, s, v) &&			\
	    BfByteTestx(ptr, 1, d, s, v) &&			\
	    BfByteTestx(ptr, 2, d, s, v))))

#define Bf_HalfwordTest(ptr, d, s, v) 				\
    ((BfHalfwordRx(0, d, s) <= 0) ? 				\
	(BfHalfwordTestx(ptr, 0, d, s, v)) :			\
	(BfHalfwordTestx(ptr, 0, d, s, v) &&			\
	BfHalfwordTestx(ptr, 1, d, s, v)))

#define Bf_WordTest(ptr, d, s, v) 				\
    ((BfWordRx(0, d, s) <= 0) ? 				\
	(BfWordTestx(ptr, 0, d, s, v)) :			\
	(BfWordTestx(ptr, 0, d, s, v) &&			\
	BfWordTestx(ptr, 1, d, s, v)))



/*
 *----------------------------------------------------------------------
 *
 * Bf_ByteGet, Bf_HalfwordGet, Bf_WordGet --
 *
 *	Returns the value in the bitfield defined by ptr, d and s.
 *
 * Results:
 *	The value of the bitfield.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#define Bf_ByteGet(ptr, d, s)	 				\
    ((BfByteRx(0, d, s) == 0) ? 				\
	(BfByteZx(ptr, 0, d, s) >> BfByteQx(0, d, s)) : 	\
	((BfByteZx(ptr, 0, d, s) << BfByteRx(0, d, s)) |	\
	((BfByteRx(1, d, s) == 0) ?   				\
	    (BfByteZx(ptr, 1, d, s) >> BfByteQx(1, d, s)) : 	\
	    ((BfByteZx(ptr, 1, d, s) << BfByteRx(1, d, s)) |	\
	    (BfByteZx(ptr, 2, d, s) >> BfByteQx(2, d, s))))))

#define Bf_HalfwordGet(ptr, d, s)	 				\
    ((BfHalfwordRx(0, d, s) == 0) ? 					\
	(BfHalfwordZx(ptr, 0, d, s) >> BfHalfwordQx(0, d, s)) : 	\
	((BfHalfwordZx(ptr, 0, d, s) << BfHalfwordRx(0, d, s)) |	\
	    (BfHalfwordZx(ptr, 1, d, s) >> BfHalfwordQx(1, d, s))))

#define Bf_WordGet(ptr, d, s)	 				\
    ((BfWordRx(0, d, s) == 0) ? 				\
	(BfWordZx(ptr, 0, d, s) >> BfWordQx(0, d, s)) : 	\
	((BfWordZx(ptr, 0, d, s) << BfWordRx(0, d, s)) |	\
	    (BfWordZx(ptr, 1, d, s) >> BfWordQx(1, d, s))))

#endif /* _BF */

