/* 
 * File:   PIC 16 to 32, a 32 bit pseudo CPU for PIC16
 * Author: dario
 *
 * Created on 21 novembre 2017, 13.02
 *	23.11.17 
 *
 * il formato delle nuove istruzioni, che occupano TUTTE 2 word, è:
 *   1°word: 000000 -> vecchio opcode, 
 *     i cui 6bit alti si trovano nel byte basso di questa word
 *     e gli 8bit bassi nel byte basso di quella seguente
 *   1°word: 100000 -> nuovo opcode, che prevede
 *     tutte le operazioni LITERAL a 32bit su W4
 *     rotate/shift a 32bit su W4
 *     inc/dec su W4
 *     branch e call W4
 */

#include <xc.h>

// PIC16F18854 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = HS     // External Oscillator mode selection bits (HS (crystal oscillator) above 4MHz; PFM set to high power)
#pragma config RSTOSC = EXT1X   // Power-up default value for COSC bits (EXTOSC operating per FEXTOSC bits)
#pragma config CLKOUTEN = OFF   // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
#pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)

// CONFIG2
#pragma config MCLRE = ON       // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config LPBOREN = OFF    // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = ON       // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
//#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
//#pragma config ZCD = OFF        // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)

// CONFIG3
//#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = ON        // WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
//#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
//#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG4
#pragma config WRT = OFF        // UserNVM self-write protection bits (Write protection off)
//#pragma config SCANE = available// Scanner Enable bit (Scanner module is available for use)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming)

// CONFIG5
#pragma config CP = OFF         // UserNVM Program memory code protection bit (Program Memory code protection disabled)
#pragma config CPD = OFF        // DataNVM code protection bit (Data EEPROM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.



#include "pic16232.h"

#define ID_CARRY 0x1
#define ID_DIGITCARRY 0x2
#define ID_ZERO 0x4
#define ID_PD 0x8
#define ID_TO 0x10
#define ID_RP0 0x20
#define ID_RP1 0x40
#define ID_IRP 0x80
#define ID_INTERRUPT 0x100


union TWOBYTES {
	unsigned int word;
	struct {
		unsigned char byte1;
		unsigned char byte2;
		} bytes;
	};
  
union FOURBYTES {
  unsigned long along;
	struct {
  	unsigned int word1;
  	unsigned int word2;
    } words;
	struct {
		unsigned char byte1;
		unsigned char byte2;
		unsigned char byte3;
		unsigned char byte4;
		} bytes;
	} Pipe;
  
void test_code(void);

#define RESET_ADDRESS &test_code  //0
#define BASE_FLASH_MEMORY 0   //0x2000
#define BASE_RAM_MEMORY 0x100
  
signed char fExit=0;
unsigned char debug=0;
const unsigned char *p=(const unsigned char *)BASE_FLASH_MEMORY;      // offset programma
unsigned char *p1=(unsigned char *)BASE_RAM_MEMORY;
unsigned char DoIRQ=0;

const unsigned char bitmask[8]={1,2,4,8,16,32,64,128};

/*
 * 
 */
void main(void) {

	Emulate();
  CLRWDT();

//	if((i=open("c64basic.bin",O_BINARY | O_RDONLY)) >= 0) {
//    }
  
  }


unsigned char _b=0;      // su enhanced sarebbero mappati in RAM!
union FOURBYTES _w;
union TWOBYTES _pc=0;
unsigned char _pch;
unsigned char _s=0;   // lo Stack è mappato in RAM su enhanced (16), o interno su normale (8)
struct REGISTRO_P {
  unsigned int Carry: 1;
  unsigned int DigitCarry: 1;
  unsigned int Zero: 1;
  unsigned int PowerDown: 1;
  unsigned int TimeOut: 1;
#if !defined(BSR)
  unsigned int RP0: 1;
  unsigned int RP1: 1;
  unsigned int IRP: 1;
#endif 
  unsigned int Interrupt32: 1;
  } _p;
#if defined(BSR)
unsigned char _saved_bsr;    // mappati anche in RAM
union FOURBYTES _saved_w;
struct REGISTRO_P _saved_status;
union TWOBYTES _saved_fsr1,_saved_fsr2;
unsigned char _saved_pch;
#endif

  
unsigned char GetValue(unsigned int t) {
	register unsigned char i;

#if defined(BSR)
#else
  if(_p.IRP) {
    j |= 0x100;
    }
#endif
	if(t >= 0x8000) {
		i=*(p+t);
		}
	else if(t >= 0x7000) {
  // a 0x7000 c'è EEprom su enhanced, solo read!
		i=*(unsigned long *)(p1+t);
		}
#if defined(BSR)
	else if(t >= 0x2000) {    // linear addressing
    t-=0x2000;
		}
#endif
	else if(t < 0x20) {
		i=*(p1+t);
		}
	else {
		i=*(p1+t);
		}
	return i;
	}

unsigned int GetIntValue(unsigned int t) {
	register unsigned int i;

#if defined(BSR)
#else
  if(_p.IRP) {
    j |= 0x100;
    }
#endif
	if(t >= 0x8000) {
		i=*(unsigned int *)(p+t);
		}
	else if(t >= 0x7000) {
  // a 0x7000 c'è EEprom su enhanced, solo read!
		i=*(unsigned long *)(p1+t);
		}
#if defined(BSR)
	else if(t >= 0x2000) {    // linear addressing
    t-=0x2000;
		}
#endif
	else if(t < 0x20) {
		i=*(unsigned int *)(p1+t);
		}
	else {
		i=*(unsigned int *)(p1+t);
		}
	return i;
	}

unsigned char GetValue7(unsigned char t) {
	register unsigned int j;

  t &= 0x7f;
#if defined(BSR)
  j = _b;
  j <<= 7;
  j |= t;   // & 0x7f
#else
  j = t;
  if(_p.RP0) {
    j |= 0x80;
    }
  if(_p.RP1) {
    j |= 0x100;
    }
#endif
	if(j == 0) {      // GESTIRE le cose comuni a tutti i banchi!
    j=GetIntValue(4);
		}
#if defined(BSR)
	else if(j == 1) {
    j=GetIntValue(6);
		}
#endif
	else if(j < 0x20) {
		}
	else {
		}
	return *(p1+j);
	}

unsigned long GetValue7L(unsigned char t) {
	register unsigned long i;
	register unsigned int j;

  t &= 0x7c;
#if defined(BSR)
  j = _b;
  j <<= 7;
  j |= t;   // & 0x7f
#else
  j = t;
  if(_p.RP0) {
    j |= 0x80;
    }
  if(_p.RP1) {
    j |= 0x100;
    }
#endif
	if(j == 0) {      // GESTIRE le cose comuni a tutti i banchi!
    j=GetIntValue(4);
		}
#if defined(BSR)
	else if(j == 1) {
    j=GetIntValue(6);
		}
#endif
	else if(j < 0x20) {
		}
	else {
		}
	return *((unsigned long *)(p1+j));
	}

unsigned long GetLongValue(unsigned int t) {

	if(t >= 0x8000) {
	return *(unsigned long *)(p+t);
		}
	else if(t >= 0x7000) {
  // a 0x7000 c'è EEprom su enhanced, solo read!
	return *(unsigned long *)(p1+t);
		}
	else if(t >= 0x2000) {    // linear addressing
	return *(unsigned long *)(p1+t);
		}
	else if(t < 0x20) {
	return *(unsigned long *)(p1+t);
		}
	else {
	return *(unsigned long *)(p1+t);
		}
	}

unsigned char GetPipe(unsigned int t) {
  
#if defined(NVMADRH)
  t += BASE_FLASH_MEMORY;
  NVMADRL=t & 0xff;
  NVMADRH=t >> 8;
  NVMCON1bits.RD=1;
  NOP();
	Pipe.bytes.byte1=NVMDATL;
	Pipe.bytes.byte2=NVMDATH;
  t++;
  NVMADRL=t & 0xff;
  NVMADRH=t >> 8;
  NVMCON1bits.RD=1;
  NOP();
	Pipe.bytes.byte3=NVMDATL;
	Pipe.bytes.byte4=NVMDATH;
#elif defined(EEADRH)
  t += BASE_FLASH_MEMORY;
  EEADRL=t & 0xff;
  EEADRH=t >> 8;
	Pipe.bytes.byte1=EEDATAL;
	Pipe.bytes.byte2=EEDATAH;
#else   // in questa modalità (vecchi PIC16) si SPRECANo i 6 bit alti!
	Pipe.bytes.byte1=*(unsigned char *)(p+t++);
	Pipe.bytes.byte2=*(unsigned char *)(p+t);
#endif

	return Pipe.bytes.byte2;
	}

void PutValue7(unsigned char t,unsigned char t1) {
	register unsigned int j;

  t &= 0x7f;
#if defined(BSR)
  j = _b;
  j <<= 7;
  j |= t;   // & 0x7f
#else
  j = t;
  if(_p.RP0) {
    j |= 0x80;
    }
  if(_p.RP1) {
    j |= 0x100;
    }
#endif

	if(j < 0x20) {
		*(p1+j)=t1;
    }
	else if(j < 0x8000) {
		*(p1+j)=t1;
		}

	}

void PutValue(unsigned int t,unsigned char t1) {
	register unsigned int i;

#if defined(BSR)
#else
  if(_p.IRP) {
    t |= 0x100;
    }
#endif
	if(t < 0x20) {
		*(p1+t)=t1;
    }
#if defined(BSR)
	else if(t < 0x2000) {
    }
#endif
	else if(t < 0x8000) {
		*(p1+t)=t1;
		}

	}

void PutValue7L(unsigned char t,unsigned long t1) {
	register unsigned int j;

  // SE TOCCO PCL (e anche altri) gestire caso particolare di PCLATH
  t &= 0x7c;
#if defined(BSR)
  j = _b;
  j <<= 7;
  j |= t;   // & 0x7f
#else
  j = t;
  if(_p.RP0) {
    j |= 0x80;
    }
  if(_p.RP1) {
    j |= 0x100;
    }
#endif

	if(j < 0x20) {
		*((unsigned long *)(p1+j))=t1;
    }
	else if(j < 0x8000) {
		*((unsigned long *)(p1+j))=t1;
		}

	}

signed char Emulate(void) {
  union FOURBYTES k2;
  unsigned char k;

	PutValue(3,0x18);     // TO, PD
  NVMCON1=0;
	_pc.word=RESET_ADDRESS     /*GetIntValue(0xfffc) fare?? */;
	do {
		if(debug) {
//			printf("%04x    %02x\n",_pc,GetValue(_pc));
			}


		if(DoIRQ) {
			if(!_p.Interrupt32) {
				_p.Interrupt32=1;
				DoIRQ=0;
        _pc.word+=2;
				*((unsigned char *)p1+_s)=_pc.bytes.byte1;
				_s--;
				*((unsigned char *)p1+_s)=_pc.bytes.byte2;
				_s--;
#if defined(BSR)    // ossia enhanced
        _saved_w=_w;
        _saved_status=_p;
        _saved_bsr=_b;
        _saved_fsr1.word=GetIntValue(4);
        _saved_fsr2.word=GetIntValue(6);
        _saved_pch=_pch;
#endif
				_pc.word=RESET_ADDRESS+0x0008;
				}
			}
//printf("Pipe2w: %04x, Pipe2b1: %02x,%02x\n",Pipe.word,Pipe.bytes.byte1,Pipe.bytes.byte2);

    GetPipe(_pc.word);
    _pc.word+=2;
    if(Pipe.bytes.byte2) {      // byte alto-1°word
      switch(Pipe.bytes.byte1) {      // byte basso 1°word
        case 0:                             // MOVWF32
          PutValue7L(Pipe.bytes.byte3,_w.along);
          break;
          
        case 1:
          if(Pipe.bytes.byte3 & 0x80)       // CLRF32
            PutValue7L(Pipe.bytes.byte3,0L);
          else               // CLRW32
            _w.along=0;
          goto aggFlagZL;
  // si potrebbe 				goto write7_Z;
          break;

        case 2:
          k2.along=GetValue7L(Pipe.bytes.byte3) -_w.along;     // SUBWF32
          goto aggSomma_7L;
          break;

        case 3:
          k2.along=GetValue7L(Pipe.bytes.byte3)-1;     // DECF32
          goto write7L_Z;
          break;
        case 11:
          k2.along=GetValue7L(Pipe.bytes.byte3)-1;     // DECFSZ32
          if(!k2.along)
            _pc.word+=2;
write7L:
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7L(Pipe.bytes.byte3,k2.along);
          else
            _w.along=k2.along;
          break;

        case 4:
          k2.along=_w.along | GetValue7L(Pipe.bytes.byte3);     // IORWF32
write7L_Z:        
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7L(Pipe.bytes.byte3,k2.along);
          else
            _w.along=k2.along;
          goto aggFlagZL;
          break;

        case 5:
          k2.along=_w.along & GetValue7L(Pipe.bytes.byte3);     // ANDWF32
          goto write7L_Z;
          break;

        case 6:
          k2.along=_w.along ^ GetValue7L(Pipe.bytes.byte3);     // XORWF32
          goto write7L_Z;
          break;

        case 7:
          k2.along=_w.along+GetValue7L(Pipe.bytes.byte3);     // ADDWF32
aggSomma_7L:
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7L(Pipe.bytes.byte3,k2.along);
          else
            _w.along=k2.bytes.byte1;
aggSommaL:
aggFlagDCZL:
          if(k2.bytes.byte1 & 0)     // FINIRE half carry!
            _p.DigitCarry=1;
          else
            _p.DigitCarry=0;
            // FINIRE_p.DigitCarry=(((signed char)_w) < 0) ? 1 : 0;
aggFlagCZL:
          if(k2.words.word2 & 0x100)
            _p.Carry=1;
          else                       // verificare
            _p.Carry=0;
aggFlagZL:
            _p.Zero=k2.along ? 0 : 1;
          break;

        case 8:
          k2.along=GetValue7L(Pipe.bytes.byte3);     // MOVF32
          if(!(Pipe.bytes.byte3 & 0x80))
            _w.along=k2.along;
          goto aggFlagZL;
          break;

        case 9:
          k2.along=~GetValue7L(Pipe.bytes.byte3);     // COMF32
          goto write7L_Z;
          break;

        case 10:
          k2.along=GetValue7L(Pipe.bytes.byte3)+1;     // INCF32
          goto write7L_Z;
          break;
        case 15:
          k2.along=GetValue7L(Pipe.bytes.byte3)+1;     // INCFSZ32
          if(!k2.along)
            _pc.word+=2;
          goto write7L;
          break;

        case 12:
          if(Pipe.bytes.byte4 & 1)
            k2.along=GetValue7L(Pipe.bytes.byte3);     // RRF32
          else
            k2.along=_w.along;     // RRW32
          k=k2.bytes.byte1 & 1;
          k2.along >>= 1;
          if(_p.Carry)
            k2.bytes.byte4 |= 0x80;
          /*else
            k2.bytes.byte4 &= 0x7f;*/
updW32_C:
          _p.Carry=k;
          if(Pipe.bytes.byte4 & 1)
            goto write7L;
          else
            _w.along=k2.along;
          break;

        case 13:
          if(Pipe.bytes.byte4 & 1)
            k2.along=GetValue7L(Pipe.bytes.byte3);     // RLF32
          else
            k2.along=_w.along;     // RLW32
          k= k2.bytes.byte4 & 0x80 ? 1 : 0;
          k2.along <<= 1;
          if(_p.Carry)
            k2.bytes.byte1 |= 1;
          /*else
            k2.bytes.byte1 &= 0xfe;*/
          goto updW32_C;
          break;

        case 48:
          if(Pipe.bytes.byte4 & 0x20)
            _w.along=Pipe.bytes.byte3;      // MOVLW32 con 8bit
          else
            _w.along=GetLongValue(0x8000 | Pipe.words.word2);      // MOVLW32 con 32bit (da ROM))
          break;

        case 52:      // RETLW32
          if(Pipe.bytes.byte4 & 0x20)
            _w.along=Pipe.bytes.byte3;      // con 8bit
          else
            _w.along=GetLongValue(0x8000 | Pipe.words.word2);      // con 32bit (da ROM))
          goto fai_return;
          break;
          
          // in QUESTE ROTATE, la variante "W" potrebbe anche non servire, dato che W è mappato in RAM...
        case 53:
          if(Pipe.bytes.byte4 & 1)
            k2.along=GetValue7L(Pipe.bytes.byte3);     // LSLF32
          else
            k2.along=_w.along;     // LSLW32
          _p.Carry= k2.bytes.byte4 & 0x80 ? 1 : 0;
          k2.along <<= 1;
updW32_CZ:
          if(Pipe.bytes.byte4 & 1)
            goto write7L_Z;
          else {
            _w.along=k2.along;
            goto aggFlagZL;
            }
          break;

        case 54:
          if(Pipe.bytes.byte4 & 1)
            k2.along=GetValue7L(Pipe.bytes.byte3);     // LSRF32
          else
            k2.along=_w.along;     // LSRW32
          _p.Carry= k2.bytes.byte1 & 1;
          k2.along >>= 1;
          goto updW32_CZ;
          break;

        case 55:
          if(Pipe.bytes.byte4 & 1)
            k2.along=GetValue7(Pipe.bytes.byte3);     // ASRF32
          else
            k2.along=_w.along;     // ASRW32
          _p.Carry= k2.bytes.byte1 & 1;
          k2.along = ((signed long)k2.along) >> 1;
          goto updW32_CZ;
          break;
          
        case 56:
          if(Pipe.bytes.byte4 & 0x20)
            _w.along |= Pipe.bytes.byte3;     // IORLW32 con 8 bit
          else
            _w.along |= GetLongValue(0x8000 | Pipe.words.word2);      // IORLW32 con 32bit (da ROM))
          goto aggFlagZL;
          break;

        case 57:
          if(Pipe.bytes.byte4 & 0x20)
            _w.along &= Pipe.bytes.byte3;     // ANDLW32 con 8 bit
          else
            _w.along &= GetLongValue(0x8000 | Pipe.words.word2);      // ANDLW32 con 32bit (da ROM))
          goto aggFlagZL;
          break;

        case 58:
          if(Pipe.bytes.byte4 & 0x20)
            _w.along ^= Pipe.bytes.byte3;     // XORLW32 con 8 bit
          else
            _w.along ^= GetLongValue(0x8000 | Pipe.words.word2);      // XORLW32 con 32bit (da ROM))
          goto aggFlagZL;
          break;

#if defined(BSR)
        case 59:
          k2.along=GetValue7L(Pipe.bytes.byte3) -_w.along+_p.Carry;     // SUBWFB
          goto aggSomma_7L;
          break;
#endif

        case 60:
          if(Pipe.bytes.byte4 & 0x20)
            k2.along = Pipe.bytes.byte3-_w.along;     // SUBLW32 con 8 bit
          else
            k2.along = GetLongValue(0x8000 | Pipe.words.word2)-_w.along;      // SUBLW32 con 32bit (da ROM))
          _w.along = k2.along;
          goto aggSommaL;
          break;

#if defined(BSR)
        case 61:
          k2.along=_w.along+GetValue7L(Pipe.bytes.byte3)+_p.Carry;     // ADDWFC32
          goto aggSomma_7L;
          break;
#endif

        case 62:
          k2.along = _w.along+Pipe.bytes.byte3;     // ADDLW32
          _w.along=k2.along;
          goto aggSommaL;
          break;
          
        }
      }
    else {
      switch(Pipe.bytes.byte1) {      // byte basso 1°word
        case 0:
          switch(Pipe.bytes.byte3) {
            case 0:       // NOP
              NOP();        // serve??
              break;
#if defined(BSR)
            case 1:       // RESET
              _pc.word=RESET_ADDRESS /*GetIntValue(0xfffa)*/;
              break;
#endif
            case 0x64:       // ClrWdt
              CLRWDT();
              _p.TimeOut=1;
              _p.PowerDown=1;
              break;
            case 0x63:       // Sleep
              _p.TimeOut=1;
              _p.PowerDown=0;
              SLEEP();
              break;
            case 0x62:       // Option
  //            OPTION_REG=_w.bytes.byte1;
              break;
            case 0x65:        // TRIS
            case 0x66:
            case 0x67:
              *(&TRISA+Pipe.bytes.byte3-0x65)=_w.bytes.byte1;
              break;
#if defined(BSR)
            case 0x0A:        // CALLW
              _pc.word+=2;
              *((unsigned char *)p1+_s)=_pc.bytes.byte1;
              _s--;
              *((unsigned char *)p1+_s)=_pc.bytes.byte2;
              _s--;
              _pc.bytes.byte1=(signed char)_w.bytes.byte1;
              _pc.bytes.byte2=_pch;
              break;
            case 0x0B:        // BRW
              _pc.word+=(signed char)_w.bytes.byte1;
              break;
#endif
            case 0x09:      // RETFIE
#ifdef BSR      //_ENHANCED_16
              _w=_saved_w;
              _p=_saved_status;
              _b=_saved_bsr;
              PutValue(4,_saved_fsr1.bytes.byte1);
              PutValue(5,_saved_fsr1.bytes.byte2);
              PutValue(6,_saved_fsr2.bytes.byte1);
              PutValue(7,_saved_fsr2.bytes.byte2);
              _pc.bytes.byte1 = _pc.bytes.byte1;
              _pc.bytes.byte2=_saved_pch;
#endif
            _p.Interrupt32=0;
              // GIE=1; FARE
            case 0x08:      // RETURN
fai_return:
              _s++;
              _pc.bytes.byte2=*((unsigned char *)p1+_s);
              _s++;
              _pc.bytes.byte1=*((unsigned char *)p1+_s);
              break;

            default:
              if(Pipe.bytes.byte3 & 0x80) {          // MOVWF
                PutValue7(Pipe.bytes.byte3,_w.bytes.byte1);
                }
#if defined(BSR)
              else if((Pipe.bytes.byte3 & 0xe0) == 0x20) {   // MOVLB
                _b=Pipe.bytes.byte3 & 0x1f;
                }
              else if((Pipe.bytes.byte3 & 0xf0) == 0x10) {   // MOVIW/MOVWI
                if(Pipe.bytes.byte3 & 4) {
                  k2.words.word1=GetIntValue(6);
                  }
                else {
                  k2.words.word1=GetIntValue(4);         // SIGNED?? !// RIPORTO BYTE ALTO!
                  }
                switch(Pipe.bytes.byte3 & 3) {
                  case 0:
                    k2.words.word1++;
                    break;
                  case 1:
                    k2.words.word1--;
                    break;
                  }
                if(Pipe.bytes.byte3 & 8)            // MOVIW
                  PutValue(k2.words.word1,_w.bytes.byte1);   
                else                                // MOVWI
                  _w.bytes.byte1=GetValue(k2.words.word1);
                switch(Pipe.bytes.byte3 & 3) {
                  case 2:
                    k2.words.word1++;
                    break;
                  case 3:
                    k2.words.word1--;
                    break;
                  }
                if(Pipe.bytes.byte3 & 4) 
                  goto aggFSR2;
                else
                  goto aggFSR1;
                if(Pipe.bytes.byte3 & 8)            // MOVIW
                  goto aggFlagZ;
                }
#endif
              break;
            }
          break;

        case 1:
          if(Pipe.bytes.byte3 & 0x80)       // CLRF
            PutValue7(Pipe.bytes.byte3,0);
          else               // CLRW
            _w.bytes.byte1=0;
          goto aggFlagZ;
  // si potrebbe 				goto write7_Z;
          break;

        case 2:
          k2.words.word1=GetValue7(Pipe.bytes.byte3) -_w.bytes.byte1;     // SUBWF
          goto aggSomma_7;
          break;

        case 3:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3)-1;     // DECF
          goto write7_Z;
          break;
        case 11:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3)-1;     // DECFSZ
          if(!k2.bytes.byte1)
            _pc.word+=2;
write7:
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7(Pipe.bytes.byte3,k2.bytes.byte1);
          else
            _w.bytes.byte1=k2.bytes.byte1;
          break;

        case 4:
          k2.bytes.byte1=_w.bytes.byte1 | GetValue7(Pipe.bytes.byte3);     // IORWF
write7_Z:        
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7(Pipe.bytes.byte3,k2.bytes.byte1);
          else
            _w.bytes.byte1=k2.bytes.byte1;
          goto aggFlagZ;
          break;

        case 5:
          k2.bytes.byte1=_w.bytes.byte1 & GetValue7(Pipe.bytes.byte3);     // ANDWF
          goto write7_Z;
          break;

        case 6:
          k2.bytes.byte1=_w.bytes.byte1 ^ GetValue7(Pipe.bytes.byte3);     // XORWF
          goto write7_Z;
          break;

        case 7:
          k2.words.word1=_w.bytes.byte1+GetValue7(Pipe.bytes.byte3);     // ADDWF
aggSomma_7:
          if(Pipe.bytes.byte3 & 0x80)
            PutValue7(Pipe.bytes.byte3,k2.bytes.byte1);
          else
            _w.bytes.byte1=k2.bytes.byte1;
aggSomma:
aggFlagDCZ:
          if(k2.bytes.byte1 & 0)     // FINIRE half carry!
            _p.DigitCarry=1;
          else
            _p.DigitCarry=0;
            // FINIRE_p.DigitCarry=(((signed char)_w.bytes.byte1) < 0) ? 1 : 0;
aggFlagCZ:
          _p.Carry=k2.bytes.byte2 & 1;
aggFlagZ:
          _p.Zero=k2.bytes.byte1 ? 0 : 1;
          break;

        case 8:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // MOVF
          if(!(Pipe.bytes.byte3 & 0x80))
            _w.bytes.byte1=k2.bytes.byte1;
          goto aggFlagZ;
          break;

        case 9:
          k2.bytes.byte1=~GetValue7(Pipe.bytes.byte3);     // COMF
          goto write7_Z;
          break;

        case 10:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3)+1;     // INCF
          goto write7_Z;
          break;
        case 15:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3)+1;     // INCFSZ
          if(!k2.bytes.byte1)
            _pc.word+=2;
          goto write7;
          break;

        case 12:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // RRF
          k=k2.bytes.byte1 & 1;
          k2.bytes.byte1 >>= 1;
          if(_p.Carry)
            k2.bytes.byte1 |= 0x80;
          /*else
            k2.bytes.byte1 &= 0x7f;*/
          _p.Carry=k;
          goto write7;
          break;

        case 13:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // RLF
          k= k2.bytes.byte1 & 0x80 ? 1 : 0;
          k2.bytes.byte1 <<= 1;
          if(_p.Carry)
            k2.bytes.byte1 |= 1;
          /*else
            k2.bytes.byte1 &= 0xfe;*/
          _p.Carry=k;
          goto write7;
          break;

        case 14:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // SWAPF
          k2.bytes.byte1=(k2.bytes.byte1 << 4) | (k2.bytes.byte1 >> 4);
          goto write7;
          break;

        case 16:
        case 17:
        case 18:
        case 19:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // BCF
          k2.bytes.byte1 &= ~bitmask[(Pipe.words.word2 >> 7) & 7];
#warning SISTEMARE BCF ecc
          PutValue7(Pipe.bytes.byte3,k2.bytes.byte1);
          break;

        case 20:
        case 21:
        case 22:
        case 23:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // BSF
          k2.bytes.byte1 |= bitmask[(Pipe.words.word2 >> 7) & 7];
          PutValue7(Pipe.bytes.byte3,k2.bytes.byte1);
          break;

        case 24:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 31:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // BTFSC
          k2.bytes.byte1 &= bitmask[(Pipe.words.word2 >> 7) & 7];
          if(Pipe.bytes.byte3 & 4) {    // BTFSS
            if(k2.bytes.byte1)
              _pc.word+=2;
            }
          else {
            if(!k2.bytes.byte1)
              _pc.word+=2;
            }
          break;

        case 32:        // CALL
        case 33:
        case 34:
        case 35:
        case 36:
        case 37:
        case 38:
        case 39:
          _pc.word+=2;
          *((unsigned char *)p1+_s)=_pc.bytes.byte1;
          _s--;
          *((unsigned char *)p1+_s)=_pc.bytes.byte2;
          _s--;
  //      printf("JSR (%04x)=%04x\n",i,_pc);
          goto fai_goto;
          break;

        case 40:        // GOTO
        case 41:
        case 42:
        case 43:
        case 44:
        case 45:
        case 46:
        case 47:
fai_goto:
          _pc.bytes.byte2=_pch & 0x78;
          _pc.bytes.byte1=Pipe.bytes.byte3;
          _pc.bytes.byte2 |= Pipe.bytes.byte1 & 0x7;
  //      printf("JMP (%04x)=%04x\n",i,_pc);
          break;

        case 48:
          _w.bytes.byte1=Pipe.bytes.byte3;      // MOVLW
          break;

        case 49:
          if(Pipe.bytes.byte3 & 0x80)    
            _pch = Pipe.bytes.byte3 & 0x7f;     // MOVLP
          else {          // ADDFSR
            if(Pipe.bytes.byte3 & 0x40) {
              k2.words.word1=GetIntValue(6);
              if(Pipe.bytes.byte3 & 0x20)
                k2.words.word1-=(32-Pipe.bytes.byte3 & 0x1f);     // SIGNED
              else
                k2.words.word1+=Pipe.bytes.byte3 & 0x1f;
aggFSR2:
              PutValue(6,k2.bytes.byte1);
              PutValue(7,k2.bytes.byte2);
              }
            else {
              k2.words.word1=GetIntValue(4);
              if(Pipe.bytes.byte3 & 0x20)
                k2.words.word1-=(32-Pipe.bytes.byte3 & 0x1f);     // SIGNED
              else
                k2.words.word1+=Pipe.bytes.byte3 & 0x1f;
aggFSR1:
              PutValue(4,k2.bytes.byte1);
              PutValue(5,k2.bytes.byte2);
              }
            }
          break;

#if defined(BSR)
        case 50:        // BRA
        case 51:
          if(Pipe.bytes.byte2 & 0x1)
            _pc.word += (256-Pipe.bytes.byte3);        // SIGNED
          else
            _pc.word += Pipe.bytes.byte3;        // SIGNED
  //      printf("JMP (%04x)=%04x\n",i,_pc);
          break;
#endif

        case 52:      // RETLW
          _w.bytes.byte1=Pipe.bytes.byte3;
          goto fai_return;
          break;

#if defined(BSR)
        case 53:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // LSLF
          _p.Carry= k2.bytes.byte1 & 0x80 ? 1 : 0;
          k2.bytes.byte1 <<= 1;
          goto write7_Z;
          break;

        case 54:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // LSRF
          _p.Carry= k2.bytes.byte1 & 1;
          k2.bytes.byte1 >>= 1;
          goto write7_Z;
          break;

        case 55:
          k2.bytes.byte1=GetValue7(Pipe.bytes.byte3);     // ASRF
          _p.Carry= k2.bytes.byte1 & 1;
          k2.bytes.byte1 = ((signed char)k2.bytes.byte1) >> 1;
          goto write7_Z;
          break;
#endif

        case 56:
          _w.bytes.byte1 |= Pipe.bytes.byte3;     // IORLW
          goto aggFlagZ;
          break;

        case 57:
          _w.bytes.byte1 &= Pipe.bytes.byte3;     // ANDLW
          goto aggFlagZ;
          break;

        case 58:
          _w.bytes.byte1 ^= Pipe.bytes.byte3;     // XORLW
          goto aggFlagZ;
          break;

#if defined(BSR)
        case 59:
          k2.words.word1=GetValue7(Pipe.bytes.byte3) -_w.bytes.byte1+_p.Carry;     // SUBWFB
          goto aggSomma_7;
          break;
#endif

        case 60:
          k2.words.word1 = Pipe.bytes.byte3-_w.bytes.byte1;     // SUBLW
          _w.bytes.byte1=k2.bytes.byte1;
          goto aggSomma;
          break;

#if defined(BSR)
        case 61:
          k2.words.word1=_w.bytes.byte1+GetValue7(Pipe.bytes.byte3)+_p.Carry;     // ADDWFC
          goto aggSomma_7;
          break;
#endif

        case 62:
          k2.words.word1 = _w.bytes.byte1+Pipe.bytes.byte3;     // ADDLW
          _w.bytes.byte1=k2.bytes.byte1;
          goto aggSomma;
          break;

#if defined(BSR)
        case 63:
          if(Pipe.bytes.byte3 & 0x40)
            k2.words.word1=GetIntValue(6);
          else
            k2.words.word1=GetIntValue(4);
          if(Pipe.bytes.byte3 & 0x20)
            k2.words.word1-=(32-Pipe.bytes.byte3 & 0x1f);     // SIGNED
          else
            k2.words.word1+=Pipe.bytes.byte3 & 0x1f;
          if(Pipe.bytes.byte3 & 0x80)    // MOVWI
            PutValue(k2.words.word1,_w.bytes.byte1);   
          else {                         // MOVIW
            _w.bytes.byte1=GetValue(k2.words.word1);
            goto aggFlagZ;
            }
#endif

          break;


        default:
          break;
        }
      }
    
		} while(!fExit);
    
    test_code();      // se no sparisce
    
  return fExit;
	}

void test_code(void) @0xc00 {
  
  #asm
  myvar EQU 0x120
  myvar1 EQU 0x121

  dw 0x0031       ;PAGESEL $ ;OCCHIO!
  dw 0x008c
  dw 0x0000       ;BANKSEL myvar1
  dw 0x0022
  dw 0x0130       ;movlw32 [myLong]   (0xc00)
  dw myLong
  dw 0x0130       ;movlw32 3
  dw 0x2003
rifo:
  dw 0x0000       ;movwf myvar
  dw 0x00a0
loop:
  dw 0x000b       ;decfsz myvar,f
  dw 0x00a0
  dw 0x002c       ;  goto loop ;OCCHIO!
  dw 0x000a
  dw 0x000a       ;incf myvar1,f
  dw 0x00a1
  dw 0x0000       ;nop
  dw 0x0000
  dw 0x0017       ;bsf myvar1,6
  dw 0x0021
  dw 0x003e       ;addlw 5
  dw 0x0005
  dw 0x010d       ;rlw32
  dw 0x0000
  dw 0x002c       ;  goto rifo ;OCCHIO
  dw 0x0008
  
myLong:          
  db 100,101,102,103    ; =hex 67666564h
    
  #endasm
  }