/*
** ppc.library emulation
** (c)1998-2001 Frank Wille <frank@phoenix.owl.de>
**
** PPC attributes, task attributes, exception handlers, etc.
**
** V0.7d (22.02.2000) phx
**       Returns value of HID1 >> 28 for PPCINFOTAG_CPUPLL, as suggested
**       by Harry Sintonen. This seems to be what original PowerUp does!
** V0.7c (11.01.2000) phx
**       Ok, mea culpa. There *are* PPC boards with LC040 out, so I can't
**       use the FPU on the M68k side. Fixed PPCINFOTAG_CPUPLL again.
**       PPCGetAttrs() will always return a result, not only when
**       ti_Data is 0.
** V0.7b (07.01.2000) phx
**       PPCINFOTAG_CPUPLL should return a special pll code and not
**       the calculated pll directly (reported by Sebastian Jedruszkiewicz).
** V0.6e (14.05.1999) phx
**       PPCSetTaskAttrs(). Supported tags: PPCTASKINFOTAG_PRIORITY,
**        PPCTASKTAG_EXTUSERDATA, PPCTASKINFOTAG_INPUTHANDLE,
**        PPCTASKINFOTAG_OUTPUTHANDLE and PPCTASKINFOTAG_ERRORHANDLE.
** V0.6d (13.05.1999) phx
**       PPCGetAttrs() returns 0x57415250 ('WARP') for PPCINFOTAG_EMULATION
**       (=0x8001f0ff), which allows a program to distinguish the
**       emulation library from the original.
** V0.5d (04.04.1999) phx
**       PPCGetTaskAttrs(). Supported tags: PPCTASKINFOTAG_TASK, VALUEPTR,
**        NAME, PRIORITY, STACKSIZE, INPUTHANDLE, OUTPUTHANDLE, ERRORHANDLE,
**        ELFOBJECT, STARTUP_MSG, STARTUP_MSGDATA, STARTUPMSG_LENGTH,
**        STARTUP_MSGID, STARTUP_MSGPORT, SIGALLOC, SIGWAIT, SIGRECVD,
**        WAITFINISHTASK. The hook and PPC-registers are not supported.
** V0.4  (21.11.1998) phx
**       created, PPCGetAttr (without PPCINFOTAG_EXCEPTIONHOOK)
*/

#include "ppclibemu.h"
#include "errors.h"
#include "supp.h"
#include "taskobject.h"
#include "mpsema_protos.h"
#include <powerup/ppclib/ppc.h>
#include <powerup/ppclib/tasks.h>
#include <proto/utility.h>
#include "oscall.h"

#define PPCINFOTAG_EMULATION (TAG_USER + 0x1f0ff)



ULONG PPCGetTaskAttrs(__reg("a0")struct TaskObject *to,
                      __reg("a1")struct TagItem *ti,
                      __reg("a6")struct PPCLibBase *ppcbase)
{
  static const char *FN = "PPCGetTaskAttrs(): ";
  struct TagItem *tag;
  ULONG ret = 0;
  ULONG *vptr;

  Dprintf(ppcbase,"%sTaskObject=0x%08lx first tag=0x%08lx\n",
          FN,to,ti->ti_Tag);

  if (tag = FindTagItem(PPCTASKINFOTAG_TASK,ti))
    to = (struct TaskObject *)tag->ti_Data;
  obtainMPSemaphore68k(ppcbase,&to->mpSema);

  if (tag = FindTagItem(PPCTASKINFOTAG_VALUEPTR,ti))
    vptr = (ULONG *)tag->ti_Data;

  if (tag = FindTagItem(PPCTASKINFOTAG_ALLTASK,ti))
    Dprintf(ppcbase,"%sALLTASK not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_HOOK,ti))
    Dprintf(ppcbase,"%sHOOK not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_NAME,ti))
    ret = (ULONG)to->n.ln_Name;

  if (tag = FindTagItem(PPCTASKINFOTAG_PRIORITY,ti))
    ret = (ULONG)((long)to->n.ln_Pri);

  if (tag = FindTagItem(PPCTASKINFOTAG_STACKSIZE,ti))
    ret = to->this->tp_StackSize;

  if (tag = FindTagItem(PPCTASKINFOTAG_USEDSTACKSIZE,ti))
    /*ret = (ULONG)to->initialstack - (ULONG)__get_r1();*/
    Dprintf(ppcbase,"%sUSEDSTACKSIZE not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_INPUTHANDLE,ti))
    ret = (ULONG)to->inputhandle;

  if (tag = FindTagItem(PPCTASKINFOTAG_OUTPUTHANDLE,ti))
    ret = (ULONG)to->outputhandle;

  if (tag = FindTagItem(PPCTASKINFOTAG_ERRORHANDLE,ti))
    ret = (ULONG)to->errorhandle;

  if (tag = FindTagItem(PPCTASKINFOTAG_ELFOBJECT,ti))
    ret = (ULONG)to->elf;

  if (tag = FindTagItem(PPCTASKINFOTAG_STARTUP_MSG,ti))
    ret = (ULONG)to->startup;

  if (tag = FindTagItem(PPCTASKINFOTAG_STARTUP_MSGDATA,ti))
    ret = (ULONG)to->msg_data;

  if (tag = FindTagItem(PPCTASKINFOTAG_STARTUP_MSGLENGTH,ti))
    ret = to->msg_length;

  if (tag = FindTagItem(PPCTASKINFOTAG_STARTUP_MSGID,ti))
    ret = to->msg_id;

  if (tag = FindTagItem(PPCTASKINFOTAG_MSGPORT,ti))
    ret = (ULONG)to->ppc_port;

  if (tag = FindTagItem(PPCTASKINFOTAG_SIGALLOC,ti))
    ret = to->this->tp_Task.tc_SigAlloc;

  if (tag = FindTagItem(PPCTASKINFOTAG_SIGWAIT,ti))
    ret = to->this->tp_Task.tc_SigWait;

  if (tag = FindTagItem(PPCTASKINFOTAG_SIGRECVD,ti))
    ret = to->this->tp_Task.tc_SigRecvd;

  if (tag = FindTagItem(PPCTASKINFOTAG_WAITFINISHTASK,ti))
    if (!(to->flags & TskObjF_Async))
      ret = (ULONG)to->m68kParent;

  if (tag = FindTagItem(PPCTASKINFOTAG_CACHEFLUSH,ti))
    Dprintf(ppcbase,"%sCACHEFLUSH not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_STATE,ti))
    Dprintf(ppcbase,"%sSTATE not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_EXCEPTIONHOOK,ti))
    Dprintf(ppcbase,"%sEXCEPTIONHOOK not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_PC,ti))
    Dprintf(ppcbase,"%sPC not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_MSR,ti))
    Dprintf(ppcbase,"%sMSR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_LR,ti))
    Dprintf(ppcbase,"%sLR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_XER,ti))
    Dprintf(ppcbase,"%sXER not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_CR,ti))
    Dprintf(ppcbase,"%sCR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_CTR,ti))
    Dprintf(ppcbase,"%sCTR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_FPSCR,ti))
    Dprintf(ppcbase,"%sFPSCR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_GPR,ti))
    Dprintf(ppcbase,"%sGPR not supported\n",FN);

  if (tag = FindTagItem(PPCTASKINFOTAG_FPR,ti))
    Dprintf(ppcbase,"%sFPR not supported\n",FN);

  releaseMPSemaphore68k(ppcbase,&to->mpSema);
  Dprintf(ppcbase,"%sreturning 0x%08lx\n",FN,ret);
  return (ret);
}


ULONG PPCSetTaskAttrs(__reg("a0")struct TaskObject *to,
                      __reg("a1")struct TagItem *ti,
                      __reg("a6")struct PPCLibBase *ppcbase)
{
  extern BOOL ppctaskattr(struct PPCLibBase *,struct TaskObject *,
                          ULONG,ULONG,ULONG *,BOOL);
  static const char *FN = "PPCSetTaskAttrs(): ";
  struct TagItem *tstate=ti,*tag;
  ULONG ret = TRUE;
  ULONG *vptr;
  struct PPCArgs pa;


  Dprintf(ppcbase,"%sTaskObject=0x%08lx\n",FN,to);
  vptr = (ULONG *)GetTagData(PPCTASKINFOTAG_VALUEPTR,NULL,ti);
  _memset(&pa,sizeof(struct PPCArgs),0);
  pa.PP_Code = (APTR)ppctaskattr;
  pa.PP_Flags = PPF_LINEAR;

  while (tag = NextTagItem(&tstate)) {
    switch (tag->ti_Tag) {
      case PPCTASKINFOTAG_VALUEPTR:
        break;
      default:
        Dprintf(ppcbase,"%stag=0x%08lx data=0x%08lx\n",
                FN,tag->ti_Tag,tag->ti_Data);
        pa.PP_Regs[0] = (ULONG)ppcbase;
        pa.PP_Regs[1] = (ULONG)to;
        pa.PP_Regs[2] = (ULONG)tag->ti_Tag;
        pa.PP_Regs[3] = tag->ti_Data;
        pa.PP_Regs[4] = (ULONG)vptr;
        pa.PP_Regs[5] = FALSE;
        RunPPC(&pa);
        if (pa.PP_Regs[0] == FALSE)
          ret = FALSE;
        break;
    }
  }

  Dprintf(ppcbase,"%sret=%d\n",FN,(int)ret);
  return (ret);
}


ULONG PPCGetAttrs(__reg("a0")struct TagItem *ti,
                  __reg("a6")struct PPCLibBase *ppcbase)
{
  struct TagItem *tag;

  Dprintf(ppcbase,"PPCGetAttrs(): first tag = 0x%08lx\n",ti->ti_Data);

  if (tag = FindTagItem(PPCINFOTAG_CPU,ti))
    return (ppcbase->ppc_PVR >> 16);

  if (tag = FindTagItem(PPCINFOTAG_CPUREV,ti))
    return (ppcbase->ppc_PVR & 0xffff);

  if (tag = FindTagItem(PPCINFOTAG_CPUCOUNT,ti))
    return (1);  /* 1 CPU is hard-coded */

  if (tag = FindTagItem(PPCINFOTAG_CPUCLOCK,ti))
    return ((ppcbase->ppc_CPUClock+500000)/1000000);

  if (tag = FindTagItem(PPCINFOTAG_CPUPLL,ti))
    return (ppcbase->ppc_HID1 >> 28);

  if (tag = FindTagItem(PPCINFOTAG_EXCEPTIONHOOK,ti)) {
    Dprintf(ppcbase,"PPCGetAttrs(): EXCEPTIONHOOK not supported\n");
    return (0);
  }

  if (tag = FindTagItem(PPCINFOTAG_EMULATION,ti))
    return (0x57415250);  /* return 'WARP', if in emulation mode */

  return (0);
}
