/*
** ppc.library emulation
** (c)1998-99 Frank Wille <frank@phoenix.owl.de>
**
** PPC inlines
**
** V0.5d (05.04.1999) phx
**       _remhead(). Fixed _head() for MP-compliance.
**       _headsucc(), _tail().
** V0.5a (26.01.1999) phx
**       __get_r1().
** V0.4c (20.01.1999) phx
**       _strcmp(), _addtail().
** V0.4b (04.01.1999) phx
**       __set_r2(), __get_r2(), _newlist(), _remove().
** V0.4  (27.11.1998) phx
**       __initbas, which also initialzed the TOC pointer, was replaced
**       by __getbase. The TOC is always available in kernel mode now.
** 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  (14.11.1998) phx
**       created
*/

#ifndef INLINEPPC_H
#define INLINEPPC_H

/* read PPCLibBase from caller's stack frame (offset 60) */
struct PPCLibBase *__getbase(void) =
        "\tlwz\tr11,0(r1)\n"
        "\tlwz\tr3,60(r11)";

/* store TOC pointer in r2, read TOC pointer from r2 */
void __set_r2(void *tocptr) = "\tmr\tr2,r3";
void *__get_r2(void) = "\tmr\tr3,r2";
void *__get_r1(void) = "\tmr\tr3,r1";

/* 64bit support */
int _cmp64(void *a,void *b) =  /* a<b:-1 a=b:0 a>b:1 */
        "\tlwz\tr5,0(r4)\n"
        "\tlwz\tr6,4(r4)\n"
        "\tlwz\tr4,4(r3)\n"
        "\tlwz\tr3,0(r3)\n"
        "\tcmpw\tr3,r5\n"
        "\tbgt\t$+16\n"
        "\tblt\t$+32\n"
        "\tcmplw\tr4,r6\n"
        "\tble\t$+12\n"
        "#barrier\n"
        "\tli\tr3,1\n"
        "\tb\t$+20\n"
        "#barrier\n"
        "\tblt\t$+12\n"
        "\tli\tr3,0\n"
        "\tb\t$+8\n"
        "#barrier\n"
        "\tli\tr3,-1\n"
        "#barrier";

void _add64(void *a,void *b) =  /* a+=b */
        "\tlwz\tr6,4(r3)\n"
        "\tlwz\tr8,4(r4)\n"
        "\taddc\tr6,r6,r8\n"
        "\tlwz\tr5,0(r3)\n"
        "\tlwz\tr7,0(r4)\n"
        "\tstw\tr6,4(r3)\n"
        "\tadde\tr5,r5,r7\n"
        "\tstw\tr5,0(r3)";

void _sub64(void *a,void *b) =  /* a-=b */
        "\tlwz\tr6,4(r3)\n"
        "\tlwz\tr8,4(r4)\n"
        "\tsubfc\tr6,r8,r6\n"
        "\tlwz\tr5,0(r3)\n"
        "\tlwz\tr7,0(r4)\n"
        "\tstw\tr6,4(r3)\n"
        "\tsubfe\tr5,r7,r5\n"
        "\tstw\tr5,0(r3)";

void _mulu64(void *c,unsigned long a,unsigned long b) =   /* c64=a32*b32 */
        "\tmullw\tr6,r4,r5\n"
        "\tmulhwu\tr0,r4,r5\n"
        "\tstw\tr6,4(r3)\n"
        "\tstw\tr0,0(r3)";

/* list functions */
void _newlist(void *l) =
        "\tstw\tr3,8(r3)\n"
        "\tli\tr0,0\n"
        "\tstwu\tr0,4(r3)\n"
        "\tstw\tr3,-4(r3)";

void _addtail(void *l,void *n) =
        "\taddi\tr0,r3,4\n"
        "\tlwz\tr5,8(r3)\n"
        "\tstw\tr0,0(r4)\n"
        "\tstw\tr5,4(r4)\n"
        "\tstw\tr4,0(r5)\n"
        "\tstw\tr4,8(r3)";

void *_head(void *l) =  /* returns head node, or NULL if list empty */
        "\taddi\tr4,r3,4\n"
        "\tlwz\tr3,0(r3)\n"
        "\tcmpw\tr3,r4\n"
        "\tbne+\t$+8\n"
        "\tli\tr3,0\n"
        "#barrier";

void *_headsucc(void *l) =  /* returns 2nd node of list, of NULL */
        "\taddi\tr4,r3,4\n"
        "\tlwz\tr3,0(r3)\n"
        "\tlwz\tr3,0(r3)\n"
        "\tmr.\tr3,r3\n"
        "\tbeq\t$+16\n"
        "\tcmpw\tr3,r4\n"
        "\tbne+\t$+8\n"
        "\tli\tr3,0\n"
        "#barrier";

void *_remhead(void *l) =
        "\tmr\tr4,r3\n"
        "\tlwz\tr5,0(r4)\n"
        "\tlwz\tr3,0(r5)\n"
        "\tmr.\tr3,r3\n"
        "\tbeq\t$+16\n"
        "\tstw\tr3,0(r4)\n"
        "\tstw\tr4,4(r3)\n"
        "\tmr\tr3,r5\n"
        "#barrier";

void *_tail(void *l) =  /* returns tail node, or NULL if list empty */
        "\tmr\tr4,r3\n"
        "\tlwz\tr3,8(r4)\n"
        "\tcmpw\tr3,r4\n"
        "\tbne+\t$+8\n"
        "\tli\tr3,0\n"
        "#barrier";

void _remove(void *n) =
        "\tlwz\tr5,4(r3)\n"
        "\tlwz\tr4,0(r3)\n"
        "\tstw\tr4,0(r5)\n"
        "\tstw\tr5,4(r4)";

void _insertbefore(void *n,void *sn) =
        "\tlwz\tr5,4(r4)\n"
        "\tstw\tr4,0(r3)\n"
        "\tstw\tr5,4(r3)\n"
        "\tstw\tr3,0(r5)\n"
        "\tstw\tr3,4(r4)";

/* common inline functions */
void _memset(__reg("r3")void *,__reg("r4")unsigned long,
             __reg("r5")unsigned char) =
        "\tmtctr\tr4\n"
        "\tsubi\tr3,r3,1\n"
        "#barrier\n"
        "\tstbu\tr5,1(r3)\n"
        "\tbdnz\t$-4";

void _memcpy(__reg("r3")void *,__reg("r4")void *,__reg("r5")unsigned long ) =
        "\tmtctr\tr5\n"
        "\tsubi\tr4,r4,1\n"
        "\tsubi\tr3,r3,1\n"
        "#barrier\n"
        "\tlbzu\tr5,1(r4)\n"
        "\tstbu\tr5,1(r3)\n"
        "\tbdnz\t$-8";

int _strlen(__reg("r3")const char *) =
        "\tsubi\tr4,r3,1\n"
        "#barrier\n"
        "\tlbzu\tr0,1(r4)\n"
        "\tcmpwi\tr0,0\n"
        "\tbne\t$-8\n"
        "\tsub\tr3,r4,r3";

char *_strcpy(__reg("r3")char *, __reg("r4")const char *) =
        "\tsubi\tr5,r3,1\n"
        "\tsubi\tr4,r4,1\n"
        "#barrier\n"
        "\tlbzu\tr0,1(r4)\n"
        "\tstbu\tr0,1(r5)\n"
        "\tcmpwi\tr0,0\n"
        "\tbne\t$-12";

int _strcmp(__reg("r3")const char *, __reg("r4")const char *) =
        "\tsubi\tr5,r3,1\n"
        "\tsubi\tr4,r4,1\n"
        "#barrier\n"
        "\tlbzu\tr3,1(r5)\n"
        "\tlbzu\tr6,1(r4)\n"
        "\tsub.\tr3,r3,r6\n"
        "\tbne\t$+12\n"
        "\tcmpwi\tr6,0\n"
        "\tbne\t$-20";


#endif /* INLINEPPC_H */
