/* http://neil.franklin.ch/Projects/VirtexTools/virtex.c */
/*   - implementation code file for libvirtex library */
/*       functions to handle Virtex (and Spartan-II) FPGA bitstreams */
/* author Neil Franklin, last modification 2002.10.06 */


/* ------ prerequisites section */

/* to really understand this code you should */
/*   have an understanding of the basics of */
/*     designing logic circuits, such as with [74|74LS|74F]xx(x) chips */
/*     basics of how programmable logic works, particularly FPGAs */
/*   have read the specifics from the */
/*     Xilinx Virtex 2.5V FPGAs (XCV00) data sheet */
/*       http://www.xilinx.com/partinfo/ds003.pdf */
/*     Xilinx Virtex-E 1.8V FPGAs (XCV00E) data sheet */
/*       http://www.xilinx.com/partinfo/ds022.pdf */
/*     Xilinx Virtex-E 1.8V Extended Memory FPGAs (XCV00E) data sheet */
/*       http://www.xilinx.com/partinfo/ds025.pdf */
/*     Xilinx Spartan[tm]-II data sheet (XC2S00) */
/*       http://www.xilinx.com/partinfo/ds001.htm */
/*     Xilinx Spartan[tm]-IIE data sheet (XC2S00E) */
/*       http://www.xilinx.com/partinfo/ds077.htm */
/*     Xilinx Application Note XAPP138, Virtex Configuration and Readback */
/*       http://www.xilinx.com/xapp/xapp138.pdf */
/*     Xilinx XAPP151, Virtex Series Configuration Architecture User Guide */
/*       http://www.xilinx.com/xapp/xapp151.pdf */


/* ------ include section, contains our prototypes */

#include "virtex.h"


/* ------ define various Virtex chip architecture constants section */

int Bit, Frame;


/* ------ define various Virtex chip model dependant constants section */

/* declaration of actual devices, this data is from the data sheets */
struct VirtexModel VirtexModels[] = {

  { "XCV50",    virtex,     24,  16,  2,  0 },
  { "XCV100",   virtex,     30,  20,  2,  0 },
  { "XCV150",   virtex,     36,  24,  2,  0 },
  { "XCV200",   virtex,     42,  28,  2,  0 },
  { "XCV300",   virtex,     48,  32,  2,  0 },
  { "XCV400",   virtex,     60,  40,  2,  0 },
  { "XCV600",   virtex,     72,  48,  2,  0 },
  { "XCV800",   virtex,     84,  56,  2,  0 },
  { "XCV1000",  virtex,     96,  64,  2,  0 },

#ifdef RISK_BROKEN_CHIP
  { "XCV50E",   virtex_e,   24,  16,  4,  6 },
  { "XCV100E",  virtex_e,   30,  20,  4, 12 },
  { "XCV200E",  virtex_e,   42,  28,  4, 12 },
  { "XCV300E",  virtex_e,   48,  32,  4, 12 },
  { "XCV400E",  virtex_e,   60,  40,  4, 12 },
  { "XCV600E",  virtex_e,   72,  48,  6, 12 },
  { "XCV1000E", virtex_e,   96,  64,  6, 12 },
  { "XCV1600E", virtex_e,  108,  72,  8, 12 },
  { "XCV2000E", virtex_e,  120,  80,  8, 12 },
  { "XCV2600E", virtex_e,  138,  92,  8, 12 },
  { "XCV3200E", virtex_e,  156, 104,  8, 12 },

  { "XCV405E",  virtex_em,  60,  40, 14,  4 },
  { "XCV812E",  virtex_em,  84,  56, 20,  4 },
#endif

  { "XC2S15",   spartan_2,  12,   8,  2,  0 },
  { "XC2S30",   spartan_2,  18,  12,  2,  0 },
  { "XC2S50",   spartan_2,  24,  16,  2,  0 },
  { "XC2S100",  spartan_2,  30,  20,  2,  0 },
  { "XC2S150",  spartan_2,  36,  24,  2,  0 },
  { "XC2S200",  spartan_2,  42,  28,  2,  0 },

#ifdef RISK_BROKEN_CHIP
  { "XC2S50E",  spartan_2e, 24,  16,  2,  0 },
  { "XC2S100E", spartan_2e, 30,  20,  2,  0 },
  { "XC2S150E", spartan_2e, 36,  24,  2,  0 },
  { "XC2S200E", spartan_2e, 42,  28,  2,  0 },
  { "XC2S300E", spartan_2e, 48,  32,  2,  0 },
#endif

  { NULL,       none,        0,   0,  0,  0 } };


/* ------ read bits from bit file section */

/* expects: nothing */
/* leaves: Bitfile opened, read in to various global variables, and closed */

FILE *Bitfile;

char *readbitfile(char *BitfileName, int Verbose) {

  static char Error[1024];
  char *serror;
  int ierror;

  if (BitfileName) {
    if (Verbose) {
      fprintf(stderr, "reading from bitfile: %s\n", BitfileName); }
    /* we open with "b" for binary, because else some systems do CRLF->LF */
    Bitfile = fopen(BitfileName, "rb");
    if (!Bitfile) {
      snprintf(Error, sizeof(Error), "%s: %s\n", strerror(errno), BitfileName);
      return (Error); } }
  else {
    if (Verbose) {
      fprintf(stderr, "reading from standard input\n"); }
    Bitfile = stdin; }

  /* read the various sections for the bitfile */
  if (Verbose) {
    fprintf(stderr, "reading bitfile header\n"); }
  serror = readfileheader();
  if (serror) {
    fclose(Bitfile);
    return (serror); }

  if (Verbose) {
    fprintf(stderr, "reading bitstream header\n"); }
  serror = readstreamheader();
  if (serror) {
    fclose(Bitfile);
    return (serror); }

  if (Verbose) {
    fprintf(stderr, "determining model being used from config size\n"); }
  serror = setmodelfromconfigsize();
  if (serror) {
    fclose(Bitfile);
    return (serror); }

  if (Verbose) {
    fprintf(stderr, "readying memory to store config data\n"); }
  serror = allocframes();
  if (serror) {
    fclose(Bitfile);
    return (serror); }

  if (Verbose) {
    fprintf(stderr, "reading main config frames\n"); }
  serror = readmainframes();
  if (serror) {
    fclose(Bitfile);
    return (serror); }

  /* at present we only read until the main frames are in */
  /*   ignore BRAM data frames and bitstream end */
  /*   we will need these when we start processing BRAMs and for writing */

  /* set CLB range to something safe, in case user forgets to do so */
  setclbrange(NULL);

  ierror = fclose(Bitfile);
  if (ierror) {
    snprintf(Error, sizeof(Error), "%s: %s\n", strerror(errno), BitfileName);
    return (Error); }

  if (Verbose) {
    fprintf(stderr, "finished reading\n"); }

  return (NULL); }


/* ------ read .bit file header section */

/* expects: open file, file pointer at nothing yet read */
/* leaves: file header read, file pointer ready to read bitstream */

/* we test here really picky, to make absolutely sure we are processing */
/* and real FPGA .bit file, to prevent random bits ending up in an FPGA */
/* which would destroy the chip due to internal shorted circuits! */

/* format from .../comp.arch.fpga/20010828_download_bitstream_to_FPGA */
/*   corrected error 2->4 bytes for field 0x65 */
/* the example data is from the JBits null300.bit file */

ushort FileheaderLength; /* 0x0009 */
ulong  FileheaderLong1;  /* 0x0ff00ff0 */
ulong  FileheaderLong2;  /* 0x0ff00ff0 */
uchar  FileheaderZero;   /* 0x00 */

ushort KeyLength;        /* 0x0001 */

uchar  DesignnameKey;    /* 0x61 */
ushort DesignnameLength; /* 0x000c */
char   *Designname;      /* "null300.ncd" */

uchar  PartnameKey;      /* 0x62 */
ushort PartnameLength;   /* 0x000a */
char   *Partname;        /* "v300BG352" */

uchar  GendateKey;       /* 0x63 */
ushort GendateLength;    /* 0x000a */
char   *Gendate;         /* "2001/3/23" */

uchar  GentimeKey;       /* 0x64 */
ushort GentimeLength;    /* 0x0009 */
char   *Gentime;         /* "11:43:57" */

uchar  BitstreamKey;     /* 0x65 */
ulong  BitstreamLength;  /* 0x00035760 */


char *readfileheader(void) {

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readfileheader(): Bitfile is NULL\n");
    abort(); }

  fread(&FileheaderLength, sizeof(short), 1, Bitfile);
  /* the bitfile is big-endian, just like network, so we can use ntoh*() */
  FileheaderLength = ntohs(FileheaderLength);
  if (FileheaderLength != 9) {
    return ("expected file header length not 9, not a bitstream file"); }
  fread(&FileheaderLong1, sizeof(ulong), 1, Bitfile);
  FileheaderLong1 = ntohl(FileheaderLong1);
  fread(&FileheaderLong2, sizeof(ulong), 1, Bitfile);
  FileheaderLong2 = ntohl(FileheaderLong2);
  fread(&FileheaderZero, sizeof(uchar), 1, Bitfile);
  if (FileheaderLong1 != 0x0FF00FF0 || FileheaderLong2 != 0x0FF00FF0 ||
      FileheaderZero != 0x00) {
    return ("expected file header not 4 0FF0 plus 00, not a bitstream file"); }

  fread(&KeyLength, sizeof(ushort), 1, Bitfile);
  KeyLength = ntohs(KeyLength);
  if (KeyLength != 1) {
    return ("key length not 1, not a bitstream file"); }

  fread(&DesignnameKey, sizeof(uchar), 1, Bitfile);
  if (DesignnameKey != 0x61) {
    return ("expected design name key missing, not a bitstream file"); }
  fread(&DesignnameLength, sizeof(ushort), 1, Bitfile);
  DesignnameLength = ntohs(DesignnameLength);
  if (DesignnameLength == 0) {
    return ("expected design name length nonzero, not a bitstream file"); }
  Designname = (char *)malloc(DesignnameLength);
  fread(Designname, sizeof(char), DesignnameLength, Bitfile);

  fread(&PartnameKey, sizeof(uchar), 1, Bitfile);
  if (PartnameKey != 0x62) {
    return ("expected part name key missing, not a bitstream file"); }
  fread(&PartnameLength, sizeof(ushort), 1, Bitfile);
  PartnameLength = ntohs(PartnameLength);
  if (PartnameLength == 0) {
    return ("expected part name length nonzero, not a bitstream file"); }
  Partname = (char *)malloc(PartnameLength);
  fread(Partname, sizeof(char), PartnameLength, Bitfile);

  fread(&GendateKey, sizeof(uchar), 1, Bitfile);
  if (GendateKey != 0x63) {
    return ("expected generation date key missing, not a bitstream file"); }
  fread(&GendateLength, sizeof(ushort), 1, Bitfile);
  GendateLength = ntohs(GendateLength);
  if (GendateLength == 0) {
    return ("expected generation date length nonzero, not a bitstream file"); }
  Gendate = (char *)malloc(GendateLength);
  fread(Gendate, sizeof(char), GendateLength, Bitfile);

  fread(&GentimeKey, sizeof(uchar), 1, Bitfile);
  if (GentimeKey != 0x64) {
    return ("expected generation time key missing, not a bitstream file"); }
  fread(&GentimeLength, sizeof(ushort), 1, Bitfile);
  GentimeLength = ntohs(GentimeLength);
  if (GentimeLength == 0) {
    return ("expected generation time length nonzero, not a bitstream file"); }
  Gentime = (char *)malloc(GentimeLength);
  fread(Gentime, sizeof(char), GentimeLength, Bitfile);

  fread(&BitstreamKey, sizeof(uchar), 1, Bitfile);
  if (BitstreamKey != 0x65) {
    return ("expected bitstream key missing, not a bitstream file"); }
  fread(&BitstreamLength, sizeof(ulong), 1, Bitfile);
  BitstreamLength = ntohl(BitstreamLength);
  if (BitstreamLength == 0) {
    return ("expected bitstream length nonzero, not a bitstream file"); }

  return(NULL); }


/* ------ read bitstream header section */

/* expects: header read, file pointer ready to read bitstream */
/* leaves: bitstream header read, file pointer ready to read frames */

/* still being really picky, to make absolutely sure we are processing */
/* an standard bitstream, we assume this is .bit file, but format may change */

/* format from XAPP138, pages 20-22 */

ulong StreamDummy;       /* 0xFFFFFFFF, so that sync contains first non-ones */
ulong StreamSync;        /* 0xAA995566, this triggers interpretation */

ulong StreamRcrcCmd;     /* 0x30008001, command register */
ulong StreamRcrc;        /* 0x00000007, reset CRC counter */

ulong StreamFlenReg;     /* 0x30016001, frame length, with fill, wo pipeline */
ulong StreamFlen;        /* 0x000000??, XV300 example 0x00000014 */

ulong StreamConfoptReg;  /* 0x30012001, configuration options */
ulong StreamConfopt;     /* 0x????????, JBits uses 0x00803f2d */

ulong StreamMaskReg;     /* 0x3000C001, control register mask */
ulong StreamMask;        /* 0x00000000, JBits uses 0x000001c6 */

ulong StreamSwitchCmd;   /* 0x30008001, command register */
ulong StreamSwitch;      /* 0x00000009, switch Cclk freq */

ulong StreamFaddrReg;    /* 0x30002001, frame address */
ulong StreamFaddr;       /* 0x00000000, from the beginning */

ulong StreamWriteCmd;    /* 0x30008001, command register */
ulong StreamWrite;       /* 0x00000001, write config data */

ulong StreamFdatinReg;   /* 0x30004000, frame data input */
ulong StreamFdatinLen;   /* 0x5???????, XV300 example 0x5000cb07 */


char *readstreamheader(void) {

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readstreamheader(): Bitfile is NULL\n");
    abort(); }

  fread(&StreamDummy, sizeof(ulong), 1, Bitfile);
  StreamDummy = ntohl(StreamDummy);
  if (StreamDummy != 0xFFFFFFFF) {
    return ("expected stream dummy missing, not a standard bitstream"); }
  fread(&StreamSync, sizeof(ulong), 1, Bitfile);
  StreamSync = ntohl(StreamSync);
  if (StreamSync != 0xAA995566) {
    return ("expected stream synchron missing, not a standard bitstream"); }

  fread(&StreamRcrcCmd, sizeof(ulong), 1, Bitfile);
  StreamRcrcCmd = ntohl(StreamRcrcCmd);
  fread(&StreamRcrc, sizeof(ulong), 1, Bitfile);
  StreamRcrc = ntohl(StreamRcrc);
  if (StreamRcrcCmd != 0x30008001 || StreamRcrc != 0x00000007) {
    return ("expected stream reset CRC missing, not a standard bitstream"); }

  fread(&StreamFlenReg, sizeof(ulong), 1, Bitfile);
  StreamFlenReg = ntohl(StreamFlenReg);
  fread(&StreamFlen, sizeof(ulong), 1, Bitfile);
  StreamFlen = ntohl(StreamFlen);
  if (StreamFlenReg != 0x30016001 || StreamFlen == 0x00000000) {
    return ("expected stream frame len nonzero, not a standard bitstream"); }

  fread(&StreamConfoptReg, sizeof(ulong), 1, Bitfile);
  StreamConfoptReg = ntohl(StreamConfoptReg);
  fread(&StreamConfopt, sizeof(ulong), 1, Bitfile);
  StreamConfopt = ntohl(StreamConfopt);
  if (StreamConfoptReg != 0x30012001) {
    return ("expected stream config opts missing, not a standard bitstream"); }

  fread(&StreamMaskReg, sizeof(ulong), 1, Bitfile);
  StreamMaskReg = ntohl(StreamMaskReg);
  fread(&StreamMask, sizeof(ulong), 1, Bitfile);
  StreamMask = ntohl(StreamMask);
  if (StreamMaskReg != 0x3000C001) {
    return ("expected stream ctrl mask missing, not a standard bitstream"); }

  fread(&StreamSwitchCmd, sizeof(ulong), 1, Bitfile);
  StreamSwitchCmd = ntohl(StreamSwitchCmd);
  fread(&StreamSwitch, sizeof(ulong), 1, Bitfile);
  StreamSwitch = ntohl(StreamSwitch);
  if (StreamSwitchCmd != 0x30008001 || StreamSwitch != 0x00000009) {
    return ("expected stream clock freq missing, not a standard bitstream"); }

  fread(&StreamFaddrReg, sizeof(ulong), 1, Bitfile);
  StreamFaddrReg = ntohl(StreamFaddrReg);
  fread(&StreamFaddr, sizeof(ulong), 1, Bitfile);
  StreamFaddr = ntohl(StreamFaddr);
  if (StreamFaddrReg != 0x30002001 || StreamFaddr != 0x00000000) {
    return ("expected stream frame addr zero, not a standard bitstream"); }

  fread(&StreamWriteCmd, sizeof(ulong), 1, Bitfile);
  StreamWriteCmd = ntohl(StreamWriteCmd);
  fread(&StreamWrite, sizeof(ulong), 1, Bitfile);
  StreamWrite = ntohl(StreamWrite);
  if (StreamWriteCmd != 0x30008001 || StreamWrite != 0x00000001) {
    return ("expected stream write cmd missing, not a standard bitstream"); }

  fread(&StreamFdatinReg, sizeof(ulong), 1, Bitfile);
  StreamFdatinReg = ntohl(StreamFdatinReg);
  fread(&StreamFdatinLen, sizeof(ulong), 1, Bitfile);
  StreamFdatinLen = ntohl(StreamFdatinLen);
  if (StreamFdatinReg != 0x30004000 || StreamFdatinLen == 0x00000000) {
    return ("expected stream data input nonzero, not a standard bitstream"); }

  return (NULL); }


/* ------ set Virtex model from config size section */

/* expects: StreamFdatinLen set so that we can find fitting Model */
/* leaves: Model set pointing to model dependant constants */

/* format from XAPP138, page 22, last row in table */

/* the actual device we are using for selecting parameters */
struct VirtexModel *Model;


char *setmodelfromconfigsize(void) {

  /* size of main config section identifies model */
  long StreamWords;

  if (!StreamFdatinLen) {
    fprintf(stderr,
      "BUGCHECK setmodelfromconfigsize(): StreamFdatinLen is 0\n");
    abort(); }

  /* extract length from type 2 packet header, see XAPP138, page 21 */
  StreamWords = StreamFdatinLen & 0x07FFFFFF;

  for (Model = VirtexModels; Model->Name != NULL; Model++) {

    long ModelWords;

    /* fill out this models computed data */
    Model->IobNSCols   = Model->ClbCols;
    Model->DllCols     = Model->BramCols;
    Model->MiddleRows  = Model->ClbRows;

    /* calculate main section size for this model */

    /* these formulas are from XAPP151, page 5 */
    Model->FrameBits = Model->MiddleRows*VirtexMiddleBits+
                       VirtexTopBotRows*VirtexTopBotBits;
    /* round up to next number dividable by 32, then divide, add 1 pipeline */
    Model->FrameWords = (((Model->FrameBits+31)&0xFFFFFFE0)/32)+1;

    /* these formulas are from XAPP151, pages 3 - 5 */
    Model->MainFrames = VirtexCenterCols*VirtexCenterFrames+
                        Model->ClbCols*VirtexClbFrames+
                        VirtexIobWECols*VirtexIobWEFrames+
                        /* BRAM data not in main frames, see XAPP151, page 3 */
                        /* so here use BramCFrames, not BramFrames */
                        Model->BramCols*VirtexBramCFrames+
                        /* and the pipelining frame */
                        1;

    ModelWords = Model->MainFrames*Model->FrameWords;

    if (ModelWords == StreamWords) {
      /* we have found right model, dont search further */
      break; } }

  /* we ran out of models to test */
  if (Model->Name == NULL) {
    return ("stream word count doesn't fit a known model, not a bitstream"); }

  return (NULL); }


/* ------ allocate memory for bitstream frame data section */

/* expects: Model set so that model dependant constants are known */
/*   also tests for not already allocated, to prevent memory leak */
/* leaves: memory ready for reading in frames data */

/* format from XAPP151, pages 3-5 */

/* data will be stored using one "ulong" for each frame of an CLB/etc */
/*   placed as Bitmap*[0..columns-1][0..rows-1][0..frames-1] */
/*   so that all frames of one column/row position are together */
/*   and all rows of one column are together */

/* C does not allow variable size arrays, so use heap memory and pointers */
/*   will require explicit pointer arithmetic everywhere */

ulong *BitmapCenter, *BitmapGclk;
ulong *BitmapClb,    *BitmapIobNS;
ulong *BitmapIobWE,  *BitmapPadIobWE;
ulong *BitmapBram,   *BitmapDll;


char *allocframes(void) {

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK allocframes(): Model or Model->Name is NULL\n");
    abort(); }

  if (BitmapCenter || BitmapGclk     || BitmapClb  || BitmapIobNS ||
      BitmapIobWE  || BitmapPadIobWE || BitmapBram || BitmapDll) {
    fprintf(stderr, "BUGCHECK allocframes(): Bitmap* are not NULL\n");
    abort(); }

  BitmapCenter = (ulong *)calloc(VirtexCenterCols*
                                 Model->MiddleRows*
                                 VirtexCenterFrames, sizeof(ulong));
  if (!BitmapCenter) {
    return ("failled to allocate memory for Center bits"); }

  BitmapGclk = (ulong *)calloc(VirtexGclkCols*
                               VirtexTopBotRows*
                               VirtexGclkFrames, sizeof(ulong));
  if (!BitmapGclk) {
    return ("failled to allocate memory for GCLK bits"); }


  BitmapClb = (ulong *)calloc(Model->ClbCols*
                              Model->MiddleRows*
                              VirtexClbFrames, sizeof(ulong));
  if (!BitmapClb) {
    return ("failled to allocate memory for CLB bits"); }

  BitmapIobNS = (ulong *)calloc(Model->IobNSCols*
                                VirtexTopBotRows*
                                VirtexIobNSFrames, sizeof(ulong));
  if (!BitmapIobNS) {
    return ("failled to allocate memory for IOB N/S bits"); }


  BitmapIobWE = (ulong *)calloc(VirtexIobWECols*
                                Model->MiddleRows*
                                VirtexIobWEFrames, sizeof(ulong));
  if (!BitmapIobWE) {
    return ("failled to allocate memory for IOB W/E bits"); }

  BitmapPadIobWE = (ulong *)calloc(VirtexPadIobWECols*
                                   VirtexTopBotRows*
                                   VirtexPadIobWEFrames, sizeof(ulong));
  if (!BitmapPadIobWE) {
    return ("failled to allocate memory for IOB W/E padding bits"); }


  /* for consistency with other rows and fitting into array of longs */
  /*   BRAMs 72 bits/frame are stored split as 4 quaters of 18 bits/frame */
  /*   as rows are direct after each other, these quaters follow each other */
  /*     so that gives 27*18+64*18+27*18+64*18+27*18+64*18+27*18+64*18 bits */
  /*     so then use BRAM row no * 4 as base and then frame indexes 0..363 */
  /*   for output then correctly as 4*((27+64)*18) underneath each other */

  /* space is allocated for BRAM control and BRAM data frames in one go */
  BitmapBram = (ulong *)calloc(Model->BramCols*
                               Model->MiddleRows*
                               VirtexBramFrames, sizeof(ulong));
  if (!BitmapBram) {
    return ("failled to allocate memory for BRAM bits"); }

  /* like for BRAMs space for DLLs and the padding above BRAM data in one go */
  /*   BRAM data padding has no effect on DLL indexing, as it is after it */
  BitmapDll = (ulong *)calloc(Model->DllCols*
                              VirtexTopBotRows*
                              VirtexDllFrames, sizeof(ulong));
  if (!BitmapDll) {
    return ("failled to allocate memory for DLL bits"); }


  return (NULL); }


/* ------ read bitstream main frame data section */

/* expects: bitstream header read, file pointer ready to read frames */
/*   and also Model set so that model dependant constants are known */
/* leaves: bitstream main frames data read, file pointer ready for BRAMd */

/* by here we must assume this to be a valid bitstream, trust rest of bits */
/* as we have no ability to do any syntactic checks any more, Banzaaaiiii!!! */

/* Xilinx thinks big endian, so we use the first/top/big/MSB 18 bits */
/*   masks for extracting top 18 bits from the 32 of an ulong */

#define TopBotBitsMask 0xFFFFC000
#define MiddleBitsMask 0xFFFFC000
#define BitsInUlong    32

char *readmainframes(void) {

  /* for stepping through frames */
  int Frame;
  /* temporary space for one frame from file, then extract to Bitmap* arrays */
  ulong *FileFrame;

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readmainframes(): Bitfile is NULL\n");
    abort(); }

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK readmainframes(): Model or Model->Name is NULL\n");
    abort(); }

  if (!(BitmapCenter && BitmapGclk     && BitmapClb  && BitmapIobNS &&
        BitmapIobWE  && BitmapPadIobWE && BitmapBram && BitmapDll)) {
    fprintf(stderr, "BUGCHECK readmainframes(): Bitmap* some are NULL\n");
    abort(); }

  FileFrame = (ulong *)calloc(Model->FrameWords, sizeof(ulong));
  if (!FileFrame) {
    return ("failled to allocate temporary memory for frame from file"); }


  for (Frame = 0; Frame < Model->MainFrames; Frame++) {

    /* running through frame from bitstream */
    ulong *Bits;

    /* running through target Bitmap*s */
    ulong *Middle, *TopBot;
    int StepMiddle, StepTopBot;
    ulong *FirstMiddle, *FirstTopBot;

    /* controlling when to jump Bitmap* and deinterleave in one Bitmap* */
    int FirstClbFrame, FirstIobWEFrame, FirstBramCFrame;
    int NextClbColFrame, NextIobWEColFrame, NextBramCColFrame;

    /* taking frame appart for putting into target words */
    int BitsLeft, Row;


    /* fetch an frame and get it ready to be taken apart */

    fread(FileFrame, sizeof(ulong), Model->FrameWords, Bitfile);
    for (Bits = FileFrame; Bits < FileFrame+Model->FrameWords; Bits++) {
      *Bits = ntohl(*Bits); }

    /* check if pipeline frame empty, don't store, so break the for () loop */
    if (Frame == Model->MainFrames-1) {
      for (Bits = FileFrame; Bits < FileFrame+Model->FrameWords; Bits++){
        if (*Bits != 0) {
          return ("Pipelining Frame bits not empty, not a bitstream"); } }
      break; }


    /* find target addresses (base and step) to write frame to */
    /*   this is complicated by wanting all words of an row together */
    /*     data will be placed Bitmap*[0..columns-1][0..rows-1][0..frames-1] */
    /*   is further complicated by different jump after column in row done */
    /*   and further by CLB columns not arriving ordered left to right */
    /*   and even further by stepping Center->Clb->IobWE->Bram sections */

    /* step target through groups, hardcoded stepping of Virtex/Spartan-II */
    /*   for Virtex-E/Virtex-EM/Spartan-IIE it will need different code */

    /* first do Center frames */
    if (Frame == 0) {
      /* frames have rows from top to bottom, we want then bottom to top */
      /*   for row indexing, so start at last row address and count down */
      Middle = BitmapCenter+(Model->MiddleRows-1)*VirtexCenterFrames;
      TopBot = BitmapGclk+(VirtexTopBotRows-1)*VirtexGclkFrames;
      /* jump downwards over space for frames of one row */
      StepMiddle = StepTopBot = -VirtexCenterFrames;
      /* when to step to processing CLB frames */
      FirstClbFrame = VirtexCenterFrames;
      /* zero these out because else they have random content */
      FirstIobWEFrame = 0; FirstBramCFrame = 0;
      NextClbColFrame = 0; NextIobWEColFrame = 0; NextBramCColFrame = 0; }

    /* after Center do CLB frames */
    else if (Frame == FirstClbFrame || Frame == NextClbColFrame) {
      /* physical is bitstream ordering:  cols .. 4 2 center 1 3 .. cols-1 */
      /*   so they start half way over chip (cols/2) and then zizag outwards */
      int PhysCol = (Frame-FirstClbFrame)/VirtexClbFrames+1;
      /* logical is usage ordering:  from left to right: 0 1 2 .. cols-1 */
      /*   if 1,3,.. add half (auto-losing 0.5), if 2,4,.. subtract half */
      int LogCol = (PhysCol&1) ? Model->ClbCols/2+PhysCol/2
                               : Model->ClbCols/2-PhysCol/2;
      /* note that C automagically multiplies "+xxx" with sizeof(ulong) */
      Middle = BitmapClb+LogCol*Model->MiddleRows*VirtexClbFrames+
        (Model->MiddleRows-1)*VirtexClbFrames;
      TopBot = BitmapIobNS+LogCol*VirtexTopBotRows*VirtexIobNSFrames+
        (VirtexTopBotRows-1)*VirtexIobNSFrames;
      StepMiddle = StepTopBot = -VirtexClbFrames;
      /* dont set when last column, else no fall through to FirstIobWEFrame */
      NextClbColFrame = (PhysCol<Model->ClbCols)
                        ? Frame+VirtexClbFrames : 0;
      FirstIobWEFrame = FirstClbFrame+Model->ClbCols*VirtexClbFrames; }

    /* after CLBs do IOB W/E frames */
    else if (Frame == FirstIobWEFrame || Frame == NextIobWEColFrame) {
      /* these are in bitstream 2 .. rest here .. 1 */
      int PhysCol = (Frame-FirstIobWEFrame)/VirtexIobWEFrames+1;
      int LogCol = (PhysCol&1) ? VirtexIobWECols/2+PhysCol/2
                               : VirtexIobWECols/2-PhysCol/2;
      Middle = BitmapIobWE+LogCol*Model->MiddleRows*VirtexIobWEFrames+
        (Model->MiddleRows-1)*VirtexIobWEFrames;
      TopBot = BitmapPadIobWE+LogCol*VirtexTopBotRows*VirtexPadIobWEFrames+
        (VirtexTopBotRows-1)*VirtexPadIobWEFrames;
      StepMiddle = StepTopBot = -VirtexIobWEFrames;
      NextIobWEColFrame = (PhysCol<VirtexIobWECols)
                          ? Frame+VirtexIobWEFrames : 0;
      FirstBramCFrame = FirstIobWEFrame+VirtexIobWECols*VirtexIobWEFrames; }

    /* after W/E IOBs do BRAM control frames */
    else if (Frame == FirstBramCFrame || Frame == NextBramCColFrame) {
      /* these are in bitstream .. 2 .. rest here .. 1 .. */
      int PhysCol = (Frame-FirstBramCFrame)/VirtexBramCFrames+1;
      int LogCol = (PhysCol&1) ? Model->BramCols/2+PhysCol/2
                               : Model->BramCols/2-PhysCol/2;
      Middle = BitmapBram+LogCol*Model->MiddleRows*VirtexBramFrames+
	(Model->MiddleRows-1)*VirtexBramFrames;
      TopBot = BitmapDll+LogCol*VirtexTopBotRows*VirtexDllFrames+
	(VirtexTopBotRows-1)*VirtexDllFrames;
      StepMiddle = StepTopBot = -VirtexBramFrames;
      NextBramCColFrame = (PhysCol<Model->BramCols)
                          ? Frame+VirtexBramCFrames : 0;
      /* no calculating First*Frame for pipeline, as it is last frame */ }

    /* still in same columns (any type of column) frames */
    else {
      /* first row of next frame one word further then first of last frame */
      Middle = FirstMiddle+1; TopBot = FirstTopBot+1; }

    /* remember new first row for next round of above calculation */
    FirstMiddle = Middle; FirstTopBot = TopBot;


    /* extract the config bits and transfer them to the target addresses */

    Bits = FileFrame;

    /* top 1 row, allways starts frame with bits alligned, no shifting*/
    *TopBot = *Bits&TopBotBitsMask;
    BitsLeft = BitsInUlong-VirtexTopBotBits;
    /* jump over space used for rest of words of this row, to next row */
    TopBot += StepTopBot;

    /* middle "MiddleRows" rows, may be missaligned, shift or even get next */
    for (Row = 0; Row < Model->MiddleRows; Row ++) {
      if (BitsLeft >= VirtexMiddleBits) {
        *Middle = (*Bits<<(BitsInUlong-BitsLeft))&MiddleBitsMask;
        BitsLeft = BitsLeft-VirtexMiddleBits; }
      /* fix for broken i386 "SALL" (Shift Arith Left Long) instruction */
      /* for BitsLeft == 0, "else" should shift 32, should give 0, does NOP */
      else if (BitsLeft == 0) {
        Bits++;
        *Middle = *Bits&MiddleBitsMask;
        BitsLeft = BitsInUlong-VirtexMiddleBits; }
      else {
        ulong FirstPart = *Bits<<(BitsInUlong-BitsLeft);
        Bits++;
        *Middle = FirstPart|(*Bits>>BitsLeft)&MiddleBitsMask;
        BitsLeft = BitsLeft+BitsInUlong-VirtexMiddleBits; }
      Middle += StepMiddle; }

    /* bottom 1 row, no need to update BitsLeft, as reset for next frame */
    if (BitsLeft >= VirtexTopBotBits) {
      *TopBot = *Bits<<(BitsInUlong-BitsLeft); }
    /* again apply the broken i386 "SALL" instruction fix */
    else if (BitsLeft == 0) {
      Bits++;
      *TopBot = *Bits&TopBotBitsMask; }
    else {
      ulong FirstPart = (*Bits<<(BitsInUlong-BitsLeft))&TopBotBitsMask;
      Bits++;
      *TopBot = FirstPart|(*Bits>>BitsLeft)&TopBotBitsMask; }
    /* may be superflouos, but consistent with Middle and does no damage */
    TopBot += StepTopBot;


    /* check if pipelining word empty, allways needs to be got, don't store */
    Bits++;
    if (*Bits != 0) {
      return ("Pipelining word not empty, not a bitstream"); } }


  /* this was only temporary, will be re-*alloc()ed if needed again */
  free(FileFrame);

  return (NULL); }


/* ------ set range vars of CLBs from range string section */

/* expects: Model set so that model dependant constants are known */
/* leaves: Range string parsed into [First|Last][Col|Sli|Row|Lut] */

/* [First/Last][Sli/Lut] for looping, Begin/end for in first/last Col/Row */
int FirstCol, LastCol, Col;
int FirstSli, LastSli, Sli, BeginSli, EndSli;
int FirstRow, LastRow, Row;
int FirstLut, LastLut, Lut, BeginLut, EndLut;

char *setclbrange(char *Range) {

  static char Error[1024];

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK setclbrange(): Model or Model->Name is NULL\n");
    abort(); }

  /* if no range given, dump entire chip, yes this is large or even massive */
  Col = FirstCol = 0;    LastCol = Model->ClbCols-1;
  Sli = FirstSli = SLIL; LastSli = SLIR;
          BeginSli = SLIL; EndSli = SLIR;
  Row = FirstRow = 0;    LastRow = Model->ClbRows-1;
  Lut = FirstLut = LUTF; LastLut = LUTG;
          BeginLut = LUTF; EndLut = LUTG;

  /* if no Range is given, return range set to with entire chip */
  /*   else evaluate Range and set range to that */
  if (Range == NULL) {
    return (NULL); }

  /* a full range string looks like this: 0L-mR/0F-nG */
  if (*Range != '/') {
    /* user is giving columns, else leave entire width */

    if (*Range != '-') {
      /* is giving column beginning, else leave default left */
      Col = LastCol = FirstCol = (int)strtoul(Range, &Range, 10);
      if (*Range == 'L') {
        /* "loop" only left slices, set everything SLIL */
        Sli = EndSli = LastSli = SLIL; Range++; }
      else if (*Range == 'R') {
        /* drop first columns left slice, begin on right */
        Sli = BeginSli = SLIR; Range++; } }

    if (*Range == '-') {
      Range++;
      /* is giving column end, else just leave one column */
      if (*Range == 0 || *Range == '/') {
        /* has given beginning and '-' but no end: set back to right */
        LastCol = Model->ClbCols-1; LastSli = SLIR; }

      else {
        /* is giving column end, else just wants one column, multi row */
        LastCol = (int)strtoul(Range, &Range, 10);
        if (*Range == 'L') {
          /* drop last columns right slice, end on left */
          EndSli = SLIL; Range++; }
        else if (*Range == 'R') {
          /* "loop" only right slices, set everything SLIR */
          Sli = BeginSli = FirstSli = SLIR; Range++; } } } }

  if (*Range == '/') {
    Range++;
    /* user is giving rows, else leave entire hight */

    if (*Range != '-') {
      /* is giving row beginning, else leave bottom */
      Row = LastRow = FirstRow = (int)strtoul(Range, &Range, 10);
      if (*Range == 'F') {
        /* "loop" only F LUTs, set everything LUTF */
        Lut = EndLut = LastLut = LUTF; Range++; }
      else if (*Range == 'G') {
        /* drop first rows F LUT, begin on G */
        Lut = BeginLut = LUTG; Range++; } }

    if (*Range == '-') {
      Range++;
      /* is giving row end, else just leave one row */
      if (*Range == 0) {
        /* has given beginning and '-' but no end: set back to top */
        LastRow = Model->ClbRows-1; LastLut = LUTG; }

      else {
        /* is giving row end, else just wants one row, multi column */
        LastRow = (int)strtoul(Range, &Range, 10);
        if (*Range == 'F') {
          /* drop last rows F LUT, end on G */
          EndLut = LUTF; Range++; }
        else if (*Range == 'G') {
          /* "loop" only G LUTs, set everything LUTG */
          Lut = BeginLut = FirstLut = LUTG; Range++; } } } }

  if (*Range != 0) {
    snprintf(Error, sizeof(Error), "unknown char in range at: %s\n\n", Range);
    return (Error); }

  /* test if we are still on the chip */
  if (FirstCol < 0 || FirstCol > Model->ClbCols-1) {
    snprintf(Error, sizeof(Error), "first column out of range %i-%i: %i\n",
      0, Model->ClbCols-1, FirstCol);
    return (Error); }
  if (LastCol < 0 || LastCol > Model->ClbCols-1) {
    snprintf(Error, sizeof(Error), "last column out of range %i-%i: %i\n",
      0, Model->ClbCols-1, LastCol);
    return (Error); }
  if (FirstRow < 0 || FirstRow > Model->ClbRows-1) {
    snprintf(Error, sizeof(Error), "first row out of range %i-%i: %i\n",
      0, Model->ClbRows-1, FirstRow);
    return (Error); }
  if (LastRow < 0 || LastRow > Model->ClbRows-1) {
    snprintf(Error, sizeof(Error), "last row out of range %i-%i: %i\n",
      0, Model->ClbRows-1, LastRow);
    return (Error); }

  return (NULL); }


/* ------ access functions */

/* expect: Model set so that model dependant constants are known */
/*   and also bitstream main frames data read in, BitmapClb pointing to them */
/* leave: same state, but return one or multiple CLB config bits */

/* Xilinx thinks big endian, so we use the first/top/big/MSB 18 bits */
/*   masks for extracting top and bottom bits from the 32 of an ulong */

#define TopBitMask  0x80000000
#define BotBitMask  0x00004000

/* no parameter variables to reduce user code size, instead imply position */
/* Col and Row are global vars, defined in range string section */
/* Bit and Frame are global vars, def in chip architecture constants section */

uint getclb(void) {

  ulong *Clb;
  ulong BitMask = TopBitMask>>Bit;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK getclb(): Model or Model->Name is NULL, no read-in?\n");
    abort(); }

  if (!BitmapClb) {
    fprintf(stderr, "BUGCHECK getclb(): BitmapClb is NULL, no read-in?\n");
    abort(); }

  Clb = BitmapClb+(Col*Model->MiddleRows+Row)*VirtexClbFrames;

  return ((Clb[Frame] & BitMask) ? 1 : 0); }


/* CLB layout of the documented LUT and FF bits */
/* derived from the formulas in XAPP151, pages 11 + 12 */

/* . = unknown, 0..9A..F = LUT bits (inverted), XY = FF bits (true sense) */
/*    Slice 1/L                              Slice 0/R        */
/*                                                            */
/*    0         1         2         3         4        frame  */
/*    012345678901234567890123456789012345678901234567 addr   */
/*   .------------------------------------------------        */
/*  0|................................................        */
/*  1|..X.....Y..............................Y.....X.. FFs    */
/*  2|FEDCBA9876543210................0123456789ABCDEF G LUTs */
/*  3|FEDCBA9876543210................0123456789ABCDEF F LUTs */
/*  4|................................................        */
/*  5|................................................        */
/*  6|................................................        */
/*  7|................................................        */
/*  8|................................................        */
/*  9|................................................        */
/* 10|................................................        */
/* 11|................................................        */
/* 12|................................................        */
/* 13|................................................        */
/* 14|................................................        */
/* 15|................................................        */
/* 16|................................................        */
/* 17|................................................        */
/* bit addr                                                   */

#define LutGBit    2
#define LutFBit    3
#define LutLFFrame 0
#define LutL0Frame 15
#define LutR0Frame 32
#define LutRFFrame 47

/* no parameter variables to reduce user code size, instead imply position */
/* Col, Sli, Row and Lut are global vars, defined in range string section */

uint getlut(void) {

  uint LutVal = 0;

  Bit = (Lut == LUTG) ? LutGBit: LutFBit;
  /* needs an if, because test <= or >= not parameterable */
  if (Sli == SLIR) {
    /* loop F bit to 0 bit, because << will make first bit go off to left */
    for (Frame = LutRFFrame; Frame >= LutR0Frame; Frame--) {
      LutVal = LutVal<<1 | getclb(); } }
  else {
    for (Frame = LutLFFrame; Frame <= LutL0Frame; Frame++) {
      LutVal = LutVal<<1 | getclb(); } }

  /* un-invert the LUT bits, as they are inverted in the bitstream */
  return (LutVal^0xFFFF); }

#define FfBit     1
#define FfLXFrame 2
#define FfLYFrame 8
#define FfRXFrame 39
#define FfRYFrame 45

uint getff(void) {

  int FfLFrame = (Lut == LUTG) ? FfLYFrame : FfLXFrame;
  int FfRFrame = (Lut == LUTG) ? FfRYFrame : FfRXFrame;

  Bit = FfBit;
  Frame = (Sli == SLIR) ? FfRFrame : FfLFrame;
  return (getclb()); }


/* ------ auxillary code for LUT comment writting section */

/* allow putting text bit patterns into LUTs */
/*   for layout display in BoardScope or VirtexView */
/*   uses LUT 16 bits displayed 0123/4567/89AB/CDEF as 4x4 pixel font */

uint LutFont[] = {
  /* 4x4 pixel bit patterns, 0xabcd d=top a=bottom row, 1=left 8=right col */
  /* all 32 control characters, as full boxes */
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  /* space !      "       #       $       %       &       ' */
  0x0000, 0x6066, 0x00AA, 0x6FF6, 0x7E5E, 0x9249, 0xE526, 0x0024,
  /* (    )       *       +       ,       -       .       / */
  0x4224, 0x2442, 0x4EE4, 0x04E4, 0x2400, 0x0F00, 0x4000, 0x1248,
  /* 0    1       2       3       4       5       6       7 */
  0x6996, 0xE464, 0xF687, 0x786F, 0x4F51, 0x787F, 0x6972, 0x248F,
  /* 8    9       :       ;       <       =       >       ? */
  0x69F6, 0x4E96, 0x0404, 0x2404, 0x2124, 0xF0F0, 0x2484, 0x4496,
  /* @    A       B       C       D       E       F       G */
  0x6FFE, 0x9F96, 0x79F7, 0xE11E, 0x7997, 0xF17F, 0x171F, 0xE91E,
  /* H    I       J       K       L       M       N       O */
  0x99F9, 0xE44E, 0x344E, 0x9759, 0xF111, 0x9BF9, 0x9DB9, 0x6996,
  /* P    Q       R       S       T       U       V       W */
  0x1797, 0x6D96, 0x9797, 0x7C3E, 0x222F, 0x6999, 0x2699, 0x6BB9,
  /* X    Y       Z       [       \       ]       ^       _ */
  0x9669, 0x1269, 0xF24F, 0x6226, 0x8421, 0x6446, 0x00A4, 0xF000,
  /* `    a       b       c       d       e       f       g */
  0x0042, 0xA560, 0x7971, 0x6160, 0x7971, 0x6F60, 0x272C, 0x6E9E,
  /* h    i       j       k       l       m       n       o */
  0x9971, 0x4604, 0x6404, 0x9791, 0xE446, 0xBB50, 0x9970, 0x6960,
  /* p    q       r       s       t       u       v       w */
  0x1797, 0x8E9E, 0x2A60, 0x7FE0, 0xC272, 0xE990, 0x2690, 0x6BB0,
  /* x    y       z       {       |       }       ~       DEL (full box) */
  0x9690, 0x2469, 0xF6F0, 0x6236, 0x4444, 0x64C6, 0x005A, 0xFFFF };

