/****************************************************************/
/*								*/
/* GALAsm.c - enthält GAL-Assembler				*/
/*								*/
/* compilieren: cc GALAsm.c					*/
/*								*/
/****************************************************************/



#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <ctype.h>
#include <stdio.h>
#include <functions.h>

#include "GALer.h"



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

extern	struct	JedecStruct	Jedec;
extern	struct	Configuration	Config;
extern	struct	RastPort	*rp;
extern	struct	MenuItem	MenuItem13, MenuItem13b;  /*GAL16V8, GAL20V8*/


struct	Pin		actPin;
struct	GAL_OLMC	OLMC[8];


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

			/*dieses Array gibt an in welcher Zeile der*/
			/*erste Eingang der OLMC-Zelle liegt*/
int	ToOLMC[8]		= { 56,48,40,32,24,16, 8, 0 };



UBYTE	PinNames[24][10], PinNamesOpt[24][10];
UBYTE	PinDecNeg[24];
UBYTE	ModeErrorStr[] = {"Modus x:  Pin xx"};
UBYTE	*pinnames;


LONG	fsize;
UBYTE	*fbuff;

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


/* AssembleInputFile:
   Eingabe-Datei assemblieren
   Aufruf: AssembleInputFile(OpMode);	(OpMode = OperationMode)
   Parameter: OpMode = ASSEMBLER : assembliere das Source-File und erstelle
				   die Jedec-Struktur
		     = OPTIMIZER : assembliere das Source-File bis zu den
				   Booleschen Gleichung und brich dann ab
   Ergebnis: 0: alles o.k.   sonst: Fehler oder Abbruch
*/
int AssembleInputFile(OpMode)
int	OpMode;
{
UBYTE	chr;
UBYTE	*bool_start;
char	prevOp;
char	*filereqtxt;
int	i, j, k, l, n, m;
int	oldMaxFuseAdr, max_chr;
int	pass, pin_num, bool_linenum;
int	actOLMC, row_offset, a_type, newline, oldline;


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

if (m) {
 if (OpMode == ASSEMBLER)
   filereqtxt = (char *)"Source-File laden";
 else
   filereqtxt = (char *)"zu optimierendes Source-File laden";

 if (MyFileReq(filereqtxt,(char *)".pld",YES)) {
   fsize=FileSize(&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(&path,fsize,fbuff))) {
       PrintText((UBYTE *)"Datei ist geladen",1);


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

       for (n=0; n<sizeof(Jedec); n++) {	/*Jedec-Sruktur zurücksetzen*/
	 if (n < LOGIC20_SIZE)
	   Jedec.GALLogic[n] = 1;		/*Fuse-Matrix auf 1*/
	 else
	   Jedec.GALLogic[n] = 0;		/*ACW, PT usw. auf 0*/
	}

       for (n=0; n<8; n++) {			/*OLMC-Sruktur auf 0 setzen*/
	 OLMC[n].Active   = 0;
	 OLMC[n].PinType  = 0;
	 OLMC[n].TriCon   = 0;
	 OLMC[n].FeedBack = 0;
	}

					/*GAL-Typ feststellen*/
       a_type = 0;
       if ((!strncmp(actptr,(UBYTE *)"GAL16V8A",8)) || (!strncmp(actptr,(UBYTE *)"GAL20V8A",8)) ||
           (!strncmp(actptr,(UBYTE *)"GAL16V8B",8)) || (!strncmp(actptr,(UBYTE *)"GAL20V8B",8))) {
	 a_type = 1;
	 if ( (*(actptr+8L) != ' ') && (*(actptr+8L) != 0x0A) && (*(actptr+8L) != 0x09) ) {
	   AsmError(1);
	   return(-1);
	  }
	}

       if (!strncmp(actptr,(UBYTE *)"GAL16V8",7)) {
	 num_of_pins = 20;			/*Anzahl der Pins   */
	 num_of_col  = MAX_FUSE_ADR16 + 1;	/*Anzahl der Spalten*/
	 gal_type    = GAL16V8;
        }
       else
         if (!strncmp(actptr,(UBYTE *)"GAL20V8",7)) {
	   num_of_pins = 24;			/*Anzahl der Pins   */
	   num_of_col  = MAX_FUSE_ADR20 + 1;	/*Anzahl der Spalten*/
	   gal_type    = GAL20V8;
	  }
	 else {
	   AsmError(1);
	   return(-1);
	  }

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



					/*Signatur (8 Bytes der 2.Zeile) in Puffer schreiben*/
       if (GetNextLine()) {			/*Datei-Ende erreicht?*/
	 AsmError(2);				/*ja, dann Fehler*/
	 return(-1);
	}
       n = m = 0;				/*Signatur in Jedec-Stuktur schreiben*/
       while((*actptr != 0x0A) && (*actptr != 0x09) && (n < 8)) { /*CR,TAB*/
	 chr = *actptr;
	 for (m=0; m<8; m++) {
	   Jedec.GALSig[n*8+m] = (chr>>(7-m)) & 0x1; 
	  }
	 actptr++;
	 n++;
	 if (actptr>buffend) {			/*Fileende erreicht ?*/
	   AsmError(2);				/*ja, dann Fehler*/
	   return(-1);
	  }
	} 

					/*Pin-Namen eintragen*/
       for (n=0; n<24; PinDecNeg[n++]=0); /*Merker für Neg. bei Pindeklara-*/
					  /*tion*/

       pinnames = &PinNames[0][0];	/*für Assembler in "PinNames"*/
       if (OpMode == OPTIMIZER)
	 pinnames = &PinNamesOpt[0][0];	/*für Optimizer in "PinNamesOpt"*/

       asmreadyflag = 0;			/*noch nicht assembliert*/
       GetNextLine();
       for (n=0; n<num_of_pins; n++) {
	  if (GetNextChar()) {			/*Dateiende?*/
	    AsmError(2);			/*ja, dann Fehler*/
	    return(-1);
	   }
	  m = 0;
	  chr = *actptr;
	  if (chr == '/') {
	    max_chr 	 = 10;
	    PinDecNeg[n] = 1;			/*Neg. bei Pindeklaration*/
	   }
	  else
	    max_chr = 9;
	  if (!(isalpha(chr) || isdigit(chr) || chr=='/')) {
	    AsmError(5);
	    return(-1);
	   }
	  k = 0;
	  while (isalpha(chr) || isdigit(chr) || chr=='/') {
	     if ((chr == '/') && (k != 0)) {	/* '/' nicht am Anfang des Pinnamens?*/
	       AsmError(10);
	       return(-1);
	      }
	     k = 1;
	     actptr++;
	     if ((chr=='/') && (!(isalpha(*actptr) || isdigit(*actptr)))) {
	       AsmError(3);
	       return(-1);
	      }
	     *(pinnames+n*10+m) = chr;
	     m++;
	     chr = *actptr;
	     if (m == max_chr) {		/*zuviele Buchstaben?*/
	       AsmError(4);
	       return(-1);
	      }
	    }
	  *(pinnames+n*10+m) = 0;		/*Stringende kennzeichnen*/

	  for (l=0; l<n; l++) {			/*Pinname doppelt?*/
	    if (strcmp(pinnames+l*10,(UBYTE *)"NC")) {
	      i = j = 0;
	      if (*(pinnames+l*10) == '/') i = 1;
	      if (*(pinnames+n*10) == '/') j = 1;
	      if (!strcmp(pinnames+l*10+i,pinnames+n*10+j)) {
		AsmError(9);
		return(-1);
	       }
	     }
	   }
						/*GND an entsprechenden Pin?*/
	  if (!strcmp(pinnames+n*10,(UBYTE *)"GND")) {
	    if (n+1 != num_of_pins/2) {
	      AsmError(6);
	      return(-1);
	     }
	   }
	  if (n+1 == num_of_pins/2) {
	    if (strcmp(pinnames+n*10,(UBYTE *)"GND")) {
	      AsmError(8);
	      return(-1);
	     }
	   }
						/*VCC an entsprechenden Pin?*/
	  if (!strcmp(pinnames+n*10,(UBYTE *)"VCC")) {
	    if (n+1 != num_of_pins) {
	      AsmError(6);
	      return(-1);
	     }
	   }
	  if (n+1 == num_of_pins) {
	    if (strcmp(pinnames+n*10,(UBYTE *)"VCC")) {
	      AsmError(7);
	      return(-1);
	     }
	   }
	}


      if (OpMode == OPTIMIZER)		/*falls vom Optimizer aufgerufen,*/
	return(0);			/*dann fertig*/



/* 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()) {			/*Dateiende?*/
	 AsmError(2);				/*ja, dann Fehler*/
	 return(-1);
	}

						/*Gleichungen vorhanden?*/
       if (!strncmp(actptr,(UBYTE *)"DESCRIPTION",11)) {
	 AsmError(33);				/*nein, dann Fehlermeldung*/
	 return(-1);
	}


       bool_start   = actptr;			/*Zeiger auf Anfang der Equations*/
       bool_linenum = linenum;			/*Zeilennummer merken*/

       for (pass=0; pass<2; pass++) {		/*2 Durchläufe*/

	 if (pass) {			/*2. Durchlauf?->ACW erstellen*/
	   modus = 0;			/*und Modus bestimmen*/
	   for (n=0; n<8; n++) {		/*alle OLMCs untersuchen*/
	     if (OLMC[n].PinType == REGOUT) {	/*OLMC als Reg. vorhanden?*/
	       modus = MODE3;			/*ja, dann MUß Mode3 vorliegen*/
	       Jedec.GALSYN = 0;		/*SYN- und AC0-Bit setzen*/
	       Jedec.GALAC0 = 1;
	       break;
	      }
	    }

	   if (!modus) {
	     for (n=0; n<8; n++) {
	       if (OLMC[n].PinType == TRIOUT) {	/*OLMC als Tri. vorhanden?*/
	         modus = MODE2;			/*ja, dann Mode2*/
	         Jedec.GALSYN = 1;		/*SYN- und AC0-Bit setzen*/
	         Jedec.GALAC0 = 1;
		 break;
	        }
	      }
	    }


	   if (!modus) {			/*wenn Verstöße gegen Mode1,*/
	     for (n=0; n<8; n++) {		/*dann automatisch in Mode2*/
	       if (OLMC[n].PinType == INPUT) {	/*schalten*/
	         if (gal_type == GAL16V8) {
		   pin_num = n + 12;
	           if ((pin_num == 15) || (pin_num == 16)) {
		     modus = MODE2;		/*Mode2*/
		     Jedec.GALSYN = 1;		/*SYN- und AC0-Bit setzen*/
		     Jedec.GALAC0 = 1;
		     break;
	            }
	          }
	         if (gal_type == GAL20V8) {
		   pin_num = n + 15;
	           if ((pin_num == 18) || (pin_num == 19)) {
		     modus = MODE2;		/*Mode2*/
		     Jedec.GALSYN = 1;		/*SYN- und AC0-Bit setzen*/
		     Jedec.GALAC0 = 1;
		     break;
	            }
	          }
	        }		/*wenn Ausgang mit Rückkopplung, dann Mode2*/
	       if ((OLMC[n].PinType == COM_TRI_OUT) && (OLMC[n].FeedBack)) {
		 modus = MODE2;			/*Mode2*/
		 Jedec.GALSYN = 1;		/*SYN- und AC0-Bit setzen*/
		 Jedec.GALAC0 = 1;
		 break;
		}
	      }
	    }


	   if (!modus) {
	     modus = MODE1;			/*noch kein Mode? dann Mode1*/
	     Jedec.GALSYN = 1;			/*SYN- und AC0-Bit setzen*/
	     Jedec.GALAC0 = 0;
	    }



					/*falls Modus 1 voliegt, alle*/
					/*Ausgänge deren Typ nicht an-*/
					/*gegeben wurde in komb. Ausgänge*/
					/*umwandeln*/
					/*falls Modus 2 oder 3 vorliegt,*/
					/*alle Ausgänge deren Typ nicht an-*/
					/*gegeben wurde in Tristate mit per-*/
	   for (n=0; n<8; n++) {	/*manenter Freischaltung umwandeln*/
	     if (OLMC[n].PinType == COM_TRI_OUT) {
	       if (modus == MODE1) {
		 OLMC[n].PinType = COMOUT;
		}
	       else {
	         OLMC[n].PinType = TRIOUT;
	         OLMC[n].TriCon  = TRI_VCC;
		}
	      }
	    }
	
					/*ACW erstellen: SYN und AC0 sind*/
					/*bereits festgelegt*/
	   for (n=0; n<PT_SIZE; n++)		/*Produkftermfreigabe auf 1*/
	     Jedec.GALPT[n] = 1;

					/*AC1-Bits bestimmen*/
	   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++) {		/*XOR-Bits bestimmen*/
	     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;
	    }

	  }



	 actptr  = bool_start;
	 linenum = bool_linenum;
	 newline = linenum;
         goto label1;

loop1:	 if (GetNextChar()) {				/*Dateiende?*/
	   AsmError(2);					/*ja, dann Fehler*/
	   return(-1);
	  }
	 chr = 0x00;
	 if (*actptr == '.') {
	   actptr++;
	   chr = *actptr;
	   if (!((chr == 'T') || (chr == 'E') || (chr == 'R'))) {
	     AsmError(13);
	     return(-1);
	    }	     
	   actptr++;
	   if (GetNextChar()) {				/*Dateiende?*/
	     AsmError(2);				/*ja, dann Fehler*/
	     return(-1);
	    }
	  }

	 actOLMC = (int)actPin.p_Pin;		/*OLMC-Offset merken*/
	 if (gal_type == GAL16V8)
	   actOLMC -= 12;
	 else
	   actOLMC -= 15;
	 row_offset  = 0;			/*Offset für OR am OLMC*/
	 prevOp	     = 0;			/*vorherige Verknüpfung*/
						/*chr enthält T,R,E oder 0x00*/
	 if (!pass) {				/*Pass 1?*/
	   if ( ((gal_type == GAL16V8)		/*OLMC-Pin?*/
		 && (actPin.p_Pin >= 12) && (actPin.p_Pin <= 19)) ||
		((gal_type == GAL20V8)
		 && (actPin.p_Pin >= 15) && (actPin.p_Pin <= 22)) ) {
	     if (gal_type == GAL16V8)
	       n=actPin.p_Pin-12;
	     if (gal_type == GAL20V8)
	       n=actPin.p_Pin-15;
	     if (chr != 'E') {			/*keine Tristate-Freigabe?*/
						/*mehrfache Zuweisung?*/
	       if ((!OLMC[n].PinType) || (OLMC[n].PinType == INPUT)) {
		 if (actPin.p_Neg)
		   OLMC[n].Active = ACTIVE_LOW;
		 else
		   OLMC[n].Active = ACTIVE_HIGH;

		 switch (chr) {
		   case 'T': { OLMC[n].PinType = TRIOUT;
			       break;
			     }
		   case 'R': { OLMC[n].PinType = REGOUT;
			       break;
			     }
		   case 0x00:{ OLMC[n].PinType = COM_TRI_OUT;
			       break;
			     }
		  }
		}
	       else {
		 AsmError(16);
		 return(-1);
		}
	      }
	     else {
	       if (OLMC[n].PinType == TRIOUT) {
		 if (actPin.p_Neg)		/*bei Tri.-Kontrolle '/'*/
		   actPin.p_Neg = 0;		/*nicht beachten*/
		 if (OLMC[n].TriCon) {		/*Tri.-Kontrolle doppelt?*/
		   AsmError(22);
		   return(-1);
		  }
		 OLMC[n].TriCon = TRICON;	/*Tri.-Kontrolle angegeben*/
		}
	       if ((!OLMC[n].PinType) || (OLMC[n].PinType == INPUT)) {
		 AsmError(17);			/*zuerst Tri.Kon.?*/
		 return(-1);			/*dann Fehler*/
		}
	       if (OLMC[n].PinType == REGOUT) { /*Register? dann Fehler*/
		 AsmError(23);
		 return(-1);
		}
	       if (OLMC[n].PinType == COM_TRI_OUT) { /*kein klares .T?*/
		 AsmError(24);
		 return(-1);
		}
	      }
	    }
	   else {
	     AsmError(15);
	     return(-1);
	    }
	  }



	 if (*actptr != '=') {				/* '=' ?*/
	   AsmError(14);				/*nein, dann Fehler*/
	   return(-1);
	  }	     
loop2:
	 actptr++;
	 if (GetNextChar()) {				/*Dateiende?*/
	   AsmError(2);					/*ja, dann Fehler*/
	   return(-1);
    	  }
	 IsPinName(pinnames,num_of_pins);
	 if (!actPin.p_Pin) {				/*Pinname?*/
	   AsmError(11);				/*nein, dann Fehler*/
	   return(-1);
	  }
	 if (actPin.p_Pin == NC_PIN) {			/*NC als Pinname?*/
	   AsmError(12);				/*ja, dann Fehler*/
	   return(-1);
	  }
	 if (*(pinnames+(long)((actPin.p_Pin-1)*10)) == '/') {
	   actPin.p_Neg = !actPin.p_Neg;	/*Negation bei Pindek.*/
	  }					/*berücksichtigen*/
	 oldline = linenum;
	 if (GetNextChar()) {				/*Dateiende?*/
	   AsmError(2);					/*ja, dann Fehler*/
	   return(-1);
	  }
	 newline = linenum;
	 linenum = oldline;

	 if (!pass) {					/*Pass 1?*/
	   if ( ((gal_type == GAL16V8)			/*OLMC-Pin?*/
		 && (actPin.p_Pin >= 12) && (actPin.p_Pin <= 19)) ||
		((gal_type == GAL20V8)
		 && (actPin.p_Pin >= 15) && (actPin.p_Pin <= 22)) ) {
	     if (gal_type == GAL16V8)
	       n=actPin.p_Pin-12;
	     if (gal_type == GAL20V8)
	       n=actPin.p_Pin-15;
	     if (!OLMC[n].PinType) {			/*OLMC bereits def.?*/
	       OLMC[n].PinType = INPUT;			/*nein, dann Eingang*/
	      }
	     OLMC[n].FeedBack = YES;	/*wenn hinter dem "=" ein OLMC-Pin*/
	    }				/*vorkommt, dann FeedBack benötigt*/
	  }
					/*im 2.Durchlauf Fuse-Matrix*/
					/*erstellen; chr = T,R,E oder 0x00*/
	 if (pass) {
	   if (chr != 'E') {
	     if (!row_offset) {			/*Zeilenoffset noch 0?*/
	       if ( (modus != MODE1) && (OLMC[actOLMC].PinType != REGOUT)) {
	         row_offset = 1;
	        }
	      }
	    }
					/*auf Verstoß gegen Modus prüfen*/
	   pin_num = actPin.p_Pin;
	   if (modus == MODE2) {		/*Verstoß gegen Mode 2?*/
	     if ((gal_type==GAL16V8) && ((pin_num==12) || (pin_num==19))) {
	       AsmError(20);
	       return(-1);
	      }
	     if ((gal_type==GAL20V8) && ((pin_num==15) || (pin_num==22))) {
	       AsmError(21);
	       return(-1);
	      }
	    }
	   if (modus == MODE3) {		/*Verstoß gegen Mode 3?*/
	     if ((gal_type==GAL16V8) && ((pin_num==1) || (pin_num==11))) {
	       AsmError(26);
	       return(-1);
	      }
	     if ((gal_type==GAL20V8) && ((pin_num==1) || (pin_num==13))) {
	       AsmError(27);
	       return(-1);
	      }
	    }
					/*wenn GND dann Zeile auf 0 setzen*/
	   if ((pin_num == num_of_pins) || (pin_num == num_of_pins/2)) {
	     if (actPin.p_Neg) {		/*kein /VCC, /GND zulassen*/
	       AsmError(25);
	       return(-1);
	      }
	     if (!prevOp && (*actptr != '*' ) && (*actptr != '+')) {
	       if (pin_num == num_of_pins/2) {
		 if (chr == 'E')		 /*bei "x.E=GND|VCC" 1.Zeile*/
		   m = ToOLMC[actOLMC] * num_of_col;	/*bei x, x.R, x.T*/
		 else				/*row_offset berücksichtigen*/
		   m = (ToOLMC[actOLMC] + row_offset) * num_of_col;
		 for (n=m; n<m+num_of_col; Jedec.GALLogic[n++]=0);
		}
	      }
	     else {
	       AsmError(28);
	       return(-1);
	      }
	    }
	   else {
	     if (chr == 'E') {
	       if (prevOp == '+') {		/*max. 1 Produktterm*/
	         AsmError(29);			/*mehr, dann Fehler*/
	         return(-1);
	        }	     			/*UND-Verknüpfung erstellen*/
	       SetAND(ToOLMC[actOLMC], pin_num, actPin.p_Neg);
	      }
	     else {
	       if (prevOp == '+') {		/*ODER-Verknüpfung?*/
	         row_offset++;			/*ja, dann nächste Zeile*/
	         if (row_offset == MAX_OR) {	/*zuviele Produktterme?*/
		   if ((modus != MODE1) && (OLMC[actOLMC].PinType != REGOUT)) {
		     AsmError(31);
		     return(-1);
		    }
		   else {
		     AsmError(30);
		     return(-1);
		    }
		  }
	        }				/*UND-Verknüpfung setzen*/
	       SetAND(ToOLMC[actOLMC]+row_offset, pin_num, actPin.p_Neg);
	      }
	    }
					/*kommt noch eine Verknüpfung?*/
	   if ((*actptr != '+') && (*actptr != '*') && (chr != 'E')) { /*nein*/
	     row_offset++;				/*Rest der OLMC- */
	     if (row_offset != MAX_OR) {		/*Zeilen auf 0    */
	       m = (ToOLMC[actOLMC] + row_offset) * num_of_col;
	       for (n=m; n<m+(MAX_OR-row_offset) * num_of_col; n++)
		 Jedec.GALLogic[n] = 0;
	      }
	    }
	  }


	 linenum = newline;

	 if ((*actptr == '+') || (*actptr == '*')) {
	   prevOp = *actptr;
	   goto loop2;
	  }


	 if (strncmp(actptr,(UBYTE *)"DESCRIPTION",11)) {
label1:	   linenum = newline;
	   IsPinName(pinnames,num_of_pins);
	   if (!actPin.p_Pin) {				/*Pinname?*/
	     AsmError(11);				/*nein, dann Fehler*/
	     return(-1);
	    }
	   if (actPin.p_Pin==NC_PIN) {			/*NC als Pinname?*/
	     AsmError(12);				/*ja, dann Fehler*/
	     return(-1);
	    }
	   if (*(pinnames+(long)((actPin.p_Pin-1)*10)) == '/') {
	     actPin.p_Neg = !actPin.p_Neg;	/*Negation bei Pindek.*/
	    }					/*berücksichtigen*/

	   goto loop1;
	  }

	}
					/*Fuse-Matrix der nichtverwendeten*/
					/*OLMCs und der OLMCs die als Eingang*/
					/*programmiert sind auf 0 setzen*/
       for (n=0; n<8; n++) {
	 if ((OLMC[n].PinType == NOTUSED) || (OLMC[n].PinType == INPUT)) {
	   l = ToOLMC[n];
	   l = l * num_of_col;
	   m = l + 8 * num_of_col;
	   for (k=l; k<m; k++)
		Jedec.GALLogic[k] = 0;
	  }
	}
					/*Jedec-Struktur ist fertig (jubel)*/

       asmreadyflag = 1;		/*File fertig assembliert*/

       FreeMem(fbuff, fsize);		/*Puffer für File .pld*/


					/* symbolisches GAL einstellen */
					/*gal_type: aus dem Source-File*/
					/*GALType : eingestelltes GAL*/
       if (Config.AutoGAL == YES) {
	 if (gal_type == GAL16V8)
	   SetGALType (GAL16V8,a_type);
	 if (gal_type == GAL20V8)
	   SetGALType (GAL20V8,a_type);
	 PrintPinNames();
	}

					/* angewählte Files erstellen*/
       if (Config.GenJedec==YES) {
         if (MyFileReq((char *)"JEDEC-Datei schreiben",(char *)".jed",!Config.AutoSave)) {
	   oldMaxFuseAdr = MaxFuseAdr;
	   if (gal_type == GAL16V8) 
	     MaxFuseAdr = MAX_FUSE_ADR16;
	   else
	     MaxFuseAdr = MAX_FUSE_ADR20;
	   WriteJedecFile();
	   MaxFuseAdr = oldMaxFuseAdr;
	  }
	}
       if (Config.GenFuse==YES)
	 WriteFuseFile();
       if (Config.GenChip==YES)
	 WriteChipFile();
       if (Config.GenPin==YES)
	 WritePinFile();
       PrintText((UBYTE *)"Datei wurde assembliert.",1);
       return(0);				/*kein Fehler aufgetreten*/
      }
     else {
       ErrorReq(3);				/*Lesefehler*/
       FreeMem(fbuff,fsize);
       return(-2);
      }
    }
   else {
     ErrorReq(2);				/*kein Speicher*/
     return(-2);
    }
  }
 else return(-1);			/*Abbruch beim FileRequester*/
 }
else return(-1);			/*Abbruch beim AsmRequester*/
}





/* setze eine UND-Verknüpfung (=0) in der Fuse-Matrix
   row     :  Zeile in der die UND-Verknüpfung entstehen soll
   pinnum  :  Pin der UND-verknüpft werden soll
   negation:  0: Pin nicht negiert; 1: Pin negiert ('/')
*/
void SetAND(row, pinnum, negation)
int    row, pinnum, negation;
{
int column;

 if (gal_type == GAL16V8) {
   if (modus == MODE1)
     column = PinToFuse16Mode1[pinnum - 1];
   if (modus == MODE2)
     column = PinToFuse16Mode2[pinnum - 1];
   if (modus == MODE3)
     column = PinToFuse16Mode3[pinnum - 1];
  }
 else {
   if (modus == MODE1)
     column  =  PinToFuse20Mode1[pinnum - 1];
   if (modus == MODE2)
     column  =  PinToFuse20Mode2[pinnum - 1];
   if (modus == MODE3)
     column  =  PinToFuse20Mode3[pinnum - 1];
  }
 Jedec.GALLogic[row * num_of_col + column + negation] = 0;
}




/* Überprüfe ob bei "actptr" ein Pinname steht der in "pinnames" eingetragen
   ist und der kein NC (not connected) ist. Die Anzahl der zu untersuchenden
   Pins steht in "numofpins".
   "actptr" wird auf erstes Zeichen hinter den Pinnamen gestellt
   actPin.p_Pin: Pinnummer oder NC_PIN; 0: kein Pinname
   actPin.p_Neg: Pinname mit '/' = 1;  ohne '/' = 0
*/
void IsPinName(pinnames, numofpins)
UBYTE	*pinnames;
int	numofpins;
{
int	i, k, n;
UBYTE	*oldactptr;

 actPin.p_Neg = 0;		/*Pin-Struktur zurücksetzen*/
 actPin.p_Pin = 0;

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

 n = 0;				/*Länge des möglichen Pinnamens ermitteln*/
 oldactptr = actptr;
 while (isalpha(*actptr) || isdigit(*actptr)) {
   actptr++;
   n++;
  }

 if (n)
   if ((n == 2 ) && !strncmp(oldactptr,(UBYTE *)"NC",2))  /*NC ?*/
     actPin.p_Pin = NC_PIN;				/*ja, dann NC-Pin*/
   else
     for (k=0; k<numofpins; k++) {	 /*List der Pinnamen durchsuchen*/
       i = 0;
       if (*(pinnames+k*10) == '/')
         i = 1;
       if (n == strlen(pinnames+k*10+i))	/*Stringlängen gleich?*/       
         if (!(strncmp(oldactptr,pinnames+k*10+i,n))) {	 /*ja, dann Strings*/
	   actPin.p_Pin = k+1;				 /*vergeichen      */
	   break;
          }
      }
}




/*suche ab "actptr" das nächste Zeichen das kein Space, TAB, LF ist
  Ergebins: 0:Zeichen gefunden, actptr=Zeiger auf dieses Zeichen
	    1:kein Zeichen mehr da
*/
int GetNextChar()
{
 for(;;) {
   switch (*actptr) {
     case 0x0A: {				/*LineFeed*/
       actptr++;
       linenum++;
       break;
      }
     case  ' ':					/*Space*/
     case 0x09: {				/*TAB*/
       actptr++;
       break;
      }
     default  : {
       if ((*actptr>' ') && (*actptr<='~')) return(0);	/*Zeichen gefunden?*/
       else actptr++;
      }
    }
   if (actptr>buffend) return(1);			/*Fileende erreicht?*/
  }
}


/*Zeiger auf zächste Zeile holen
  Ergebins: 0:Zeile gefunden, actptr=Zeiger auf diese Zeile
	    1:File-Ende erreicht
*/
int GetNextLine()
{
 for(;;) {
   if (*actptr == 0x0A) {
     actptr++;
     linenum++;
     return(0);
    }
   if (actptr>buffend) return(1);			/*Fileende erreicht*/
   actptr++;
  }
}




/* gibt Fehlermeldungen des GAL-Assemblers aus
   und gibt Speicher für File-Puffer wieder frei
*/
void AsmError(errornum)
int	errornum;
{
 FreeMem(fbuff,fsize);
 MyRequest(ERR_REQ,(UBYTE *)"Fehler in der Eingabe-Datei");
 PrintErrorLine(linenum);
 switch (errornum) {
   case  1:
     PrintText((UBYTE *)"Zeile 1: GAL-Typ erwartet",1);
     break;
   case  2:
     PrintText((UBYTE *)"unerwartetes Ende der Eingabe-Datei",1);
     break;
   case  3:
     PrintText((UBYTE *)"habe nach '/' Pinnamen erwartet",1);
     break;
   case  4:
     PrintText((UBYTE *)"Pinname hat mehr als 8 Buchstaben und Ziffern",1);
     break;
   case  5:
     PrintText((UBYTE *)"unerlaubtes Zeichen bei Pin-Definition",1);
     break;
   case  6:
     PrintText((UBYTE *)"VCC/GND-Zuweisung nur an den entsprechenden Pins erlaubt",1);
     break;
   case  7:
     PrintText((UBYTE *)"für VCC-Pin Zuweisung VCC erwartet",1);
     break;
   case  8:
     PrintText((UBYTE *)"für GND-Pin Zuweisung GND erwartet",1);
     break;
   case  9:
     PrintText((UBYTE *)"gleicher Pinname kommt mehrfach vor",1);
     break;
   case 10:
     PrintText((UBYTE *)"unerlaubte Verwendung von '/'",1);
     break;
   case 11:
     PrintText((UBYTE *)"unbekannter Pin-Name in den Booleschen Gleichungen",1);
     break;
   case 12:
     PrintText((UBYTE *)"NC (Not Connected) in Booleschen Gleichungen nicht erlaubt",1);
     break;
   case 13:
     PrintText((UBYTE *)"nach '.' wird ein 'T', 'E' oder 'R' erwartet",1);
     break;
   case 14:
     PrintText((UBYTE *)"'=' wurde erwartet",1);
     break;
   case 15:
     PrintText((UBYTE *)"Pin kann nicht als Ausgang programmiert werden",1);
     break;
   case 16:
     PrintText((UBYTE *)"gleicher Pin ist mehrfach als Ausgang definiert worden",1);
     break;
   case 17:
     PrintText((UBYTE *)"Tristate-Kontrolle: Tristate-Ausgang noch nicht definiert",1);
     break;

   case 20:
     PrintText((UBYTE *)"Betriebsmodus 2: Pins 12,19 können nicht als Eingang verwendet werden",1);
     break;
   case 21:
     PrintText((UBYTE *)"Betriebsmodus 2: Pins 15,22 können nicht als Eingang verwendet werden",1);
     break;
   case 22:
     PrintText((UBYTE *)"Tristate-Kontrolle wurde mehrfach angegeben",1);
     break;
   case 23:
     PrintText((UBYTE *)"Tristate-Kontrolle wurde auf Registerausgang angewendet",1);
     break;
   case 24:
     PrintText((UBYTE *)"Tristate-Kontrolle ohne vorheriges '.T'",1);
     break;
   case 25:
     PrintText((UBYTE *)"statt /VCC, /GND bitte GND, VCC verwenden",1);
     break;
   case 26:
     PrintText((UBYTE *)"Betriebsmodus 3: Pins 1,11 für 'Clock' und '/OE' reserviert",1);
     break;
   case 27:
     PrintText((UBYTE *)"Betriebsmodus 3: Pins 1,13 für 'Clock' und '/OE' reserviert",1);
     break;
   case 28:
     PrintText((UBYTE *)"VCC und GND nicht in Booleschen Ausdrücken erlaubt",1);
     break;
   case 29:
     PrintText((UBYTE *)"bei der Tristate-Kontrolle ist nur EIN Produktterm erlaubt",1);
     break;
   case 30:
     PrintText((UBYTE *)"maximal 8 Produktterme erlaubt",1);
     break;
   case 31:
     PrintText((UBYTE *)"maximal 7 Produktterme erlaubt",1);
     break;
   case 33:
     PrintText((UBYTE *)"keine Booleschen Gleichungen vorhanden",1);
     break;
  }
}






/****************************************************************/
/* ab hier stehen die Routinen, die für die Erstellung der      */
/* Dokumentations-Files zuständig sind				*/
/****************************************************************/


/* erstelle das Chip-File*/
void WriteChipFile()
{
extern	char	path;
FILE	*fp;
int	n;

   if (MyFileReq((char *)"Chip-Datei schreiben",(char *)".chp",!Config.AutoSave)) {
     PrintText((UBYTE *)"schreibe Chip-File...",1);
     if (fp=fopen(&path,(UBYTE *)"w")) {
       fprintf(fp,"\n\n");
       WriteSpaces(fp,32);
       if (gal_type == GAL16V8)	fprintf(fp,"GAL16V8\n\n");
       else fprintf(fp,"GAL20V8\n\n");
       WriteSpaces(fp,26);
       fprintf(fp,"-------\\___/-------\n");

       for (n=0; n<num_of_pins/2; n++) {
	 WriteSpaces(fp,25-strlen(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((UBYTE *)" Fehler!",0);
         ErrorReq(8);			/*Datei läßt sich nicht schließen*/
	 return;
	}
      }
     else {
       PrintText((UBYTE *)" Fehler!",0);
       ErrorReq(13);
       return;
      }
     PrintText((UBYTE *)" o.k.",0);
    }
}





/* erstelle das Pin-File*/
void WritePinFile()
{
extern	char	path;
FILE	*fp;
int	k, n, flag;

   if (MyFileReq((char *)"Pin-Datei schreiben",(char *)".pin",!Config.AutoSave)) {
     PrintText((UBYTE *)"schreibe Pin-File...",1);
     if (fp=fopen(&path,(UBYTE *)"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-strlen(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 ((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;
	    }
	  }
							/*OLMC-Pin?*/
	 if ( ((gal_type == GAL16V8) && (n >= 12) && (n <= 19)) ||
	      ((gal_type == GAL20V8) && (n >= 15) && (n <= 22)) ) {
	   if (gal_type == GAL16V8)
	     k = n-12;
	   else
	     k = n-15;
	   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((UBYTE *)" Fehler!",0);
	 ErrorReq(8);			/*Datei läßt sich nicht schließen*/
	 return;
	}
      }
     else {
       PrintText((UBYTE *)" Fehler!",0);
       ErrorReq(13);
       return;
      }
     PrintText((UBYTE *)" o.k.",0);
    }
}



/* erstelle das Fuse-File*/
void WriteFuseFile()
{
extern	char	path;
FILE	*fp;
int	row, col, pin;
int	xor, ac1;

   if (MyFileReq((char *)"Fuse-Datei schreiben",(char *)".fus",!Config.AutoSave)) {
    PrintText((UBYTE *)"schreibe Fuse-File...",1);
    if (fp=fopen(&path,(UBYTE *)"w")) {
       if (gal_type == GAL16V8)
	 pin = 19;
       else
	 pin = 22;
       for (row=0; row<ROW_SIZE; row++) {
	 if (!((row) % 8)) {
	   fprintf(fp,"\n\nPin %2d = ",pin);
	   fprintf(fp,"%s",pinnames+(pin-1)*10);
	   WriteSpaces(fp,13-strlen(pinnames+(pin-1)*10));
	   if (gal_type == GAL16V8) {
	     xor = Jedec.GALXOR[19-pin];
	     ac1 = Jedec.GALAC1[19-pin];
	    }
	   else {
	     xor = Jedec.GALXOR[22-pin];
	     ac1 = Jedec.GALAC1[22-pin];
	    }
	   fprintf(fp,"XOR = %1d   AC1 = %1d",xor,ac1);
	   pin--;	
	  }
	 fprintf(fp,"\n%2d ",row);
	 for (col=0; col<num_of_col; col++) {
	   if (!( (col) % 4) )
	     fprintf(fp," ");
	   if (Jedec.GALLogic[row * num_of_col + col])
	     fprintf(fp,"-");
	   else
	     fprintf(fp,"x");
	  }
	}
       fprintf(fp,"\n\n");
       if (fclose(fp)==EOF) {
	 PrintText((UBYTE *)" Fehler!",0);
	 ErrorReq(8);			/*Datei läßt sich nicht schließen*/
	 return;
	}
      }
     else {
       PrintText((UBYTE *)" Fehler!",0);
       ErrorReq(13);
       return;
      }
     PrintText((UBYTE *)" o.k.",0);
    }
}





/* schreibt Anzahl "numof" Spaces in File "fp"*/
void WriteSpaces(fp, numof)
FILE	*fp;
int	numof;
{
int n;

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

