/* 
 * Apple // emulator for *ix
 *
 * This software package is subject to the GNU General Public License
 * version 3 or later (your choice) as published by the Free Software 
 * Foundation.
 *
 * Copyright 1994 Alexander Jean-Claude Bottema
 * Copyright 1995 Stephen Lee
 * Copyright 1997, 1998 Aaron Culliney
 * Copyright 1998, 1999, 2000 Michael Deutschmann
 * Copyright 2013-2015 Aaron Culliney
 *
 */

#include "vm.h"
#include "cpu-regs.h"

/*
 * These "glue" macros code become auto-generated trampoline functions for the exclusive use of cpu65_run() CPU module
 * to make calls back into C that conform with the x86 and x86_64 calling ABIs.
 */

#define GLUE_EXTERN_C_READ(func)

#define GLUE_BANK_MAYBE_READ_CX(func,pointer) \
ENTRY(func)             testLQ  $SS_CXROM, SOFTSWITCHES(reg_args); \
                        jnz     1f; \
                        callLQ  *pointer(reg_args); \
                        ret; \
1:                      addLQ   pointer(reg_args), EffectiveAddr_X; \
                        movb    (EffectiveAddr_X),%al; \
                        subLQ   pointer(reg_args), EffectiveAddr_X; \
                        ret;

#define GLUE_BANK_MAYBE_READ_C3(func,pointer) \
ENTRY(func)             testLQ  $SS_CXROM, SOFTSWITCHES(reg_args); \
                        jnz     1f; \
                        testLQ  $SS_C3ROM, SOFTSWITCHES(reg_args); \
                        jnz     1f; \
                        callLQ  *pointer(reg_args); \
                        ret; \
1:                      addLQ   pointer(reg_args), EffectiveAddr_X; \
                        movb    (EffectiveAddr_X),%al; \
                        subLQ   pointer(reg_args), EffectiveAddr_X; \
                        ret;

#define GLUE_BANK_READ(func,pointer) \
ENTRY(func)             addLQ   pointer(reg_args), EffectiveAddr_X; \
                        movb    (EffectiveAddr_X),%al; \
                        subLQ   pointer(reg_args), EffectiveAddr_X; \
                        ret;

#define GLUE_BANK_WRITE(func,pointer) \
ENTRY(func)             addLQ   pointer(reg_args), EffectiveAddr_X; \
                        movb    %al,(EffectiveAddr_X); \
                        subLQ   pointer(reg_args), EffectiveAddr_X; \
                        ret;

#define GLUE_BANK_MAYBEWRITE(func,pointer) \
ENTRY(func)             addLQ   pointer(reg_args), EffectiveAddr_X; \
                        cmpl    $0, pointer(reg_args); \
                        jz      1f; \
                        movb    %al,(EffectiveAddr_X); \
1:                      subLQ   pointer(reg_args), EffectiveAddr_X; \
                        ret;

#define GLUE_INLINE_READ(func,off) \
ENTRY(func)             movb    off(reg_args), %al; \
                        ret;


#ifdef __LP64__
#   define _PUSH_ARGS   pushLQ  EffectiveAddr_X; /* preserve */ \
                        movLQ   _XAX, %rsi; /* %rdi = ea, %rsi = byte */
#   define _POP_ARGS    popLQ   EffectiveAddr_X; /* restore */
#else
#   define _PUSH_ARGS   pushLQ  _XAX; /* byte is arg2 */ \
                        pushLQ  EffectiveAddr_X; /* ea is arg1 (and preserved) */
#   define _POP_ARGS    popLQ   EffectiveAddr_X; /* restore ea */ \
                        popLQ   _XAX;
#endif

#if __APPLE__
// Xcode/lldb gets confused if _XBP is hosed
#   define _XORLQ_XBP   xorLQ _XBP, _XBP;
#else
#   define _XORLQ_XBP
#endif

#define GLUE_C_WRITE(func) \
ENTRY(func)             pushLQ  _XAX; \
                        pushLQ  XY_Reg_X; \
                        pushLQ  AF_Reg_X; \
                        pushLQ  reg_args; \
                        pushLQ  PC_Reg_X; \
                        andLQ   $0xff,_XAX; \
                        _XORLQ_XBP \
                        _PUSH_ARGS \
                        callLQ  CALL(c_##func); \
                        _POP_ARGS \
                        popLQ   PC_Reg_X; \
                        popLQ   reg_args; \
                        popLQ   AF_Reg_X; \
                        popLQ   XY_Reg_X; \
                        popLQ   _XAX; \
                        ret;

#define _GLUE_C_READ(func) \
ENTRY(func)             pushLQ  XY_Reg_X; \
                        pushLQ  AF_Reg_X; \
                        pushLQ  reg_args; \
                        pushLQ  PC_Reg_X; \
                        pushLQ  _XAX; /* HACK: works around mysterious issue with generated mov(_XAX), _XAX ... */ \
                        _XORLQ_XBP \
                        pushLQ  EffectiveAddr_X; /* ea is arg0 (and preserved) */ \
                        callLQ  CALL(c_##func); \
                        popLQ   EffectiveAddr_X; /* restore ea */ \
                        movb    %al, %dl; \
                        popLQ   _XAX; /* ... ugh */ \
                        movb    %dl, %al; \
                        popLQ   PC_Reg_X; \
                        popLQ   reg_args; \
                        popLQ   AF_Reg_X; \
                        popLQ   XY_Reg_X; \
                        ret;

#define GLUE_C_READ(FUNC) _GLUE_C_READ(FUNC)

#define GLUE_C_READ_ALTZP(FUNC) _GLUE_C_READ(FUNC)

