// loader.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/*** defines ***/
#undef  LINUX     /* activate linux compatibility stuff */
#define DOS 1

/*** includes ***/
#include <stdio.h>
#include "pport.h"
#include <conio.h>
#include <dos.h>

#define SSTEP 0
#define RHPDEBUG 0

#define WAIT  50


/*** typedefs ***/

/*** globals ***/

/*** func protos ***/
static int flip_byte(int byte);
void init_ports();
void frob_cclk();
void one_byte(unsigned char c);
void print_banner();


void init_ports() {
  /* init_ports */
  /* locals */

  /* body */

#ifdef LINUX
  ioperm((unsigned long) LP1_BASE, (unsigned long) 0x3, 0x2 );
#endif

} /* init_ports */



static int flip_byte(int byte)
{ /* flip_byte */
  int bit=0, result = 0;
  
  for (bit = 0; bit < 8; bit++)
    if (byte & (1 << bit))
      result |= (1 << (7 - bit));
  
  return (result);
} /* flip_bypte */



void frob_cclk() {
  /* frob_cclk */
  /* locals */
  long wait;

  /* body */
  outb( (char) (inb( LP1_CR ) & ~CR_STB) & 0xFF, LP1_CR );
#if SSTEP
    printf( "strobe is now high\n" );
    getchar();
#endif

  for( wait = 0; wait < WAIT; wait++ )
	;
  outb( (char) (inb( LP1_CR )  | CR_STB) & 0xFF, LP1_CR );
#if SSTEP
    printf( "strobe is now low\n" );
    getchar();
#endif
  for( wait = 0; wait < WAIT; wait++ )
	;

    outb( (char) (inb( LP1_CR ) & ~CR_STB) & 0xFF, LP1_CR );
#if SSTEP
    printf( "strobe is now high\n" );
    getchar();
#endif

  for( wait = 0; wait < WAIT; wait++ )
	;

} /* frob_cclk */



void one_byte(unsigned char c) {
  /* one_byte */
  /* locals */
  int i;

  /* body */
  for( i = 0 ; i < 8; i++ ) {
    outb( (char) c, LP1_DR );
    frob_cclk();
    c >>= 1;
  }
} /* one_byte */



int main( int argc, char *argv[] ) {
  /* main */
  /* locals */
  unsigned int count, j;
  unsigned long i;
  long  wait;
  FILE *bitstream = NULL;
  char  c;
  int verbose = 0;
  char *fname;
  char data;

  /* body */
#if LINUX
  scanargv( argc, argv, 
	    "%s [-v] [-f filename]", 
	    "[-v %+|-f %r]",
	    &verbose, &bitstream );
#else
  /* dos mode substitute...hack hack */
  fname = argv[1];
  if( NULL IS (bitstream = fopen( fname, "r" ) ) ) {
	printf( "Can't open %s...\n", fname );
	return(0);
  } /* if */
  verbose = 0;
#endif
  
  if( verbose ) 
    print_banner();

  /***** 
   * init any machine-specific stuph 
   *****/
  init_ports();

/* for(;;) { frob_cclk(); } */

  /*****
   * open the bitfile for reading 
   *****/
  if( bitstream IS NULL ) {
    if( verbose ) 
      printf( "using crypt.bit\n" );
    if( NULL IS (bitstream = fopen( "exp1.bit", "r" )) ) {
      printf("Can't open crypt.bit for reading.\n");
      return(0);
    } /* if */
  } /* if */

	data = inb( LP1_BASE + 0x402 );
	printf( "ECR mode: %02X\n", data & 0xFF );
	outb( (data & 0x1F) | 0x00, LP1_BASE + 0x402 );
	outb( 0x0, LP1_CR );

  /*****
   * perform a low-level init and clear of the logic cell array
   *****/
  /* set strobe to inactive value */
  outb( (char) (inb( LP1_CR ) | CR_STB) & 0xFF, LP1_CR ); /* clear strobe */
  
  /* initialize the LCA */
  /* this is done by slamming program low and holding it there */
  /* then returning it to the high value */
  outb( (char) inb( LP1_CR ) | CR_SEL, LP1_CR );
  for( wait = 0; wait < 40000; wait++ )
   ; /* wait for LCA to reset */
#if RHPDEBUG
  printf( "Initialize array\n" );
  getchar();
#endif
  outb( (char) inb( LP1_CR ) & ~CR_SEL, LP1_CR );



  /* wait for /init to go high */
  /* this allows us to determine if the device is connected */
  count = 0;
  while( !(inb( LP1_SR ) & SR_SEL) ) {
    count++;
    if( count > TIMEOUT ) {
      printf( "Init did not go high; is it plugged in?\n" );
      return(0);
    } /* if */
  } /* while */
  
  /*****
   * upload the bitstream 
   *****/
  /* scan past the bitfile header */
  c = 0;
  count = 0;
  while( (unsigned char) c AINT 0xFF ) {
    fread( &c, 1, 1, bitstream );
    count++;
  } /* while */
  
  /* set the data output to all 1's to handle weird parallel ports */
  outb( (char) 0xFF, LP1_DR );
  
  /* from cclk once to get the FPGA in the proper state */
  for(wait = 0; wait < 40000; wait++ )
   ;
  frob_cclk(); 
  for(wait = 0; wait < 40000; wait++ )
   ;

#if RHPDEBUG  
  printf( "Entering main loop.\n" );
  getchar();
#endif

  /*****
   * main upload loop
   *****/
  while( !feof( bitstream ) ) {
    fread( &c, 1, 1, bitstream );
    count++; /* keep a running count of bytes processed, incl header */
    
    /* check for error by INIT going low */
    if(!( inb(LP1_SR) & SR_SEL)) {
      printf( "Got error while downloading on byte %d.\n", count );
      return(0);
    } /* if */
    
    /* bizarrity #2935: MSB and LSB are mixed up in Xilinx world */
    /* outb( (char) flip_byte(c) & 0xFF, LP1_DR ); */
/*    outb( (char) c & 0xFF, LP1_DR ); */

/*    printf( "data now available: %X.\n", c & 0xFF );
    getchar(); */

#if SSTEP
    printf( "Data now available: %X.\n", c & 0xFF );
    getchar();
#endif

    /* send the byte to the FPGA */
    one_byte( (unsigned char) flip_byte( (int) c) );
    
    /* martching .'s to monitor progress */
    if( !(count % 1024) ) {
      /* printf( "count: %d\n", count ); */
      printf( "." );
      fflush(stdout);   /* in case of buffered I/O */
    } /* if */

  } /* while */

  one_byte(0xFF);
  one_byte(0xFF);
  frob_cclk();
  frob_cclk();
  outb( (char) (inb( LP1_CR )  | CR_STB) & 0xFF, LP1_CR );
  outb( (char) inb( LP1_CR ) & ~CR_SEL, LP1_CR );

  printf( "\nuploaded %d bytes\n", count );

#if 0
  printf( "hit return to frob data bits\n" );
  getchar();

  j = 0;
  while( 1 ) {
	outb( (char) j++, LP1_DR );
	for( i = 0; i < 5000000; i++ ) 
		;
	printf( "%ld\n", i );
  }
#endif

  return(0);
} /* main */


void print_banner() {
  /* print_banner */
  /* locals */

  /* body */
  printf( "loader v0.8 (11/1/99)\n" );

} /* print_banner */

/*****
 * misc development notes
 *****/

/* to fix: move WS from 7404 to latch; disconnect cclk. fix M0-2. wire
   rdy/bsy again -- 8/1/97 */

/* cclk uses negative logic in this prototype -- 7/30/97 */

