/* rcsid[]="$Header: vmmac.h,v 820.1 86/12/04 19:49:44 root Exp $" */
/* sccsid[]="%W% %Y% %Q% %G%" */

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

#ifndef	VMMAC_ALREADY_DEFINED
#define	VMMAC_ALREADY_DEFINED

/*	vmmac.h	6.1	83/07/29	*/

/*
 *	Macros for management of virtual memory. 
 *
 * 860415 jht -- Lexical cleanup -- more intellegible.
 */

#ifdef	KERNEL
#include "../machine/pte.h"
#include "../machine/cpu.h"
#else
#include <machine/pte.h>
#include <machine/cpu.h>
#endif

/*
 * Virtual memory related conversion macros
 * ----------------------------------------
 */

/*
 * Core clicks to number of pages of page tables needed to map that much
 */
#define	ctopt(x)	(((x)+NPTEPG-1)/NPTEPG)

/*
 * Virtual page numbers to text|data|stack segment page numbers and back
 */
#define	vtotp(p, v)	((int)(v)-LOWPAGES)
#ifdef s32

#define	nsegs(p)							\
	(mmu_sizing[ ( proc0Initd	/* Safe now */			\
			? ((   ((p)->p_mmuIndx >= MMU_MIN_INDX)		\
			    && ((p)->p_mmuIndx <= MMU_MAX_INDX)		\
			   )						\
			     ? (p)->p_mmuIndx				\
			     : (cdebugger("nsegs/E: p_mmuIndx out of range"),\
			        normalMmuIndx				\
			       )					\
			  )						\
			: (cdebugger("nsegs/E: used prior to proc0Initd"),\
			   normalMmuIndx				\
			  )						\
		     )							\
		   ].mmu_nsegs						\
	)

#define	nsmaps(p)    nsegs(p)

/*
 * In deference to the cdebugger() and minimization of blab,
 * we don't printf()
 *
 * BUG:  'vaGate' and 'normalMmuIndx' MUST be synchronized!
 */
#define	usrtop(p)   (mmu_sizing[(   ((p)->p_mmuIndx >= MMU_MIN_INDX)	\
			         && ((p)->p_mmuIndx <= MMU_MAX_INDX)	\
				)					\
			           ? (p)->p_mmuIndx			\
			           : normalMmuIndx			\
			       ].mmu_usrtop				\
		    )

#define	usrstack(p) (mmu_sizing[(   ((p)->p_mmuIndx >= MMU_MIN_INDX)	\
			         && ((p)->p_mmuIndx <= MMU_MAX_INDX)	\
				)					\
			           ? (p)->p_mmuIndx			\
			           : (cdebugger("usrstack/E: p_mmuIndx out of range"),\
				      normalMmuIndx)			\
			       ].mmu_usrstack				\
		    )
/*
 * These last three macros, 'maxVSmaps', 'p1pages', and 'mbutl'
 * are infrequently used, but nevertheless crucial.
 * To ammeloriate my paranoia,
 * I (jht) included the 'proc0Initd' firedoors.
 * The others above are known to work.
 */
#define	maxVSmaps(p)							\
	(mmu_sizing[ ( proc0Initd	/* Save now */			\
			? ((   ((p)->p_mmuIndx >= MMU_MIN_INDX)		\
			    && ((p)->p_mmuIndx <= MMU_MAX_INDX)		\
			   )						\
			    ? (p)->p_mmuIndx				\
			    :(cdebugger("maxVSmaps/E: p_mmuIndx out of range"),\
			       normalMmuIndx				\
			     )						\
			  )						\
			: normalMmuIndx					\
		     )							\
		   ].mmu_maxVSmaps					\
	)

#define	p1pages(p)							\
	(mmu_sizing[ ( proc0Initd	/* Safe now */			\
			? ((    ((p)->p_mmuIndx >= MMU_MIN_INDX)	\
			     && ((p)->p_mmuIndx <= MMU_MAX_INDX)	\
			   )						\
			     ? (p)->p_mmuIndx				\
			     : (cdebugger("p1pages/E: p_mmuIndx out of range"),\
			         normalMmuIndx				\
			       )					\
			  )						\
			: normalMmuIndx					\
		     )							\
		   ].mmu_p1pages					\
	)

#define	mbutl(p)							\
	(mmu_sizing[ ( proc0Initd	/* Safe now */			\
			? (   ((p)->p_mmuIndx >= MMU_MIN_INDX)		\
			   && ((p)->p_mmuIndx <= MMU_MAX_INDX)		\
			  )						\
			    ? (p)->p_mmuIndx				\
			    : (cdebugger("mbutl/E: p_mmuIndx out of range"),\
			        normalMmuIndx				\
			      )						\
			: normalMmuIndx					\
		     )							\
		   ].mmu_mbutl						\
	    )

#define	vtodp(p, vpno)	((int)((vpno) - (p)->p_tsize - LOWPAGES))
#define	vtosp(p, vpno)	((int)(usrtop(p) - 1 - (vpno)))
#else s32
#define	vtodp(p, v)	((int)((v) - stoc(ctos((p)->p_tsize)) - LOWPAGES))
#define	vtosp(p, v)	((int)(btop(USRSTACK) - 1 - (v)))
#endif s32
#define	tptov(p, i)	((unsigned)(i) + LOWPAGES)
#ifdef s32
#define	dptov(p, i)	((unsigned)((p)->p_tsize + (i) + LOWPAGES))
#define	sptov(p, i)	((unsigned)(usrtop(p) - 1 - (i)))
#else s32

#define	dptov(p, i)	((unsigned)(stoc(ctos((p)->p_tsize)) + (i) + LOWPAGES))
#define	sptov(p, i)	((unsigned)(btop(USRSTACK) - 1 - (i)))
#endif s32

/*
 * Tell whether virtual page numbers are in text|data|stack segment
 */
#ifdef s32
#define	isassv(p, v)	((v) >= usrtop(p) - (p)->p_ssize && \
			 (v) <  usrtop(p))
#define	isatsv(p, v)	((p)->p_textp && (v) - LOWPAGES < (p)->p_textp->x_size)
#define	isadsv(p, v)	((v) - LOWPAGES >= (p)->p_tsize && \
			 (v) - LOWPAGES <  (p)->p_tsize + \
					    (p)->p_dsize )
#else s32
#define	isassv(p, v)	((v) >= btop(USRSTACK) - (p)->p_ssize)
#define	isatsv(p, v)	((v) - LOWPAGES < (p)->p_tsize)
			!isassv(p, v))
#endif s32

/*
 * Tell whether pte's are text|data|stack
 */
#define	isaspte(p, pte)		((pte) > sptopte(p, (p)->p_ssize))
#define	isatpte(p, pte)		((pte) < dptopte(p, 0))
#define	isadpte(p, pte)		(!isaspte(p, pte) && !isatpte(p, pte))

/*
 * Text|data|stack pte's to segment page numbers and back
 */
#define	ptetotp(p, pte)		((pte) - (p)->p_p0br)
#define	ptetodp(p, pte)		((pte) - ((p)->p_p0br + (p)->p_tsize))
#ifdef s32
#define	ptetosp(p, pte)	\
	(((p)->p_p0br + (p)->p_szpt*NPTEPG - UPAGES - UWASTE - 1) - (pte))
#else
#define	ptetosp(p, pte)	\
	(((p)->p_p0br + (p)->p_szpt*NPTEPG - UPAGES - 1) - (pte))
#endif

#define	tptopte(p, i)		((p)->p_p0br + (i))
#define	dptopte(p, i)		((p)->p_p0br + (p)->p_tsize + (i))

#ifdef s32
#define	sptopte(p, i) \
	(((p)->p_p0br + (p)->p_szpt*NPTEPG - UPAGES - UWASTE - 1) - (i))
#else
#define	sptopte(p, i) \
	(((p)->p_p0br + (p)->p_szpt*NPTEPG - UPAGES - 1) - (i))
#endif


/*
 * Bytes to pages without rounding, and back
 */
#define	btop(x)		(((unsigned)(x)) >> PGSHIFT)
#define	ptob(x)		((caddr_t)((x) << PGSHIFT))

/*
 * Turn virtual addresses into kernel map indices
 */
#define	kmxtob(a)	(usrpt + (a) * NPTEPG)
#define	btokmx(b)	(((b) - usrpt) / NPTEPG)

/*
 * User area address and pcb bases
 */
#define	uaddr(p)	(&((p)->p_p0br[(p)->p_szpt * NPTEPG - UPAGES]))
#ifdef vax
#define	pcbb(p)		((p)->p_addr[0].pg_pfnum)
#endif
#ifdef s32
#define	pcbb(p)		((p)->p_addr[0].pg_pfnum)
#endif s32

/*
 * Average new into old with aging factor time
 */
#define	ave(smooth, cnt, time) \
	smooth = ((time - 1) * (smooth) + (cnt)) / (time)

/*
 * Abstract machine dependent operations
 */
#ifdef vax
#define	setp0br(x)	(u.u_pcb.pcb_p0br = (x), mtpr(P0BR, x))
#define	setp0lr(x)	(u.u_pcb.pcb_p0lr = \
			    (x) | (u.u_pcb.pcb_p0lr & AST_CLR), \
			 mtpr(P0LR, x))
#define	setp1br(x)	(u.u_pcb.pcb_p1br = (x), mtpr(P1BR, x))
#define	setp1lr(x)	(u.u_pcb.pcb_p1lr = (x), mtpr(P1LR, x))
#define	initp1br(x)	((x) - P1PAGES)
#endif
#ifdef s32
#define	setp0br(x)	(u.u_pcb.pcb_p0br = suregp0br = (x))
#define	setp0lr(x)	(u.u_pcb.pcb_p0lr = suregp0lr = (x))
#define	setp1br(x)	(u.u_pcb.pcb_p1br = suregp1br = (x))
#define	setp1lr(x)	(u.u_pcb.pcb_p1lr = suregp1lr = (x))

/*
 * We default to 'normalMmuIndx',
 * which is likely to be 32MB,
 * even though it is outrageously large
 * for most nominal UNIX utilities.
 *
 * NOTE: suregp1lr must be maintained
 * in synchronization with p1pages!
 */
#define	initP1br(x)   ((x) - mmu_sizing[ normalMmuIndx ].mmu_p1pages)

#define	initp1br(x,p)							\
	((x) - mmu_sizing[( proc0Initd	/* Safe now */			\
				? (					\
				      ((p)->p_mmuIndx >= MMU_MIN_INDX)	\
				   && ((p)->p_mmuIndx <= MMU_MAX_INDX)	\
				  )					\
					  ? (p)->p_mmuIndx		\
					  : (cdebugger("initp1br/E: p_mmuIndx out of range"),\
					     normalMmuIndx)		\
				: normalMmuIndx				\
			  )						\
		         ].mmu_p1pages					\
	      )
#define	getp0br()	suregp0br
#define	getp0lr()	suregp0lr
#define	getp1br()	suregp1br
#define	getp1lr()	suregp1lr
#endif s32

#define	outofmem()	wakeup((caddr_t)&proc[2]);

/*
 * Page clustering macros.
 * 
 * dirtycl(pte)			is the page cluster dirty?
 * anycl(pte,fld)		does any pte in the cluster has fld set?
 * zapcl(pte,fld) = val		set all fields fld in the cluster to val
 * distcl(pte)			distribute high bits to cluster; note that
 *				distcl copies everything but pg_pfnum,
 *				INCLUDING pg_m!!!
 *
 * In all cases, pte must be the low pte in the cluster, even if
 * the segment grows backwards (e.g. the stack).
 */
#define	H(pte)	((struct hpte *)(pte))

#if CLSIZE==1
#define	dirtycl(pte)	dirty(pte)
#define	anycl(pte,fld)	((pte)->fld)
#define	zapcl(pte,fld)	(pte)->fld
#define	distcl(pte)
#endif

#if CLSIZE==2
#define	dirtycl(pte)	(dirty(pte) || dirty((pte)+1))
#define	anycl(pte,fld)	((pte)->fld || (((pte)+1)->fld))
#define	zapcl(pte,fld)	(pte)[1].fld = (pte)[0].fld
#endif

#if CLSIZE==4
#define	dirtycl(pte) \
    (dirty(pte) || dirty((pte)+1) || dirty((pte)+2) || dirty((pte)+3))
#define	anycl(pte,fld) \
    ((pte)->fld || (((pte)+1)->fld) || (((pte)+2)->fld) || (((pte)+3)->fld))
#define	zapcl(pte,fld) \
    (pte)[3].fld = (pte)[2].fld = (pte)[1].fld = (pte)[0].fld
#endif

#ifndef distcl
#define	distcl(pte)	zapcl(H(pte),pg_high)
#endif
#endif	VMMAC_ALREADY_DEFINED
