/*********************************************************************
 *
 * Copyright (c) 1998-1999
 * 3Com/Palm Computing Division.  All rights reserved.
 *
 * Portions copyright (c) 1995-1998
 * Bernd Schmidt.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgement:
 *
 *		This product includes software developed by 3Com and its
 *		contributors.
 *
 * 4. Neither 3Com nor the names of its contributors may be used to
 *    endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY 3COM AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 3COM OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 *******************************************************************/

 /*
  * UAE - The Un*x Amiga Emulator
  *
  * m68k -> i386 compiler
  *
  * (c) 1995 Bernd Schmidt
  */

#ifdef __cplusplus
extern "C" {
#endif

typedef uaecptr (*code_execfunc)(void);

struct code_page {
    struct code_page *next;
    uae_u32 allocmask;
};

struct hash_block {
    struct hash_block *lru_next, *lru_prev;
    struct hash_entry *he_first;

    struct code_page *cpage;
    int alloclen;
    uae_u32 page_allocmask;
    char *compile_start;

    int nrefs;

    int translated:1;
    int untranslatable:1;
    int allocfailed:1;
};

struct hash_entry {
    code_execfunc execute; /* For the sake of the stubs in X86.S */
    struct hash_entry *next,*prev;
    struct hash_entry *next_same_block, *lru_next, *lru_prev;
    struct hash_block *block;

    uaecptr addr;
    uae_u32 matchword;
    int ncalls:8;
    int locked:1;
    int cacheflush:1;
};

extern int nr_bbs_start;
extern uae_u8 nr_bbs_to_run;
extern code_execfunc exec_me;

#ifdef USE_COMPILER
static __inline__ void run_compiled_code(void)
{

    /*if (regs.spcflags == SPCFLAG_EXEC && may_run_compiled) {*/
	while (regs.spcflags == SPCFLAG_EXEC) {
	    uaecptr newpc;
	    regs.spcflags = 0;
	    /*		newpc = (*exec_me)();*/
	    __asm__ __volatile__ ("pushl %%ebp; call *%1; popl %%ebp" : "=a" (newpc) : "r" (exec_me) :
				  "%eax", "%edx", "%ecx", "%ebx",
				  "%edi", "%esi", "memory", "cc");
	    if (nr_bbs_to_run == 0) {
		struct hash_entry *h = (struct hash_entry *)newpc;
		regs.spcflags = SPCFLAG_EXEC;
		exec_me = h->execute;
		regs.pc = h->addr;
		regs.pc_p = regs.pc_oldp = get_real_address(h->addr);
		nr_bbs_to_run = nr_bbs_start;
	    } else
		m68k_setpc_fast(newpc);
	    do_cycles();
	}
/*} else */
	regs.spcflags &= ~SPCFLAG_EXEC;
}

extern void compiler_init(void);
extern void possible_loadseg(void);

extern void m68k_do_rts(void);
extern void m68k_do_bsr(uaecptr, uae_s32);
extern void m68k_do_jsr(uaecptr, uaecptr);
extern void compiler_flush_jsr_stack(void);

#else

#define run_compiled_code() do { ; } while (0)
#define compiler_init() do { ; } while (0)
#define possible_loadseg() do { ; } while (0)
#define compiler_flush_jsr_stack() do { ; } while (0)

extern void Software_ProcessLINK (uae_s32 linkSize);
extern int Software_ProcessRTS (void);
extern int Software_ProcessRTE (uaecptr newpc);
extern int Software_ProcessJSR (uaecptr oldpc, uaecptr dest);
extern int Software_ProcessJSR_Ind (uaecptr oldpc);
extern void Software_CheckStackPointer (int opcodeType, uaecptr oldA7);
enum {
	kUnspecifiedOpcode,
	kMoveOpcode,
	kMoveAOpcode,
	kLEAOpcode,
	kLEA7Opcode,	// LEA, where srcreg is A7
	kEXGOpcode
};

static __inline__ void m68k_do_rts(void)
{
	if (Software_ProcessRTS ())
		return;

    m68k_setpc(get_long(m68k_areg(regs, 7)));
    m68k_areg(regs, 7) += 4;
}

static __inline__ void m68k_do_rte(uaecptr newpc)
{
	if (Software_ProcessRTE(newpc))
		return;

	m68k_setpc_rte(newpc);
}

static __inline__ void m68k_do_bsr(uaecptr oldpc, uae_s32 offset)
{
    m68k_areg(regs, 7) -= 4;
    put_long(m68k_areg(regs, 7), oldpc);
    m68k_incpc(offset);
}

static __inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest)
{
	uaecptr oldA7 = m68k_areg(regs, 7);

	if (Software_ProcessJSR (oldpc, dest))
		return;

    m68k_areg(regs, 7) -= 4;
    put_long(m68k_areg(regs, 7), oldpc);
    m68k_setpc(dest);

	Software_CheckStackPointer (0, oldA7);
}

#endif	/* USE_COMPILER */

#ifdef __cplusplus
}
#endif

