#include <stdio.h>
#include <stdlib.h>
#include "kernel.h"
#include "vfpmath.h"

#define VFPSupport_CheckContext 0x58EC0
#define VFPSupport_CreateContext 0x58EC1
#define VFPSupport_DestroyContext 0x58EC2

extern double *swapend(double *x, int n);
extern double *fntable(double *x, int n, double (*fn)(double xx));
extern double *fnotable(double *x, double *y, int n, double (*fn)(double xx));
extern double *linrange(double *array, int n, double x, double y);
extern double *fnerror(double *array, double *exptd, int n);

double *x, *y, *exacty;

int createctx(unsigned int flags, int regs, int *prev) {
  _kernel_swi_regs r;

  r.r[0]=flags;
  r.r[1]=regs;
  _kernel_swi(VFPSupport_CheckContext, &r, &r);
  flags|=(1<<31);
  r.r[0]=flags;
  r.r[2]=0;
  r.r[3]=0;
  _kernel_swi(VFPSupport_CreateContext, &r, &r);
  *prev=r.r[1];
  return(r.r[0]);
}

int destroyctx(int ctx, int prev) {
  _kernel_swi_regs r;

  r.r[0]=ctx;
  r.r[1]=prev;
  _kernel_swi(VFPSupport_DestroyContext, &r, &r);
  return(r.r[0]);
}

void testsin(void) {
  int i;
  const double pi=3.141592653589793238;
  double st, ct, sa, ca, temp;
  
  linrange(x, 7, 0.0, pi/2.0);
  fnotable(x, y, 7, &vfp_sin);
  sa=st=exacty[5]; ca=ct=exacty[1];
  puts("Testing sin function: known values\n");
  for(i=0; i<=6; i++) {
    printf("%f: sin=%12.10f\n", x[i], y[i]);
  }
  fnerror(y, exacty, 7);
  puts("Errors:\n");
  for(i=0; i<=6; i++) {
    printf("%f: error=%e\n", x[i], y[i]);
  }
  puts("Range reduction:\n");
  for(i=2; i<=24; i++) {
    temp=st*ca+ct*sa;
    ct=ct*ca-st*sa;
    st=temp;
    temp=vfp_sin(5.0*i*pi/12.0);
    printf("%d: sin=%f error=%e\n", i, temp, temp-st);
  }
}

void testarcsin(void) {
  int i;

  fntable(exacty, 7, &vfp_arcsin);
  puts("Testing arcsin function: known values\n");
  for(i=0; i<=6; i++) {
    printf("%d: arcsin=%12.10f\n", i, exacty[i]);
  }
  fnerror(exacty, x, 7);
  puts("Errors:\n");
  for(i=0; i<=6; i++) {
    printf("%f: error=%e\n", x[i], exacty[i]);
  }
}

void trigvalues(double *sval) {
  double r2, r3;

  r2=vfp_sqrt(2.0);
  r3=vfp_sqrt(3.0);
  sval[0]=0.0; sval[6]=1.0;
  sval[1]=0.25*r2*(r3-1.0); sval[5]=0.25*r2*(r3+1.0);
  sval[2]=0.5; sval[4]=0.5*r3;
  sval[3]=0.5*r2;
}

int main(void) {
  int ctx, savedctx;
  char nstring[24];
  
  ctx=createctx(1, 32, &savedctx);
  printf("Current context: %x; previous context: %x\n", ctx, savedctx);
  x=malloc(21*sizeof(double));
  y=x+7; exacty=x+14;
  trigvalues(exacty);
  testsin();
  testarcsin();
  destroyctx(ctx, savedctx);
  return(0);
}

