/* vim: set filetype=c:
 *
 * common.h86  -  Common definitions for all target source files
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: common.h86,v 1.13 2007/01/06 18:30:52 gkminix Exp $
 */

#ifndef COMMON_H86
#define COMMON_H86



/*
 * This file should only be included into target source files
 */
#if !defined(_TARGET_) || !defined(i386)
#error Unable to include common.h86 into target source file
#endif
#if defined(_ASSEMBLY_)
#error Unable to include common.h86 into target assembler file
#endif
#if !defined(__GNUC__)
#error Target source files need to be compiled using GCC
#endif
#if __GNUC__ < 3
#error GCC version 3 or above required to compile target source file
#endif



/*
 * Include version and configuration header file
 *
 * Note that these are the only files which can be safely included
 * into any host or target source file.
 */
#include <version.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif



/*
 * Define some generally useful macros
 */
#ifndef roundup
# define roundup(x, y)	((((x)+((y)-1))/(y))*(y))
#endif
#ifndef howmany
# define howmany(x, y)	(((x)+((y)-1))/(y))
#endif
#ifndef MIN
# define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
# define MAX(a,b) (((a)>(b))?(a):(b))
#endif



/*
 * The C compiler is unable to see if a C function gets called by an assembly
 * routine. To avoid the compiler optimizing away such functions we have to
 * use function attributes. However, older GCC versions needed the "unused"
 * attribute, while newer versions correctly understand the "used" attribute.
 */
#ifdef HAVE_USED_ATTRIBUTE
# define used_by_asm	used
#else
# define used_by_asm	unused
#endif



/*
 * Older GCC versions don't support the "always_inline" function attribute.
 * Those older versions always inline a function if it has the inline
 * keyword. We use the "no_instrument_function" attribute instead, which is
 * functionally a noop.
 */
#ifndef HAVE_ALWAYS_INLINE_ATTRIBUTE
# define always_inline	no_instrument_function
# define __nb_inline__	__attribute__((unused)) static __inline__
#else
# define __nb_inline__	__attribute__((unused,always_inline)) static __inline__
#endif



/*
 * config.h can possibly define the "inline" keyword to nothing. Since we always
 * use GCC for target C code, which always understands "inline", we have to undefine
 * this keyword again. This is the same with the keywords "const" and "volatile".
 */
#ifdef inline
# undef inline
#endif
#ifdef const
# undef const
#endif
#ifdef volatile
# undef volatile
#endif



/*
 * Define data types needed to represent a certain data width
 *
 * We can safely assume fixed types here, since we can be sure that this
 * file can only be compiled using GCC for a x86 target system.
 */
typedef unsigned char  __u8;		/* 8-bit data type */
typedef unsigned short __u16;		/* 16-bit data type */
typedef unsigned long  __u32;		/* 32-bit data type */

typedef unsigned short __nptr;		/* near pointer */
typedef unsigned long  __fptr;		/* far pointer */
typedef unsigned long  __lptr;		/* linear address */

typedef unsigned short __word;		/* short word */
typedef unsigned long  __long;		/* long word */

typedef unsigned short size_t;		/* length value */
typedef unsigned char  bool_t;		/* boolean value */



/*
 * GCC uses 32-bit values internally as pointers, even for near
 * pointers. We use the following macro to convert those pointers
 * into 16-bit values - which is safe because this code always runs
 * in real mode which can only use addresses up to 16 bits.
 */
#define _NP(p)	((__nptr)((int)(p)))



/*
 * Macros to allow using far pointers
 */
#define FP_OFF(fp)	((__u16)(fp))
#define FP_SEG(fp)	((__u16)((fp) >> 16))
#define MK_FP(seg,ofs)	((__fptr)((((__u32)(seg) & 0xFFFFUL) << 16) | \
					((__u16)((__u32)(ofs)) & 0xFFFFUL)))


/* Convert a far pointer into a 32-bit linear address */
__attribute__((always_inline,const)) static inline __lptr far2linear(__fptr ptr)
{
  return(((ptr >> 12) & 0x000FFFF0UL) + (ptr & 0x0000FFFFUL));
}
#define far2long(x)	(unsigned long)far2linear(x)


/* Convert a 32-bit linear address into a far pointer */
__attribute__((always_inline,const)) static inline __fptr linear2far(__lptr l)
{
  return(((l << 12) & 0xFFFF0000UL) + (l & 0x0000000FUL));
}
#define long2far(x)	linear2far((unsigned long)(x))



/*
 * General definitions. These can usually be found in a system header
 * file, but for the target system we don't assume to have any system
 * header files at all.
 */
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef NULL
# define NULL  (void *)0		/* generic pointer */
#endif
#ifndef NNULL
# define NNULL (__nptr)0		/* near pointer */
#endif
#ifndef FNULL
# define FNULL (__fptr)0		/* far pointer */
#endif
#ifndef LNULL
# define LNULL (__lptr)0		/* linear address */
#endif



/*
 * Macros to define the stack and heap size values
 */
#define SET_STACK_SIZE(a)	__asm__(				\
					".set\t__stack_size," #a "\n"	\
					".type\t__stack_size,@object\n"	\
					".global\t__stack_size")

#define SET_HEAP_SIZE(a)	__asm__(				\
					".set\t__heap_size," #a "\n"	\
					".type\t__heap_size,@object\n"	\
					".global\t__heap_size")


#endif

