/*
 * common.i86  -  general include file for target assembler files
 *
 * Copyright (C) 2002-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.i86,v 1.15 2007/01/06 18:30:52 gkminix Exp $
 */
#ifndef COMMON_I86
#define COMMON_I86


/*
 * This file should only be included into target assembler files
 */
#if !defined(_ASSEMBLY_) || !defined(_TARGET_) || !defined(i386)
#error Unable to include common.i86 into target assembler file
#endif
#undef i386


/*
 * We use 16-bit 386 code
 *
 * The .arch pseudo-opcode is not supported by all GAS versions. Those
 * which dont support it, do always assume i386 source code.
 */
.intel_syntax noprefix
#ifdef HAVE_ARCH_I386
.arch i386
#endif
.code16



/*
 *====================================================================
 *
 * 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



/*
 *====================================================================
 *
 * Some older versions of GAS dont produce correct opcodes for the
 * variants of movzx and movsx, where a 16-bit value gets expanded
 * into a 32-bit value. Those GAS versions have to use the data32
 * prefix, and are identified by configure with GAS_NEED_DATA32. We
 * define macros here to allow for easy usage of these instructions.
 *
 * movzx32 macro
 */
#ifdef GAS_NEED_DATA32
# define movzx32	data32 movzx
#else
# define movzx32	movzx
#endif



/*
 * movsx32 macro
 */
#ifdef GAS_NEED_DATA32
# define movsx32	data32 movsx
#else
# define movsx32	movsx
#endif



/*
 * movsd32 macro
 */
#ifdef GAS_NEED_DATA32
# define movsd32	data32 movsw
#else
# define movsd32	movsd
#endif




/*
 *====================================================================
 *
 * When using Intel syntax with GAS, it is not possible to use symbols
 * as immediate values, like in:
 *
 *	.equ	t,2
 *
 *	mox	ax,t
 *
 * In this case, GAS treats `t' as a memory reference and assembles this
 * instruction as to move a word value from address 0x0002 into AX, which
 * is obviously wrong. In order to still be able to use the .equ or `='
 * instructions, we have to prepend the word FLAT in front of each use
 * of an immediate symbol. To make this easier we provide the following
 * macro.
 * However note that when using CPP macros to define numbers this is
 * not necessary. GAS treats numbers as op-code parameters always as
 * immediate values. Therefore
 *
 *	mov	ax,2
 *
 * will correctly load the immediate value 2 into AX. And since CPP
 * substitutes a macro name with a number, GAS will see a number
 * constant, and not a symbol.
 * Newer versions of GAS (2.16.90 and up) correctly process immediate
 * values (except for external symbols!!), and therefore don't need
 * the "flat" workaround, so we disable it with undefining GAS_NEED_FLAT.
 * For externals, we need to define a special workaround.
 *
 * To make it easier to distinguish between these cases in the source
 * code, we use upper-case names for CPP macros, and lower-case names
 * or names with a leading _ for GAS symbols.
 */
#ifdef GAS_NEED_FLAT
# define _I(x)			flat x
# define heap_size_value	flat __heap_size
# define stack_size_value	flat __stack_size
# define file_size_value	flat __file_size
#else
# define _I(x)			x
# define heap_size_value	offset __heap_size
# define stack_size_value	offset __stack_size
# define file_size_value	offset __file_size
#endif




/*
 *====================================================================
 *
 * With Intel syntax, GAS is unable to use the tilde character for
 * a logical negation. We use the following macro instead.
 */
#define _NOT(x)	(0 - (x) - 1)




/*
 *====================================================================
 *
 * Convert C argument number into BP offset for standard stack frame
 */
#define _ARG(x)	(4 * (x + 1))




/*
 *====================================================================
 *
 * Define the size and offsets of the pusha/pushad instructions on
 * the stack
 */
#define PUSHA_AX	0x0010
#define PUSHA_CX	0x000E
#define PUSHA_DX	0x000C
#define PUSHA_BX	0x000A
#define PUSHA_SP	0x0008
#define PUSHA_BP	0x0004
#define PUSHA_SI	0x0002
#define PUSHA_DI	0x0000
#define PUSHA_SIZE	0x0010

#define PUSHAD_AX	0x001C
#define PUSHAD_CX	0x0018
#define PUSHAD_DX	0x0014
#define PUSHAD_BX	0x0010
#define PUSHAD_SP	0x000C
#define PUSHAD_BP	0x0008
#define PUSHAD_SI	0x0004
#define PUSHAD_DI	0x0000
#define PUSHAD_SIZE	0x0020




/*
 *====================================================================
 *
 * Definition of read-only data segment
 */
#define _rodata .section .rodata




/*
 *====================================================================
 *
 * Define some external linker symbols.
 *
 * These are not standard symbols defined by the GNU linker, but will
 * be defined within the netboot linker script files.
 */

	.extern	__text_end		# end of text section
	.extern	__initext_end		# end of init text section
	.extern __data_start		# start of data section
	.extern	__data_end		# end of data section
	.extern	__bss_start		# start of BSS section
	.extern	__bss_end		# end of BSS section
	.extern	__file_size		# size of loadable file (e.g. text plus
					# data plus padding in between)

#ifndef DEF_STACK_SIZE
	.extern	__stack_size		# size of stack
#else
	.global	__stack_size
	.type	__stack_size,@object
#endif

#ifndef DEF_HEAP_SIZE
	.extern	__heap_size		# size of heap
#else
	.global	__heap_size
	.type	__heap_size,@object
#endif


	.struct	0			# switch to absolute segment


#endif

