/*****************************************************************************

			       XCopilot

This code is part of XCopilot, a port of copilot

     Portions of this code are Copyright (C) 1997 Ivan A. Curtis
		       icurtis@radlogic.com.au

The original MS-Windows95 copilot emulator was written by Greg Hewgill.
The following copyright notice appeared on the original copilot sources:

		  Copyright (c) 1996 Greg Hewgill

 MC68000 Emulation code is from Bernd Schmidt's Unix Amiga Emulator.
       The following copyright notice appeared in those files:

	  Original UAE code Copyright (c) 1995 Bernd Schmidt

This code must not be distributed without these copyright notices intact.

*******************************************************************************
*******************************************************************************

Filename:	fakecall.c

Description:	support for Copilot debug module

Update History:   (most recent first)
   Ian Goldberg 11-Sep-97 09:48 -- added bus error support
   I. Curtis    28-Feb-97 22:52 -- created

******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "sysdeps.h"
#include "shared.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"
#include "pilotcpu.h"
#include "fakecall.h"

#define addrstart 0x2000

FakeCall *fc_New(shared_img *shptr)
{
  FakeCall *fc;
  fc = (FakeCall *)malloc(sizeof(FakeCall));
  CPU_getregs(shptr, &(fc->origregs));
  fc->regs = fc->origregs;
  fc->SaveMemory = (char *)malloc(4096);
  memcpy(fc->SaveMemory, CPU_getmemptr(addrstart), 4096);
  fc->nextaddr = addrstart;
  return fc;
}

void fc_Dispose(FakeCall *fc, shared_img *shptr)
{
  CPU_setregs(shptr, &(fc->origregs));
  memcpy(CPU_getmemptr(addrstart), fc->SaveMemory, 4096);
  free(fc->SaveMemory);
  free(fc);
}

void fc_PushWord(FakeCall *fc, UWORD x)
{
  (fc->regs).a[7] -= 2;
  CPU_putword((fc->regs).a[7], x);
}

void fc_PushLong(FakeCall *fc, unsigned long x)
{
  (fc->regs).a[7] -= 4;
  CPU_putlong((fc->regs).a[7], x);
}

void *fc_PushPtr(FakeCall *fc, int size)
{
  void *r;
  (fc->regs).a[7] -= 4;
  if (size == 0) {
    CPU_putlong((fc->regs).a[7], 0);
    return NULL;
  }
  CPU_putlong((fc->regs).a[7], fc->nextaddr);
  r = CPU_getmemptr(fc->nextaddr);
  fc->nextaddr += size + (size & 1);
  return r;
}

UWORD swap(UWORD x)
{ 
  return (x << 8) | ((x >> 8) & 0xff);
}

void fc_PutSwap(unsigned long addr, UWORD word)
{
  UWORD *p;
  p = (UWORD *)CPU_getmemptr(addr);
  *p = swap(word);
  if (CPU_getword(addr) != word) {
    *p = swap(word);
  }
}

void fc_SwapRange(unsigned long startaddr, unsigned long endaddr)
{
  UWORD *p, *e;
  p = (UWORD *)CPU_getmemptr(startaddr);
  e = (UWORD *)CPU_getmemptr(endaddr);
  while (p < e) {
    *p = swap(*p);
    p++;
  }
}

void fc_Call(FakeCall *fc, shared_img *shptr, UWORD api, int debug)
{
  UWORD oldapi;
  UWORD oldnxt;
  int savewrite = shptr->allowromwrites;
  shptr->allowromwrites = 1;
  /* fc_SwapRange(addrstart, fc->nextaddr); */
  oldapi = CPU_getword((fc->regs).pc + 2);
  oldnxt = CPU_getword((fc->regs).pc + 4);
  /* fc_PutSwap((fc->regs).pc + 2, api); */
  CPU_putword((fc->regs).pc + 2, api);
  /* fc_PutSwap((fc->regs).pc + 4, 0x4AFC); */
  CPU_putword((fc->regs).pc + 4, 0x4AFC);
  CPU_setregs(shptr, &(fc->regs));
/******************************
  if (debug) {
    StartDebugger();
    Sleep(INFINITE);
  }
*********************************/

  MC68000_run();

  CPU_getregs(shptr, &(fc->regs));
  CPU_setregs(shptr, &(fc->origregs));
  /* fc_PutSwap((fc->origregs).pc + 2, oldapi); */
  /* fc_PutSwap((fc->origregs).pc + 4, oldnxt); */
  CPU_putword((fc->origregs).pc + 2, oldapi);
  CPU_putword((fc->origregs).pc + 4, oldnxt);
  /* fc_SwapRange(addrstart, fc->nextaddr); */
  shptr->allowromwrites = savewrite;
}

unsigned long fc_GetResultD0(FakeCall *fc)
{
  return (fc->regs).d[0];
}

unsigned long GetResultA0(FakeCall *fc)
{
  return (fc->regs).a[0];
}
