#include "willepr.h"

//--------------------------------
//            MCS-51
//--------------------------------
class Eprom
{
    private:

    public:
	unsigned long size;
	unsigned int  type1,type2,type3;
	unsigned int  tWP,tWC;
	unsigned int  sector_size;
	unsigned char flag_err;
}Epr;

class mcs51
{
    private:
	unsigned long P2_6,P2_7,P3_6,P3_7;
	unsigned long P33,P34,P35,P37;   	   // AT89Cx051
	unsigned long Prog,Clk,Rst,Pwrite,Pread,Plb1,Plb2,
		      Perase,Psig;
	unsigned long mode_wr,mode_rd,mode_erase, mode_sig,
		      mode_bit1, mode_bit2, mode_bit3;
	unsigned char p12,d;
	unsigned char Dout(unsigned char data);    // arrange D0-D7
	unsigned char Din(unsigned char data);
	void lockbit(unsigned long bit);

    public:
	unsigned char sig30,sig31,sig32;
	unsigned int  at89s,tWP,tWC,Pulses,type;
	void initl_code(void);
	void write_code(unsigned long address,unsigned char data);
	unsigned char read_code(unsigned long address);
	void write_mode_LB(int mode);
	void erase_chip(void);
	void read_sign(void);
	void inc_adres(void);  // AT89Cx051
	void setup(void);
}AT89Cxx;

void mcs51::initl_code(void)
{
	P2_6 = 0x8000;
	P2_7 = 0x10000;
	P3_6 = 0x20000;
	P3_7 = 0x40000;
	mode_wr   = P2_7|P3_6|P3_7;	// 0111
	mode_rd   = P3_6|P3_7;		// 0011
	mode_erase = P2_6;              // 1000
	mode_sig  = 0x00;               // 0000
	mode_bit1 = P2_6|P2_7|P3_6|P3_7;// 1111
	mode_bit2 = P2_6|P2_7;          // 1100
	mode_bit3 = P2_6|P3_6;          // 1010

	// AT89Cx051
	P33 = 0x00040;
	P34 = 0x00100;
	P35 = 0x00080;
	P37 = 0x00200;
	Prog = 0x40000;
	Rst  = 0x20000;
	Clk  = 0x18000;
	Pwrite = P34|P35|P37;
	Pread  = P35|P37;
	Plb1   = P33|P34|P35|P37;
	Plb2   = P33|P34;
	Perase = P33;
	//----------------

	at89s = 0;
	tWP = 10;
	tWC = 2200;
	p12 = 0xff;
	Pulses = 1;
	type = DIP40;
}

//--------------- AT89Cx051 -------------
void mcs51::inc_adres(void){
     read;assert;r_adres_28C(Pwrite|Clk);ms_delay(10);
     pgrlo;assert; ms_delay(10); pgrhi;assert;
     ms_delay(10);
}

unsigned char mcs51::Dout(unsigned char data){

       unsigned ch = 0x00;     // arrange D0-D7 Data to AT89Cx051
       ch |= ((data >> 4) & 0x08);   // D7 -> D3
       ch |= ((data >> 4) & 0x04);   // D6 -> D2
       ch |= ((data >> 1) & 0x10);   // D5 -> D4
       ch |= ((data >> 3) & 0x02);   // D4 -> D1
       ch |= ((data << 2) & 0x20);   // D3 -> D5
       ch |= ((data >> 2) & 0x01);   // D2 -> D0
       ch |= ((data << 5) & 0x40);   // D1 -> D6
       ch |= ((data << 7) & 0x80);   // D0 -> D7
       return(ch);
}

unsigned char mcs51::Din(unsigned char data){

       unsigned char ch2 = 0x00;   // arrange D0-D7 from AT89Cx051
       ch2 |= ((data << 4) & 0x80);   // D7 <- D3
       ch2 |= ((data << 4) & 0x40);   // D6 <- D2
       ch2 |= ((data << 1) & 0x20);   // D5 <- D4
       ch2 |= ((data << 3) & 0x10);   // D4 <- D1
       ch2 |= ((data >> 2) & 0x08);   // D3 <- D5
       ch2 |= ((data << 2) & 0x04);   // D2 <- D0
       ch2 |= ((data >> 5) & 0x02);   // D1 <- D6
       ch2 |= ((data >> 7) & 0x01);   // D0 <- D7
       return(ch2);
}

void mcs51::setup(void){
     initl_code();
     type = DIP20;
     setup_28C();
     read;assert;r_adres_28C(Rst);ms_delay(20);
     pgrlo;assert;
     ms_delay(30000);  // RST,XTAL1 = LOW
     ms_delay(30000);  // delay 60 mS
     pgrhi;assert;
     ms_delay(20);

}
// ----- end sub. AT89Cx051 -----
//
// ----- AT89Cxx,AT89Sxx,AT89Cx051 -----

void mcs51::write_code(unsigned long address,unsigned char data)
{
	int loop;

	pgrhi;assert;
	if(p12==0xff){
		ppon;assert;
	} else p12 = 00;

	pgrhi;assert;
	switch(type) {
		case DIP40: read;assert;r_adres_28C(address|mode_wr);ms_delay(15);
			 write;assert;ms_delay(10);outportb(poort,data);ms_delay(15);
			 break;
		case DIP20: read;assert;r_adres_28C(Pwrite|Prog);ms_delay(15);
			 write;assert;ms_delay(10);
			 outportb( poort,Dout(data) ); ms_delay(15);
			 break;
	}

	for(loop = Pulses; loop > 0; loop--) {
		pgrlo;assert; ms_delay(tWP); pgrhi;assert;
		ms_delay(20);
	}
	ppoff;assert;adrlo;clklo;clalo;asadres;
	ms_delay(tWC);
}

void mcs51::lockbit(unsigned long bit)
{
	pgrhi;assert;
	if(p12==0xff){
		ppon;assert;
	} else p12 = 00;
	switch(type) {
		case DIP40: read;assert; r_adres_28C(bit);ms_delay(15);
			 write;assert;ms_delay(10);
			 outportb(poort,d);ms_delay(15);
			 break;
		case DIP20: read;assert; r_adres_28C(bit|Prog);ms_delay(15);
			 break;
	}
	pgrlo;assert; ms_delay(tWP);pgrhi;assert;
	ms_delay(15);
	ppoff;assert;adrlo;clklo;clalo;asadres;
	ms_delay(tWC);
}

void mcs51::write_mode_LB(int mode)
{
	switch(type) {
		case DIP40:if(at89s == 0) {
				d = read_code(0);
				switch (mode) {  //AT89Cxx
					case 1: lockbit(mode_bit1); break;
					case 2: lockbit(mode_bit1);
						lockbit(mode_bit2); break;
					case 3: lockbit(mode_bit1);
						lockbit(mode_bit2);
						lockbit(mode_bit3); break;
				}
			}
			else { switch (mode) {  // AT89Sxx
					case 1: d = 0x7F;lockbit(mode_bit3); break;
					case 2: d = 0x3F;lockbit(mode_bit3); break;
					case 3: d = 0x1F;lockbit(mode_bit3); break;
				}
			}break;
		case DIP20: switch(mode) {  //AT89Cx051
				case 1: lockbit(Plb1); break;
				case 2: lockbit(Plb1);
					lockbit(Plb2); break;
			}break;
	}
}

unsigned char mcs51::read_code(unsigned long address)
{
	unsigned char ch;

	read;pgrhi;ppoff;assert;
	ms_delay(10);
	switch(type) {
		case DIP40:if(at89s == 1){
				ppon;assert;
				ms_delay(30);
			}
			r_adres_28C(address|mode_rd);ms_delay(20);
			ppoff;assert;
			ch = in_word_28C();
			break;

		case DIP20:r_adres_28C(Pread);ms_delay(20);
			ch = Din(in_word_28C()) ;
			break;
	}
	return(ch);
}

void mcs51::erase_chip(void)
{
	switch (type) {
		case DIP40: read;pgrhi;assert;r_adres_28C(mode_erase);
			break;
		case DIP20:read;pgrhi;assert;r_adres_28C(Perase|Prog);
			break;
	}
       write;assert;
       ms_delay(20);
       if(p12){ppon;assert;}
       ms_delay(40);
       pgrlo;assert;ms_delay(25000);   // 25 mS
       pgrhi;assert;
       ms_delay(40); ppoff;assert;
       ms_delay(20000);
}

void mcs51::read_sign(void)
{
	pgrhi;read;assert;
	ms_delay(100);
	switch(type) {
		case DIP40:r_adres_28C(0x30);ms_delay(10);sig30=in_word();
			if(sig30 == 0xFF) {
				ppon;assert; ms_delay(20);
				r_adres_28C(0x30);ms_delay(10);sig30=in_word();
			}
			r_adres_28C(0x31);ms_delay(10);sig31=in_word();
			r_adres_28C(0x32);ms_delay(10);sig32=in_word();
			break;
		case DIP20:
			r_adres_28C(0x00);ms_delay(20);sig30=Din(in_word());
			inc_adres();
			r_adres_28C(0x00);ms_delay(10);sig31=Din(in_word());
			inc_adres();
			r_adres_28C(0x00);ms_delay(10);sig32=Din(in_word());
			break;
	}
	p12 = sig32;
	ms_delay(20);
	ppoff;assert;
	ms_delay(100);
}

//----------------- End object class MCS51 ------------------

void verify_AT89C(void)
{		//DW: added void

	long e=0, t=aantal/52, i, y;
	unsigned char g,q;

	if(st!=0)getoff();
	show_action("Verifying chip",BLUE);

	if(eep == 10) AT89Cxx.setup();		// AT89Cx051
	else setup_28C();
	q = 1;

	if(grot>=aantal)grot=aantal-1;
	for(i=0;i<=grot;i++){
		y = i;
loop_comp:
		g = AT89Cxx.read_code(i);
		if( g!=*(rombuf+XMSCurrent(y,0))){		// DW: Made this XMS-aware
		      if(q == 25){
			show_error(i,st,g);
			break;
		       }
		       q++; goto loop_comp;
		}
		if(eep == 10) AT89Cxx.inc_adres();	// AT89Cx051

		if(e==t){ tcu_wprintf(&window4,"þ");e=0;}
		e++;
		if(rb){	if(kbhit()){ if(getch()==27) break;}}
		q = 1;
	}
	reset_timer(); tcu_warnbeep(); setup_timer(0xb0);
	tcu_close_window(&window4);
	power_down();/*assert;*/          //ARW: was powoff
}

void prog_AT89C(void)
{
	long e=0, t=aantal/52,y, i=0;
	unsigned char g,at;
	int q=1;

	if(st!=0)getoff();
	show_action("programming chip");

	if(eep == 10) AT89Cxx.setup();		// AT89Cx051
	else setup_28C();

	Epr.flag_err = OFF;
	if(grot>=aantal)grot=aantal-1;
	for(i=0;i<=grot;i++){

		g=*(rombuf+XMSCurrent(i,0));
w89:
		AT89Cxx.write_code(i+st,g);
		at = AT89Cxx.read_code(i+st);
		if(at!=g){
		     if(q>10){
			    tcu_wprintf(&window4," \n");
			    show_error(i,st,g);
			    Epr.flag_err = ON;
			    goto P89E;
			}
			else {q++; goto w89;}
		}
		if(eep == 10) AT89Cxx.inc_adres();	// AT89Cx051

		if(e==t){tcu_wprintf(&window4,"þ");e=0;}
		e++;
		q=1;
	}
P89E:
	tcu_close_window(&window4);
	if(!Epr.flag_err) verify_AT89C();
	power_down();/*assert;*/        //ARW: was powoff
}

void erase_AT89C(void)
{           // DW: added void
      show_action("Erasing chip");

      setup_28C();
      AT89Cxx.erase_chip();
      power_down();
      tcu_wprintf(&window4,"              -----erase completed-----");getch();
      tcu_close_window(&window4);
}

void CRead_AT89C(void)
{		//DW: added void

	long e=0;long t=aantal/52;
	long i,y;

	ClearBuf();		// DW: Made this XMS-aware	memset(rombuf,0,aantal);
	if(st!=0)getoff();
	show_action("reading chip",BLACK);

	if(eep==10) AT89Cxx.setup();   // AT89Cx051
	else setup_28C();

	for(i=0;i<aantal;i++){
		y = i;
		r_adres(i);

		rombuf[XMSCurrent(y,1)]=AT89Cxx.read_code(i);
		if(eep == 10) AT89Cxx.inc_adres();     	// AT89Cx051
		if(e==t){tcu_wprintf(&window4,"þ");e=0;}
		e++;
		if(rb){if(kbhit()){if(getch()==27) break;}}
	}
	reset_timer(); tcu_warnbeep(); setup_timer(0xb0);
	grot=aantal;
	tcu_close_window(&window4);
	power_down();
	strcpy(statbuf,"Chip Dump");winstat();
}

void lockbit_AT89C(void)
{		//DW: added void
	int i,j;

	tcu_display_menu(&LockBit89C,17,10);
	i=tcu_read_menu_selection (&LockBit89C);
	tcu_remove_menu (&LockBit89C);
	switch (i) {
	       case 2:  show_action ("Lock bit 1");break;
	       case 3:  show_action ("Lock bit 1&2");break;
	       case 4:	show_action ("Lock bit 1&2&3");break;
	}
	if(i>1) {
		if(eep == 10) AT89Cxx.setup();
		else setup_28C();
		AT89Cxx.write_mode_LB(i-1);
		ms_delay(30000);
		power_down();
		reset_timer(); tcu_warnbeep(); setup_timer(0xb0); getch();
		tcu_close_window(&window4);
	}
}

void empty_AT89C(void)
{		//DW: added void
	long e=0, t=aantal/52, i;
	unsigned char h;
	if(st!=0)getoff();
	show_action("CheckEmpty chip");

	if(eep==10) AT89Cxx.setup();
	else setup_28C();

	for(i=0;i<aantal;i++){
rep_check:
		h = AT89Cxx.read_code(i+st);
		if(h!=0xff){
			power_down();
			tcu_wprintf(&window4,"Error at 0x%lX",i+st);		// DW: added offset
			reset_timer();tcu_warnbeep();
			setup_timer(0xb0);getch();
			break;
		}
		if(eep == 10) AT89Cxx.inc_adres();     // AT89Cx051
		if(e==t){tcu_wprintf(&window4,"þ");e=0;}
		e++;
		if(rb){if(kbhit()){if(getch()==27) break;}}
	}
	reset_timer(); tcu_warnbeep(); setup_timer(0xb0);
	tcu_close_window(&window4);
	power_down();/*assert;*/               //ARW: was powoff
}

void id_AT89C(void)
{           // DW: added void
      show_action("Read Signature chip",BLACK);

      setup_28C();
      AT89Cxx.read_sign();
      power_down();
      tcu_wprintf(&window4," Signature = %2X%2X%2X",
		  AT89Cxx.sig30,AT89Cxx.sig31,AT89Cxx.sig32);
      getch();
      tcu_close_window(&window4);

      if(eep == 10) AT2051_r(1);
      else  MCS51_r(1);
}

void MCS51_r(int id)
{		//DW: added void
	int i,temp;

	Dip(13); temp = eep; eep = 8;
	if(id == 0) {
		tcu_display_menu(&MCS51,29,14);
		i=tcu_read_menu_selection (&MCS51);
		tcu_remove_menu (&MCS51);
	} else i = 1;

	AT89Cxx.initl_code();
	AT89Cxx.at89s = 0;
	AT89Cxx.tWP = 10;
	AT89Cxx.Pulses = 1;
	AT89Cxx.type = DIP40;
	if(i == 1) {
		setup_28C();
		AT89Cxx.read_sign();
		switch(AT89Cxx.sig30) {
		    case 0x1E: switch(AT89Cxx.sig31){ //ATMEL
					case 0x61:              //AT89LV51
					case 0x51: i=2; break;  //AT89C51
					case 0x62:              //AT89LV52
					case 0x52: i=3; break;  //AT89C52
					case 0x65:              //AT89LV55
					case 0x55: i=4; break;  //AT89C55
					case 0x82:              //AT89LS8252
					case 0x72: i=5; break;  //AT89S8252
					case 0x63:              //AT89LS53
					case 0x53: i=6; break;  //AT89S53
					case 0x87:switch(AT89Cxx.sig32) {
							case 0x01: i=2;break;	// AT87F51
							case 0x02: i=3;break;	// AT87F52
						  }
				 }break;
		    case 0x89: switch(AT89Cxx.sig31) { // Intel
				       case 0x57: i=7;break;	//i87C51   4KB
				       case 0x58: i=9;break;	//i87C54   16KB
				       case 0x50: i=8;break;	//i87C51FA 8KB
				       case 0x5F: i=9;break;    //i87C51FB 16KB
				}break;

		 }
	}
	power_down();

	switch(i){
		case 2:if( Newaantal(0x1000)) strcpy(statdev,"AT89C51 (4KB)"); break;
		case 3:if( Newaantal(0x2000)) strcpy(statdev,"AT89C52 (8KB)"); break;
		case 4:if( Newaantal(0x5000)) strcpy(statdev,"AT89C55 (20KB)"); break;
		case 5:if( Newaantal(0x2800)) {
			     strcpy(statdev,"AT89S8252 (8K+2K)");
			    AT89Cxx.at89s = 1; AT89Cxx.tWP = 30;
			}break;
		case 6:if( Newaantal(0x3000)){
			    strcpy(statdev,"AT89S53 (12KB)");
			    AT89Cxx.at89s = 1; AT89Cxx.tWP = 30;
			 }break;
		case 7:if( Newaantal(0x1000)){
			    strcpy(statdev,"i8xC51 4KB");
			    AT89Cxx.tWP = 110; AT89Cxx.Pulses = 25;
			 }break;
		case 8:if( Newaantal(0x2000)){
			    strcpy(statdev,"i8xC52 8KB");
			    AT89Cxx.tWP = 110; AT89Cxx.Pulses = 25;
			 }break;
		case 9:if( Newaantal(0x4000)){
			    strcpy(statdev,"i8xC54 16KB");
			    AT89Cxx.tWP = 110; AT89Cxx.Pulses = 25;
			 }break;
		case 10:if( Newaantal(0x8000)){
			    strcpy(statdev,"i8xC58 32KB");
			    AT89Cxx.tWP = 110; AT89Cxx.Pulses = 25;
			 }break;
		default: strcpy(statdev,"xxxxxx");
			 eep = temp;
			 break;
	} winstat();
}

void AT2051_r(int id)
{		//DW: added void
	int i,temp;

	Dip(14); temp = eep; eep = 10;
	if(id == 0) {
		tcu_display_menu(&AT2051,29,16);
		i=tcu_read_menu_selection (&AT2051);
		tcu_remove_menu (&AT2051);
	} else i = 1;

	AT89Cxx.initl_code();
	AT89Cxx.at89s = 0;
	AT89Cxx.tWP = 12;
	AT89Cxx.Pulses = 1;
	AT89Cxx.type = DIP20;
	if(i == 1) {
		AT89Cxx.setup();
		AT89Cxx.read_sign();
		if(AT89Cxx.sig30 == 0x1E ) {
		    switch(AT89Cxx.sig31){
			case 0x11: i=2; break;
			case 0x21: i=3; break;
			case 0x41: i=4; break;
		     }
		 }
	}
	power_down();

	switch(i){
		case 2:if( Newaantal(0x400))  strcpy(statdev,"AT89C1051 (1KB)");break;
		case 3:if( Newaantal(0x800))  strcpy(statdev,"AT89C2051 (2KB)");break;
		case 4:if( Newaantal(0x1000)) strcpy(statdev,"AT89C4051 (4KB)"); break;
		default: strcpy(statdev,"xxxxxx");  eep = temp;  break;
	} winstat();
}
