/*
#ident "@(#)smail/src:RELEASE-3_2_0_120:smailarch.h,v 1.3 2004/07/24 16:17:24 woods Exp"
 */

/*
 *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
 *    Copyright (C) 1992  Ronald S. Karr
 * 
 * See the file COPYING, distributed with smail, for restriction
 * and warranty information.
 */

/*
 * arch:
 *	deal with hardware/architectural issues
 *
 *	Architecure-independent aspects of architecture configuration.
 *	To specify a new architecture, create a file under the smail
 *	conf/arch directory, and refer to the new architecture in the
 *	conf/EDIT_ME file.
 */

#ifdef CHAR_BIT					/* <limits.h> */
# if (BITS_PER_CHAR != CHAR_BIT)
#  include "ERROR: BITS_PER_CHAR does not match platform CHAR_BIT value!"
# endif
#endif

/*
 * This trick will count char bits at runtime
 *
 * We assume a char cannot be as wide as 0xffffffffUL
 */
#define CHAR_BITCOUNT		(((_CHAR_BX((char) -1) + (_CHAR_BX((char) -1) >> 4)) & (char) 0x0f0f0f0fL) % 255)
#define _CHAR_BX(x)		((x) - (((x) >> 1) & (unsigned char) 0x77777777UL)	\
				     - (((x) >> 2) & (unsigned char) 0x33333333UL)	\
				     - (((x) >> 3) & (unsigned char) 0x11111111UL))

/*
 * Derive bit counts extended to other types
 *
 * If BITS_PER_LONG < 32 be careful!  Along with other things, the hash_str()
 * function in hash.c will need to be changed.
 */
#define BITS_PER_LONG	(sizeof(long) * BITS_PER_CHAR)
#define BITS_PER_INT	(sizeof(int) * BITS_PER_CHAR)
#define BITS_PER_SHORT	(sizeof(short) * BITS_PER_CHAR)

/*
 * pointer - same size as a pointer to a structure
 *
 * Setup the typedef so that `pointer' is the same size as a pointer to a
 * structure.  On most machines, this is a long.  On some machines where long
 * is larger than an int, `pointer' is an unsigned int.  Woe to machines with
 * hardware addresses < 19 bits.  (smail might not even fit in that case!)
 *
 * Assume:
 *	typedef long pointer_t;
 *	struct foo *p;		<-- some j-random pointer
 *	long v;			<-- same type as the typedef
 *	union offptr {
 *		struct foo *ptr;
 *		pointer_t addr;
 *	} x;			<-- union of a pointer and the typedef
 *
 * then the following must be true:
 *	x.addr = v;			  implies   v == (pointer_t) (x.ptr)
 *	x.addr = (pointer_t) p;		  implies   p == x.ptr
 *	x.addr == (pointer_t) (x.ptr)
 *	x.ptr  = p;			  implies   p == (struct foo *) (x.addr)
 *	x.ptr  = (struct foo *) v;	  implies   v == x.addr
 *	x.ptr  == (struct foo *) (x.addr)
 */
typedef POINTER_TYPE pointer_t;

/*
 * BYTES_PER_ALIGN - what byte-resolution should be used for alignment
 *
 * Typically BYTES_PER_ALIGN should be equal to the width of the path to memory
 * for a machine, as this is the smallest alignment for which there no
 * performance penalty in accessing an object of any size.
 *
 * In general though sizeof(ALIGNED_TYPE) suffices, unless that's less than the
 * size of pointer_t.
 *
 * Note Smail itself never stores float, double, or long double values in
 * allocated storage so max(sizeof(pointer_t), sizeof(long long)) is the
 * largest alignment value we have to worry about in terms of protecting
 * ourselves from triggering SIGBUS.
 */
#define BYTES_PER_ALIGN		(sizeof(ALIGNED_TYPE))

/*
 * even bytes and odd bytes
 *
 * The hash system used by hash.c (on disk and in memory) relies on the fact
 * that BYTES_PER_ALIGN (see above) will align things to an even byte boundary.
 *
 * Any hash `pointer' that refers to an odd value (2n+1) is taken to mean an
 * offset rather than a real address.  Note that odd valued pointers are never
 * dereferenced.
 *
 * We need to be able to distinguish between even and odd addresses, and to
 * convert to/from even/odd addresseses.  On most machines this is a trivial
 * macro.  Brain damaged machines with brain damaged segment addressing may
 * have to form their own creative macros.
 *
 * Assume:
 *	#define NULL 0		<-- for the sake of this example
 *	struct foobar *ptr;	<-- ptr points to a BYTES_PER_ALIGN object
 *	pointer addr;		<-- addr is of a BYTES_PER_ALIGN object
 *
 * Then these conversion macros must perform the following:
 *   to_odd() and to_even() do not distroy data:
 *	addr = to_odd(ptr)  ==>  ptr == to_even(addr)
 *	addr = to_even(ptr) ==>  ptr == to_odd(addr)
 *   is_even() and is_odd() are reflexive:
 *	is_odd(addr)  != 0  ==>  is_even(to_even(addr)) == 0
 *	is_odd(ptr)   != 0  ==>  is_even(to_even(ptr)) == 0
 *	is_even(addr) != 0  ==>  is_odd(to_odd(addr)) == 0
 *	is_even(ptr)  != 0  ==>  is_odd(to_odd(ptr)) == 0
 *   NULL is an even pointer:
 *	is_even(NULL) != 0
 */
#define is_odd(addr)	((pointer_t) (addr) & 0x1)	/* non-zero if odd pointer */
#define is_even(addr)	(! is_odd(addr))		/* non-zero if even pointer */
#define to_odd(addr)	((pointer_t) (addr) | 0x1)	/* from even or odd to odd */
#define to_even(addr)	((pointer_t) (addr) & ~0x1)	/* from even or odd to even */

/*
 * set_ptr(ptr,addr) places the numeric value of `addr' into the pointer `ptr'.
 * That is, we borrow the pointer `ptr' to store numeric data.
 *
 * get_ptr(ptr) converts a pointer `ptr' back into the value which was stored
 * into it by set_ptr().
 */
#define get_ptr(ptr)		(*(pointer_t *) &(ptr))
#define set_ptr(ptr,addr)	(get_ptr(ptr) = (pointer_t) (addr))

/* 
 * Local Variables:
 * c-file-style: "smail"
 * End:
 */
