#include <vo_stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <vstypes.h>
#include <vs1005h.h>
#include <clockspeed.h>
#include <audio.h>
#include <timers.h>
#include <crc32.h>
#include <apploader.h>
#include <kernel.h>
#include "romtestc.h"
#include "imem.h"


#define MIN(a,b) (((a)<(b))?(a):(b))




u_int16 buf[256];

ioresult CalcCrc32File(register char *fileName, register u_int16 verbose,
		       register s_int16 times) {
  ioresult ret = S_ERROR;
  FILE *fp = fopen(fileName, "rb");
  u_int32 bytes = 0, bytesLeft = 0;
  u_int32 crc32[8] = {0};
  u_int32 startTime, totTime;
  int i;

  if (!fp) {
    printf("E: File \"%s\" not found\n", fileName);
    goto finally;
  }

  fseek(fp, 0, SEEK_END);
  bytes = bytesLeft = ftell(fp);
  fseek(fp, 0, SEEK_SET);
  printf("BYTES    0x%08lx = %ld\n", bytes, bytes);

  startTime = ReadTimeCount();

  while (bytesLeft > 1) {
    u_int16 toRead = (u_int16)MIN(bytesLeft, 512) >> 1;
    fread(buf, 1, toRead, fp);
    for (i=0; i<times; i++) {
      crc32[i] = CalcCrc32(crc32[i], buf, 2*toRead);
    }
    bytesLeft -= 2*toRead;
  }
  if (bytesLeft) {
    char c = fgetc(fp);
    for (i=0; i<times; i++) {
      crc32[i] = CalcCrc32Byte(crc32[i], c);
    }
  }

  totTime = ReadTimeCount() - startTime;
  if (!totTime) totTime++;

  for (i=0; i<times; i++) {
    printf("CRC32[%d] 0x%08lx\n", i, crc32[i]);
  }
  if (verbose) {
    printf("TIME     %d.%03d s\n", (int)(totTime/1000), (int)(totTime%1000));
    printf("SPEED    %d KB/s\n", (int)(bytes/totTime));
  }
  ret = S_OK;

 finally:
  if (fp) {
    fclose(fp);
    fp = NULL;
  }
  return ret;
}


ioresult main(char *parameters) {
  int nParam, i;
  char *p = parameters;
  ioresult ret = S_ERROR;
  int verbose = 0, times = 1;

  nParam = RunProgram("ParamSpl", parameters);
  for (i=0; i<nParam; i++) {
    if (!strcmp(p, "-h")) {
      printf("Usage: Crc32 [-v|+v|-i|+i|-x[d]|-h] file1 [...]\n"
	     "-v|+v\tVerbose on|off\n"
	     "-i|+i\tIgnore CRC32 calculation on|off\n"
	     "-x[d]\tCalculate CRC32 d times, allowed range is 0...8\n"
	     "-h\tShow this help\n");
      ret = S_OK;
      goto finally;
    } else if (!strcmp(p, "-v")) {
      verbose = 1;
    } else if (!strcmp(p, "+v")) {
      verbose = 0;
    } else if (!strcmp(p, "-i")) {
      times = 0;
    } else if (!strcmp(p, "+i")) {
      times = 1;
    } else if (!strncmp(p, "-x", 2)) {
      times = (int)(strtol(p+2, NULL, 0));
      if (times < 0 || times > 8) {
	printf("E: Illegal value for parameter \"%s\"\n", p);
	goto finally;
      }
    } else if (!strcmp(p, "-r")) {
      u_int32 calcCrc, goodCrc;
      calcCrc = IRomTestC(0x8000, 0x8000);
      goodCrc = ReadIMem(0xffff);
      printf("I: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
      calcCrc = XRomTestC(0x8000, 0x8000);
      goodCrc = USEX(0xfffe) | ((u_int32)USEX(0xffff) << 16);
      printf("X: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
      calcCrc = YRomTestC(0x8000, 0x7400);
      goodCrc = USEY(0xf3fe) | ((u_int32)USEY(0xf3ff) << 16);
      printf("Y: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
    } else if (!strcmp(p, "-s")) {
      u_int32 calcCrc, goodCrc;
      FILE *fp = NULL;
      calcCrc = IRomTestC(0x8000, 0x8000);
      goodCrc = ReadIMem(0xffff);
      printf("I: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
      if ((fp = fopen("D:I.txt", "wb"))) {
	u_int16 addr, i;
	for (i=0; i<0x8000U; i++) {
	  fprintf(fp, "%d : %032lb;\n", i, ReadIMem(0x8000+i));
	}
	fclose(fp);
	fp = NULL;
      }
      calcCrc = XRomTestC(0x8000, 0x8000);
      goodCrc = USEX(0xfffe) | ((u_int32)USEX(0xffff) << 16);
      printf("X: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
      if ((fp = fopen("D:X.txt", "wb"))) {
	u_int16 addr, i;
	for (i=0; i<0x8000U; i++) {
	  fprintf(fp, "%d : %016b;\n", i, USEX(0x8000+i));
	}
	fclose(fp);
	fp = NULL;
      }
      calcCrc = YRomTestC(0x8000, 0x7400);
      goodCrc = USEY(0xf3fe) | ((u_int32)USEY(0xf3ff) << 16);
      printf("Y: calc CRC 0x%08lx, rom CRC 0x%08lx -> %s\n",
	     calcCrc, goodCrc, (calcCrc == goodCrc) ? "ok" : "*FAIL*");
      if ((fp = fopen("D:Y.txt", "wb"))) {
	u_int16 addr, i;
	for (i=0; i<0x7400U; i++) {
	  fprintf(fp, "%d : %016b;\n", i, USEY(0x8000+i));
	}
	fclose(fp);
	fp = NULL;
      }
    } else {
      if (CalcCrc32File(p, verbose, times)) {
	goto finally;
      }
    }
    p += strlen(p)+1;
  }

  ret = S_OK;

 finally:
  return ret;
}
