/*
** gen_ppc_stubs.c for vbcc-PowerOpen/WarpOS
**
** Read names and offsets from a data file and generate assembler stubs.
**
**
** v1.1 29-Oct-98 phx
**      .sdreg
** v1.0 08-Jul-98 phx
**      Deleted definition of @_-symbols. vlink will create them on demand.
**      vbcc-WarpOS is ready for beta stage.
** v0.9 03-May-98 phx
**      The '(r2)' in "lwz r3,_PowerBCBase(r2)" was missing.
**      There are no other known problems. The program should still
**      work, when vbcc supports TOC-variables.
** v0.3 21-Apr-98 phx
**      Better use 128-bit stack frame alignment, not 64.
** v0.2 10-Mar-98 phx
**      Prefix for TOC symbols is "@_" and not "@".
** V0.1 06-Mar-98 phx
**      created
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LINELEN 79



main(int argc,char *argv[])
{
  FILE *fo,*fi = stdin;
  char buf[LINELEN+1],name[LINELEN+1],srcname[LINELEN+3];
  char *ppcbase = "_PowerPCBase";
  char *path = "";
  char *slash = "";
  int i,lvo,nargs;
  int line=0,rc=0;

  if (argc > 1) {
    path = argv[1];
    if (argc == 2) {
      if (argv[1][0]=='?' || argv[1][0]=='-') {
        printf("%s - written by Frank Wille 1998\n\nUsage:\n"
               "  %s [<dest.path> [<lib lvo file>]]\n\n"
               "Creates PowerPC assembler stub routines for the WarpOS "
               "powerpc.library.\nIf <lib lvo file> is missing, input "
               "will be taken from stdin.\nThe input file must have lines "
               "in the following format:\n<function name> <library vector "
               "offset> <number of arguments>\n",argv[0],argv[0]);
        exit(1);
      }
    }
    else {
      path = argv[1];  /* path for stubs */
      if (!(fi = fopen(argv[2],"r"))) {
        fprintf(stderr,"%s: can't open %s!\n",argv[0],argv[2]);
        exit(10);
      }
    }
  }
  if (i = strlen(path))
    if (path[i-1]!='/' && path[i-1]!=':')
      slash = "/";

  while (fgets(buf,LINELEN,fi)) {
    ++line;
    if (sscanf(buf,"%s%d%d",name,&lvo,&nargs) != 3) {
      fprintf(stderr,"%s: Line %d in %s is illegal:\n%s\n",
              argv[0],line,argv[2],buf);
      rc = 10;
      break;
    }
    if (nargs>7 || nargs<0) {
      fprintf(stderr,"%s: Illegal number of arguments in line %d "
              "of %s:\n%s\n",argv[0],line,argv[2],buf);
      rc = 10;
      break;
    }

    /* generate PPC code for stub function in T: */
    sprintf(srcname,"%s%s%s.s",path,slash,name);
    if (fo = fopen(srcname,"w")) {
      fprintf(fo,"\t.file\t\"%s.s\"\n\n\t.text\n\t.sdreg\tr2\n"
              "\t.extern %s\n\n\t.align\t3\n\t.globl\t_%s\n_%s:\n"
              "\tmflr\tr0\n"
              "\tstw\tr0,8(r1)\n"
              "\tstwu\tr1,-32(r1)\n",name,ppcbase,name,name);

      for (i=0; i<nargs; i++)
        /* copy all arguments to next register */
        fprintf(fo,"\tmr\tr%d,r%d\n",nargs+3-i,nargs+2-i);

      /* load PowerPCBase and LVO, then call LVO via LR */
      fprintf(fo,
              "\tlwz\tr3,%s(r2)\n"
              "\tlwz\tr0,%d(r3)\n"
              "\tmtlr\tr0\n"
              "\tblrl\n"
              "\taddi\tr1,r1,32\n"
              "\tlwz\tr0,8(r1)\n"
              "\tmtlr\tr0\n"
              "\tblr\n"
              "\t.type\t_%s,@function\n"
              "\t.size\t_%s,$-_%s\n",
              ppcbase,lvo+2,name,name,name);
      fclose(fo);
    }
    else {
      fprintf(stderr,"%s: Unable to create stub file %s!\n",
              argv[0],srcname);
      rc = 10;
      break;
    }
  }

  if (fi != stdin)
    fclose(fi);
  exit(rc);
}
