/*
	AEPROM.C   PROGRAMATOR EPROMOV

Nastavitve:
	 BYTE aligment! , SIGNED char, NO stack verflow test,
	 8088/86 instruction set, Optimize for SIZE, Use REGISTER variables,
	 REGISTER & JUMP optimization, COMPACT memory model
*/


#ifndef __COMPACT__

#error Preberi si zacetek programa

#endif


#include <stdio.h>

#include <dos.h>

#include <stdlib.h>

#include <alloc.h>

#include <time.h>

#include "getopt.c"



void syntax(void)
{ puts(
"\nAltera EPROM programator Verzija 1.01 (C) 1991 Leon Kos, Cerknica, 791084\n"
"Sintaksa: AEPROM [-celwa<ARG>] [-ivhqpmtbr]\n\n"
"Opcije so ena ali vec opcijskih crk z argumentom ali brez, predznacenih z "
"\"-\"\npo standardni UNIX System V notaciji za opcije programov.\n"
"   -w<file> pisi eprom na disk     -l<file>beri BIN datoteko v spomin\n"
"   -cnumber kanal programatorja    -eeprom tip eproma (2732..27512A)\n"
"   -i izpis tekocega stanja        -v preveri praznost eproma\n"
"   -h 21Vpp PGM napetost           -q quiet, brez odvecnih sporocil\n"
"   -m primerjaj spomin in eprom    -a<n|f> normal, fast algoritem\n"
"   -p programiranje eproma         -b beep   -r reset programator\n"
"\n"
"2716,2732 in nekateri 2764 nimajo elektronske signature, zato je potrebna\n"
"rocna nastavitev tipa eproma. 2716 se lahko programira le ce ima 21Vpgm (25V).\n\n"
"Primer: AEPROM -ea -ivqlc:\\xasm51\\mc.bin -pbbb \n"
"\tAVTOdetekcija eproma in kanala izpis informacij, kontrola praznosti,\n"
"\tbranje datoteke v spomin, programiranje eproma in zvok ob koncu.\n"
"Primer: AEPROM -e2764A -c1 -ld:\\aztecc\\plt.bin -m\n"
"\tIzbira eproma in kanala 1, branje podatkov v spomin in primerjava.\n"
"Primer: AEPROM -ea -iwepr12.bin\n"
"\tAVTOdetekcija eproma in kopiranje eproma na disk.");
}

#define BASE  0x0280	/* naslov kanala 0			*/

#define LDIN  (chan+0)	/* Latched Data In offset	IC5	*/

#define LDOUT (chan+3)	/*  --||-- -||- Out offset	IC11	*/

#define CA10   (chan+1)	/* Latched Address register	IC10	*/

#define CA9    (chan+2)	/* Control register		IC9	*/

#define CA8    (chan+0)	/*  --||-- --||--		IC8	*/


/* Napetostni nivoji */

#define VL   0		/* 0 Volts  napetost za V<0..3> oz VD<0..3> */

#define VH   1		/* H nivo */

#define V5   2		/* +5V nivo za VD<0..3> sekcijo		    */

#define VP   3		/* Programska napetost na V<0..3> sekciji   */

#define VZ   3		/* Visoka impendanca za VPGM		    */



/* Prikljucki za EPROM programetor */
/* 	PIN	NET		VALID STATES	- REGISTER*/
#define A9 	ctrl.bit.V0	/* VL|VH|VP 	- RA10*/

#define A10	ctrl.bit.LA0	/* VL|VP 	- RA10*/

#define A11	ctrl.bit.V1	/* VL|V5|VP	- RA9 */

#define A12	ctrl.bit.LA3	/* VL|VH	- RA10*/

#define A13	ctrl.bit.V3	/* VL|V5|VP 	- RA8 */

#define A14	ctrl.bit.LA2	/* VL|VH 	- RA10*/

#define A15	ctrl.bit.VPGM	/* VL|VH|V5|VZ  - RA8 */

#define OE_	ctrl.bit.V2	/* VL|V5|VP 	- RA9 */

#define CE_	ctrl.bit.LA1	/* VL|VH 	- RA10*/

#define OC_	ctrl.bit.TRIS_	/* VL|VH 	- RA8 */

#define RST	ctrl.bit.LA5	/* VL|VH 	- RA9 */

#define CLK	ctrl.bit.LA4	/* VL|VH 	- RA9 */

#define VCC	ctrl.bit.VC	/* VL|VH 	- RA9 */

#define CR8	ctrl.reg.c8	/* 6 bitni register */

#define CR9	ctrl.reg.c9	/* 8 bitni register */

#define CR10	ctrl.reg.c10	/* 6 bitni register */


/* makro funkcije */
#define UD8 outportb(CA8, CR8)	/* Update register 8 */

#define UD9 outportb(CA9, CR9)	/* Update register 9 */

#define UD10 outportb(CA10, CR10)/* Update register 10 */


enum VPP_VOLTAGE {VPP12, VPP12_5, VPP19_7, VPP21};
enum VCC_VOLTAGE {VCC5, VCC6};
enum EPROM_STYLE {M2716=2716, M2732=2732, M2764=2764, M27128=27128,
		 M27256=27256, M27512=27512};
enum READ_OPERATION {READ, COMPARE, VERIFY};
enum ALGORITHM {NORMAL, FAST, INTERACTIVE, FLASHRITE, QUICK_PULSE};

/* public spremenljivke */
int chan;		/* kanal programatorja		*/
long addr;		/* stevec naslovov A<0..15>	*/
unsigned normPW=50;	/* sirina PGM pulza v ms pri norm. nacinu */
unsigned fastPW=1;	/* sirina PGM pulza v ms pri hitrem nacinu */
unsigned char quiet=0;	/* stikalo programiranje brez izpisa */

struct {
	int type;
	char version;
	unsigned char manufacturer_code;
	unsigned char device_code;
	unsigned char vpp, algorithm;
	}eprom = {0,' ',0,0,VPP12_5,NORMAL};

struct {      		/* pomnilniski bazen za tekoce delo */
	unsigned char huge *buffer;
	long size;
	long offset;
	}pool;

union {
   struct {/* polje registrov */
	unsigned c8 		:6;
	unsigned c9		:8;
	unsigned c10		:6;
	}reg;
   struct {/* polje bitov */
	unsigned VPGM 		:2; /* c8 bit_0 */
	unsigned V3		:2;
	unsigned TRIS_		:1;
	unsigned V1		:2; /* c8 bit_5 & c9 bit_0 */
	unsigned LA4		:1;
	unsigned V2		:2;
	unsigned VS2		:1; /* c9 bit_4 */
	unsigned VC		:1;
	unsigned VS1		:1;
	unsigned LA5		:1;
	unsigned LA0		:1; /* c10 bit_0 */
	unsigned LA1		:1;
	unsigned LA2		:1;
	unsigned LA3		:1;
	unsigned V0		:2; /* c10 bit_5_to_6 */
   }bit;
}ctrl={0,0,0};

void print_info(void)	/*izpise tekoce informacije na stdout*/
{
  printf(
  "Kanal %d = %04Xh\t\t"
  "Tip eproma: %d%c\n"
  "Koda proizvajalca: %02X \tProizvajalec: ",
	(chan-BASE)/4, chan, eprom.type, eprom.version,
	 eprom.manufacturer_code);
  switch(eprom.manufacturer_code){
    case 0x01: printf("AMD\n"); break;
    case 0x24: printf("Hitachi\n"); break;
    case 0x20: printf("SGS-Thomson\n"); break;
    case 0x89: printf("Intel\n");break;
    default:   printf("Nepoznan\n"); break;
  }
  printf("Koda eproma: %02X \tEprom: ", eprom.device_code);
  switch(eprom.device_code){
    case 0x18:	printf("2764\n"); break;
    case 0x08:  printf("2764A\n"); break;
    case 0x20:	printf("2764A\n"); break;
    case 0x83:	printf("27128\n");  break;
    case 0x89:	printf("27128A\n"); break;
    case 0x04:	printf("27256A\n"); break;
    case 0x0D:	printf("27512A\n"); break;
    case 0x15:	printf("27C64\n"); break;
    case 0x16:	printf("27C128\n"); break;
    case 0x10:	printf("27C256\n"); break;
    case 0x91:	printf("27C512\n"); break;
    default:	printf("______\n"); break;
  }
  printf("Programska napetost %.1f V\nAlgoritem: ",
    (eprom.vpp==VPP12_5) ? 12.5:21.0);
  switch(eprom.algorithm){
    case NORMAL: 	printf("Normal\n"); break;
    case FAST:	 	printf("Fast Programming\n"); break;
    case INTERACTIVE: 	printf("Interactive\n"); break;
    case FLASHRITE: 	printf("Flashrite\n"); break;
    case QUICK_PULSE: 	printf("Quick Pulse\n"); break;
    default:		printf("None\n");
  }
  printf("Podatki v spominu dolzine %u bytov in offset 0x%04X\n",
	pool.size, pool.offset);
}

void set_vpp(int vpp)	/* nastavi ustrezno programsko napetost */
{
  switch(vpp){
    case VPP12:		ctrl.bit.VS1=VL; ctrl.bit.VS2=VL; break;
    case VPP12_5:	ctrl.bit.VS1=VH; ctrl.bit.VS2=VL; break;
    case VPP19_7:	ctrl.bit.VS1=VL; ctrl.bit.VS2=VH; break;
    case VPP21:		ctrl.bit.VS1=VH; ctrl.bit.VS2=VH; break;
    default: printf("nepravilna programska napetost\n");exit(1);
  }
}

void reset_addr(int eprom) /* zbrise stevec naslovov eproma na 0000h */
{
  CLK=VL; RST=VH; UD9; delay(1); /* brisemo A<0..8> */
  addr=0;
  switch(eprom){
    case M27512:	A15=VL;
    case M27256:	A14=VL;
    case M27128:	A13=VL;
    case M2764:		A12=VL;
    case M2732:		A11=VL;
    case M2716:		A10=VL;
			A9 =VL;
			break;
    default: printf("Tip eproma ni podan\n"); exit(1);
  }
  RST=VL; UD9; delay(1);
}

void inc_addr(int eprom)	/* naslov se poveca za 1 */
{
  CLK=VH; UD9;
  addr++;
  switch(eprom){
    case M27512:	A15= (addr & 0x8000)&&1;
    case M27256:	A14= (addr & 0x4000)&&1;
    case M27128:	A13=((addr & 0x2000)&&1)<<1;
    case M2764:		A12= (addr & 0x1000)&&1;
    case M2732:		A11=((addr & 0x0800)&&1)<<1;
    case M2716:		A10= (addr & 0x0400)&&1;
			A9 =((addr & 0x0200)&&1)<<1;
			break;
    default: printf("Tip eproma ni podan\n"); exit(1);
  }
  UD8;UD10;
  CLK=VL; UD9; /* Povecaj naslov za 1 se za A<0..8> */
}

long get_last_addr(int eprom) /*vrne zadnji naslov v epromu*/
{
  switch(eprom){
    case M2716:  return 2047;
    case M2732:  return 4095;
    case M2764:  return 8191;
    case M27128: return 16383;
    case M27256: return 32767;
    case M27512: return -1;
    default:  printf("Tip eproma ni podan\n"); exit(1);
  }
  return 0;
}


int read_eprom(int eprom, int operation) /* Operation: 0=beri v bazen,*/
{					 /* 1=compare, 2=verify 0xFF  */
					/* ob uspehu vrne 0, sicer vrne -1 */
  long last;
  set_vpp(VPP12);
  CE_=OE_=OC_=VL;
  switch(eprom){
    case M2716: A11=V5;
    case M2732:	A13=V5; break;
    case M2764:  case M27128:
    case M27256: case M27512:	A14=A15=VH; break;
    default: 	printf("Tip eproma ni podan pravilno\n");
		exit(1);

  }
  reset_addr(eprom);
  UD8; UD9; UD10;

  switch(operation){
    case COMPARE: for(;addr<pool.size;inc_addr(eprom))
		    if(inportb(LDIN)!=pool.buffer[addr]) return -1;
		  break;
    case VERIFY: last=get_last_addr(eprom);
		 for(; addr<=last; inc_addr(eprom))
		   if(inportb(LDIN)!=0xFF) return -1;
		 break;
    case READ:last=get_last_addr(eprom);
	    for(; addr<=last; inc_addr(eprom))
	      pool.buffer[addr]=inportb(LDIN);
	    { long c;
	      for(c=last; pool.buffer[c]==0xFF; c--);
	    pool.size=c+1;
	    }
	    break;
  }
  return 0;
}


void prog_normal(int eprom)	/*normalen 50ms programski algoritem*/
{

  if(!quiet){
    printf("Predviden cas programiranja je %.1f minute\n\n",
      (float)pool.size*(float)(1+normPW)/60000.0);
  }

  while(addr<=pool.size+pool.offset){
    if(pool.buffer[addr]==0xFF) goto next; /* FFh ni potrebno programirati*/
    outportb(LDOUT,pool.buffer[addr]);
    if(!(addr%100)&& !quiet) printf("\r%3.1f'",
      (float)(pool.size-addr)*(float)normPW/60000.0);

    switch(eprom){ /*programiramo 1 byte*/
      case M2716:	CE_=VH; UD10; delay(normPW); CE_=VL; UD10; break;
      case M2732:	CE_=VL; UD10; delay(normPW); CE_=VH; UD10; break;
      case M2764:
      case M27128:	A14=VL; UD10; delay(normPW); A14=VH; UD10; break;
      case M27256:
      case M27512:	CE_=VL; UD10; delay(normPW); CE_=VH; UD10; break;
    }
next:
    inc_addr(eprom);
  }
}

unsigned char read_one_byte(int eprom) /* bere byte pri hitrem programiranju */
{
  unsigned char one_byte;
  OC_=VL; UD8;
  switch(eprom){
    case M2716:
    case M2764:
    case M27128:
    case M27256: OE_=VL; UD9; one_byte=inportb(LDIN); break;
    case M2732:
    case M27512: OE_=VL; UD9; CE_=VL; UD10; one_byte=inportb(LDIN); break;
  }
  switch(eprom){
    case M2716:
    case M2764:
    case M27128:
    case M27256: OE_=V5; UD9;  break;
    case M2732:
    case M27512: CE_=VH; UD10; OE_=VP; UD9; break;
  }
  return one_byte;
}


void prog_fast(int eprom)	/*hiter programski algoritem*/
{
  unsigned x;

  VCC=VCC6;  UD9;

  while(addr<=pool.size+pool.offset){
    outportb(LDOUT,pool.buffer[addr]);
    if(!(addr%100)&& !quiet) printf("\r%3.1f%%  ",
      (float)(pool.size-addr)/(float)pool.size*100.0);

    for(x=0;;x++){
      OC_=VH; UD8;
      switch(eprom){ /*programiramo 1 byte 1ms*/
	case M2716:	CE_=VH; UD10; delay(fastPW); CE_=VL; UD10; break;
	case M2732:	CE_=VL; UD10; delay(fastPW); CE_=VH; UD10; break;
	case M2764:
	case M27128:	A14=VL; UD10; delay(fastPW); A14=VH; UD10; break;
	case M27256:
	case M27512:	CE_=VL; UD10; delay(fastPW); CE_=VH; UD10; break;
      }
      if(x==26){
	printf("\rProgramiranje eproma ni uspelo na lokaciji 0x%04X\n",addr);
	return;
      }
      if(read_one_byte(eprom)==pool.buffer[addr]) break;
    }
    OC_=VH; UD8;
    switch(eprom){ /*programiramo 1 byte 3*x casa da je gotovo zapecen*/
      case M2716:	CE_=VH; UD10; delay(3*x*fastPW); CE_=VL; UD10; break;
      case M2732:	CE_=VL; UD10; delay(3*x*fastPW); CE_=VH; UD10; break;
      case M2764:
      case M27128:	A14=VL; UD10; delay(3*x*fastPW); A14=VH; UD10; break;
      case M27256:
      case M27512:	CE_=VL; UD10; delay(3*x*fastPW); CE_=VH; UD10; break;
    }
    inc_addr(eprom);
  }
  VCC=VCC5; UD9;
}


void program(void)	/* glavna rutina ze programiranje eproma */
{
  clock_t start_time, elapsed_time; /*cas v sekundah porabljen za prog. */

  if(!quiet){
    char odgovor;
    fflush(stdin);
    print_info();
    printf("Ali naj programiram? (D:N) >>>");
    scanf("%c",&odgovor);
    if(odgovor!='d' && odgovor!='D') return;
  }

  if(pool.size==0) {
    printf("Ni podatkov v spomin za programiranje eproma\n");
    return;
  }

  start_time=clock();

  if(eprom.vpp==VPP12_5) set_vpp(VPP12_5);
  else set_vpp(VPP21);

  reset_addr(eprom.type);
  if(pool.offset!=0) for(;addr!=pool.offset;inc_addr(eprom.type));

  OC_=VL; VCC=VCC5;


  switch(eprom.type){ /*nastavimo zacetna programska pogoje */
    case M2716:	 A13=A15=V5; UD8; CE_=VL; UD10; OE_=V5; A11=VP; UD9; break;
    case M2732:	 A13=A15=V5; UD8; CE_=VH; UD10; OE_=VP; UD9; break;
    case M2764:
    case M27128: CE_=VL; A14=VH; UD10; OE_=V5; UD9; A15=V5; UD8; break;
    case M27256: CE_=VH; UD10; OE_=V5; UD9; A15=V5; UD8; break;
    case M27512: CE_=VH; UD10; OE_=VP; UD9; break;
    default:  printf("Tip eproma ni podan\n"); exit(1);
  }

  outportb(LDOUT,123);
  OC_=VH; UD8;
  if(inportb(LDIN)!=123){
    printf("Napacen naslov programatorja %xh\n",chan);
    exit(1);
  }

  delay(2); /* pocakaj se kaksno milisekundo da se stvari normalizirajo */

  switch(eprom.algorithm){
    case NORMAL: prog_normal(eprom.type); break;
    case FAST:	 prog_fast(eprom.type); break;
    default: printf("Ostali algoritmi se niso sprogramirani!\n");
		exit(1);
  }

  switch(eprom.type){ /*nastavimo normalne pogoje */
    case M2716:	 A11=VL; OE_=V5; UD9; A13=A15=VL; UD8; CE_=VH; UD10;  break;
    case M2732:	 OE_=V5; UD9; A13=A15=VL; UD8; CE_=VH; UD10; break;
    case M2764:
    case M27128: A15=VL; UD8; A14=VL; UD10; OE_=V5; UD9; break;
    case M27256: A15=VL; UD8; CE_=VH; UD10; OE_=V5; UD9;  break;
    case M27512: OE_=V5; UD9; CE_=VH; UD10; break;
  }
  CE_=VH; OE_=V5; A15=VL; reset_addr(eprom.type); UD8; UD10;

  if(!quiet){
    if(read_eprom(eprom.type,COMPARE))
       printf("\rEprom ni uspesno sprogramiran !\n");
    else {
      printf("\rEprom je sprogramiran !\n");
      elapsed_time = (clock()-start_time)/CLK_TCK;
      printf("Potrebno je bilo %.1f minute",
	 (float)elapsed_time/60.0);
      if(eprom.algorithm!=NORMAL && elapsed_time!= 0){
	printf(" kar je %.0f krat hitreje kot pri normalnem algoritmu.\n",
	  (float)pool.size*(float)normPW/1000.0 / (float)elapsed_time);
      }
      else puts(".\n");
    }
  }
}


int find_chan(void)		/* avtomatsko isce kanal programatorja */
{
  for(chan=BASE;chan<BASE+16*4;chan+=4){
    reset_addr(M27512);
    OE_=V5; CE_=VH; VCC=VCC5;
    UD9; UD10; OC_=VH; UD8;
    outportb(LDOUT,0xAA);
    if(inportb(LDIN)==0xAA){
      outportb(LDOUT,0x55);
      if(inportb(LDIN)==0x55)
	return chan;	/* vrne HEX naslov kanala */
    }
  }
  return -1;		/* ob neuspehu vrne -1 */
}

void detect_device(void)	/* avtomatsko detektira eprom v podnozju */
{				/* ob uspehu nastavi vse potrebne stvari */
  set_vpp(VPP12);
  reset_addr(M27512);
  OC_=VL; UD8;
  VCC=VCC5;
  CE_=VL; OE_=VL; A14=A15=VH; UD9; UD8;
  A9=VP; UD10;
  eprom.manufacturer_code=inportb(LDIN);
  CLK=VH; UD9; CLK=VL; UD9; /* Povecaj naslov za 1*/
  eprom.device_code=inportb(LDIN);
  A9=A14=A15=VL; UD8; OE_=V5; CE_=VH; UD9; UD10;
  reset_addr(M27512);

  eprom.algorithm=NORMAL;

  switch(eprom.device_code){
    case 0x18:	eprom.type=M2764;  eprom.version=' '; eprom.vpp=VPP21; break;
    case 0x08:	eprom.type=M2764;  eprom.version='A'; break;
    case 0x20:	eprom.type=M2764;  eprom.version='A'; break;
    case 0x83:	eprom.type=M27128; eprom.version=' '; break;
    case 0x89:	eprom.type=M27128; eprom.version='A'; break;
    case 0x04:	eprom.type=M27256; eprom.version='A'; break;
    case 0x0D:	eprom.type=M27512; eprom.version='A'; break;
    case 0x15:	eprom.type=M2764;  eprom.version='C'; break;
    case 0x16:	eprom.type=M27128; eprom.version='C'; break;
    case 0x10:	eprom.type=M27256; eprom.version='C'; break;
    case 0x91:	eprom.type=M27512; eprom.version='C'; break;
    default:	eprom.type=0;	   eprom.version='A'; eprom.vpp=VPP12_5;
		printf("Detekcija eproma je vprasljiva!\n");
  }

  switch(eprom.device_code){
    case 0x20: case 0x89: case 0x04: case 0x0D: case 0x15: case 0x16:
    case 0x10: case 0x91: case 0x08: eprom.vpp=VPP12_5; eprom.algorithm=FAST;
  }
}

void test(void)	/* trash */
{
  outportb(CA8,0x00);
  outportb(CA9,0x00);
  outportb(CA10,0x30);
  CR8=CR9=CR10=0;

  OC_=VL;

  OE_=V5;
  UD8;UD9; UD10;
}




void key(void)           /* flush stdin in caka na tipko */
{
  bdos(0x0C,0x0000,0x07);
}

void trim(int chan)	/* nastavljanje trimer potenciometrov programatorja*/
{
  int i;

  printf("ALTERA APLUS programator\n\n"
	 "Nastavljanje napetosti programatorja\n(C) 1991 L.K.\n\n");

  for(i=0;i<16;i++) printf("Ch %2d = %04Xh\t", i, BASE+i*4);

  while(chan<BASE || chan>BASE+15*4){
    fflush(stdin);
    printf("Kanal programatorja (0..15) >>> ");
    scanf("%d",&chan);
  }

  printf("\nNastavi napetost VR2 s trimerjem R30 na 5.33V\n");
  outportb(chan+2,0); key();
  printf("Napetost VR2 je sedaj cca 6.23V\n");
  outportb(chan+2,0xFF); key();
  printf("Zdaj pa je spet 5.33V\n\n");
  outportb(chan+2,0); key();

  printf("Nastavi napetost VR1 s trimerjem R27 na 12.5V\n");
  outportb(chan+2,0x40); key();
  printf("Nastavi napetost VR1 s trimerjem R28 na 21.1V\n");
  outportb(chan+2,0x50); key();
  printf("Nastavi napetost VR1 s trimerjem R32 na 19.7V\n");
  outportb(chan+2,0x10); key();
  printf("Napetost VR1 mora sedaj biti 12.0V\n\n");
  outportb(chan+2,0x00); key();

  printf("Meri programsko napetost na uporu R23\n"
	 "Zdaj mora biti napetost 0V\n");
  outportb(chan,0x00); key();
  printf("Zdaj je 5.0V\n");
  outportb(chan+2,0x00); outportb(chan,0x01); key();
  printf("Zdaj je 5.9V\n");
  outportb(chan+2,0x20); outportb(chan,0x01); key();
  printf("Zdaj je 12.0V\n");
  outportb(chan+2,0x20); outportb(chan,0x02); key();
  printf("Zdaj je 12.5V\n");
  outportb(chan+2,0x40); outportb(chan,0x02); key();
  printf("Zdaj je 19.7V\n");
  outportb(chan+2,0x10); outportb(chan,0x02); key();
  printf("Zdaj je 21.1V\n");
  outportb(chan+2,0x50); outportb(chan,0x02); key();
  printf("Zdaj je 5.3V plavajoce napetosti Z=50kohm\n");
  outportb(chan+2,0x00); outportb(chan,0x03); key();
}



void main(int argc, char *argv[])
{
 char *optionS="e:tc:zl:ivhqpw:mbra:";
 int opt;
 FILE *fp;


 if(argc==1) {
   syntax();
   exit(0);
 }


 if((pool.buffer=(unsigned char *)farmalloc(0x10000L))==NULL){
    perror("64k farmalloc ");		/*rezerviramo pomnilnik za bazen*/
    exit(errno);
 }

 pool.offset=0;
 chan=find_chan();

 SW='-';	/* opijsko stikalo*/

 while((opt=getopt(argc,argv,optionS))!=EOF){
   switch(opt) {
     case 't':	trim(chan);
		exit(0);
     case 'c':  if(sscanf(optarg,"%d",&chan)==1)
		  chan=BASE+4*chan;
		if(chan<BASE || chan>BASE+15*4) {
		  printf("Napacen kanal programatorja #%d (0..15)",chan);
		  exit(1);
		}
		chan=find_chan();
		CR8=CR9=CR10=0; reset_addr(M27512);
		OE_=V5; CE_=VH; UD8;UD9;UD10;
                break;
     case 'h':	eprom.vpp=VPP21;
		break;
     case 'q':	quiet++; break;
     case 'e':  eprom.version=' ';
		if(sscanf(optarg,"%d%c",&eprom.type,&eprom.version)==0 &&
		   optarg[0]=='a') detect_device();
		else {
		    if(eprom.version==-1)
		      eprom.vpp=VPP21;
		    else
		      eprom.vpp=VPP12_5;
		  switch(eprom.type){
		    case M2716: case M2732: eprom.algorithm=NORMAL; break;
		    default: eprom.algorithm=FAST;
		  }
		}
		break;

     case 'l':  /* bere binarno datoteko v bazen */
		if((fp=fopen(optarg,"rb"))==NULL){
		  perror(optarg);
		  exit(errno);
		}
		pool.size=0;
		while(!feof(fp))
		  pool.buffer[pool.size++]=(unsigned char)fgetc(fp);
		pool.size--;
		if(errno) {
		  perror(optarg); exit(errno);
		}
		fclose(fp);
		break;
     case 'w':  /*pise vsebino eproma v bazen in na disk*/
		if((fp=fopen(optarg,"wb"))==NULL){
		  perror(optarg);
		  exit(errno);
		}
		read_eprom(eprom.type,READ);
		for(addr=0;addr<pool.size;addr++)
		  if(fputc(pool.buffer[addr],fp)==EOF){
		    perror(optarg);
		    exit(errno);
		  }
		fclose(fp);
		break;
     case 'i':	print_info();
		break;
     case 'v':  if(read_eprom(eprom.type,VERIFY))
		  printf("Eprom ni prazen!\n");
		else
		  printf("Eprom je prazen.\n");
		break;
     case 'p':	program(); break;
     case 'z':	test();
		break;
     case 'm':  if(read_eprom(eprom.type,COMPARE))
		  printf("Eprom in podatki niso enaki\n");
		else
		  printf("Eprom in podatki so identicni.\n");
		break;
     case 'b':  sound(1000); delay(200); nosound();
     case 'r':  CR8=CR9=CR10=0; reset_addr(M27512);
		OE_=V5; CE_=VH; UD8;UD9;UD10;
		break;
     case 'a':  switch(optarg[0]){
		  case 'n': eprom.algorithm=NORMAL; break;
		  case 'f': eprom.algorithm=FAST; break;
		  default: printf("Nepravilen algoritem %c.\n"
			"Pravilno je -an ali -af .\n",optarg[0]);
		}
		break;
   }
 }
 CR8=CR9=CR10=0; reset_addr(M27512);
 OE_=V5; CE_=VH; UD8;UD9;UD10;
 farfree((void *)pool.buffer);
}