/*
** ppc.library emulation
** (c)1998-99 Frank Wille <frank@phoenix.owl.de>
**
** Memory functions
**
** V0.7  (12.12.1999) phx
**       PPCAllocVec/PPCAllocMem will get 32-byte aligned memory again.
**       Since V15 the AllocVecPPC function from WarpOS does only guarantee
**       8-byte alignment, because memory is always from a pool, so there
**       are no cache line problems - but maybe PowerUp software could
**       be annoyed by this fact.
** V0.6d (11.05.1999) phx
**       MEMF_NOCACHEPPC,MEMF_NOCACHEM68K,MEMF_WRITETHROUGHPPC and
**       MEMF_WRITETHROUGHM68K are supported for PPCAllocVec(),
**       PPCAllocMem() and PPCCreatePool().
** V0.6b (17.04.1999) phx
**       Rewrote mem68k.asm as ppcmem.c in C.
**       Alloc/Free functions call the appropriate PPC-functions now,
**       by doing a context-switch.
**       Support for pooled memory: PPCAllocPooled,PPCFreePooled,
**        PPCAllocVecPooled,PPCFreeVecPooled,PPCCreatePool,PPCDeletePool.
** V0.4  (22.11.1998) phx
**       Read/write data by PowerPC:
**         PPCReadByte,WriteByte,ReadWord,WriteWord,ReadLong,WriteLong,
**         WriteLongFlush.
** V0.1  (15.11.1998) phx
**       First partially working ppc.library emulation. Synchronous PPC
**       tasks, started by runelf, which only use the basic PowerUp kernel
**       functions for I/O, memory and context-switch seem to work fine.
** V0.0  (31.10.1998) phx
**       created
*/

#include "ppclibemu.h"
#include "errors.h"
#include "supp.h"
#include <powerup/ppclib/memory.h>
#include <powerpc/memoryPPC.h>


/* PPC functions to call: */
extern ULONG ppc_rb();
extern ULONG ppc_rw();
extern ULONG ppc_rl();
extern void ppc_wb();
extern void ppc_ww();
extern void ppc_wl();
extern void ppc_wli();

APTR getWarpLVO(__reg("a0")struct PPCBase *,__reg("d0")long) =
  "\tmove.l\t0(a0,d0.l),d0";



void *PPCAllocMem(__reg("d0")ULONG size,__reg("d1")ULONG attr,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCAllocMem(): ";
  struct PPCArgs pa;
  ULONG wosattr = attr & ~(MEMF_NOCACHESYNCPPC|MEMF_NOCACHESYNCM68K|
                           MEMF_NOCACHEPPC|MEMF_NOCACHEM68K|
                           MEMF_WRITETHROUGHPPC|MEMF_WRITETHROUGHM68K);
  void *p;

  Dprintf(ppcbase,"%s%ld bytes, attr=0x%08lx\n",FN,size,attr);
  if (attr & (MEMF_NOCACHEPPC|MEMF_NOCACHESYNCPPC|MEMF_WRITETHROUGHPPC))
    wosattr |= MEMF_CACHEOFF;
  if (attr & (MEMF_NOCACHEM68K|MEMF_NOCACHESYNCM68K|MEMF_WRITETHROUGHM68K))
    wosattr |= MEMF_CHIP;  /* a bad solution, but better than failing */
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-322); /* AllocVecPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = size;
  pa.PP_Regs[PPREG_A0] = wosattr;
  pa.PP_Regs[PPREG_A1] = 32;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  p = (void *)pa.PP_Regs[PPREG_D0];
  Dprintf(ppcbase,"%s-> 0x%08lx\n",FN,p);
  return (p);
}


void PPCFreeMem(__reg("a1")APTR mem,__reg("d0")ULONG size,
                 __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCFreeMem(): ";
  struct PPCArgs pa;

  Dprintf(ppcbase,"%s%ld bytes at 0x%08lx\n",FN,size,mem);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-328); /* FreeVecPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)mem;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void *PPCAllocVec(__reg("d0")ULONG size,__reg("d1")ULONG attr,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCAllocVec(): ";
  struct PPCArgs pa;
  ULONG wosattr = attr & ~(MEMF_NOCACHESYNCPPC|MEMF_NOCACHESYNCM68K|
                           MEMF_NOCACHEPPC|MEMF_NOCACHEM68K|
                           MEMF_WRITETHROUGHPPC|MEMF_WRITETHROUGHM68K);
  void *p;

  Dprintf(ppcbase,"%s%ld bytes, attr=0x%08lx\n",FN,size,attr);
  if (attr & (MEMF_NOCACHEPPC|MEMF_NOCACHESYNCPPC|MEMF_WRITETHROUGHPPC))
    wosattr |= MEMF_CACHEOFF;
  if (attr & (MEMF_NOCACHEM68K|MEMF_NOCACHESYNCM68K|MEMF_WRITETHROUGHM68K))
    wosattr |= MEMF_CHIP;  /* a bad solution, but better than failing */
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-322); /* AllocVecPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = size;
  pa.PP_Regs[PPREG_A0] = wosattr;
  pa.PP_Regs[PPREG_A1] = 32;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  p = (void *)pa.PP_Regs[PPREG_D0];
  Dprintf(ppcbase,"%s-> 0x%08lx\n",FN,p);
  return (p);
}


void PPCFreeVec(__reg("a1")APTR mem,__reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCFreeVec(): ";
  struct PPCArgs pa;

  Dprintf(ppcbase,"%sat 0x%08lx\n",FN,mem);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-328); /* FreeVecPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)mem;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void *PPCCreatePool(__reg("d0")ULONG attr,__reg("d1")ULONG puddleSize,
                    __reg("d2")ULONG threshSize,
                    __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCCreatePool(): ";
  struct PPCArgs pa;
  ULONG wosattr = attr & ~(MEMF_NOCACHESYNCPPC|MEMF_NOCACHESYNCM68K|
                           MEMF_NOCACHEPPC|MEMF_NOCACHEM68K|
                           MEMF_WRITETHROUGHPPC|MEMF_WRITETHROUGHM68K);
  void *p;

  Dprintf(ppcbase,"%sattr=0x%08lx, puddle=%ld thresh=%ld\n",
          FN,attr,puddleSize,threshSize);
  if (attr & (MEMF_NOCACHEPPC|MEMF_NOCACHESYNCPPC|MEMF_WRITETHROUGHPPC))
    wosattr |= MEMF_CACHEOFF;
  if (attr & (MEMF_NOCACHEM68K|MEMF_NOCACHESYNCM68K|MEMF_WRITETHROUGHM68K))
    wosattr |= MEMF_CHIP;  /* a bad solution, but better than failing */
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-814); /* CreatePoolPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = wosattr;
  pa.PP_Regs[PPREG_A0] = puddleSize;
  pa.PP_Regs[PPREG_A1] = threshSize;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  p = (void *)pa.PP_Regs[PPREG_D0];
  Dprintf(ppcbase,"%s-> 0x%08lx\n",FN,p);
  return (p);
}


void PPCDeletePool(__reg("a0")void *p,__reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCDeletePool(): ";
  struct PPCArgs pa;

  Dprintf(ppcbase,"%sat 0x%08lx\n",FN,p);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-820); /* DeletePoolPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)p;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void *PPCAllocPooled(__reg("a0")void *pool,__reg("d0")ULONG size,
                     __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCAllocPooled(): ";
  struct PPCArgs pa;
  void *p;

  Dprintf(ppcbase,"%s%ld bytes from pool 0x%08lx\n",FN,size,pool);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-826); /* AllocPooledPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)pool;
  pa.PP_Regs[PPREG_A0] = size;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  p = (void *)pa.PP_Regs[PPREG_D0];
  Dprintf(ppcbase,"%s-> 0x%08lx\n",FN,p);
  return (p);
}


void PPCFreePooled(__reg("a0")void *pool,__reg("a1")APTR mem,
                    __reg("d0")ULONG size,
                    __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCFreePooled(): ";
  struct PPCArgs pa;

  Dprintf(ppcbase,"%s%ld bytes at 0x%08lx (pool 0x%08lx)\n",FN,size,mem,pool);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-832); /* FreePooledPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)pool;
  pa.PP_Regs[PPREG_A0] = (ULONG)mem;
  pa.PP_Regs[PPREG_A1] = size;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void *PPCAllocVecPooled(__reg("a0")void *pool,__reg("d0")ULONG size,
                        __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCAllocVecPooled(): ";
  struct PPCArgs pa;
  void *p;

  Dprintf(ppcbase,"%s%ld bytes from pool 0x%08lx\n",FN,size,pool);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-826); /* AllocPooledPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)pool;
  pa.PP_Regs[PPREG_A0] = size;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  p = (void *)pa.PP_Regs[PPREG_D0];
  Dprintf(ppcbase,"%s-> 0x%08lx\n",FN,p);
  return (p);
}


void PPCFreeVecPooled(__reg("a0")void *pool,__reg("a1")APTR mem,
                       __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  static const char *FN = "PPCFreeVecPooled(): ";
  struct PPCArgs pa;

  Dprintf(ppcbase,"%sat 0x%08lx (pool 0x%08lx)\n",FN,mem,pool);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = getWarpLVO(wosbase,-832); /* FreePooledPPC */
  pa.PP_Regs[PPREG_D0] = (ULONG)wosbase;
  pa.PP_Regs[PPREG_D1] = (ULONG)pool;
  pa.PP_Regs[PPREG_A0] = (ULONG)mem;
  pa.PP_Regs[PPREG_A1] = 0;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


UBYTE PPCReadByte(__reg("a0")UBYTE *p,__reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_rb;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  return ((UBYTE)pa.PP_Regs[PPREG_D0]);
}


UWORD PPCReadWord(__reg("a0")UWORD *p,__reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_rw;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  return ((UWORD)pa.PP_Regs[PPREG_D0]);
}


ULONG PPCReadLong(__reg("a0")ULONG *p,__reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_rl;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
  return ((ULONG)pa.PP_Regs[PPREG_D0]);
}


void PPCWriteByte(__reg("a0")UBYTE *p,__reg("d0")ULONG val,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_wb;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_D1] = val;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void PPCWriteWord(__reg("a0")UWORD *p,__reg("d0")ULONG val,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_ww;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_D1] = val;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void PPCWriteLong(__reg("a0")ULONG *p,__reg("d0")ULONG val,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_wl;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_D1] = val;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}


void PPCWriteLongFlush(__reg("a0")ULONG *p,__reg("d0")ULONG val,
                       __reg("a6")struct PPCLibBase *ppcbase)
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCArgs pa;

  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppc_wli;
  pa.PP_Regs[PPREG_D0] = (ULONG)p;
  pa.PP_Regs[PPREG_D1] = val;
  pa.PP_Regs[PPREG_A4] = (ULONG)ppcbase->WOSLinkerDB;
  __RunPPC(&pa,wosbase);
}
