/****************************************************************/
/*								*/
/* GALAsm.c - this file includes the GAL-Assembler		*/
/*								*/
/* 								*/
/****************************************************************/



#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/locale.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include <proto/locale.h>
#include <proto/intuition.h>
#include <proto/exec.h>

#include "GALer.h"
#include "Localize.h"





#define	SUFFIX_NON		0	/* possible suffixes */
#define SUFFIX_T		1
#define SUFFIX_R		2
#define SUFFIX_E		3
#define SUFFIX_CLK		4
#define SUFFIX_APRST		5
#define SUFFIX_ARST		6

#define	DUMMY_OLMC11		24
#define DUMMY_OLMC12		25




extern	struct  AppString { LONG   as_ID;
		 	    STRPTR as_Str;
			  };

extern	struct  AppString AppStrings[];


extern	int	linenum, MaxFuseAdr, SigAdr, RowSize, GALType;
extern	UBYTE	*actptr, *buffend;
extern  char	path;


extern	struct	JedecStruct	Jedec;
extern	struct	Configuration	Config;
extern	struct	Catalog		*catalog;

struct	Pin		actPin;
struct	GAL_OLMC	OLMC[12];


			/*Diese Arrays geben an, in welche Spalte der ent- */
			/*sprechende Pin eingekoppelt (bzw. rückgekoppelt) */
			/*wird. Für die invertierende Einkopplung ist 1 zu */
			/*addieren, um die entsprechende Spalte zu erhalten*/
			/* -1: keine Einkopplung auf Fuse-Matrix vorhanden */

			/* GAL16V8 */
int	PinToFuse16Mode1[20]	= {  2,  0,  4,  8, 12, 16, 20, 24, 28, -1,
				    30, 26, 22, 18, -1, -1, 14, 10,  6, -1 };

int	PinToFuse16Mode2[20]	= {  2,  0,  4,  8, 12, 16, 20, 24, 28, -1,
				    30, -1, 26, 22, 18, 14, 10,  6, -1, -1 };

int	PinToFuse16Mode3[20]	= { -1,  0,  4,  8, 12, 16, 20, 24, 28, -1,
				    -1, 30, 26, 22, 18, 14, 10,  6,  2, -1 };

			/* GAL20V8 */
int	PinToFuse20Mode1[24]	= {  2, 0, 4, 8,12,16,20,24,28,32,36,-1,
				    38,34,30,26,22,-1,-1,18,14,10, 6,-1 };

int	PinToFuse20Mode2[24]	= {  2, 0, 4, 8,12,16,20,24,28,32,36,-1,
				    38,34,-1,30,26,22,18,14,10,-1, 6,-1 };

int	PinToFuse20Mode3[24]	= { -1, 0, 4, 8,12,16,20,24,28,32,36,-1,
				    -1,38,34,30,26,22,18,14,10, 6, 2,-1 };


			/* GAL22V10 */
int	PinToFuse22V10[24]	= {  0, 4, 8,12,16,20,24,28,32,36,40,-1,
				    42,38,34,30,26,22,18,14,10, 6, 2,-1 };


			/* GAL20RA10 */
int	PinToFuse20RA10[24]	= { -1, 0, 4, 8,12,16,20,24,28,32,36,-1,
				    -1,38,34,30,26,22,18,14,10, 6, 2,-1 };




			/* This arrays show which row is connected to */
			/* which OLMC */
			/*diese Arrays geben an, in welcher Zeile der*/
			/*erste Eingang der OLMC-Zelle liegt*/

int	ToOLMC[8]	  = { 56, 48, 40, 32, 24, 16, 8, 0 };

int	ToOLMC22V10[12]	  = { 122, 111, 98, 83, 66, 49, 34, 21, 10, 1, 0, 131 };

int	ToOLMC20RA10[10]  = { 72, 64, 56, 48, 40, 32, 24, 16, 8, 0 };


					/* this array shows the size of the */
					/* 22V10-OLMCs ( AR and SP = 1 )    */
int	OLMCSize22V10[12] = { 9, 11, 13, 15, 17, 17, 15, 13, 11, 9, 1, 1 };

		/* The last two entries of the 22V10 arrays are for the   */
		/* AR and SP rows of the 22V10 GAL. This rows are not     */
		/* connected to an OLMC. But to keep the assembler as     */
		/* simple as possible, I introduced  two "OLMCs" for the  */
		/* AR and SP. The assembler treads them like real OLMCs.  */
		/* So don't become confused when OLMC number 11 and 12    */
		/* are used as inputs, outputs, pins... by the assembler. */
		/* These two OLMCs are just dummy-OLMCs.		  */


UBYTE	PinNames[24][10], PinNamesOpt[26][10];
UBYTE	PinDecNeg[24];
UBYTE	ModeErrorStr[] = "Mode  x:  Pin xx";
UBYTE	*pinnames;


LONG	fsize;
UBYTE	*fbuff;

int	num_of_pins, num_of_col, modus, gal_type;
int	asmreadyflag;


/* AssembleInputFile:
   assemble source file (boolean equations)

   Call:      AssembleInputFile(OpMode);	(OpMode = OperationMode)
   Parameter: OpMode = ASSEMBLER : assemble source file and generate JEDEC
				   structure
		     = OPTIMIZER : assemble source file up to the Boolean
				   equations and return without generating
				   the JEDEC structure
				   Booleschen Gleichung und brich dann ab
   Result:  0: o.k.  else: error or cancel
*/
int AssembleInputFile(int OpMode)
{
UBYTE	chr;
UBYTE	*bool_start, *oldptr;
char	prevOp;
char	suffix_strn[MAX_SUFFIX_SIZE];
int	i, j, k, l, n, m;
int	max_chr, pass, pin_num, bool_linenum;
int	actOLMC, row_offset, newline, oldline;
int	suffix, start_row, max_row, num_of_olmcs;


  m = YES;

  if (OpMode == ASSEMBLER)
    m = AsmRequester();

  if (m) {					/* load source file */

    if (MyFileReq(AppStrings[MSG_LOAD_SOURCE].as_Str, ".pld", YES, LOAD)) {

      fsize = FileSize((UBYTE *)&path);

      switch (fsize) {
	case -1L:
	  ErrorReq(1);
	  return(-1);
	  break;

	case -2L:
	  ErrorReq(2);
	  return(-2);
	  break;

	case 0L:
	  ErrorReq(4);
	  return(-4);
	  break;
      }


      if ((fbuff = (UBYTE *)AllocMem(fsize,MEMF_PUBLIC))) {

        if ((ReadFile((UBYTE *)&path, fsize, fbuff))) {

          PrintText(AppStrings[MSG_FILE_LOADED].as_Str, 1);

	  actptr  = fbuff;
	  buffend = fbuff+fsize;
	  linenum = 1;

	  for (n = 0; n < sizeof(Jedec); n++) {	/* init. JEDEC structure */
	    if (n < LOGIC22V10_SIZE)
	      Jedec.GALLogic[n] = 1;		/* set fuses */
	    else
	      Jedec.GALLogic[n] = 0;		/* clear ACW... */
	  }



	  for (n = 0; n < 12; n++) {		/* clear OLMC structure */
	    OLMC[n].Active   = 0;
	    OLMC[n].PinType  = 0;
	    OLMC[n].TriCon   = 0;
	    OLMC[n].Clock    = 0;
	    OLMC[n].ARST     = 0;
	    OLMC[n].APRST    = 0;
	    OLMC[n].FeedBack = 0;
	  }


					/*** get type of GAL ***/

	  if (!strncmp((char *)actptr, "GAL16V8", (size_t)7)) {
	    num_of_olmcs = 8;			/* number of OLMCs */

	    num_of_pins  = 20;			/* number of pins */

	    num_of_col   = MAX_FUSE_ADR16 + 1;	/* number of columns */

	    gal_type     = GAL16V8;

	    if ((*(actptr+7L) != ' ') && (*(actptr+7L) != 0x0A) && (*(actptr+7L) != 0x09)) {
	      AsmError(1, 0);
	      return(-1);
	    }
 	  }
	  else
	    if (!strncmp((char *)actptr, "GAL20V8", (size_t)7)) {
	      num_of_olmcs = 8;				/* number of OLMCs */

	      num_of_pins  = 24;			/* number of pins */

	      num_of_col   = MAX_FUSE_ADR20 + 1;	/* number of columns */

	      gal_type     = GAL20V8;

	      if ((*(actptr+7L) != ' ') && (*(actptr+7L) != 0x0A) && (*(actptr+7L) != 0x09)) {
	        AsmError(1, 0);
	        return(-1);
	      }
  	    }
	    else
	      if (!strncmp((char *)actptr, "GAL20RA10", (size_t)9)) {
		num_of_olmcs = 10;			/* number of OLMCs */

	  	num_of_pins  = 24;			/* number of pins */

		num_of_col   = MAX_FUSE_ADR20RA10 + 1;	/* number of columns */

		gal_type     = GAL20RA10;

	 	if ((*(actptr+9L) != ' ') && (*(actptr+9L) != 0x0A) && (*(actptr+9L) != 0x09) ) {
		  AsmError(1, 0);
		  return(-1);
	        }
  	      }
	      else
	        if (!strncmp((char *)actptr, "GAL22V10", (size_t)8)) {
		  num_of_olmcs = 10;			/* number of OLMCs */

	  	  num_of_pins  = 24;			/* number of pins */

		  num_of_col   = MAX_FUSE_ADR22V10 + 1;	/* number of columns */

		  gal_type     = GAL22V10;

	 	  if ((*(actptr+8L) != ' ') && (*(actptr+8L) != 0x0A) && (*(actptr+8L) != 0x09) ) {
		    AsmError(1, 0);
		    return(-1);
	          }
  	        }
		else {
		  AsmError(1, 0);
		  return(-1);
	        }


				/*** get the leading 8 bytes of the second ***/
				/*** line as signature			   ***/


	  if (GetNextLine()) {			/* end of file? */
	    AsmError(2, 0);			/* yes, then error */
	    return(-1);
	  }
						/* store signature in the */
	  n = m = 0;				/* JEDEC structure        */
					/* end of signature: after eight */
					/* characters, CR or TAB */
	  while((*actptr != 0x0A) && (*actptr != 0x09) && (n < 8)) {
	    chr = *actptr;

	    for (m = 0; m < 8; m++)
	      Jedec.GALSig[n*8 + m] = (chr >> (7 - m)) & 0x1;

	    actptr++;				/* increment pointer and */
	    n++;				/* character-counter     */

	    if (actptr>buffend) {		/* end of file ?*/
	      AsmError(2, 0);			/* yes, then error */
	      return(-1);
	    }
	  } 


				/*** get name of pins ***/

					/* clear flags for negations */
					/* in the pin declaration */
	  for (n = 0; n < 24; PinDecNeg[n++] = 0);


	  pinnames = &PinNames[0][0];	/*assembler: pin names in PinNames*/

	  if (OpMode == OPTIMIZER)	/*optimizer: pin names in PinNamesOpt*/
	    pinnames = &PinNamesOpt[0][0];

	  asmreadyflag = 0;			/* set flag 'not assembled' */

	  GetNextLine();

	  for (n = 0; n < num_of_pins; n++) {
	    if (GetNextChar()) {		/*unexpected end of file?*/
	      AsmError(2, 0);			/*yes, then error*/
	      return(-1);
	    }

	    m = 0;

	    chr = *actptr;			/* get character */

	    if (IsNEG(chr)) {			/* is there a negation? */
	      max_chr 	   = 10;
	      PinDecNeg[n] = 1;			/* yes, then set flag */
	    }
	    else
	      max_chr = 9;

	    if (!(isalpha(chr) || isdigit(chr) || IsNEG(chr))) {
	      AsmError(5, 0);			/* is character a legal */
	      return(-1);			/* one? */
	    }

	    k = 0;

	    while (isalpha(chr) || isdigit(chr) || IsNEG(chr)) {
	      if (IsNEG(chr) && k != 0) {	/* check position of '/' */
	        AsmError(10, 0);			/* must be at the beginning */
	        return(-1);			/* of the pin name */
	      }

	      k = 1;

	      actptr++;

	      if (IsNEG(chr) && (!(isalpha(*actptr) || isdigit(*actptr)))) {
	        AsmError(3, 0);
	        return(-1);
	      }

	      *(pinnames + n*10 + m) = chr;

	      m++;

	      chr = *actptr;

	      if (m == max_chr) {		/*check number of characters*/
	        AsmError(4, 0);			/*in this pinname*/
	        return(-1);			/* error: too many char. */
	       }

	    }

	    *(pinnames+n*10+m) = 0;		/* mark end of string */

	    for (l = 0; l < n; l++) {		/* pin name twice ? */
	      if (strcmp((char *)pinnames+l*10, "NC")) {
	        i = j = 0;

	        if (IsNEG(*(pinnames+l*10)))	/* skip negation sign */
		  i = 1;

	        if (IsNEG(*(pinnames+n*10)))
		  j = 1;

	        if (!strcmp((char *)(pinnames+l*10+i), (char *)(pinnames+n*10+j))) {
	  	  AsmError(9, 0);		/* pin name defined twice */
		  return(-1);
	        }
	      }
	    }
						/* is GND at the GND-pin? */
	    if (!strcmp((char *)(pinnames + n*10), "GND")) {
	      if (n+1 != num_of_pins/2) {
	        AsmError(6, 0);
	        return(-1);
	      }
	    }
	    if (n + 1 == num_of_pins/2) {
	      if (strcmp((char *)(pinnames + n*10), "GND")) {
	        AsmError(8, 0);
	        return(-1);
	      }
	    }
						/* is VCC at the VCC pin? */
	    if (!strcmp((char *)(pinnames + n*10), "VCC")) {
	      if (n+1 != num_of_pins) {
	       AsmError(6, 0);
	       return(-1);
	      }
	    }
	    if (n + 1 == num_of_pins) {
	      if (strcmp((char *)(pinnames + n*10), "VCC")) {
	        AsmError(7, 0);
	        return(-1);
	      }
	    }
					/* AR and SP are key words for 22V10 */
					/* they are not allowed in the pin */
					/* declaration */
	   if (gal_type == GAL22V10) {
	     if (!strcmp((char *)(pinnames+n*10), "AR")) {
	       AsmError(18, 0);
	       return(-1);
	     }

	     if (!strcmp((char *)(pinnames + n*10), "SP")) {
	       AsmError(18, 0);
	       return(-1);
	     }
	   }


	 }


	 if (OpMode == OPTIMIZER)	/* if this routine is called from */
	   return(0);			/* the optimizer, then finish */



/* Boolean-Equations auswerten:
   Dabei werden die Boolean-Equations zweimal untersucht. Beim ersten
   Durchlauf werden die OLMC-Pins ausgewertet und die OLMC-Struktur ge-
   füllt. Mit Hilfe dieser Struktur läßt sich auf dem notwendigen Modus
   (1, 2 oder 3) schließen. Beim zweiten Durchlauf wird dann die
   Fuse-Matrix erstellt.
*/


  if (GetNextChar()) {			/* end of file? */
    AsmError(2, 0);			/* yes, then error */
    return(-1);
  }

					/* are there any equations? */
  if (!strncmp((char *)actptr, "DESCRIPTION", (size_t)11)) {
    AsmError(33, 0);			/* no, then error */
    return(-1);
  }


  bool_start   = actptr;		/*set pointer to the beginning of*/
  bool_linenum = linenum;		/*the equations and save line number*/


  for (pass = 0; pass < 2; pass++) {	/*this is a tow-pass-assembler*/

    if (pass) {				/* 2. pass? => make ACW and get */
					/* the mode for 16V8,20V8 GALs  */
      modus = 0;
				/*** GAL16V8, GAL20V8 ***/

      if (gal_type == GAL16V8 || gal_type == GAL20V8) {

	for (n = 0; n < 8; n++) {		/* examine all OLMCs */
	   if (OLMC[n].PinType == REGOUT) { /* is there a registered OLMC? */
	     modus = MODE3;		 /* yes, then GAL's mode is mode 3 */

	     Jedec.GALSYN = 0;		 /* set SYN and AC0 for mode 3 */

	     Jedec.GALAC0 = 1;

	     break;
	   }
        }

        if (!modus) {
	  for (n = 0; n < 8; n++) {	/* examine all OLMCs */
	    if (OLMC[n].PinType == TRIOUT) { /* is there a tristate OLMC? */
	      modus = MODE2;		/* yes then GAL's mode is mode 2 */

	      Jedec.GALSYN = 1;		/* set SYN und AC0 bit for mode 2 */

	      Jedec.GALAC0 = 1;

	      break;
	    }
	  }
        }


        if (!modus) {			/*if there is a violation of mode 1,*/
	  for (n = 0; n < 8; n++) {	/*then use automatically mode 2*/
	    if (OLMC[n].PinType == INPUT) {
	      if (gal_type == GAL16V8) {
	        pin_num = n + 12;

	        if ((pin_num == 15) || (pin_num == 16)) {
		  modus = MODE2;		/* mode 2 */

		  Jedec.GALSYN = 1;		/* set SYN and AC0 bit */

		  Jedec.GALAC0 = 1;

		  break;
	        }

	      }

	      if (gal_type == GAL20V8) {
	        pin_num = n + 15;

	        if ((pin_num == 18) || (pin_num == 19)) {
		  modus = MODE2;		/* mode 2 */

		  Jedec.GALSYN = 1;		/* set SYN and AC0 bit */

		  Jedec.GALAC0 = 1;

		  break;
	        }
	      }
	    }				/* output and feedback? then mode 2 */

	    if ((OLMC[n].PinType == COM_TRI_OUT) && (OLMC[n].FeedBack)) {
	      modus = MODE2;			/* mode 2 */

	      Jedec.GALSYN = 1;			/* set SYN and AC0 bit */

	      Jedec.GALAC0 = 1;

	      break;
	    }
          }
        }


        if (!modus) {			/* if there is still no mode */
	  modus = MODE1;		/* defined, use mode 1 */

	  Jedec.GALSYN = 1;		/* set SYN and AC0 bit */

	  Jedec.GALAC0 = 0;
        }



		/* If GAL's mode is mode 1, use all OLMCs which type is   */
		/* not defined explicitly as combinational outputs.       */
		/* If GAL's mode is mode 2 or 3, use all OLMCs which type */
		/* is not defined explicitly as tristate output which is  */
		/* always enabled */

	for (n = 0; n < 8; n++) {			/* examine all OLMCs */
	  if (OLMC[n].PinType == COM_TRI_OUT) {	/* is OLMC's type defined */
	    if (modus == MODE1)			/* explicitly? */
	      OLMC[n].PinType = COMOUT;		/* mode 1? then comb. output */
	    else {
	      OLMC[n].PinType = TRIOUT;		/* mode 2, 3? then tri. output */

	      OLMC[n].TriCon  = TRI_VCC;	/* tristate control = TRUE */
	    }
	  }
        }
	
					/* make ACW; (SYN and AC0 are */
					/* defined already) */

	for (n = 0; n < PT_SIZE; n++)	/* set product term disalbe */
	  Jedec.GALPT[n] = 1;

					/* get AC1 bits */
	for (n = 0; n < AC1_SIZE; n++) {
	  if ((OLMC[n].PinType == INPUT) || (OLMC[n].PinType == TRIOUT))
	    Jedec.GALAC1[AC1_SIZE - 1 - n] = 1;
        }

	for (n = 0; n < XOR_SIZE; n++) {	/* get XOR bits */
	  if (((OLMC[n].PinType == COMOUT) || (OLMC[n].PinType == TRIOUT) ||
	       (OLMC[n].PinType == REGOUT)) && (OLMC[n].Active  == ACTIVE_HIGH))
            Jedec.GALXOR[XOR_SIZE - 1 - n] = 1;
	}

      }
				/*** GAL22V10 ***/

      if (gal_type == GAL22V10) {

	for (n = 0; n < 10; n++) {
						/* get XOR bits (S0) */
	  if (OLMC[n].PinType == COM_TRI_OUT)	/* output can be */
	    OLMC[n].PinType = TRIOUT;		/* tristate or register */

	  if (((OLMC[n].PinType == COMOUT) || (OLMC[n].PinType == TRIOUT) ||
	       (OLMC[n].PinType == REGOUT)) && (OLMC[n].Active  == ACTIVE_HIGH))
            Jedec.GALXOR[9 - n] = 1;

						/* get AC1 bits (S1) */
	  if ((OLMC[n].PinType == INPUT) || (OLMC[n].PinType == TRIOUT))
	    Jedec.GALS1[9 - n] = 1;
	}

      }

				/*** GAL20RA10 ***/

      if (gal_type == GAL20RA10) {
						/* get XOR bits (S0) */
	for (n = 0; n < 10; n++) {
	  if (OLMC[n].PinType == COM_TRI_OUT)	/* output can be tristate */
	    OLMC[n].PinType = TRIOUT;		/* or register */

	  if (((OLMC[n].PinType == COMOUT) || (OLMC[n].PinType == TRIOUT) ||
	       (OLMC[n].PinType == REGOUT)) && (OLMC[n].Active  == ACTIVE_HIGH))
            Jedec.GALXOR[9 - n] = 1;
	}
      }

    }


    actptr  = bool_start;

    linenum = bool_linenum;

    newline = linenum;

    goto label1;		/* Shit, don't blame me for the gotos.       */
				/* I know, goto is a very bad command in C   */
				/* and in the most other languages. But it   */
				/* is very hard to remove them in this case. */

loop1:

    if (GetNextChar()) {			/* end of file? */
      AsmError(2, 0);				/* yes then error */
      return(-1);
    }

    suffix = SUFFIX_NON;

    if (*actptr == '.') {			/* is there a suffix? */
      actptr++;					/* yes, then get the string */

      if (gal_type == GAL22V10 && (actPin.p_Pin == 24 || actPin.p_Pin == 25)) {
	AsmError(39, 0);				/* no suffix allowed at */
	return(-1);				/* AR and SP */
      }


      n = 0;
      while (isalpha(*actptr)) {		/* copy suffix string into */
	if (n < MAX_SUFFIX_SIZE)	 	/* suffix array */
	  suffix_strn[n++] = *actptr++;
	else {					/* string too long, then */
	  AsmError(13, 0);				/* unknown suffix */
	  return(-1);
	}
      }

      suffix_strn[n] = 0;			/* mark end of string */

      if (!strcmp(&suffix_strn[0], "T"))
	suffix = SUFFIX_T;
      else
	if (!strcmp(&suffix_strn[0], "R"))
	  suffix = SUFFIX_R;
	else
	  if (!strcmp(&suffix_strn[0], "E"))
	    suffix = SUFFIX_E;
	  else
	    if (!strcmp(&suffix_strn[0], "CLK"))
	      suffix = SUFFIX_CLK;
	    else
	      if (!strcmp(&suffix_strn[0], "ARST"))
		suffix = SUFFIX_ARST;
	      else
	 	if (!strcmp(&suffix_strn[0], "APRST"))
		  suffix = SUFFIX_APRST;
		else {
		  AsmError(13, 0);
		  return(-1);
		}
					/* check whether suffix is */
					/* allowed or not */
      if (gal_type != GAL20RA10) {
	switch (suffix) {
	  case SUFFIX_CLK:
	    AsmError(34, 0);			/* no .CLK allowed */
	    return(-1);
	    break;

	  case SUFFIX_ARST:
	    AsmError(35, 0);			/* .ARST is not allowed */
	    return(-1);
	    break;

	  case SUFFIX_APRST:
	    AsmError(36, 0);			/* .APRST is not allowed */
	    return(-1);
	    break;
	}
      }

      if (GetNextChar()) {			/* end of file? */
        AsmError(2, 0);				/* yes, then error */
        return(-1);
      }
    }



    actOLMC = (int)actPin.p_Pin;		/* save offset of OLMC */



    if (gal_type == GAL16V8)
      actOLMC -= 12;
    else
      if (gal_type == GAL20V8)
        actOLMC -= 15;
      else
	actOLMC -= 14;


    row_offset = 0;			/* offset for OR at OLMC*/

    prevOp     = 0;			/* previous operator */


    if (!pass) {			/* is this pass 1? */
					/* is pin a OLMC pin? */
      if ( ((gal_type == GAL16V8)
	       && (actPin.p_Pin >= 12) && (actPin.p_Pin <= 19)) ||
           ((gal_type == GAL20V8)
	       && (actPin.p_Pin >= 15) && (actPin.p_Pin <= 22)) ||
	   ((gal_type == GAL22V10) 
	       && (actPin.p_Pin >= 14) && (actPin.p_Pin <= DUMMY_OLMC12)) ||
	   ((gal_type == GAL20RA10) 
	       && (actPin.p_Pin >= 14) && (actPin.p_Pin <= 23)) ) {


	switch (gal_type) {			/* get OLMC number */
	  case GAL16V8:
	    n = actPin.p_Pin - 12;
	    break;

	  case GAL20V8:
	    n = actPin.p_Pin - 15;
	    break;

	  case GAL22V10:
	  case GAL20RA10:
	    n = actPin.p_Pin - 14;
	    break;
	}



	switch (suffix) {

	  case SUFFIX_R:		/* output definition */
	  case SUFFIX_T:
	  case SUFFIX_NON:

	    if ((!OLMC[n].PinType) || (OLMC[n].PinType == INPUT)) {

	      if (actPin.p_Neg)			/* get pin's activation */
	        OLMC[n].Active = ACTIVE_LOW;
	      else
	        OLMC[n].Active = ACTIVE_HIGH;

	      if (suffix == SUFFIX_T)
	        OLMC[n].PinType = TRIOUT;	/* tristate output */

	      if (suffix == SUFFIX_R)
		OLMC[n].PinType = REGOUT;	/* registered output */

	      if (suffix == SUFFIX_NON)		/* type of output is not */
		OLMC[n].PinType = COM_TRI_OUT;	/* defined explicitly */

	    }
	    else {
	      if (gal_type == GAL22V10 && (n == 10 || n == 11)) {
		AsmError(40, 0);		/* AR or SP is defined*/
		return(-1);			/* twice */
	      }
	      else {
		AsmError(16, 0);		/* pin is defined twice as */
		return(-1);			/* output */
	      }
	    }

	    break;



	  case SUFFIX_E:

	    if (actPin.p_Neg) {			/* negation of the trisate */
	      AsmError(19, 0);			/* control is not allowed */
	      return(-1);
	    }

	    if (OLMC[n].TriCon) {		/* tri. control twice? */
	      AsmError(22, 0);			/* yes, then error */
	      return(-1);
	    }

	    OLMC[n].TriCon = TRICON;		/* set the flag that there is */
						/* a tri. control equation */

	    if ((!OLMC[n].PinType) || (OLMC[n].PinType == INPUT)) {
	      AsmError(17, 0);			/* the sequence must be output */
	      return(-1);			/* followed by the tri. control  */
	    }


	    if (OLMC[n].PinType == REGOUT &&
	       (gal_type == GAL16V8 || gal_type == GAL20V8)) {
	      AsmError(23, 0);		/* GAL16V8/20V8: tristate control */
	      return(-1);		/* for reg. output is not allowed */
	    }


	    if (OLMC[n].PinType == COM_TRI_OUT) { /* no tristate .T? */
	      AsmError(24, 0);			  /* then error */
	      return(-1);
	    }

	    break;



	    case SUFFIX_CLK:

	      if (actPin.p_Neg) {		/* negation of the .CLK */
	        AsmError(19, 0);		/* control is not allowed */
	        return(-1);
	      }

	      if (OLMC[n].PinType == NOTUSED) {
		AsmError(42, 0);		/* sequence must be: output */
		return(-1);			/* def., .CLK definition */
	      }

	      if (OLMC[n].Clock) {		/* is .CLK defined twice? */
		AsmError(45, 0);		/* yes, then error */
		return(-1);
	      }

	      OLMC[n].Clock = 1;		/* set flag that there is */
						/* a .CLK equation */
	      if (OLMC[n].PinType != REGOUT) {
		AsmError(48, 0);		/* no .CLK allowed when */
		return(-1);			/* output is not registered */
	      }

	      break;
	


	    case SUFFIX_ARST:

	      if (actPin.p_Neg) {		/* negation of the .ARST */
	        AsmError(19, 0);		/* control is not allowed */
	        return(-1);
	      }

	      if (OLMC[n].PinType == NOTUSED) {
		AsmError(43, 0);		/* sequence must be: output */
		return(-1);			/* def., .ARST definition */
	      }

	      if (OLMC[n].ARST) {		/* is .ARST defined twice? */
		AsmError(46, 0);		/* yes, then error */
		return(-1);
	      }

	      OLMC[n].ARST = 1;			/* set flag that there is */
						/* a .ARST equation */
	      if (OLMC[n].PinType != REGOUT) {
		AsmError(48, 0);		/* no .CLK allowed when */
		return(-1);			/* output is not registered */
	      }

	      break;



	    case SUFFIX_APRST:

	      if (actPin.p_Neg) {		/* negation of the .APRST */
	        AsmError(19, 0);		/* control is not allowed */
	        return(-1);
	      }

	      if (OLMC[n].PinType == NOTUSED) {
		AsmError(44, 0);		/* sequence must be: output */
		return(-1);			/* def., .APRST definition */
	      }

	      if (OLMC[n].APRST) {		/* is .APRST defined twice? */
		AsmError(47, 0);		/* yes, then error */
		return(-1);
	      }

	      OLMC[n].APRST = 1;		/* set flag that there is */
						/* a .APRST equation */
	      if (OLMC[n].PinType != REGOUT) {
		AsmError(48, 0);		/* no .CLK allowed when */
		return(-1);			/* output is not registered */
	      }

	      break;
	}

      }
      else {
	AsmError(15, 0);			/* pin can't be programmed */
	return(-1);				/* as output */
      }
    }



    switch (gal_type) {				/* get first row of the */
      case GAL16V8:				/* OLMC and the number of */
      case GAL20V8:				/* rows which areavailable */
	start_row = ToOLMC[actOLMC];
	max_row   = 8;
	break;

      case GAL22V10:
	start_row = ToOLMC22V10[actOLMC];
	max_row   = OLMCSize22V10[actOLMC];
	break;

      case GAL20RA10:
	start_row = ToOLMC20RA10[actOLMC];
	max_row   = 8;
	break;
    }




    if (*actptr != '=') {			/* '=' ?*/
      AsmError(14, 0);				/*no, then error */
      return(-1);
    }	     

loop2:

    actptr++;

    if (GetNextChar()) {			/* end of file? */
      AsmError(2, 0);				/* yes, then error */
      return(-1);
    }

    oldptr = actptr;				/* save pointer */

    IsPinName(pinnames, num_of_pins);

    if (gal_type == GAL22V10 && !actPin.p_Pin) { /* AR and SP is not allowed */
      Is_AR_SP(oldptr);				 /* in terms of an equation */

      if (actPin.p_Pin) {			 /* when used, then error */
	AsmError(31, 0);
	return(-1);
      }
    }


    if (!actPin.p_Pin) {			/* pin name? */
      AsmError(11, 0);				/* no, then error */
      return(-1);
    }


    if (actPin.p_Pin == NC_PIN) {		/* NC used as pin name? */
      AsmError(12, 0);				/* yes, then error */
      return(-1);
    }

    if (IsNEG(*(pinnames+(long)((actPin.p_Pin-1)*10))))
      actPin.p_Neg = !actPin.p_Neg;		/* consider negation in the */
						/* pin declartion */

    oldline = linenum;

    if (GetNextChar()) {			/* end of file? */
      AsmError(2, 0);				/* yes, then error */
      return(-1);
    }

    newline = linenum;

    linenum = oldline;


    if (!pass) {				/* is this pass 1?*/
      if ( ((gal_type == GAL16V8)		/* is this pin an OLMC pin? */
	       && (actPin.p_Pin >= 12) && (actPin.p_Pin <= 19)) ||
           ((gal_type == GAL20V8)
	       && (actPin.p_Pin >= 15) && (actPin.p_Pin <= 22)) ||
	   ((gal_type == GAL22V10) 
	       && (actPin.p_Pin >= 14) && (actPin.p_Pin <= DUMMY_OLMC12)) ||
	   ((gal_type == GAL20RA10) 
	       && (actPin.p_Pin >= 14) && (actPin.p_Pin <= 23)) ) {


	switch (gal_type) {			/* get OLMC number */
	  case GAL16V8:
	    n = actPin.p_Pin - 12;
	    break;

	  case GAL20V8:
	    n = actPin.p_Pin - 15;
	    break;

	  case GAL22V10:
	  case GAL20RA10:
	    n = actPin.p_Pin - 14;
	    break;
	}


	if (!OLMC[n].PinType)			/* is OLMC's type already */
	  OLMC[n].PinType = INPUT;		/* defined? no, then use  */
						/* it as input */
	OLMC[n].FeedBack = YES;		/* if a OLMC pin is used within an */
      }					/* equation, a feedback is needed  */
    }

				/* in pass 2 we have to make the fuse matrix */
    if (pass) {
   
      switch (gal_type) {		/* get row offset */
	case GAL16V8:
	case GAL20V8:

	  if (suffix == SUFFIX_E)	/* when tristate control use first */
	    row_offset = 0;		/* row (=> offset = 0) */
	  else
	    if (!row_offset)		/* is offset of rows still equal 0?*/
	      if ((modus != MODE1) && (OLMC[actOLMC].PinType != REGOUT))
	        row_offset = 1;		/* then init. row-offset */

	  break;

	case GAL22V10:

	  if (suffix == SUFFIX_E)	/* enable is the first row */
	    row_offset = 0;		/* of the OLMC */
	  else {
	    if (actOLMC == 10 || actOLMC == 11) 
	      row_offset = 0;		/* AR, SP?, then no offset */
	    else
	      if (!row_offset)		/* output starts at the second row */
	        row_offset = 1;		/* => offset = 1 */
	  }

	  break;

	case GAL20RA10:
	  switch (suffix) {
	    case SUFFIX_E:		/* enable is the first row */
	      row_offset = 0;		/* of the OLMC */
	      break;

	    case SUFFIX_CLK:		/* Clock is the second row */
	      row_offset = 1;		/* of the OLMC */
	      break;

	    case SUFFIX_ARST:		/* AReset is the third row */
	      row_offset = 2;		/* of the OLMC */
	      break;

	    case SUFFIX_APRST:		/* APreset is the fourth row */
	      row_offset = 3;		/* of the OLMC */
	      break;

	    default:			/* output equation starts at */
	      if (row_offset <= 3)	/* the fifth row */
		row_offset = 4;
	  }
	  break;
      }

      pin_num = actPin.p_Pin;

				/* is there a valuation of GAL's mode? */

      if (gal_type == GAL16V8 || gal_type == GAL20V8) {

	if (modus == MODE2) {			/* valuation of mode 2? */
	  if ((gal_type == GAL16V8) && ((pin_num == 12) || (pin_num == 19))) {
	    AsmError(20, 0);
	    return(-1);
	  }

	  if ((gal_type == GAL20V8) && ((pin_num == 15) || (pin_num == 22))) {
	    AsmError(21, 0);
	    return(-1);
	  }
        }

        if (modus == MODE3) {			/* valuation of mode 3? */
	  if ((gal_type == GAL16V8) && ((pin_num == 1) || (pin_num == 11))) {
	    AsmError(26, 0);
	    return(-1);
	  }

	  if ((gal_type == GAL20V8) && ((pin_num == 1) || (pin_num == 13))) {
	    AsmError(27, 0);
	    return(-1);
	  }
        }
      }

      if (gal_type == GAL20RA10) {	/* valuation of 20RA10? */
	if (pin_num == 1) {			/* pin 1 is reserved for */
	  AsmError(37, 0);				/* /PL (preload) */
	  return(-1);
	}

	if (pin_num == 13) {			/* pin 13 is reserved for */
	  AsmError(38, 0);				/* /OE (output enable) */
	  return(-1);
	}
      }


					/* if GND, set row equal 0 */
      if ((pin_num == num_of_pins) || (pin_num == num_of_pins/2)) {
	if (actPin.p_Neg) {		/* /VCC and /GND are not allowed */
	  AsmError(25, 0);
	  return(-1);
	}

        if (!prevOp && !IsAND(*actptr) && !IsOR(*actptr)) {

	  if (pin_num == num_of_pins/2) {

	    m = (start_row + row_offset) * num_of_col;
							   /* set row equal 0 */
	    for (n = m; n < m+num_of_col; Jedec.GALLogic[n++] = 0);

	  }
	}
	else {
	  AsmError(28, 0);
	  return(-1);
	}
      }
      else {

	if (suffix == SUFFIX_E || suffix == SUFFIX_CLK ||
	    suffix == SUFFIX_ARST || suffix == SUFFIX_APRST ||
	   (gal_type == GAL22V10 && (actOLMC == 10 || actOLMC == 11))) {

	  if (IsOR(prevOp)) {			/* max. one product term */
	    AsmError(29, 0);			/* for CLK, ARST, APRST, E*/
	    return(-1);				/* and 22V10: AR, SP */
	  }

	  SetAND(start_row + row_offset, pin_num, actPin.p_Neg);
	}
	else {
	  if (IsOR(prevOp)) {			/* OR operation? yes, then*/
	    row_offset++;			/* take the next row */

	    if (row_offset == max_row) {	/* too many ORs?*/
	      AsmError(30, 0);
	      return(-1);
	    }
	  }
						/* set ANDs */
	  SetAND(start_row + row_offset, pin_num, actPin.p_Neg);
	}
      }


					/* are there any more terms? */
      if (!IsOR(*actptr) && !IsAND(*actptr) && suffix != SUFFIX_E
	  && suffix != SUFFIX_CLK && suffix != SUFFIX_ARST
          && suffix != SUFFIX_APRST) {
						/* no?, then */
	row_offset++;				/* set unused rows of the */
						/* OLMC equal 0 */
	if (row_offset != max_row) {
	  m = (start_row + row_offset) * num_of_col;

	  for (n = m; n < m + (max_row - row_offset) * num_of_col; n++)
	    Jedec.GALLogic[n] = 0;

	}
      }
    }


    linenum = newline;

    if (IsOR(*actptr) || IsAND(*actptr)) {
      prevOp = *actptr;
      goto loop2;
    }

    if (strncmp((char *)actptr, "DESCRIPTION", (size_t)11)) {

label1:

      linenum = newline;

      oldptr = actptr;

      IsPinName(pinnames, num_of_pins);

      if (gal_type == GAL22V10 && !actPin.p_Pin) { /* no pin name? then  */
	Is_AR_SP(oldptr);			   /* check whether name */
						   /* is AR or SP */
	if (actPin.p_Pin && actPin.p_Neg) {	/* but no negation of */
	  AsmError(32, 0);				/* AR or SP */
	  return(-1);
	}
      }
	
      if (!actPin.p_Pin) {			/* pin name? */
	AsmError(11, 0);				/* no, then error */
	return(-1);
      }

      if (actPin.p_Pin == NC_PIN) {		/* NC used as pin name? */
	AsmError(12, 0);				/* yes, then error */
	return(-1);
      }

      if (IsNEG(*(pinnames+(long)((actPin.p_Pin-1)*10))))
	actPin.p_Neg = !actPin.p_Neg;		/* negation at pin declaration */

      goto loop1;

    }
  }


			/* set fuse matrix of unused OLMCs and of OLMCs */
			/* which are programmed as input equal 0 */

  for (n = 0; n < num_of_olmcs; n++) {
    if ((OLMC[n].PinType == NOTUSED) || (OLMC[n].PinType == INPUT)) {

      switch (gal_type) {			/* get first row of the */
        case GAL16V8:				/* OLMC and the number of */
        case GAL20V8:				/* rows which are available */
	  l = ToOLMC[n];
	  i = 8;
	  break;

        case GAL22V10:
	  l = ToOLMC22V10[n];
	  i = OLMCSize22V10[n];
	  break;

        case GAL20RA10:
	  l = ToOLMC20RA10[n];
	  i = 8;
	  break;
      }

      l = l * num_of_col;

      m = l + i * num_of_col;

      for (k = l; k < m; k++)
	Jedec.GALLogic[k] = 0;
    }
  }


  if (gal_type == GAL22V10) {		/* if AR or SP is not defined,   */
					/* set corresponding row equal 0 */
    if (!OLMC[10].PinType)			   /* set row of AR equal 0 */
      for (n = 0; n < num_of_col; Jedec.GALLogic[n++] = 0);

    if (!OLMC[11].PinType)			   /* set row of SP equal 0 */
      for (n = 5764; n < 5764 + num_of_col; Jedec.GALLogic[n++] = 0);
  }


  if (gal_type == GAL20RA10) {			/* set unused CLK, ARST */
						/* and APRST equal 0 */
    for (n = 0; n < num_of_olmcs; n++) {	/* examine all OLMCs */

      if (OLMC[n].PinType != NOTUSED) {		/* is OLMC used? */

	if (OLMC[n].PinType == REGOUT && !OLMC[n].Clock) {
	  AsmError(41, n+14);			/* register output */
	  return(-1);				/* needs clock definition */
	}

	if (!OLMC[n].Clock) {			/* is clock unused? */
	  l = (ToOLMC20RA10[n] + 1) * num_of_col;   /* yes, then clear */
						    /* the row */
	  for (k = l; k < l + num_of_col; k++)
	    Jedec.GALLogic[k] = 0;
	}

	if (OLMC[n].PinType == REGOUT) {
	  if (!OLMC[n].ARST) {			/* is ARST unused? */
	    l = (ToOLMC20RA10[n] + 2) * num_of_col;

	    for (k = l; k < l + num_of_col; k++)
	      Jedec.GALLogic[k] = 0;
	  }

	  if (!OLMC[n].APRST) {			/* is APRST unused? */
	    l = (ToOLMC20RA10[n] + 3) * num_of_col;

	    for (k = l; k < l + num_of_col; k++)
	      Jedec.GALLogic[k] = 0;
	  }
	}

      }

    }

  }





/* now the JEDEC structure is ready */
/* (be happy, it was a hard task) */



	 asmreadyflag = 1;		/* set flag, so that we can see that  */
					/* this file is assembled succesfully */

	 FreeMem(fbuff, fsize);		/* free buffer of the source file */



	 if (Config.AutoGAL == YES) {	/* redraw the symbolic GAL and print */
	   SetGALType(gal_type);	/* the names of the GAL's pins */

	   PrintPinNames();
	 }


				/*** now make the selected files ***/

         if (Config.GenJedec == YES)
	   if (MyFileReq(AppStrings[MSG_WRITE_JED].as_Str, ".jed", !Config.AutoSave, SAVE))
	     WriteJedecFile(gal_type);

	 if (Config.GenFuse == YES)
	   WriteFuseFile();

	 if (Config.GenChip == YES)
	   WriteChipFile();

	 if (Config.GenPin == YES)
	   WritePinFile();

	  PrintText(AppStrings[MSG_FILE_ASM].as_Str, 1);
          return(0);				/* there was no error */

        }
        else {
	  ErrorReq(3);				/* read error */
	  FreeMem(fbuff,fsize);			/* can't load source file */
	  return(-2);
	}
      }
      else {
	ErrorReq(2);				/* no more free memory */
	return(-2);
      }
    }
    else
      return(-1);			/* file requester canceled */
  }
  else
    return(-1);				/* assembler requester canceled */
}






/* set an AND (=0) in the fuse matrix
   row     :  row in which the AND should be set
   pinnum  :  pin which sould be ANDed
   negation:  0: pin without negation; 1: pin with negation sign ('/')
*/
void SetAND(int row, int pinnum, int negation)
{
int column;

  switch (gal_type) {
    case GAL16V8:
      if (modus == MODE1)
	column = PinToFuse16Mode1[pinnum - 1];
      if (modus == MODE2)
	column = PinToFuse16Mode2[pinnum - 1];
      if (modus == MODE3)
	column = PinToFuse16Mode3[pinnum - 1];
      break;

    case GAL20V8:
      if (modus == MODE1)
        column  =  PinToFuse20Mode1[pinnum - 1];
      if (modus == MODE2)
	column  =  PinToFuse20Mode2[pinnum - 1];
      if (modus == MODE3)
	column  =  PinToFuse20Mode3[pinnum - 1];
      break;

    case GAL22V10:
      column  =  PinToFuse22V10[pinnum - 1];
      break;

    case GAL20RA10:
      column  =  PinToFuse20RA10[pinnum - 1];
      break;
  }

  Jedec.GALLogic[row * num_of_col + column + negation] = 0;

}




/* check whether actptr points to a pinname or not
   numofpins: number of the GAL's pins
   actptr:    pointer to the first character of the pinname
   actPin.p_Pin: number of pin or NC_PIN; 0: no pin
   actPin.p_Neg: pinname with '/' = 1;  without '/' = 0
*/
void IsPinName(UBYTE *pinnames, int numofpins)
{
int	i, k, n;
UBYTE	*oldactptr;

  actPin.p_Neg = 0;			/* install structure for pin */
  actPin.p_Pin = 0;

  if (IsNEG(*actptr)) {			/* negation? */
    actptr++;
    actPin.p_Neg = 1;
  }

  n = 0;				/* get length of pin name */

  oldactptr = actptr;

  while (isalpha(*actptr) || isdigit(*actptr)) {
    actptr++;
    n++;
  }

  if (n)
    if ((n == 2 ) && !strncmp((char *)oldactptr, "NC", (size_t)2))  /*NC ?*/
      actPin.p_Pin = NC_PIN;				/*yes, then NC pin*/
  else
    for (k = 0; k < numofpins; k++) {		/* examine list of pin names */
      i = 0;

      if (IsNEG(*(pinnames+k*10)))
        i = 1;

      if (n == strlen((char *)(pinnames+k*10+i)))    /* string sizes equal?*/       
        if (!(strncmp((char *)oldactptr, (char *)(pinnames+k*10+i) , (size_t)n))) {
	  actPin.p_Pin = k + 1;			 /*yes, then compare*/
	  break;				 /*this strings*/
        }
    }
}




/* check whether actptr points to a AR or SP
   ptr:    pointer to the first character of the name
result:
   actPin.p_Pin: 23: AR, 24: SP, 0: no AR, SP
   actPin.p_Neg: pinname with '/' = 1;  without '/' = 0
*/
void Is_AR_SP(UBYTE *ptr)
{
int	n;
UBYTE	*oldptr;

  actPin.p_Neg = 0;			/* install structure for pin */
  actPin.p_Pin = 0;

  if (IsNEG(*ptr)) {			/* negation? */
    ptr++;
    actPin.p_Neg = 1;
  }

  n = 0;				/* get length of pin name */

  oldptr = ptr;

  while (isalpha(*ptr) || isdigit(*ptr)) {
    ptr++;
    n++;
  }
			/* assign AR to "OLMC 11" ("pin 24") and */
  if (n) {		/* assign SP to "OLMC 12" ("pin 25")     */
    if ((n == 2 ) && !strncmp((char *)oldptr, "AR", (size_t)2))
      actPin.p_Pin = DUMMY_OLMC11;

    if ((n == 2 ) && !strncmp((char *)oldptr, "SP", (size_t)2))
      actPin.p_Pin = DUMMY_OLMC12;
  }
}





/* search the next character which is no comment, space, TAB, LF
  result 0: character found, actptr points on this
         1: no character found
*/
int GetNextChar(void)
{

  for(;;) {
    switch (*actptr) {
      case 0x0A:				/* LineFeed */
        actptr++;
        linenum++;
        break;

      case ' ':					/* space */
      case 0x09:				/* TAB */
        actptr++;
        break;

      case ';':					/* comment found? */
	if (GetNextLine())			/* then skip rest of line */
	  return(0);
	break;

     default:
       if ((*actptr > ' ') && (*actptr <= '~'))	/* was there a character? */
	 return(0);
       else
	 actptr++;
    }

    if (actptr > buffend)			/* end of file? */
      return(1);
  }
}



/* get pointer to next line
  result:  0: line found,  actptr points to this line
	   1: end of file reached
*/
int GetNextLine(void)
{
  for(;;) {
    if (*actptr == 0x0A) {
      actptr++;
      linenum++;
      return(0);
    }

    if (actptr > buffend)			/* end of file? */
      return(1);

    actptr++;
  }
}




/* print error message of the GAL-assembler and free
   the memory of the file buffer
 parameter: errornum: number of error to print
	    pinnum = 0: print "Error in line linenum: of error
		   > 0: print "Pin pinnum:"
*/
void AsmError(int errornum, int pinnum)
{
static char pin[] = "Pin xx:";		/* this string is not localized  */
					/* since "pin" is a well known   */
					/* word for electronic freaks (or */
					/* isn't it?) */
  FreeMem(fbuff,fsize);

  MyRequest(ERR_REQ, AppStrings[MSG_ERR_ASM].as_Str);

  if (!pinnum)
    PrintErrorLine(linenum);
  else {
    sprintf(&pin[4], "%2d", pinnum);
    pin[6] = ':';
    PrintText(pin, 1);
  }

  switch (errornum) {
    case  1:
      PrintText(AppStrings[MSG_ERR_ASM1].as_Str, 1);
      break;

    case  2:
      PrintText(AppStrings[MSG_ERR_ASM2].as_Str, 1);
      break;

    case  3:
      PrintText(AppStrings[MSG_ERR_ASM3].as_Str, 1);
      break;

    case  4:
      PrintText(AppStrings[MSG_ERR_ASM4].as_Str, 1);
      break;

    case  5:
      PrintText(AppStrings[MSG_ERR_ASM5].as_Str, 1);
      break;

    case  6:
      PrintText(AppStrings[MSG_ERR_ASM6].as_Str, 1);
      break;

    case  7:
      PrintText(AppStrings[MSG_ERR_ASM7].as_Str, 1);
      break;

    case  8:
      PrintText(AppStrings[MSG_ERR_ASM8].as_Str, 1);
      break;

    case  9:
      PrintText(AppStrings[MSG_ERR_ASM9].as_Str, 1);
      break;

    case 10:
      PrintText(AppStrings[MSG_ERR_ASM10].as_Str, 1);
      break;

    case 11:
      PrintText(AppStrings[MSG_ERR_ASM11].as_Str, 1);
      break;

    case 12:
      PrintText(AppStrings[MSG_ERR_ASM12].as_Str, 1);
      break;

    case 13:
      PrintText(AppStrings[MSG_ERR_ASM13].as_Str, 1);
      break;

    case 14:
      PrintText(AppStrings[MSG_ERR_ASM14].as_Str, 1);
      break;

    case 15:
      PrintText(AppStrings[MSG_ERR_ASM15].as_Str, 1);
      break;

    case 16:
      PrintText(AppStrings[MSG_ERR_ASM16].as_Str, 1);
      break;

    case 17:
      PrintText(AppStrings[MSG_ERR_ASM17].as_Str, 1);
      break;
 
    case 18:
      PrintText(AppStrings[MSG_ERR_ASM18].as_Str, 1);
      break;

    case 19:
      PrintText(AppStrings[MSG_ERR_ASM19].as_Str, 1);
      break;

    case 20:
      PrintText(AppStrings[MSG_ERR_ASM20].as_Str, 1);
      break;

    case 21:
      PrintText(AppStrings[MSG_ERR_ASM21].as_Str, 1);
      break;

    case 22:
      PrintText(AppStrings[MSG_ERR_ASM22].as_Str, 1);
      break;

    case 23:
      PrintText(AppStrings[MSG_ERR_ASM23].as_Str, 1);
      break;

    case 24:
      PrintText(AppStrings[MSG_ERR_ASM24].as_Str, 1);
      break;

    case 25:
      PrintText(AppStrings[MSG_ERR_ASM25].as_Str, 1);
      break;

    case 26:
      PrintText(AppStrings[MSG_ERR_ASM26].as_Str, 1);
      break;

    case 27:
      PrintText(AppStrings[MSG_ERR_ASM27].as_Str, 1);
      break;

    case 28:
      PrintText(AppStrings[MSG_ERR_ASM28].as_Str, 1);
      break;

    case 29:
      PrintText(AppStrings[MSG_ERR_ASM29].as_Str, 1);
      break;

    case 30:
      PrintText(AppStrings[MSG_ERR_ASM30].as_Str, 1);
      break;

    case 31:
      PrintText(AppStrings[MSG_ERR_ASM31].as_Str, 1);
      break;

    case 32:
      PrintText(AppStrings[MSG_ERR_ASM32].as_Str, 1);
      break;

    case 33:
      PrintText(AppStrings[MSG_ERR_ASM33].as_Str, 1);
      break;

    case 34:
      PrintText(AppStrings[MSG_ERR_ASM34].as_Str, 1);
      break;

    case 35:
      PrintText(AppStrings[MSG_ERR_ASM35].as_Str, 1);
      break;

    case 36:
      PrintText(AppStrings[MSG_ERR_ASM36].as_Str, 1);
      break;

    case 37:
      PrintText(AppStrings[MSG_ERR_ASM37].as_Str, 1);
      break;

    case 38:
      PrintText(AppStrings[MSG_ERR_ASM38].as_Str, 1);
      break;

    case 39:
      PrintText(AppStrings[MSG_ERR_ASM39].as_Str, 1);
      break;

    case 40:
      PrintText(AppStrings[MSG_ERR_ASM40].as_Str, 1);
      break;

    case 41:
      PrintText(AppStrings[MSG_ERR_ASM41].as_Str, 1);
      break;

    case 42:
      PrintText(AppStrings[MSG_ERR_ASM42].as_Str, 1);
      break;

    case 43:
      PrintText(AppStrings[MSG_ERR_ASM43].as_Str, 1);
      break;

    case 44:
      PrintText(AppStrings[MSG_ERR_ASM44].as_Str, 1);
      break;

    case 45:
      PrintText(AppStrings[MSG_ERR_ASM45].as_Str, 1);
      break;

    case 46:
      PrintText(AppStrings[MSG_ERR_ASM46].as_Str, 1);
      break;

    case 47:
      PrintText(AppStrings[MSG_ERR_ASM47].as_Str, 1);
      break;

    case 48:
      PrintText(AppStrings[MSG_ERR_ASM48].as_Str, 1);
      break;
  }
} 
 





/********************************************************/
/* the following routines are for the creation of the 	*/
/* documentation files					*/
/********************************************************/


/* make chip file */
void WriteChipFile(void)
{
extern	char	path;
FILE	*fp;
int	n;

   if (MyFileReq(AppStrings[MSG_WRITE_CHIP].as_Str, ".chp", !Config.AutoSave, SAVE)) {

     PrintText(AppStrings[MSG_WRITING_CHIP].as_Str, 1);

     if (fp = fopen(&path, (char *)"w")) {

       fprintf(fp, "\n\n");

       WriteSpaces(fp, 31);

       if (gal_type == GAL16V8)
	 fprintf(fp, " GAL16V8\n\n");

       if (gal_type == GAL20V8)
	 fprintf(fp, " GAL20V8\n\n");

       if (gal_type == GAL22V10)
	 fprintf(fp, " GAL22V10\n\n");

       if (gal_type == GAL20RA10)
	 fprintf(fp, "GAL20RA10\n\n");


       WriteSpaces(fp, 26);

       fprintf(fp,"-------\\___/-------\n");

       for (n = 0; n < num_of_pins/2; n++) {

	 WriteSpaces(fp, 25 - (int)strlen((char *)(pinnames+n*10)));

	 fprintf(fp,"%s | %2d           %2d | %s\n", pinnames+n*10, n+1, num_of_pins-n, pinnames+(num_of_pins-n-1)*10);

	 if (n < num_of_pins/2 - 1) {
	   WriteSpaces(fp, 26);

	   fprintf(fp, "|                 |\n");
	  }
	}

       WriteSpaces(fp, 26);

       fprintf(fp, "-------------------\n");

       if (fclose(fp) == EOF) {
	 PrintText(AppStrings[MSG_ERROR].as_Str, 0);

         ErrorReq(8);			/* can't close file */

	 return;
	}
     }
     else {
       PrintText(AppStrings[MSG_ERROR].as_Str, 0);

       ErrorReq(13);

       return;
     }

     PrintText(AppStrings[MSG_LOWER_OK].as_Str, 0);
   }
}





/* generate the pin filee*/
void WritePinFile(void)
{
extern	char	path;
FILE	*fp;
int	k, n, flag;


   if (MyFileReq(AppStrings[MSG_WRITE_PIN].as_Str, ".pin", !Config.AutoSave, SAVE)) {

     PrintText(AppStrings[MSG_WRITING_PIN].as_Str, 1);

     if (fp = fopen(&path, (char *)"w")) {
       fprintf(fp, "\n\n");

       fprintf(fp, " Pin # | Name     | Pin Type\n");

       fprintf(fp, "-----------------------------\n");

       for (n = 1; n <= num_of_pins; n++) {
	 fprintf(fp,"  %2d   | ",n);

	 fprintf(fp,"%s",pinnames+(n-1)*10);

	 WriteSpaces(fp, 9-(int)strlen((char *)(pinnames+(n-1)*10)));

	 flag = 0;

	 if (n == num_of_pins/2) {
	   fprintf(fp,"| GND\n");
	   flag = 1;
	 }

	 if (n == num_of_pins) {
	   fprintf(fp,"| VCC\n\n");
	   flag = 1;
	 }


	 if (gal_type == GAL16V8 || gal_type == GAL20V8) {

	   if (modus == MODE3 && n == 1) {
	     fprintf(fp, "| Clock\n");
	     flag = 1;
	   }

	   if (modus == MODE3) {
	     if (gal_type == GAL16V8 && n == 11) {
	       fprintf(fp, "| /OE\n");
	       flag = 1;
	     }

	     if (gal_type == GAL20V8 && n == 13) {
	       fprintf(fp, "| /OE\n");
	       flag = 1;
	     }
	   }
	 }

	 if (gal_type == GAL22V10 && n == 1) {
	   fprintf(fp, "| Clock/Input\n");
	   flag = 1;
	 }

							/* OLMC pin?*/

	 if ( (gal_type == GAL16V8   && n >= 12 && n <= 19) ||
	      (gal_type == GAL20V8   && n >= 15 && n <= 22) ||
	      (gal_type == GAL20RA10 && n >= 14 && n <= 23) ||
	      (gal_type == GAL22V10  && n >= 14 && n <= 23) ) {


	   if (gal_type == GAL16V8)
	     k = n - 12;
	   else
	     if (gal_type == GAL20V8)
	       k = n - 15;
	     else
	       k = n - 14;

	   if (OLMC[k].PinType != INPUT)
	     if (OLMC[k].PinType)
	       fprintf(fp,"| Output\n");
	     else
	       fprintf(fp,"| NC\n");
	   else
	     fprintf(fp,"| Input\n");
	 }
	 else {
	   if (!flag) 
	     fprintf(fp,"| Input\n");
	 }
       }

       if (fclose(fp) == EOF) {
	 PrintText(AppStrings[MSG_ERROR].as_Str, 0);
	 ErrorReq(8);				/* can't close file */
	 return;
	}
     }
     else {
       PrintText(AppStrings[MSG_ERROR].as_Str, 0);
       ErrorReq(13);
       return;
     }
     PrintText(AppStrings[MSG_LOWER_OK].as_Str, 0);
   }
}



/* WriteRow: write a row of an OLMC to fp
   Prameter: row: number of row which should be written
	     fp:  pointer to file handle
   global variable: row_of_col
*/
void WriteRow(FILE *fp, int row)
{
int col;


  fprintf(fp, "\n%3d ", row);			/* print row number */

  for (col = 0; col < num_of_col; col++) {	/* print fuses of */
    if (!( (col) % 4) )				/* a row   */
      fprintf(fp, " ");

    if (Jedec.GALLogic[row * num_of_col + col])
      fprintf(fp, "-");
    else
      fprintf(fp, "x");
  }

}




/* generate fuse file */
void WriteFuseFile(void)
{
extern	char	path;
FILE	*fp;
int	row, pin, n, numofOLMCs, numofrows, olmc;


  if (MyFileReq(AppStrings[MSG_WRITE_FUSE].as_Str, ".fus", !Config.AutoSave, SAVE)) {
    PrintText(AppStrings[MSG_WRITING_FUSE].as_Str, 1);

    if (fp = fopen(&path,(char *)"w")) {
      if (gal_type == GAL16V8) {
        pin = 19;
	numofOLMCs = 8;
      }
      else
        if (gal_type == GAL20V8) {
	  pin = 22;
	  numofOLMCs = 8;
	}
        else {					/* 22V10, 20RA10 */
	  pin = 23;
	  numofOLMCs = 10;
	}



      row = 0;

      for (olmc = 0; olmc < numofOLMCs; olmc++) {

	if (gal_type == GAL22V10 && olmc == 0) {  /* AR when 22V10 */
	  fprintf(fp, "\n\nAR");
	  WriteRow(fp, row);
	  row++;
	}

	if (gal_type == GAL22V10)		/* get number of rows */
	  numofrows = OLMCSize22V10[olmc];	/* of an OLMC */
	else
	  numofrows = 8;



	fprintf(fp, "\n\nPin %2d = ", pin);		/* print pin */

	fprintf(fp, "%s", pinnames + (pin - 1)*10);

	WriteSpaces(fp, 13-(int)strlen((char *)(pinnames+(pin-1)*10)));


	if (gal_type == GAL16V8)
	  fprintf(fp, "XOR = %1d   AC1 = %1d", Jedec.GALXOR[19 - pin],
					       Jedec.GALAC1[19 - pin]);
	else
	  if (gal_type == GAL20V8)
	    fprintf(fp, "XOR = %1d   AC1 = %1d", Jedec.GALXOR[22 - pin],
					         Jedec.GALAC1[22 - pin]);
	  else
	    if (gal_type == GAL22V10)
	      fprintf(fp, "S0 = %1d   S1 = %1d", Jedec.GALXOR[23 - pin],
					          Jedec.GALAC1[23 - pin]);
	    else
	      if (gal_type == GAL20RA10)
	        fprintf(fp, "S0 = %1d", Jedec.GALXOR[23 - pin]);



	for (n = 0; n < numofrows; n++) {	/* print all fuses of an OLMC */
	  WriteRow(fp, row);
	  row++;
	}


	if (gal_type == GAL22V10 && olmc == 9) {  /* SP when 22V10 */
	  fprintf(fp, "\n\nSP");
	  WriteRow(fp, row);
	}

	pin--;
      }


      fprintf(fp, "\n\n");

      if (fclose(fp) == EOF) {
        PrintText(AppStrings[MSG_ERROR].as_Str, 0);
        ErrorReq(8);				/* can't close file */
        return;
      }
    }
    else {
      PrintText(AppStrings[MSG_ERROR].as_Str, 0);
      ErrorReq(13);
      return;
    }

    PrintText(AppStrings[MSG_LOWER_OK].as_Str, 0);
  }
}





/* write "numof" spaces
*/
void WriteSpaces(FILE *fp, int numof)
{
int n;

 for (n = 0; n < numof; n++)
   fprintf(fp, " ");

}




/* checks whether chr is a OR sign or not
** result: 1: chr is a OR
** 	   0: chr is no OR
*/
int IsOR(char chr)
{
  if (chr == '+' || chr == '#')
    return(1);
  else
    return(0);
}



/* checks whether chr is a AND sign or not
** result: 1: chr is a AND
** 	   0: chr is no AND
*/
int IsAND(char chr)
{
  if (chr == '*' || chr == '&')
    return(1);
  else
    return(0);
}


/* checks whether chr is a negation sign or not
** result: 1: chr is a negation
** 	   0: chr is no negation
*/
int IsNEG(char chr)
{
  if (chr == '/' || chr == '!')
    return(1);
  else
    return(0);
}



