/*
** ppc.library emulation
** (c)1998-99 Frank Wille <frank@phoenix.owl.de>
**
** M68k support functions
**
** V0.4c (21.01.1999) phx
**       Rewritten from scratch. Always use 32-byte aligned memory.
**       Old functions: outofmem(), Dprintf().
**       New: alloc32, alloc32c, newpool32, allocp32, allocpstr
**       As powerpc.library V14 doesn't support pooled memory, I'm
**       trying to simulate this until V15 is ready.
** 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  (02.11.1998) phx
**       created
*/

#include "ppclibemu.h"
#include "errors.h"
#include <exec/memory.h>
#include <exec/lists.h>
#include <proto/exec.h>
#include <proto/powerpc.h>


/* @@@ V14 only! @@@ ---> */

struct Puddle
{
  struct MinNode n;
  char reserved[24];
};

/* <--- @@@ V14 only! @@@ */



static void outofmem(struct PPCLibBase *ppcbase,ULONG bytes)
{
  error1(ppcbase,"While trying to allocate %ld bytes:\n"
         "Out of memory!",bytes);
}


void *alloc32(ULONG size,struct PPCLibBase *ppcbase)
{
  void *p;

  if (!(p = __AllocVec32(size,MEMF_PUBLIC,ppcbase->PowerPCBase)))
    outofmem(ppcbase,size);
  return (p);
}


void *alloc32c(ULONG size,struct PPCLibBase *ppcbase)
{
  void *p;

  if (!(p = __AllocVec32(size,MEMF_CLEAR|MEMF_PUBLIC,ppcbase->PowerPCBase)))
    outofmem(ppcbase,size);
  return (p);
}


void *newpool32(ULONG psize,struct PPCLibBase *ppcbase)
{
#if 0 /* powerpc.library V15 */
  void *p;

  if (!(p = __CreatePool32(MEMF_ANY|MEMF_PUBLIC,psize,psize,
                           ppcbase->PowerPCBase)))
    outofmem(ppcbase,psize);
  return (p);

#else
/* @@@ V14 only! @@@ ---> */

  struct MinList *pool;

  if (pool = alloc32(sizeof(struct MinList),ppcbase))
    _newlist((struct List *)pool);
  return ((void *)pool);

/* <--- @@@ V14 only! @@@ */
#endif
}


/* @@@ V14 only! @@@ ---> */
void freepool32(void *pool,struct PPCLibBase *ppcbase)
{
  if (pool) {
    struct Puddle *p;

    while (p = (struct Puddle *)_remhead((struct List *)pool))
      __FreeVec32(p,ppcbase->PowerPCBase);
    __FreeVec32(pool,ppcbase->PowerPCBase);
  }
}
/* <--- @@@ V14 only! @@@ */


void *allocp32(void *pool,ULONG size,struct PPCLibBase *ppcbase)
{
#if 0 /* powerpc.library V15 */
  void *p;

  if (!(p = __AllocPooled32(pool,size,ppcbase->PowerPCBase)))
    outofmem(ppcbase,size);
  return (p);

#else
/* @@@ V14 only! @@@ ---> */

  struct Puddle *p;

  if (p = alloc32(sizeof(struct Puddle)+size,ppcbase)) {
    _addhead((struct List *)pool,(struct Node *)&p->n);
    p++;
  }
  else
    outofmem(ppcbase,size);
  return ((void *)p);

/* <--- @@@ V14 only! @@@ */
#endif
}


char *allocpstr(void *pool,char *s,struct PPCLibBase *ppcbase)
{
#if 0 /* powerpc.library V15 */
  char *d;
  ULONG size = _strlen(s)+1;

  if (!(d = __AllocPooled32(pool,size,ppcbase->PowerPCBase)))
    outofmem(ppcbase,size);
  _strcpy(d,s);
  return (d);

#else
/* @@@ V14 only! @@@ ---> */
  char *d;
  ULONG size = _strlen(s)+1;

  if (d = allocp32(pool,size,ppcbase))
    _strcpy(d,s);
  return (d);

/* <--- @@@ V14 only! @@@ */
#endif
}


void Dprintf(struct PPCLibBase *ppcbase,char *fmt,...)
{
  if (ppcbase->Flags & PPCLibF_Debug) {
    va_list vl;

    va_start(vl,fmt);
    __SPrintF68K((STRPTR)fmt,(APTR)vl,ppcbase->PowerPCBase);
    va_end(vl);
  }
}
