/* 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 2003.09.17 */


/* ------ 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 */

/* ushort, ulong */
#include <sys/types.h>
/* malloc(), calloc(), free(), abort() */
#include <stdlib.h>
/* fopen(), fclose(), fread(), fprintf(), printf(), stdin, stdour, stderr */
#include <stdio.h>
/* ntohs(), ntohl() */
#include <netinet/in.h>
/* strerror() */
#include <string.h>
/* errno */
#include <errno.h>

/* our own functions and definitions */
#include "virtex.h"


/* ------ 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: Bitfile open */
/* leaves: read in to various global variables */

/* this needs to be global, as all read*() functions use it for fread() */
FILE *Bitfile;

char *readbitfile(FILE *BitfilePtr, int Verbose) {

  char *serror;

  Bitfile = BitfilePtr;

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

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

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

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

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

  if (Verbose) {
    fprintf(stderr, "reading BRAM data frames\n"); }
  serror = readbramdframes();
  if (serror) {
    return (serror); }

  if (Verbose) {
    fprintf(stderr, "reading bitstream tail\n"); }
  serror = readstreamtail();
  if (serror) {
    return (serror); }

  /* set range to work to something safe, in case the user forgets to do so */
  /*   use as default the entire chip, this may be lots of data */
  setlutrange("-/-");

  if (Verbose) {
    fprintf(stderr, "finished reading from bitfile\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 2.8 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");
    fprintf(stderr, "         forgot to open file before calling?\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??, example XV300 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???????, example XV300 0x5000cb07 */


char *readstreamheader(void) {

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readstreamheader(): Bitfile is NULL\n");
    fprintf(stderr, "         forgot to open file before calling?\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 */

/* 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");
    fprintf(stderr,
      "         forgot to read in bitstream header before calling?\n");
    abort(); }

  /* extract length from type 2 packet header, see XAPP138, page 21+22 */
  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 frames 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 tile */
/*   (center/GCLK/CLB/IOB N/S/IOB W/E/corner/BRAM/DLL) */
/*   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,  *BitmapCorner;
ulong *BitmapBramC,  *BitmapDll;
ulong *BitmapBramD,  *BitmapBramDPad;


char *allocframes(void) {

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK allocframes(): Model or Model->Name is NULL\n");
    fprintf(stderr,
      "         forgot to set model before calling?\n");
    abort(); }

  if (BitmapCenter || BitmapGclk     || BitmapClb   || BitmapIobNS ||
      BitmapIobWE  || BitmapCorner   || BitmapBramC || BitmapDll   ||
      BitmapBramD  || BitmapBramDPad ) {
    fprintf(stderr, "BUGCHECK allocframes(): Bitmap* are not all NULL\n");
    fprintf(stderr, "         trying to allocate frame memory twice?\n");
    abort(); }

  /* center officially should be empty, but seems to have content */
  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"); }

  /* corners officially should be empty, but seem to have content */
  BitmapCorner = (ulong *)calloc(VirtexCornerCols*
                                 VirtexTopBotRows*
                                 VirtexCornerFrames, sizeof(ulong));
  if (!BitmapCorner) {
    return ("failled to allocate memory for corner bits"); }


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

  BitmapBramC = (ulong *)calloc(Model->BramCols*
                                Model->MiddleRows*
                                VirtexBramCFrames, sizeof(ulong));
  if (!BitmapBramC) {
    return ("failled to allocate memory for BRAM control bits"); }

  BitmapDll = (ulong *)calloc(Model->DllCols*
                              VirtexTopBotRows*
                              VirtexDllFrames, sizeof(ulong));
  if (!BitmapDll) {
    return ("failled to allocate memory for DLL bits"); }


  BitmapBramD = (ulong *)calloc(Model->BramCols*
                                Model->MiddleRows*
                                VirtexBramDFrames, sizeof(ulong));
  if (!BitmapBramD) {
    return ("failled to allocate memory for BRAM data bits"); }

  BitmapBramDPad = (ulong *)calloc(Model->BramCols*
                                   Model->MiddleRows*
                                   VirtexBramDPadFrames, sizeof(ulong));
  if (!BitmapBramDPad) {
    return ("failled to allocate memory for BRAM data pad bits"); }


  return (NULL); }


/* ------ read bitstream main frames 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!!! */

char *readmainframes(void) {

  /* bitstream columns are not numbered same as logical columns */
  int BitstreamCol, Frame;

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readmainframes(): Bitfile is NULL\n");
    fprintf(stderr, "         forgot to open file before calling?\n");
    abort(); }

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK readmainframes(): Model or Model->Name is NULL\n");
    fprintf(stderr,
      "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapCenter || !BitmapGclk   || !BitmapClb   || !BitmapIobNS ||
      !BitmapIobWE  || !BitmapCorner || !BitmapBramC || !BitmapDll   ) {
    fprintf(stderr, "BUGCHECK readmainframes(): Bitmap* are not all set\n");
    fprintf(stderr, "         forgot to allocate frame memory before call?\n");
    abort(); }


  /* 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 columns not arriving ordered left to right */

  /* 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 */
  /*   column step downwards over space for frames of one row */

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


  /* first in the bitstream are the GCLK + center frames */
  /*   only one of these, but in "for" so that variable also local */
  for (BitstreamCol = 1; BitstreamCol <= 1; BitstreamCol++) {
    ulong *Top     = BitmapGclk  +(VirtexTopBotRows-1) *VirtexGclkFrames;
    ulong *Middle  = BitmapCenter+(Model->MiddleRows-1)*VirtexCenterFrames;
    int StepMiddle = -VirtexCenterFrames;
    ulong *Bottom  = BitmapGclk;
    for (Frame = 0; Frame < VirtexCenterFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      /* first row of next frame one word further then first of last frame */
      Top++; Middle++; Bottom++; } }

  /* after GCLK + center come IOB N/S + CLB frames */
  for (BitstreamCol = 1; BitstreamCol <= Model->ClbCols; BitstreamCol++) {
    /* bitstream ordering: cols .. 4 2 center 1 3 .. cols-1 */
    /*   so they start half way over chip (cols/2) and then zizag outwards */
    /* logical (= 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 Col        = (BitstreamCol&1) ? Model->ClbCols/2+BitstreamCol/2
                                      : Model->ClbCols/2-BitstreamCol/2;
    /* note that C automagically multiplies "+xxx" with sizeof(ulong) */
    ulong *Top     = BitmapIobNS+Col*VirtexTopBotRows *VirtexIobNSFrames+
                     (VirtexTopBotRows-1) *VirtexIobNSFrames;
    ulong *Middle  = BitmapClb  +Col*Model->MiddleRows*VirtexClbFrames+
                     (Model->MiddleRows-1)*VirtexClbFrames;
    int StepMiddle = -VirtexClbFrames;
    ulong *Bottom  = BitmapIobNS+Col*VirtexTopBotRows *VirtexIobNSFrames;
    for (Frame = 0; Frame < VirtexClbFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      Top++; Middle++; Bottom++; } }

  /* after IOB N/S + CLBs come corner + IOB W/E frames */
  for (BitstreamCol = 1; BitstreamCol <= VirtexIobWECols; BitstreamCol++) {
    /* these are in bitstream 2 .. rest here .. 1 */
    int Col        = (BitstreamCol&1) ? VirtexIobWECols/2+BitstreamCol/2
                                      : VirtexIobWECols/2-BitstreamCol/2;
    ulong *Top     = BitmapCorner+Col*VirtexTopBotRows *VirtexIobWEFrames+
                     (VirtexTopBotRows-1) *VirtexIobWEFrames;
    ulong *Middle  = BitmapIobWE +Col*Model->MiddleRows*VirtexIobWEFrames+
                     (Model->MiddleRows-1)*VirtexIobWEFrames;
    int StepMiddle = -VirtexIobWEFrames;
    ulong *Bottom  = BitmapCorner+Col*VirtexTopBotRows *VirtexIobWEFrames;
    for (Frame = 0; Frame < VirtexIobWEFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      Top++; Middle++; Bottom++; } }

  /* after corner + W/E IOBs come DLL + BRAM control frames */
  /*   BRAM data frames come later, separate blocks, not in main frame block */
  for (BitstreamCol = 1; BitstreamCol <= Model->BramCols; BitstreamCol++) {
    /* these are in bitstream .. 2 .. rest here .. 1 .. */
    int Col        = (BitstreamCol&1) ? Model->BramCols/2+BitstreamCol/2
                                      : Model->BramCols/2-BitstreamCol/2;
    ulong *Top     = BitmapDll +Col*VirtexTopBotRows *VirtexDllFrames+
                     (VirtexTopBotRows-1) *VirtexDllFrames;
    ulong *Middle  = BitmapBramC+Col*Model->MiddleRows*VirtexBramCFrames+
                     (Model->MiddleRows-1)*VirtexBramCFrames;
    int StepMiddle = -VirtexBramCFrames;
    ulong *Bottom  = BitmapDll +Col*VirtexTopBotRows *VirtexDllFrames;
    for (Frame = 0; Frame < VirtexBramCFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      Top++; Middle++; Bottom++; } }


  /* at the end of this frame block comes its pipelining frame */
  for (BitstreamCol = 1; BitstreamCol <= 1; BitstreamCol++) {
    for (Frame = 0; Frame < 1; Frame++) {
      char *serror = readpipeframe();
      if (serror) {
        return (serror); } } }

  return (NULL); }


/* ------ read bitstream single frame section */

/* expects: bitstream header read, file pointer ready to read frames */
/*   and also Model set so that model dependant constants are known */
/*   and Middle/TopBot pointing to space for this next frame */
/* leaves: single frame in Middle/TopBot, file pointer ready for next */

/* 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 TopBitsMask    0xFFFFC000
#define MiddleBitsMask 0xFFFFC000
#define BitsInUlong    32

char *readframe(ulong *Top, ulong *Middle, int StepMiddle, ulong *Bottom) {

  ulong *Frame, *FrameWord;
  int BitsLeft, Row;


  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readframe(): Bitfile is NULL\n");
    fprintf(stderr, "         forgot to open file before calling?\n");
    abort(); }

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK readframe(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }


  Frame = (ulong *)malloc(Model->FrameWords*sizeof(ulong));
  if (!Frame) {
    return ("failled to allocate memory for processing an frame"); }


  /* fetch an frame and get it ready to be taken apart */
  fread(Frame, sizeof(ulong), Model->FrameWords, Bitfile);

  for (FrameWord = Frame; FrameWord < Frame+Model->FrameWords; FrameWord++) {
    *FrameWord = ntohl(*FrameWord); }


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

  FrameWord = Frame;


  /* top 1 row, always starts frame with bits alligned, no shifting */
  *Top = *FrameWord&TopBitsMask;
  BitsLeft = BitsInUlong-VirtexTopBotBits;

  /* middle "MiddleRows" rows, may be missaligned, so shift */
  /*                           or even not enough bits left, get next word */
  for (Row = 0; Row < Model->MiddleRows; Row ++) {
    if (BitsLeft >= VirtexMiddleBits) {
      *Middle = (*FrameWord<<(BitsInUlong-BitsLeft))&MiddleBitsMask;
      BitsLeft = BitsLeft-VirtexMiddleBits; }
    /* fix for the broken i386 "SALL" (Shift Arith Left Long) instruction */
    /*   for BitsLeft == 0 it would shift 32, should give 0, but does NOP */
    /*   yes C language definition is also broken, allowing this uncorrected */
    else if (BitsLeft == 0) {
      FrameWord++;
      *Middle = *FrameWord&MiddleBitsMask;
      BitsLeft = BitsInUlong-VirtexMiddleBits; }
    else {
      ulong FirstPart = *FrameWord<<(BitsInUlong-BitsLeft);
      FrameWord++;
      *Middle = FirstPart|(*FrameWord>>BitsLeft)&MiddleBitsMask;
      BitsLeft = BitsLeft+BitsInUlong-VirtexMiddleBits; }
    Middle += StepMiddle; }

  /* bottom 1 row, same as middle, only once, remaining bits = 0, no mask */
  if (BitsLeft >= VirtexTopBotBits) {
    *Bottom = *FrameWord<<(BitsInUlong-BitsLeft);
    BitsLeft = BitsLeft-VirtexMiddleBits; }
  /* again apply the broken i386 "SALL" instruction fix */
  else if (BitsLeft == 0) {
    FrameWord++;
    *Bottom = *FrameWord;
    BitsLeft = BitsInUlong-VirtexMiddleBits; }
  else {
    ulong FirstPart = *FrameWord<<(BitsInUlong-BitsLeft);
    FrameWord++;
    *Bottom = FirstPart|(*FrameWord>>BitsLeft);
    BitsLeft = BitsLeft+BitsInUlong-VirtexMiddleBits; }


  /* check if rest of last frame word empty, allways enough, don't store */
  if (BitsLeft >= 0) {
    if ((*FrameWord<<(BitsInUlong-BitsLeft)) != 0) {
      return ("Rest of last config word not empty, not a bitstream"); } }


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


  free(Frame);

  return (NULL); }


/* ------ read bitstream pipelining frame section */

/* expects: bitstream header read, file pointer ready to read an pipe frame */
/*   and also Model set so that model dependant constants are known */
/* leaves: file pointer advanced to after pipelining frame */

char *readpipeframe(void) {

  /* frame is empty, no need to store, so we use only temporary storage */
  ulong PipeTop, *PipeMiddle, PipeBottom, Pipe;

  int Row; char *serror;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK readpipeframe(): Model or Model->Name is NULL\n");
    fprintf(stderr,
      "         forgot to set model before calling?\n");
    abort(); }

  PipeMiddle = (ulong *)calloc(Model->MiddleRows, sizeof(ulong));
  if (!PipeMiddle) {
    return ("failled to allocate memory for pipelining frame middle bits"); }

  serror = readframe(&PipeTop, PipeMiddle, 1, &PipeBottom);
  if (serror) {
    return (serror); }

  /* check if pipelining frame was empty, good to detect if we lost sync */
  /*   without check we would have done readframe(&Pipe, &Pipe, 0, &Pipe); */
  Pipe =  PipeTop;
  for (Row = 0; Row < Model->MiddleRows; Row++) {
    Pipe |= *(PipeMiddle+Row); }
  Pipe |= PipeBottom;
  if (Pipe) {
    return ("Pipelining frame not empty, not a bitstream"); }

  free(PipeMiddle);

  return (NULL); }


/* ------ read bitstream BRAM data frames section */

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

/* now come the BRAM data frames, in separate frame blocks, one per column */
/*   not in together with the BRAM control frames, together with all others */
/*   why these frames are separate from all others is a open question */
/* and the last (pipeline) frame of the last block is even totally separate */
/*   it comes after the CRC check has been set up, for some odd reason */

/* step target through groups, hardcoded stepping for Virtex/Spartan-II */
/*   only 2 columns supported, right out at edges */
/*   for Virtex-E/Virtex-EM/Spartan-IIE we will need different code */

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

ulong StreamFaddrB1Reg;  /* 0x30002001, frame address */
ulong StreamFaddrB1;     /* 0x02000000, from BRAM 1 data on */

ulong StreamFdatinB1Reg; /* 0x30004???, BRAM 1 frame data input */
                                     /* example XV300 0x30004555 */

/* here come BRAM data 1 frames */

ulong StreamFaddrB2Reg;  /* 0x30002001, frame address */
ulong StreamFaddrB2;     /* 0x02020000, from BRAM 2 data on */

ulong StreamFdatinB2Reg; /* 0x30004???, BRAM 2 frame data input */
                                     /* example XV300 0x30004540 */

/* here come BRAM data 2 frames, without pipeline frame, so last not written */

ulong StreamCrcReg;      /* 0x30000001, CRC register */
ulong StreamCrc;         /* 0x????????, different in every bitstream */

ulong StreamLfrmCmd;     /* 0x30008001, command register */
ulong StreamLfrm;        /* 0x00000003, last frame coming now */

ulong StreamFdatinFiReg; /* 0x30004???, final frame data input */
                                     /* example XV300 0x30004015 */

/* here comes BRAM data 2 last frame (pipelining) so last gets written */


char *readbramdframes(void) {

  /* here we only use logical columns, no BitstreamCol */
  int Col, Frame;

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readbramdframes(): Bitfile is NULL\n");
    fprintf(stderr, "         forgot to open file before calling?\n");
    abort(); }

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr,
      "BUGCHECK readbramdframes(): Model or Model->Name is NULL\n");
    fprintf(stderr,
      "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapBramD || !BitmapBramDPad ) {
    fprintf(stderr, "BUGCHECK readbramdframes(): Bitmap* are not all set\n");
    fprintf(stderr, "         forgot to allocate frame memory before call?\n");
    abort(); }


  fread(&StreamFaddrB1Reg, sizeof(ulong), 1, Bitfile);
  StreamFaddrB1Reg = ntohl(StreamFaddrB1Reg);
  fread(&StreamFaddrB1, sizeof(ulong), 1, Bitfile);
  StreamFaddrB1 = ntohl(StreamFaddrB1);
  if (StreamFaddrB1Reg != 0x30002001 || StreamFaddrB1 != 0x02000000) {
    return ("expected stream frame addr 02000000, not a standard bitstream"); }

  fread(&StreamFdatinB1Reg, sizeof(ulong), 1, Bitfile);
  StreamFdatinB1Reg = ntohl(StreamFdatinB1Reg);
  if (StreamFdatinB1Reg <= 0x30004000) {
    return ("expected stream data input >0, not a standard bitstream"); }


  /* first comes left column BRAM data, according to XAPP151, page 4 */
  for (Col = 0; Col < 1; Col++) {
    ulong *Top     = BitmapBramDPad+Col*VirtexTopBotRows *VirtexBramDPadFrames+
                     (VirtexTopBotRows-1) *VirtexBramDPadFrames;
    ulong *Middle  = BitmapBramD   +Col*Model->MiddleRows*VirtexBramDFrames+
                     (Model->MiddleRows-1)*VirtexBramDFrames;
    int StepMiddle = -VirtexBramDFrames;
    ulong *Bottom  = BitmapBramDPad+Col*VirtexTopBotRows *VirtexBramDPadFrames;
    for (Frame = 0; Frame < VirtexBramDFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      if (*Top|*Bottom) {
        return ("BRAM data padding not empty, not a bitstream"); }
      Top++; Middle++; Bottom++; }

    /* at the end of this frame block comes its pipelining frame */
    for (Frame = 0; Frame < 1; Frame++) {
      char *serror = readpipeframe();
      if (serror) {
        return (serror); } } }


  fread(&StreamFaddrB2Reg, sizeof(ulong), 1, Bitfile);
  StreamFaddrB2Reg = ntohl(StreamFaddrB2Reg);
  fread(&StreamFaddrB2, sizeof(ulong), 1, Bitfile);
  StreamFaddrB2 = ntohl(StreamFaddrB2);
  if (StreamFaddrB2Reg != 0x30002001 || StreamFaddrB2 != 0x02020000) {
    return ("expected stream frame addr 02020000, not a standard bitstream"); }

  fread(&StreamFdatinB2Reg, sizeof(ulong), 1, Bitfile);
  StreamFdatinB2Reg = ntohl(StreamFdatinB2Reg);
  if (StreamFdatinB2Reg <= 0x30004000) {
    return ("expected stream data input >0, not a standard bitstream"); }


  /* then comes right column BRAM data, according to XAPP151, page 4 */
  for (Col = 1; Col < 2; Col++) {
    ulong *Top     = BitmapBramDPad+Col*VirtexTopBotRows *VirtexBramDPadFrames+
                     (VirtexTopBotRows-1) *VirtexBramDPadFrames;
    ulong *Middle  = BitmapBramD+Col*Model->MiddleRows*VirtexBramDFrames+
                     (Model->MiddleRows-1)*VirtexBramDFrames;
    int StepMiddle = -VirtexBramDFrames;
    ulong *Bottom  = BitmapBramDPad+Col*VirtexTopBotRows *VirtexBramDPadFrames;
    for (Frame = 0; Frame < VirtexBramDFrames; Frame++) {
      char *serror = readframe(Top, Middle, StepMiddle, Bottom);
      if (serror) {
        return (serror); }
      if (*Top|*Bottom) {
        return ("BRAM data padding not empty, not a bitstream"); }
      Top++; Middle++; Bottom++; } }

    /* no pipeline frame get/check here, comes later, after CRC stuff */


  fread(&StreamCrcReg, sizeof(ulong), 1, Bitfile);
  StreamCrcReg = ntohl(StreamCrcReg);
  fread(&StreamCrc, sizeof(ulong), 1, Bitfile);
  StreamCrc = ntohl(StreamCrc);
  /* XAPP138 "The Standard Bitstream", page 22, documents here check CRC */
  /*   but the null300.bit file from JBits 2.8 does reset CRC instead, huh? */
  /*   so allow both variants to cover as much as possible */
  if ((StreamCrcReg != 0x30000001) &&
      (StreamCrcReg != 0x30008001 || StreamCrc != 0x00000007)) {
    return ("expected stream CRC or reset CRC, not a standard bitstream"); }

  fread(&StreamLfrmCmd, sizeof(ulong), 1, Bitfile);
  StreamLfrmCmd = ntohl(StreamLfrmCmd);
  fread(&StreamLfrm, sizeof(ulong), 1, Bitfile);
  StreamLfrm = ntohl(StreamLfrm);
  if (StreamLfrmCmd != 0x30008001 || StreamLfrm != 0x00000003) {
    return ("expected stream last frame command, not a standard bitstream"); }


  fread(&StreamFdatinFiReg, sizeof(ulong), 1, Bitfile);
  StreamFdatinFiReg = ntohl(StreamFdatinFiReg);
  if (StreamFdatinFiReg <= 0x30004000) {
    return ("expected stream data input >0, not a standard bitstream"); }


  /* and now comes the final pipelining frame get/check */
  for (Col = 1; Col < 2; Col++) {
    for (Frame = 0; Frame < 1; Frame++) {
      char *serror = readpipeframe();
      if (serror) {
        return (serror); } } }


  return (NULL); }


/* ------ read bitstream tail section */

/* expects: bitstream header and all frames read */
/*   file pointer ready to read stream tail */
/*   and also Model set so that model dependant constants are known */
/* leaves: bitstream entirely read, ready to close file */

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

ulong StreamStartCmd;    /* 0x30008001, command register */
ulong StreamStart;       /* 0x00000005, start up the fpga */

ulong StreamComdCtl;     /* 0x3000A001, control register */
ulong StreamComd;        /* 0x00000000, control something, seemingly null */
                                     /* documented 0x00000000, is 0x00000040 */

ulong StreamCrcFiReg;    /* 0x30000001, final frame CRC register */
ulong StreamCrcFi;       /* 0x????????, different in every bitstream */

ulong StreamDummy1;      /* 0x00000000, give time for internal startup */
ulong StreamDummy2;      /* 0x00000000, give time for internal startup */
ulong StreamDummy3;      /* 0x00000000, give time for internal startup */
ulong StreamDummy4;      /* 0x00000000, give time for internal startup */


char *readstreamtail(void) {

  if (!Bitfile) {
    fprintf(stderr, "BUGCHECK readstreamtail(): Bitfile is NULL\n");
    fprintf(stderr, "         forgot to open file before calling?\n");
    abort(); }

  fread(&StreamStartCmd, sizeof(ulong), 1, Bitfile);
  StreamStartCmd = ntohl(StreamStartCmd);
  fread(&StreamStart, sizeof(ulong), 1, Bitfile);
  StreamStart = ntohl(StreamStart);
  if (StreamStartCmd != 0x30008001 || StreamStart != 0x00000005) {
    return ("expected stream start command, not a standard bitstream"); }

  fread(&StreamComdCtl, sizeof(ulong), 1, Bitfile);
  StreamComdCtl = ntohl(StreamComdCtl);
  fread(&StreamComd, sizeof(ulong), 1, Bitfile);
  StreamComd = ntohl(StreamComd);
  if (StreamComdCtl != 0x3000A001) {
    return ("expected stream control command, not a standard bitstream"); }

  fread(&StreamCrcFiReg, sizeof(ulong), 1, Bitfile);
  StreamCrcFiReg = ntohl(StreamCrcFiReg);
  fread(&StreamCrcFi, sizeof(ulong), 1, Bitfile);
  StreamCrcFi = ntohl(StreamCrcFi);
  /* same "check CRC or reset CRC" game as above in readbramdframes() */
  if ((StreamCrcReg != 0x30000001) &&
      (StreamCrcReg != 0x30008001 || StreamCrc != 0x00000007)) {
    return ("expected stream CRC or reset CRC, not a standard bitstream"); }


  fread(&StreamDummy1, sizeof(ulong), 1, Bitfile);
  StreamDummy1 = ntohl(StreamDummy1);
  fread(&StreamDummy2, sizeof(ulong), 1, Bitfile);
  StreamDummy2 = ntohl(StreamDummy2);
  fread(&StreamDummy3, sizeof(ulong), 1, Bitfile);
  StreamDummy3 = ntohl(StreamDummy3);
  fread(&StreamDummy4, sizeof(ulong), 1, Bitfile);
  StreamDummy4 = ntohl(StreamDummy4);
  if (StreamDummy1 != 0x00000000 || StreamDummy2 != 0x00000000 ||
      StreamDummy3 != 0x00000000 || StreamDummy4 != 0x00000000) {
    return ("expected stream dummy words, not a standard bitstream"); }


  return (NULL); }


/* ------ set range vars 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] */


/* declare various usefull range variables */
/*   [First|Last]* are for the loop ranges */
/*   [Begin|End]* are for pruning in first/last slice/LUT */
int  FirstCol, LastCol;
char FirstSli, LastSli, BeginSli, EndSli;
int  FirstRow, LastRow;
char FirstLut, LastLut, BeginLut, EndLut;


/* constants for selecting slices and LUTs */

#define SLIL 'L'
#define SLIR 'R'

#define LUTF 'F'
#define LUTG 'G'


char *setlutrange(char *Range) {

  static char Error[1024];

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK setlutrange(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (Range == NULL) {
    fprintf(stderr, "BUGCHECK setlutrange(): Range is NULL\n");
    fprintf(stderr, "         forgot to initialise an range string?\n");
    abort(); }

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

  /* 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 */
      LastCol = FirstCol = (int)strtoul(Range, &Range, 10);
      if (*Range == 'L') {
        /* "loop" only left slices, set everything SLIL */
        EndSli = LastSli = SLIL; Range++; }
      else if (*Range == 'R') {
        /* drop first columns left slice, begin on right */
        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 */
          BeginSli = FirstSli = SLIR; Range++; } } } }

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

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

  /* set to something safe, in case user fails to do so */
  firstsli(); firstlut();

  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); }


/* ------ current LUT position setting, looping and output functions section */

/* declare various usefull position / loop index variables */
int  Col, Row;
char Sli, Lut;


/* setting and looping and testing Sli (and Col) position (= horizontal) */
/* [first|last]*() set up, [next|prev]*() move, isin*s() tests */

void firstsli(void) {
  Col = FirstCol; Sli = FirstSli;
  /* chop off possible first slice in first column */
  if (BeginSli == SLIR) {
    Sli = BeginSli; } }

void lastsli(void) {
  Col = LastCol; Sli = LastSli;
  /* chop off possible last slice in last column */
  if (EndSli == SLIL) {
    Sli = EndSli; } }

void nextsli(void) {
  if (Sli == LastSli) {
    Sli = FirstSli; Col++; }
  else {
    Sli = LastSli; } }

void prevsli(void) {
  if (Sli == FirstSli) {
    Sli = LastSli; Col--; }
  else {
    Sli = FirstSli; } }

int isinslis(void) {
  return ((Col == FirstCol && Sli >= BeginSli) ||
          (Col >  FirstCol && Col <  LastCol)  ||
          (Col == LastCol  && Sli <= EndSli)   ); }


/* setting and looping and testing Lut (and Row) position (= vertical) */

void firstlut(void) {
  Row = FirstRow; Lut = FirstLut;
  /* chop off possible first LUT in first row */
  if (BeginLut == LUTG) {
    Lut = BeginLut; } }

void lastlut(void) {
  Row = LastRow; Lut = LastLut;
  /* chop off possible last LUT in last row */
  if (EndLut == LUTF) {
    Lut = EndLut; } }

void nextlut(void) {
  if (Lut == LastLut) {
    Lut = FirstLut; Row++; }
  else {
    Lut = LastLut; } }

void prevlut(void) {
  if (Lut == FirstLut) {
    Lut = LastLut; Row--; }
  else {
    Lut = FirstLut; } }

int isinluts(void) {
  return ((Row == FirstRow && Lut >= BeginLut) ||
          (Row >  FirstRow && Row <  LastRow)  ||
          (Row == LastRow  && Lut <= EndLut)   ); }


/* read out current Col+Sli/Row+Lut position, with Sli/Lut conv to chars */

lutpos Lutpos;

lutpos *getlutpos(void) {

  Lutpos.Col = Col; Lutpos.Sli = Sli;
  Lutpos.Row = Row; Lutpos.Lut = Lut;

  return (&Lutpos); }


/* ------ bitstream frame data access functions section */

/* expect: Model set so that model dependant constants are known */
/*   and also bitstream main frames data read in, BitmapClb pointing to them */
/*   current LUT/CLB position the user is working on stored in Col and Row */
/*     getcenterbit() and getgclkbit() only 1 coulmn, so they ignore Col */
/*     Sli and Lut are allways ignored, as we are working with entire tiles */
/* leave: same state, but return one config bit */

/* 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


int getcenterbit(int Frame, int Bit) {

  ulong *Center;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getcenterbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapCenter) {
    fprintf(stderr, "BUGCHECK getcenterbit(): BitmapCenter is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  Center = BitmapCenter+Row*VirtexCenterFrames;

  return ((*(Center+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getgclkbit(int Frame, int Bit) {

  int TBRow = (Row < Model->MiddleRows/2) ? 0 : 1;
  ulong *Gclk;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getgclkbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapGclk) {
    fprintf(stderr, "BUGCHECK getgclkbit(): BitmapGclk is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  Gclk = BitmapGclk+TBRow*VirtexGclkFrames;

  return ((*(Gclk+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getclbbit(int Frame, int Bit) {

  ulong *Clb;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getclbbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapClb) {
    fprintf(stderr, "BUGCHECK getclbbit(): BitmapClb is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

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

  return ((*(Clb+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getiobnsbit(int Frame, int Bit) {

  int TBRow = (Row < Model->MiddleRows/2) ? 0 : 1;
  ulong *IobNS;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getiobnsbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapIobNS) {
    fprintf(stderr, "BUGCHECK getiobnsbit(): BitmapIobNS is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  IobNS = BitmapIobNS+(Col*VirtexTopBotRows+TBRow)*VirtexIobNSFrames;

  return ((*(IobNS+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getiobwebit(int Frame, int Bit) {

  int IobWECol = (Col < Model->ClbCols/2) ? 0 : 1;
  ulong *IobWE;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getiobwebit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapIobWE) {
    fprintf(stderr, "BUGCHECK getiobwebit(): BitmapIobWE is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  IobWE = BitmapIobWE+(IobWECol*Model->MiddleRows+Row)*VirtexIobWEFrames;

  return ((*(IobWE+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getcornerbit(int Frame, int Bit) {

  int CornerCol = (Col < Model->ClbCols/2) ? 0 : 1;
  int TBRow = (Row < Model->MiddleRows/2) ? 0 : 1;
  ulong *Corner;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getcornerbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapCorner) {
    fprintf(stderr, "BUGCHECK getcornerbit(): BitmapCorner is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  Corner = BitmapCorner+(CornerCol*VirtexTopBotRows+TBRow)*VirtexCornerFrames;

  return ((*(Corner+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getbramcbit(int Frame, int Bit) {

  /* this fails with >2 BRAM columns, needs rework for Virtex-E and above */
  int BramCCol = (Col < Model->ClbCols/2) ? 0 : 1;
  ulong *BramC;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getbramcbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapBramC) {
    fprintf(stderr, "BUGCHECK getbramcbit(): BitmapBramC is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  BramC = BitmapBramC+(BramCCol*Model->MiddleRows+Row)*VirtexBramCFrames;

  return ((*(BramC+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getdllbit(int Frame, int Bit) {

  /* this fails with >2 BRAM columns, needs rework for Virtex-E and above */
  int DllCol = (Col < Model->ClbCols/2) ? 0 : 1;
  int TBRow = (Row < Model->MiddleRows/2) ? 0 : 1;
  ulong *Dll;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getdllbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapDll) {
    fprintf(stderr, "BUGCHECK getdllbit(): BitmapDll is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  Dll = BitmapDll+(DllCol*VirtexTopBotRows+TBRow)*VirtexDllFrames;

  return ((*(Dll+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getbramdbit(int Frame, int Bit) {

  /* this fails with >2 BRAM columns, needs rework for Virtex-E and above */
  int BramDCol = (Col < Model->ClbCols/2) ? 0 : 1;
  ulong *BramD;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getbramdbit(): Model or Model->Name is NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapBramD) {
    fprintf(stderr, "BUGCHECK getbramdbit(): BitmapBramD is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  BramD = BitmapBramD+(BramDCol*Model->MiddleRows+Row)*VirtexBramDFrames;

  return ((*(BramD+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


int getbramdpadbit(int Frame, int Bit) {

  /* this fails with >2 BRAM columns, needs rework for Virtex-E and above */
  int BramDPadCol = (Col < Model->ClbCols/2) ? 0 : 1;
  int TBRow = (Row < Model->MiddleRows/2) ? 0 : 1;
  ulong *BramDPad;

  if (Model == NULL || Model->Name == NULL) {
    fprintf(stderr, "BUGCHECK getbramdpadbit(): Model or Model->Name NULL\n");
    fprintf(stderr, "         forgot to set model before calling?\n");
    abort(); }

  if (!BitmapBramDPad) {
    fprintf(stderr, "BUGCHECK getbramdpadbit(): BitmapBramDPad is NULL\n");
    fprintf(stderr, "         forgot to allocate frame memory?\n");
    abort(); }

  BramDPad = BitmapBramDPad+
             (BramDPadCol*VirtexTopBotRows+TBRow)*VirtexBramDPadFrames;

  return ((*(BramDPad+Frame) & (TopBitMask>>Bit)) ? 1 : 0); }


/* ------ bits for function selection functions section */

/* 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 is left(!) in the CLB, see XAPP page 11, table 7, formula MNA */
/*    Slice 1/L                              Slice 0/R         */
/*                                                             */
/*    0         1         2         3         4        frame   */
/*    012345678901234567890123456789012345678901234567 address */
/*   .------------------------------------------------         */
/*  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 address                                                 */


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

lutval getlut(void) {

  lutval LutVal = 0;

  /* what Bit address our LUT is on "G"s are on 2, "F"s are on 3 */
  int Bit = (Lut == LUTG) ? 2 : 3;
  /* needs an if, because test direction <= or >= not parameterable */
  if (Sli == SLIR) {
    /* loop F bit to 0 bit, because << will make first bit go off to left */
    int Frame;
    for (Frame = 47; Frame >= 32; Frame--) {
      LutVal = LutVal<<1 | getclbbit(Frame, Bit); } }
  else {
    int Frame;
    for (Frame = 0; Frame <= 15; Frame++) {
      LutVal = LutVal<<1 | getclbbit(Frame, Bit); } }

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


int getff(void) {

  int RightFrame = (Lut == LUTG) ? 45 : 39;
  int LeftFrame = (Lut == LUTG) ? 8 : 2;
  int Frame = (Sli == SLIR) ? RightFrame : LeftFrame;

  return (getclbbit(Frame, 1)); }


/* ------ LUT text writing font pattern section */

/* allow putting text bit patterns into LUTs */
/*   uses the 16 LUT bits as an 4x4 pixel bitmap font */
/*   arranged the same way as as LUT bits are displayed by VirtexView */

lutval LutFont[] = {
  /* 4x4 pixel bit patterns, encoded as 0xabcd: */
  /*   d: 1248 bit values */
  /*   c: 1248            */
  /*   b: 1248            */
  /*   a: 1248            */
  /* all 32 control characters (as full boxes, no room for 2-char mnemonics) */
  /* NUL  SOH     STX     ETX     EOT     ENQ     ACK     BEL     */
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  /* BS   HT      LF      VT      FF      CR      SO      SI      */
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  /* DLE  DC1     DC2     DC3     DC3     NAK     SYN     ETB     */
  0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
  /* CAN  EM      SUB     ESC     FS      GS      RS      US      */
  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 (as full box) */
  0x9690, 0x2469, 0xF6F0, 0x6236, 0x4444, 0x64C6, 0x005A, 0xFFFF };

