/* processor.cpp
 */

#include <stdio.h>
#include <stdlib.h>
#include "processor.h"
#include "exception.h"

// Carica taebella operazioni
#include "optab.h"

// Contiene il codice da scaricare nel micro per programmarlo
// #include "fp4h"
#include "fp32.h"
#include "fpqtqy.h"
#include "fpqb.h"
#include "fplb.h"
// Contiene il codice da scaricare nel micro per cancellarlo (a seconda dei modelli)
#include "fe32.h"
#include "feqtqy.h"
#include "feqb.h"
#include "felb.h"

int Processor::prrtAddrs [] = {  // Indrizzi da verificare per il fingerprint
    0x2800, 0x2803, 0x2806, 0x2809, 0x280C, 0xFE9F, 0xFEA1, 0xFEAA, 0xFED0, 0xFED6, // Check ROM
    0x10060                                     // Check RAM
    };
// #define   NUMFPPOINTS (sizeof (prrtAddrs) / sizeof (int))

#define ISRAM 0x55
unsigned char Processor::prints [][NUMFPPOINTS] = {
  { 0xad, 0xad, 0xad, 0xad, 0xad, 0x80, 0x2c, 0x89, 0xa6, 0x00, ISRAM, },   // 0 = GP32
  { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x24, 0x89, 0x5b, 0x5b, 0xff, 0xad, },    // 1 = QT4/ QY4
  { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf7, 0xae, 0xad, 0x36, 0x20, 0xcd, },    // 2 = QB4
  { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf7, 0xae, 0xad, 0x36, 0x20, ISRAM, },   // 3 = QB8
  { 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xf7, 0xae, 0xad, 0x36, 0x20, 0xcd, },  // 4 = LB8
};
#define   NUMPRINTS (sizeof (prints) / NUMFPPOINTS)

unsigned char Processor::clean [] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

progRoutines Processor::procConfigs [] = {
  /* 0 ROM 8000 - ffff 32K Ram 0x40 0x240 512 Byte Pagina 64 Byte */
  { fp32, STARTAD_fp32, ENDAD_fp32, NUMIST_fp32,
    fe32, STARTAD_fe32, ENDAD_fe32, NUMIST_fe32,
    0x40, 64, 0x8000, 0xFF7E,
    "MC68HC908GP32" },          // GP32
  /* 1 Rom f400/f800 ffff 2/4K Ram 0x40 - 0x7f 128 byte Pagina 32 Byte */
  { fpqtqy, STARTAD_fpqtqy, ENDAD_fpqtqy, NUMIST_fpqtqy,
    feqtqy, STARTAD_feqtqy, ENDAD_feqtqy, NUMIST_feqtqy,
    0x80, 32, 0xf800, 0xFFBE,
    "MC68HC908QT/QY1/2/4" },  // QT / QY non HLC (EPROM for QT/QY1)
  /* 2 ROM DE00/EE00 4K RAM 0x80-0xff 128Byte (QB4 -> ) Pagina 32 byte */
  { fpqb, STARTAD_fpqb, ENDAD_fpqb, NUMIST_fpqb,
    feqb, STARTAD_feqb, ENDAD_feqb, NUMIST_feqb,
    0x80, 32, 0xEE00, 0xFFBE,
    "MC68HC908QB4" },  // QB4
  /* 3 ROM DE00/FDFF 8 RAM 0x40-0x13f 256Byte Pagina 32 byte */
  { fpqb, STARTAD_fpqb, ENDAD_fpqb, NUMIST_fpqb,
    feqb, STARTAD_feqb, ENDAD_feqb, NUMIST_feqb,
    0x80, 32, 0xEE00, 0xFFBE,
    "MC68HC908QB8" },  // QB8
  /* 3 ROM DE00/FDFF 8 RAM 0x80-0xff 128Byte Pagina 32 byte */
  { fplb, STARTAD_fplb, ENDAD_fplb, NUMIST_fplb,
    felb, STARTAD_felb, ENDAD_felb, NUMIST_felb,
    0x80, 32, 0xEE00, 0xFF7E,
    "MC68HC908LB8" },  // LB8
};

// constants for programming record
#define HEADLEN   4

unsigned char Processor::getMem (unsigned int i) {
	if (i < IMGEND) {
		for (IoPort *p = ports; p; p=p->getNext ()) {
			if (p->isPort (i)) {
				return p->getValue (i);
			}
		}
		return memory[i];
	}
	return 0; 
}

void Processor::setMem(unsigned int i, unsigned char d) {
	if (i < IMGEND) {
		for (IoPort *p = ports; p; p=p->getNext ()) {
			if (p->isPort (i)) {
				p->setValue (i, d);
			}
		}
		memory[i] = d;
	}
}

int Processor::readMem (int Addr) {
  return (Addr < IMGEND) ? ((emulating) ? memory[Addr] : Monitor::read(Addr)) : 0;
}

int Processor::read (int Addr) {
  return (Addr < IMGEND) ? ((emulating) ? getMem (Addr) : Monitor::read(Addr)) : 0;
}

void Processor::write (int Addr, int Dato) {
  if (Addr < IMGEND) {
    if (emulating) {
	  setMem(Addr, Dato);
    } else {
      Monitor::write(Addr, Dato);
    }
  }
}

void Processor::stackprep () {
unsigned char oldReg [6], newReg [6];
int i, p;
/*
 * 1. Read stack pointer to get (SP+1) high byte
 *    and (SP+1) low byte                             ($0C)
 * 2. Write $00 to (SP+1) low byte   ($49, $00, [(SP+1) low byte], $00) - H
 * 3. Indexed write $68 to (SP+1) low byte+1          ($19, $68) - oldCcr =  v11hInzc - Interrupt disabilitati
 * 4. Indexed write $00 to (SP+1) low byte+2          ($19, $00) - A
 * 5. Indexed write $00 to (SP+1) low byte+3          ($19, $00) - X
 * 6. Indexed write $00 to (SP+1) low byte+4          ($19, $00) - PCh
 * 7. Indexed write $A8 to (SP+1) low byte+5          ($19, $A8) - PCl
 * 8. Issue RUN command.                              ($28)
 */
  sp = readsp ();

  // Copies old register in array
  oldReg [0] = oldHx >> 8;      // H (high byte of index register)
  oldReg [1] = oldCcr;            // Condition Code Register (come al reset - interrupt disabilitati)
  oldReg [2] = oldA;              // Accumulator
  oldReg [3] = oldHx & 0xff;      // X (low byte of index register)
  oldReg [4] = oldPc >> 8;        // Indirizzo PGM Hi
  oldReg [5] = oldPc & 0xff;      // Indirizzo PGM Lo
  // Copies new registers in array
  newReg [0] = hx >> 8;   // H (high byte of index register)
  newReg [1] = ccr;         // Condition Code Register (come al reset - interrupt disabilitati)
  newReg [2] = a;           // Accumulator
  newReg [3] = hx & 0xff;   // X (low byte of index register)
  newReg [4] = pc >> 8;     // Indirizzo PGM Hi
  newReg [5] = pc & 0xff;   // Indirizzo PGM Lo

  for (i = 0, p=0; i < 6; i++) {
    if (newReg [i] != oldReg [i]) { // Must update Processor stack
      if (p) {          // It's correctly positioned (after oldA previous write)
        iwrite (newReg [i]);  // Writes without repositioning
      } else {
        write (sp + i, newReg [i]); // Positions and writes
        p = -1;         // Marks positioned
      }
    } else {            // Doesn't update stack - are the same
      p = 0;            // marks to reposition
    }
  }
  // Updates old register values, as copied into the processor
  oldPc = pc;
  oldHx = hx;
  oldA = a;
  oldCcr = ccr;
}

void Processor::readRegisters () {
int d;
    // Legge il contenuto dello stack
    /*
     * 1. Read stack pointer to get (SP+1) high byte
     *    and (SP+1) low byte
     * 2. (SP+1) H
     * 3. (SP+2) oldCcr
     * 4. (SP+3) A
     * 5. (SP+4) X
     * 6. (SP+5) PCh
     * 7. (SP+6) PCl
     */
    sp = readsp ();

    d = read (sp);           // H (high byte of index register)
    oldHx = d << 8;
    d = read (sp + 1);            // CCR
    ccr = oldCcr = d;
    d = iread ();                // oldA (h) x (l)
    a = oldA = d >> 8;
    oldHx |= d & 0xff;
    hx = oldHx;
    pc = oldPc = iread ();                // PC
}

#define BRKH      0xFE09
#define BRKL      0xFE0A
#define BRKSCR    0xFE0B
#define BRKAR     0xFE02

/* BFCR ? */

// To move into "processor description" structure
#define MINRAM    0x40
#define MAXRAM    0x13f

int Processor::nextBp (int mode, int opcode, int opcode2, op *curop)
{
int d;
    d = pc + 1;
    // Controlla le istruzioni di trasferimento del controllo
    switch (opcode) {
    case 0x24 : // BCC        Branch if Carry Bit Clear
                // BHS        Branch if Higher or Same
      break;
    case 0x25 : // BCS        Branch if Carry Bit Set
                // BLO        Branch if Lower
      break;
    case 0x27 : // BEQ        Branch if Equal
      break;
    case 0x90 : // BGE        Branch if Greater Than or Equal To
      break;
    case 0x92 : // BGT        Branch if Greater Than
      break;
    case 0x28 : // BHCC       Branch if Half Carry Bit Clear
      break;
    case 0x29 : // BHCS       Branch if Half Carry Bit Set
      break;
    case 0x22 : // BHI        Branch if Higher
      break;
    case 0x2f : // BIH        Branch if IRQ Pin High
      break;
    case 0x2e : // BIL        Branch if IRQ Pin Low
      break;
    case 0x93 : // BLE        Branch if Less Than or Equal To
      break;
    case 0x23 : // BLS        Branch if Lower or Same
      break;
    case 0x91 : // BLT        Branch if Less Than
      break;
    case 0x2c : // BMC        Branch if Interrupt Mask Clear
      break;
    case 0x2b : // BMI        Branch if Minus
      break;
    case 0x2d : // BMS        Branch if Interrupt Mask Set
      break;
    case 0x26 : // BNE        Branch if Not Equal
      break;
    case 0x2A : // BPL        Branch if Plus
      break;
    case 0x20 : // BRA        Branch Always
      break;
    case 0x01 : // BRCLR0 n   Branch if Bit n in Memory Clear
      break;
    case 0x03 : // BRCLR1 n   Branch if Bit n in Memory Clear
      break;
    case 0x05 : // BRCLR2 n   Branch if Bit n in Memory Clear
      break;
    case 0x07 : // BRCLR3 n   Branch if Bit n in Memory Clear
      break;
    case 0x09 : // BRCLR4 n   Branch if Bit n in Memory Clear
      break;
    case 0x0b : // BRCLR5 n   Branch if Bit n in Memory Clear
      break;
    case 0x0d : // BRCLR6 n   Branch if Bit n in Memory Clear
      break;
    case 0x0f : // BRCLR7 n   Branch if Bit n in Memory Clear
      break;
    case 0x00 : // BRSET0 n   Branch if Bit n in Memory Set
      break;
    case 0x02 : // BRSET1 n   Branch if Bit n in Memory Set
      break;
    case 0x04 : // BRSET2 n   Branch if Bit n in Memory Set
      break;
    case 0x06 : // BRSET3 n   Branch if Bit n in Memory Set
      break;
    case 0x08 : // BRSET4 n   Branch if Bit n in Memory Set
      break;
    case 0x0A : // BRSET5 n   Branch if Bit n in Memory Set
      break;
    case 0x0c : // BRSET6 n   Branch if Bit n in Memory Set
      break;
    case 0x0e : // BRSET7 n   Branch if Bit n in Memory Set
      break;
    case 0xad : // BSR        Branch to Subroutine
      if (mode == RUN_STEP_OVER) {
        d = pc + curop->op_len; // Salta il "BSR", quindi la subroutine
      }
      break;
    case 0x31 : // CBEQ     Compare and Branch if Equal
      break;
    case 0x41 : // CBEQA    Compare and Branch if Equal
      break;
    case 0x51 : // CBEQX    Compare and Branch if Equal
      break;
    case 0x61 : // CBEQX+     Compare and Branch if Equal
      break;
    case 0x71 : // CBEQ..     Compare and Branch if Equal
      break;
    case 0x9e :
      switch (opcode2) {
        case 0x61 : // CBEQ     Compare and Branch if Equal
          break;
        case 0x6b : // DBNZ     Decrement and Branch if Not Zero
          break;
      }
      break;
    case 0x3b : // DBNZ     Decrement and Branch if Not Zero
      break;
    case 0x4b : // DBNZA    Decrement and Branch if Not Zero
      break;
    case 0x5b : // DBNZX    Decrement and Branch if Not Zero
      break;
    case 0x6b : // DBNZ     Decrement and Branch if Not Zero
      break;
    case 0x7b : // DBNZ     Decrement and Branch if Not Zero
      break;
    case 0xbc : // JMP      Jump
      break;
    case 0xcc : // JMP      Jump
      break;
    case 0xdc : // JMP      Jump
      break;
    case 0xec : // JMP      Jump
      break;
    case 0xfc : // JMP      Jump
      break;
    case 0xbd : // JSR      Jump to Subroutine
    case 0xcd : // JSR      Jump to Subroutine
    case 0xdd : // JSR      Jump to Subroutine
    case 0xed : // JSR      Jump to Subroutine
    case 0xfd : // JSR      Jump to Subroutine
      if (mode == RUN_STEP_OVER) {
        d = pc + curop->op_len; // Salta il "JSR", quindi la subroutine
      }
      break;
    case 0x80 : // RTI      Return from Interrupt
      // sp + 6 -> app stack; oldCcr, A, X, PCh, PCl
        d = (read (sp+9)<<8) + read (sp+10); // Return address after Stack of SWI
      break;
    case 0x81 : // RTS      Return from Subroutine
        d = (read (sp+6)<<8) + read (sp+7); // Return address after Stack of SWI
      break;
    case 0x83 : // SWI      Software Interrupt
        throw (new Exception ("Termino debug - SWI ritorna al monitor"));
    case 0x94 : // TXS      Transfer Index Register to Stack Pointer
      if (oldHx > MAXRAM || oldHx <= MINRAM + 7) {
          throw (new Exception ("Impostazione Stack fuori RAM (%04x - min %04x, max 0x%04x)",
            oldHx, MINRAM, MAXRAM));
      }
      break;
    case 0x8f : // WAIT     Enable Interrupts; Stop Processor
        throw (new Exception ("Processore entrato in Wait"));
    }

  return d;
}


char *Processor::step (int Bp)
{
op *curop;
int opcode, opcode2;
int d;

    opcode = read (pc);
    if (opcode == 0x9e) {
      opcode2 = read (pc+1);
      switch (opcode2 & 0xF0) {
        case 0x60 :
          curop = opcodes9E6 + (opcode2 & 0xf);
          break;
        case 0xD0 :
          curop = opcodes9ED + (opcode2 & 0xf);
          break;
        case 0xE0 :
          curop = opcodes9EE + (opcode2 & 0xf);
          break;
        default :
          throw (new Exception ("istruzione 9E %02X illegale", opcode2));
      }
      if (curop -> op_len == 0) {
        throw (new Exception ("istruzione 9E %02X illegale\n", opcode2));
      }
    } else {
      curop = opcodes + opcode;
    }
  if (curop -> op_len == 0) {
      throw (new Exception ("istruzione %02X illegale", opcode));
  }
  if (Bp >= 0) {
    d = Bp;
  } else if (Bp == RUN_TO_BREAK) {
    if (tmpBpAddress != NOBREAKPOINT) {
      d = tmpBpAddress;
    } else {
      d = bpAddress;
    }
  } else {
    d = nextBp (Bp, opcode, opcode2, curop);
  }
    sprintf (disass, "%04X %-10s ", pc, curop -> op_name);

    stackprep ();
    // Imposta il breakpoint (se c'e')
    if (d >= 0) {
      write (BRKH, d >> 8);
      iwrite (d & 0xff);
      iwrite (0x80);   // BRKE = 1; BRKA = 0;
    }
    run ();
    procRunning = true;
  return disass;
}

int Processor::disassembly (int disassPC, char *buffer)
{
op *curop;
int opcode, opcode2;
int oprAddr = disassPC;
int opr1,opr2;
char params [30];
  params [0] = 0;   // Tronca stringa
    opcode = read (disassPC);
  oprAddr ++;
    if (opcode == 0x9e) {
      opcode2 = read (disassPC+1);
    oprAddr ++;
      switch (opcode2 & 0xF0) {
        case 0x60 :
          curop = opcodes9E6 + (opcode2 & 0xf);
          break;
        case 0xD0 :
          curop = opcodes9ED + (opcode2 & 0xf);
          break;
        case 0xE0 :
          curop = opcodes9EE + (opcode2 & 0xf);
          break;
        default :
          sprintf (buffer, "istruzione 9E %02X illegale", opcode2);
        return disassPC+2;
      }
      if (curop -> op_len == 0) {
        sprintf (buffer, "istruzione 9E %02X illegale\n", opcode2);
      return disassPC+2;
      }
    } else {
      curop = opcodes + opcode;
    }
  if (curop -> op_len == 0) {
      sprintf (buffer, "istruzione %02X illegale", opcode);
    return disassPC+1;
  }
  switch (curop -> op_mode)
  {
    case DIR_REL :  // Direct8, Relative
      opr1 = read (oprAddr++) & 0xff;
      opr2 = signExtend8 (read (oprAddr++));
      opr2 += oprAddr;
        sprintf (params, "$%02X,%04x", opr1, opr2);
      break;
    case IMM_REL :  // Direct8, Relative
      opr1 = read (oprAddr++) & 0xff;
      opr2 = signExtend8 (read (oprAddr++));
      opr2 += oprAddr;
        sprintf (params, "#%02X,%04x", opr1, opr2);
      break;
    case DIR8 : // Direct8
      opr1 = read (oprAddr++) & 0xff;
      sprintf (params, "$%02X", opr1);
      break;
    case REL :  // Relative
      opr1 = signExtend8 (read (oprAddr++));
      opr1 += oprAddr;
        sprintf (params, "%04x", opr1);
      break;
    case INH :  // Inherent
      break;
    case IMM :  // Immediate (8 bit)
      opr1 = read (oprAddr++) & 0xff;
        sprintf (params, "#%02X", opr1);
      break;
    case IMM16 :  // Immediate (16 bit)
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "$%02X%02x", opr1, opr2);
      break;
    case EXT :  // Extended: Direct/16bit addr
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "#%02X%02x", opr1, opr2);
      break;
    case JEXT : // Extended: Direct/16bit addr - Jump
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "%02X%02x", opr1, opr2);
      break;
    case IX :
      sprintf (params, ",X");
      break;
    case IX1 :  // opr8,X X plus offset
      opr1 = read (oprAddr++) & 0xff;
      if (opr1 & 0x80)
      {
        opr1 = -1&opr1; // esegue la sign-extention
      }
        sprintf (params, "%d, X", opr1);
      break;
    case IX2 :  // Opr16, X
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "$%02X%02x", opr1, opr2);
      break;
    case SP1 :  // opr8,SP
      opr1 = read (oprAddr++) & 0xff;
        sprintf (params, "$%02X, X+", opr1);
      break;
    case SP1_REL :  // opr8,SP, rel
      opr1 = read (oprAddr++) & 0xff;
      opr2 = signExtend8 (read (oprAddr++));
      opr2 += oprAddr;
        sprintf (params, "$%02X, SP, %04x", opr1,opr2);
      break;
    case SP2 :  // opr16,SP
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "$%02X%02x, SP", opr1, opr2);
      break;
    case DIX_P :  // Direct, X+
      opr1 = read (oprAddr++) & 0xff;
        sprintf (params, "$%02X, X+", opr1);
      break;
    case IX1_P_REL :
      opr1 = signExtend8 (read (oprAddr++));
      opr2 = signExtend8 (read (oprAddr++));
      opr2 += oprAddr;
      sprintf (params, "%d, X+, %04x", opr1,opr2);
      break;
    case IX_P_REL :
      opr1 = signExtend8 (read (oprAddr++));
      opr1 += oprAddr;
      sprintf (params, ",X+, %04x", opr1);
      break;
    case IX_P_D : // X+, $dir8
      opr1 = read (oprAddr++) & 0xff;
      sprintf (params, "X+, $%02X", opr1);
      break;
    case DD :
      break;
    case IMD :  // Immediate 8 bit, Direct 8 bit
      opr1 = read (oprAddr++) & 0xff;
      opr2 = read (oprAddr++);
        sprintf (params, "#%02X, $%02x", opr1, opr2);
      break;
  }
    sprintf (buffer, "%s %s", curop -> op_name, params);
  return disassPC + curop -> op_len;
}

bool Processor::runEnded ()
{
  if (procRunning) {
      try {
        schGetc (10000);    // Attende per 10mS il breack di rientro nel monitor
    } catch (Exception *e) {
      return false;
    }
      procRunning = false;
  }
  return true;
}


void Processor::endStep ()
{
    // Entra in monitor con un break - lo intercetto
    write (BRKSCR, 0);    // Disables breakpoints
    tmpBpAddress = NOBREAKPOINT;  // Clears temporary breakpoint
  readRegisters ();
}

/* Subito dopo il reset occorre inviare il "codice di sblocco" per abilitare la letura
 * Se al funzione ritorna "false", il codice era errato, altimenti era corretto */
int Processor::resetVector (unsigned char *vector)
{
 int i;
  if (!vector) {
    vector = clean;
  }
  PowerOnReset ();
  for (i = 0; i < 8; i++) {
    schPutc (vector [i]);
    // prt->printf ("%02X ",vector [i]);
  }
  // prt->printf ("\n");
  // Adesso deve arrivare un "break"
//  mysleep (22920);  /* corrispondono a 22 bit a 9600 baud */
  mysleep (50000);  /* corrispondono a 22 bit a 9600 baud */
  flushInput ();  // Scarte l'eventuale break
  curProcessor = fingerPrint ();
  if (curProcessor < 0) { // Processore non riconosciuto - non programmabile
    return 0; // Scrittura disabilitata
  }
  // Se il bit 6 della cella 0x40 (prima della RAM) e' settato, il codice era corretto
  return read (procConfigs [curProcessor].ramstart) & 0x40;
}

int Processor::fingerPrint ()
{
unsigned char curprints [NUMFPPOINTS];
unsigned int i, j, d;
  prt->printf ("{ ");
  for (i = 0; i < NUMFPPOINTS; i++) {
    d = read (prrtAddrs [i]);
    if (prrtAddrs [i] > 0xffff) { // RAM test
      write (prrtAddrs [i], ISRAM); // Writes a standard value (0x55)
      // For RAM cells, the fingetrpint contains the standard value (0x55) if the RAM is present
      // or 0xAD (illegal access) if ti's not RAM
      curprints [i] = read (prrtAddrs [i]);
      write (prrtAddrs [i], d); // Rewrites original value (if RAM)
      prt->printf ("0x%02x /* 0x%02x */, ", curprints [i], d);
    } else {
      curprints [i] = d;
      prt->printf ("0x%02x, ", curprints [i]);
    }
  }
  prt->printf ("},\n");
  for (i = 0; i < NUMPRINTS; i++) {
    for (j = 0; j < NUMFPPOINTS; j++) {
      if (prrtAddrs [j] > 0xffff) { // RAM test
        if (curprints [j] != ISRAM && prints [i][j] == ISRAM) {
          prt->printf ("RAM (%d, %d) : 0x%02x, (richiesta %02x)\n", i, j, curprints [i], prints [i][j]);
          break;  // Fingerprint doesn't match
        }
      } else {
        if (curprints [j] != prints [i][j]) {
          prt->printf ("ROM (%d, %d) : 0x%02x, (richiesta %02x)\n", i, j, curprints [i], prints [i][j]);
          break;  // Fingerprint doesn't match
        }
      }
    }
    if (j == NUMFPPOINTS) { // ha finito il ciclo, quindi il fingerprint e' corretto
      prt->printf ("Processore %s\n", procConfigs [i].descr);
      return i;
    }
  }
  prt->printf ("Processore Non Riconosciuto\n");
  return -1;
}

void Processor::clearChip ()
{
int n;
  n = resetVector (NULL);
  if (curProcessor < 0) {
    throw (new Exception ("Processore sconosciuto, non posso programmarlo\n"));
  }
  uploadPrg (eraCode (), eraCodeStart (), eraCodeLen ());
  // * When in Monitor mode, with security sequence failed (see 15.5 Security), write to the FLASH
  // block protect register instead of any FLASH address.
  // sendWrCommand (int stad, int datalen, unsigned char *data, int pagelen)
  mysleep (50000);  // Aggiunto, prima della priogrammazione, per il QT
  sendWrCommand (eraAddress (n), pageLen () + 0x10, clean, pageLen ());
}

void Processor::uploadPrg (const unsigned char *pgm, int start, int num)
{
int i;
  prt->printf ("Scarico il programma di scrittura in RAM\n");
  // Scarica in RAM il programma
  // prt->printf ("[");
  // for (i = 0; i < num; i+=32) {
  //   prt->printf (" ");
  // }
  // printf ("]\r[");
  for (i = 0; i < num; i++) {
    if (i % 32 == 0) {
      // prt->printf(".");
      fflush (stdout);
      write (start + i, pgm [i]);
    } else {
      iwrite (pgm [i]);
    }
  }

  go (start);
}

void Processor::go (int start)
{
  if (start > 0) {
    setPc (start);
  }
  stackprep ();
  run (); // Lancia il programma in RAM
  prt->printf ("\nProgramma scaricato e lanciato (pgm = %04X)\n", start);
}

/*
Message Byte                    Description                  Final RAM
  Location                                                    Location

             Count of the total number of bytes
      1       to be downloaded, including this byte             $50

             First address where the following data is
     2­3      to be programmed                                $51­$52

             Number of bytes to be programmed, or $00
              to just dump this referenced row, or a value
      4       between $80 and $FF to erase the entire           $53
              FLASH array

    5­68     Locations for 64 bytes of data to be programmed  $54­$93

NOTE: If byte 4 is equal to 0, then nothing will be programmed. But the content
      of the row referenced by the first address bytes will be uploaded to the
      host. This first address, in this case, need not be the starting address for
      this row, but the 64 bytes downloaded will be within the row boundary.
      For example, if address $B3B3 is downloaded with byte 4 being 0, then
      the 64 bytes in the range $B380­$B3BF will be downloaded. This may
      be useful when performing host verification without programming.
      Note also that if byte 4 is a value between $80 and $FF, then the entire
      FLASH array will be erased. In this case, the first row of the erased
      FLASH ($B000­$B03F) is uploaded.
      Uploads will not have header bytes. Instead, they will contain only 64
      data bytes. The host message format should be sent with the same
      protocol for which the SCI has been initialized, namely 9600 baud, one
      start bit, one stop bit, and no parity.
 */
void Processor::sendWrCommand (int stad, int datalen, unsigned char *data, int pagelen)
{
int j,b,sendlen;
  if (datalen <= pagelen) {
    sendlen = datalen;
  } else {
    sendlen = 0;
    datalen = pagelen;
  }
  schPutc (sendlen+HEADLEN);  // Dimensione record
  schPutc (stad>>8);        // Indirizzo Hi
  schPutc (stad&0xff);      // Indirizzo Lo
  schPutc (datalen);      // Dimensione Dati
  // Spedisce i byte
  for (j = 0; j < sendlen; j++) {
    schPutc (data [j]);     // Dati
  }
  // Legge i byte ritornati
  try {
  for (j = 0; j < pagelen; j++) {
    b = schGetc ((j) ? STDTIMEOUT : LONGTIMEOUT);
    if (j % 16 == 0) {
      prt->printf ("\n%04X ",j + stad);
    }
    prt->printf (" %02x", b & 0xff);
  }
    prt->printf ("\n");
  } catch (void *) {
    prt->printf (" (!)\n");
  }
}

/* La ROM e' cancellata se le locazioni fffe ed ffff sono entrambe ad FF */
/* m = 0 -> Rom erased, Write enabled
 * m = 1 -> Rom programmed, Write enabled
 * m = 2 -> Rom erased, Write protected (bad programming)
 * m = 3 -> Rom programmed, Write Protected
 */
int Processor::isErased (unsigned char *resVector)
{
int r0, r1, m;
  if (resetVector (resVector)) {
    m = 0;
    prt->printf ("La scrittura e' abilitata\n");
  } else {
    m = 2;
    prt->printf ("La scrittura e' disabilitata - occorre cancellare il Chip\n");
  }

  r0 = read (0xfffe);
  r1 = read (0xffff);
  return ((r0 == 0xff && r1 == 0xff) ? 0 : 1) + m;
}

void Processor::programChip (const char *hexfile)
{
int i;
int n = 0;
int s;

  n = isErased (NULL);
  if (!n) {
    prt->printf ("La ROM e' cancellata\n");
  } else if (n == -1) {
    throw (new Exception ("La ROM e' prgrammata\n"));
  }
  uploadPrg (pgmCode (), pgmCodeStart (), pgmCodeLen ());

/*
Message Byte                    Description                  Final RAM
  Location                                                    Location

             Count of the total number of bytes
      1       to be downloaded, including this byte             $50

             First address where the following data is
     2­3      to be programmed                                $51­$52

             Number of bytes to be programmed, or $00
              to just dump this referenced row, or a value
      4       between $80 and $FF to erase the entire           $53
              FLASH array

    5­68     Locations for 64 bytes of data to be programmed  $54­$93

NOTE: If byte 4 is equal to 0, then nothing will be programmed. But the content
      of the row referenced by the first address bytes will be uploaded to the
      host. This first address, in this case, need not be the starting address for
      this row, but the 64 bytes downloaded will be within the row boundary.
      For example, if address $B3B3 is downloaded with byte 4 being 0, then
      the 64 bytes in the range $B380­$B3BF will be downloaded. This may
      be useful when performing host verification without programming.
      Note also that if byte 4 is a value between $80 and $FF, then the entire
      FLASH array will be erased. In this case, the first row of the erased
      FLASH ($B000­$B03F) is uploaded.
      Uploads will not have header bytes. Instead, they will contain only 64
      data bytes. The host message format should be sent with the same
      protocol for which the SCI has been initialized, namely 9600 baud, one
      start bit, one stop bit, and no parity.
 */

  programS19 (hexfile);
}

int Processor::programS19 (const char *hexfile)
{
unsigned char *prog, *used;
int i, h, r;

  prog = (unsigned char *) malloc (IMGLEN); // Il programma scaricato
  used = (unsigned char *) malloc (FLGLEN); // Mappa delle pagine scritte (pagina = 64 byte)
  if (!prog || !used) {
    throw (new Exception ("Errore!!! manca memoria\n"));
  }
  readS19 (hexfile, IMGSTART, IMGLEN, prog, used);

  mysleep (50000);  // Aggiunto, prima della priogrammazione, per il QT

  for (i = 0;i*pageLen () < IMGLEN; i++) {
    if (used [i]) { // Registra la pagina - ci sono dati letti
    int j, base, st = -1, en = 0,len;
      base = (i*pageLen ());
      for (j = 0; j < pageLen (); j++) {
        if (prog [base+j] != 0xff) {
          en = base+j;
          if (st < 0) {
            st = base+j;
          }
        }
      }
      len = en - st + 1;
      prt->printf ("Programmo da %04x per %02x byte [%d su %d]\n",st + IMGSTART,len, i, FLGLEN);
      sendWrCommand (st + IMGSTART, len, prog + st, pageLen ());
    }
  }

  free (prog);
  free (used);
  prt->printf ("\n");
  return 0;
}

/* ************************************************************ */
/* Funzioni per file HEX S19                                    */
/* ************************************************************ */
#define MAXLINE 1024

int Processor::hex0 (char c)
{
  return (c >= '0' && c <= '9') ? (c - '0') : ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :
    ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0));
}

int Processor::hex (char *c)
{
  return hex0 (c[0]) * 16 + hex0 (c [1]);
}

/* Reads an S19 Hex file and comares it with the content
 * of the procesor ROM.
 * Return 0 on error (different contents) and -1 on success (program matches ROM)
 */
int Processor::verifyChip (const char *hexfile)
{
char line [MAXLINE + 1];
int len,i,cks, address;
int h;
FILE *s19;

  s19 = fopen (hexfile,"r");
  if (!s19) {
    throw (new Exception ("ERRORE: non posso aprire il file '%s'\n", hexfile));
  }

  while (!feof (s19)) {
    if (fgets (line, MAXLINE, s19)) {
      // puts (line);
      if (line[0] != 's' && line [0] != 'S') {
        prt->printf ("WARNING: Record non riconosciuto\n");
        continue;
      }

      len = hex (line+2);
      for (cks = i = 0; i<len; i++) {
        cks += hex (line + (2 * i + 2));  // Chacksum dalla lunghezza compresa al checksum escluso
      }

      cks = (cks & 0xff) ^ 0xff;
      if (cks != hex (line + (2 * i + 2))) {
        fclose (s19);
        throw (new Exception ("ERRORE: Linea scorretta (Lunghezza %d (%02x), Checksum calcolato %02x, letto %02x)\n", len, len, cks,
          hex (line + (2 * i + 2))));
      }

      switch (line[1]) {
        case '0' :  // E' una stringa di descrizione
          // prt->printf ("Record S0 di descrizione; contentuo:\n");
          for (i = 0; i<len - 3; i++) {
            putchar (hex (line + (2 * i + 8)));
          }
          prt->printf ("\n\n");
          break;
        case '1' :  // Mi interessano solo i dati con indirizzo a 16 bit
          // prt->printf ("Record S1 di dati con indirizzo a 16 bit; contentuo");
          address = hex (line + (4)) * 256 + hex (line + (6));
          for (i = 0; i < len - 3; i++) {
            h = hex (line + (2 * i + 8));
            int r = read (address);
            if (r != h) { // There is a difference
            prt->printf ("Error at address %04x: Found %02x, expcted %02x\n", address, r, h);
              return 0;
            }
            address ++;
          }
          break;
        case '9' :  // Terminatore
          prt->printf ("\nRecord S9: Fine dati HEX\n");
          break;
        default:
          prt->printf ("\nWARNING: Record s%c non supportato\n", line [1]);
          continue;
      }
    }
  }
  fclose (s19);
  return -1;
}

void Processor::readS19 (const char *hexfile, int start, int imglen,unsigned char *prog, unsigned char *used)
{
char line [MAXLINE + 1];
int len,i,cks, address;
int h;
FILE *s19;

  s19 = fopen (hexfile,"r");
  if (!s19) {
    throw (new Exception ("ERRORE: non posso aprire il file '%s'\n", hexfile));
  }

  for (i = 0;i < imglen; i++) {
    prog [i] = 0xff;
  }
  if (used) {
    for (i = 0;i < imglen/pageLen (); i++) {
      used [i] = 0;
    }
  }

  while (!feof (s19)) {
    if (fgets (line, MAXLINE, s19)) {
      // puts (line);
      if (line[0] != 's' && line [0] != 'S') {
        prt->printf ("WARNING: Record non riconosciuto\n");
        continue;
      }

      len = hex (line+2);
      for (cks = i = 0; i<len; i++) {
        cks += hex (line + (2 * i + 2));  // Chacksum dalla lunghezza compresa al checksum escluso
      }

      cks = (cks & 0xff) ^ 0xff;
      if (cks != hex (line + (2 * i + 2))) {
        fclose (s19);
        throw (new Exception ("ERRORE: Linea scorretta (Lunghezza %d (%02x), Checksum calcolato %02x, letto %02x)\n", len, len, cks,
          hex (line + (2 * i + 2))));
      }

      switch (line[1]) {
        case '0' :  // E' una stringa di descrizione
          // prt->printf ("Record S0 di descrizione; contentuo:\n");
          for (i = 0; i<len - 3; i++) {
            putchar (hex (line + (2 * i + 8)));
          }
          prt->printf ("\n\n");
          break;
        case '1' :  // Mi interessano solo i dati con indirizzo a 16 bit
          // prt->printf ("Record S1 di dati con indirizzo a 16 bit; contentuo");
          address = hex (line + (4)) * 256 + hex (line + (6));
          for (i = 0; i < len - 3; i++) {
            h = hex (line + (2 * i + 8));
            if (address >= start && address < (start + imglen)) {
              prog [address - start] = h;
              if (used) {
                used [(address - start)/pageLen ()] = 1;
              }
            }
            /* if (i % 16 == 0) {
              prt->printf ("\n%04x ", address);
            }
            prt->printf (" %02x", h); */
            address ++;
          }
          // prt->printf ("\n");
          break;
        case '9' :  // Terminatore
          prt->printf ("\nRecord S9: Fine dati HEX\n");
          break;
        default:
          prt->printf ("\nWARNING: Record s%c non supportato\n", line [1]);
          continue;
      }
    }
  }
  fclose (s19);
}

void Processor::reset () {
  pc = (memory[0xfffe] << 8) | memory[0xffff];
  sp = 0x00ff;
}

void Processor::emulateProgram (const char *hexfile) {
  emulating = true;
  memory = new unsigned char [IMGEND];  // Alloca la RAM-ROM-I/O
  printf ("Carico il file %s; %d byte di memoria disponibile\n", hexfile, IMGEND);
  firstOp = secondOp = -1;
  readS19 (hexfile, 0, IMGEND, memory, NULL);
  reset ();
}

int Processor::signExtend8 (unsigned int n) {
  if (n & 0x80) {
    n = (-1 & ~0xff) | n;
  }
  return n;
}

unsigned int Processor::rel () {
  return pc + signExtend8(read(pc++)) + 1;
}

// Ritorna sempre il primo indirizzamento del tipo
unsigned int Processor::getAddr (admod modo) {
  unsigned int addr = 0;
  switch (modo) {
    case DIR_REL :
    case DD :         // MOV dir, dir (4e)
    case DIR8 :
      addr = read(pc++);
      break;
    case REL :
      addr = rel();
      break;
    case INH :
      addr =  0;
      break;
    case IMM_REL :
    case IMM :
    case IMD :        // MOV IMM,DIR (6e)
    case IMM16 :
    case DIX_P :  // MOV mem,mem - DIR/IX+ (5E)
      addr =  pc++;
      break;
    case EXT :
    case JEXT :
      addr = read(pc++) << 8;
      addr |= read(pc++);
      break;
    case IX :
      addr = hx;
      break;
    case IX1 :
      addr = hx + read(pc++);
      break;
    case IX2 :
      addr = read(pc++) << 8;
      addr = hx + addr + read(pc++);
      break;
    case SP1 :
    case SP1_REL :
      addr = sp + read(pc++);
      break;
    case SP2 :
      addr = read(pc++) << 8;
      addr = sp + addr + read(pc++);
      break;
    case IX_P_REL : // CBEQ ,IX+,rel (71)
    case IX_P_D :     // MOV ,IX,DIR (7e)
      addr = hx++;
      break;
    case IX1_P_REL :  // CBEQ off,IX+,rel (61)
      addr = hx++ + read(pc++);
      break;
  }

  switch (modo) {
    case DIR_REL :
    case DD :         // MOV dir, dir (4e)
    case DIR8 :
    case IMM16 :
    case DIX_P :  // MOV mem,mem - DIR/IX+ (5E)
    case EXT :
    case IX :
    case IX1 :
    case IX2 :
    case SP1 :
    case SP1_REL :
    case SP2 :
    case IX_P_REL : // CBEQ ,IX+,rel (71)
    case IX_P_D :     // MOV ,IX,DIR (7e)
    case IX1_P_REL :  // CBEQ off,IX+,rel (61)
      if (firstOp < 0) {
        firstOp = addr;
      } else {
        secondOp = addr;
      }
      break;
  }

  return addr & 0xffff;
}

void Processor::push (unsigned char d) {
  write (sp--, d);
}

unsigned char Processor::pull () {
  return read (++sp);
}

#define M15     (m&0x8000)
#define R15     (r&0x8000)
#define R8		(r&0x100)
#define H7      (hx&0x8000)
#define X7      (hx&0x80)
#define A7      (a&0x80)
#define R7      (r&0x80)
#define M7      (m&0x80)
#define A3      (a&0x8)
#define R3      (r&0x8)
#define M3      (m&0x8)
#define M0      (m&0x1)

#define H       (hx&0xff00)
#define X       (hx&0xff)

#define BASECCR 0x60
#define CBIT    0x1
#define NOTCBIT 0xfe
#define ZBIT    0x2
#define NOTZBIT 0xfd
#define NBIT    0x4
#define NOTNBIT 0xfb
#define IBIT    0x8
#define NOTIBIT 0xf7
#define HBIT    0x10
#define NOTHBIT 0xef
#define VBIT    0x80
#define NOTVBIT 0x7f

#define ISC     (ccr&CBIT)
#define ISZ     (ccr&ZBIT)
#define ISN     (ccr&NBIT)
#define ISI     (ccr&IBIT)
#define ISH     (ccr&HBIT)
#define ISV     (ccr&VBIT)


void Processor::noop () {
}

void Processor::adc (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned short r = a + m + (ccr & 0x1);
  ccr = (ccr & 0x8) | 0x60;
  if ((A7 && M7 && !R7) || (!A7 && !M7 && R7)) { // V - overflow
    ccr |= VBIT;
  }
  if ((A3 && M3) || (M3 && !R3) || (!R3 && A3)) { // H - half-carry
    ccr |= HBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(a & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (R8) { // C - Carry
    ccr |= CBIT;
  }
  a = r & 0xff;
}

void Processor::add (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned short r = a + m;
  ccr = (ccr & 0x8) | 0x60;
  if ((A7 && M7 && !R7) || (!A7 && !M7 && R7)) { // V - overflow
    ccr |= VBIT;
  }
  if ((A3 && M3) || (M3 && !R3) || (!R3 && A3)) { // H - half-carry
    ccr |= HBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (R8) { // C - Carry
    ccr |= CBIT;
  }
  a = r & 0xff;
}

void Processor::andl (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a & m;
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  a = r;
}

unsigned char Processor::asl (unsigned char m) {
  unsigned char r = (m  << 1) & 0xfe;
  ccr = (ccr & 0x78) | 0x60;
  if ((M7 && R7) || (!M7 && !R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (M7) { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

unsigned char Processor::asr (unsigned char m) {
  unsigned char r = ((m  >> 1) & 0x7f) || M7;
  ccr = (ccr & 0x78) | 0x60;
  if ((M0 && R7) || (!M0 && !R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (M0) { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

void Processor::bitl (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a & m;
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::cmp (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned short r = a - m;
  ccr = (ccr & 0x78) | 0x60;
  if ((A7 && !M7 && !R7) || (!A7 && M7 && R7)) { // V - overflow
  // if ((R8 && (R7 != A7)) || (!R8 && (R7 == A7))) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (R8) { // C - Carry
    ccr |= CBIT;
  }
}

unsigned char Processor::com (unsigned char m) {
  unsigned char r = ~m;
  ccr = (ccr & BASECCR) | (CBIT);
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }

  return r;
}

void Processor::comm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, com (read (addr)));
}

void Processor::cphx (admod am) {
  unsigned addr = getAddr (am);
  unsigned short r,m;
  m = (read(addr) << 8) || read (addr+1);
  r = hx - m;
  ccr = (ccr & 0x78) | BASECCR;
  if ((H7 && !M15 && !R15) || (!H7 && M15 && R15)) { // V - overflow
    ccr |= VBIT;
  }
  if (R15) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xffff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if ((!H7 && M15) || (M15 && R15) || (R15 & !H7)) { // C - Carry
    ccr |= CBIT;
  }
}

void Processor::cpx (admod am) {
  unsigned addr = getAddr (am);
  unsigned char r,m;
  m = read(addr);
  r = X - m;
  ccr = (ccr & 0x78) | BASECCR;
  if ((X7 && !M7 && !R7 )|| (!X7 && M7 && R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if ((!X7 && M7) || (M7 && R7) || (R7 && !X7)) { // C - Carry
    ccr |= CBIT;
  }
}

void Processor::daa () {
  unsigned char r,cf = 0;
  if (ISC) {
    if (ISH) {
      cf = 0x66;
    } else {
      if ((a&0xf) > 9) {
        cf = 0x66;
        ccr |= CBIT;
      } else {
        cf = 0x60;
        ccr |= CBIT;
      }
    }
  } else {
    if (ISH) {
      if (a > 0x90) {
        cf = 0x66;
        ccr |= CBIT;
      } else {
        cf = 0x6;
      }
    } else {
      if ((a&0xf) > 9) {
        if ((a & 0xf0) < 9) {
          cf = 0x6;
        } else {
          cf = 0x66;
          ccr |= CBIT;
        }
      } else {
        if ((a&0xf0) > 9) {
          cf = 0x60;
          ccr |= CBIT;
        }
      }
    }
  }
  r = a + cf;
  ccr = (ccr & 0x79) | BASECCR;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  a = r;
}

int Processor::dnz (admod am) {
  unsigned addr = getAddr (am);
  unsigned char m = read(addr) -1;
  write (addr,m);
  return m;
}

unsigned char Processor::dec (unsigned char m) {
  unsigned char r = m - 1;
  ccr = (ccr & (BASECCR | CBIT)) | (BASECCR);
  if (!R7 & !M7) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }

  return r;
}

void Processor::decm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, dec (read (addr)));
}

void Processor::div () {
  unsigned d = H | (a & 0xff);
  unsigned char x = X;
  ccr = (ccr & 0xfc) | (BASECCR);
  if (x) {
    a = d / x;
    hx = ((d % x) << 8) | x;
  } else {
    ccr |= CBIT;
  }
  if (!(a & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::eor (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a ^ m;
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  a = r;
}

unsigned char Processor::inc (unsigned char m) {
  unsigned char r = m + 1;
  ccr = (ccr & (BASECCR | CBIT)) | (BASECCR);
  if (!A7 && R7) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }

  return r;
}

void Processor::incm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, inc (read (addr)));
}

void Processor::jsr (admod am) {
  unsigned int addr = getAddr(am);
  push (pc & 0xff);
  push ((pc >> 8) & 0xff);
  pc = addr;
}

void Processor::lda (admod am) {
  unsigned char r = read (getAddr (am));
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  a = r;
}

void Processor::ldhx (admod am) {
  unsigned addr = getAddr (am);
  unsigned short m;
  m = (read(addr) << 8) | read (addr+1);
  ccr = (ccr & 0x79) | BASECCR;
  if (M15) { // N - Negative
    ccr |= NBIT;
  }
  if (!(m & 0xffff)) { // Z - Zero
    ccr |= ZBIT;
  }
  hx = m;
}

void Processor::ldx (admod am) {
  unsigned char r = read (getAddr (am));
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  hx = H | (r & 0xff);
}

unsigned char Processor::lsr (unsigned char m) {
  unsigned char r = (m  >> 1) & 0x7f;
  ccr = (ccr & 0x78) | 0x60;
  if (M0) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if M0 { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

void Processor::lsrm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, lsr (read (addr)));
}

void Processor::mul () {
  unsigned d = X * a;
  ccr = (ccr & 0xee) | (BASECCR);
  hx = H | ((d >> 8) & 0xff);
  a = d & 0xff;
}

void Processor::ora (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a | m;
  ccr = (ccr & 0x79) | 0x60;
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  a = r;
}

unsigned char Processor::neg (unsigned char m) {
  unsigned char r = - m;
  ccr = (ccr & 0x78) | 0x60;
  if (M7 && R7) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (r & 0xff) { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

void Processor::negm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, neg (read (addr)));
}

unsigned char Processor::rol (unsigned char m) {
  unsigned char r = (m  << 1) & 0xfe | (ccr & 0x80);
  ccr = (ccr & 0x78) | 0x60;
  if ((!R7 && !M7) || (R7 && M7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if (M7) { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

void Processor::rolm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, rol (read (addr)));
}

unsigned char Processor::ror (unsigned char m) {
  unsigned char r = (m  >> 1) & 0x7f | ((ccr << 7) & 0x80);
  ccr = (ccr & 0x78) | 0x60;
  if ((M0 && R7) || (!M0 && ! !R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if M0 { // C - Carry
    ccr |= CBIT;
  }
  return r;
}

void Processor::rorm (admod am) {
  unsigned addr = getAddr (am);
  write (addr, ror (read (addr)));
}

void Processor::sbc (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a - m - (ccr & 0x1);
  ccr = (ccr & 0x78) | 0x60;
  if ((A7 && !M7 && !R7) || (!A7 && M7 && R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if ((!A7 && M7) || (M7 && R7) || (R7 && !A7)) { // C - Carry
    ccr |= CBIT;
  }
  a = r;
}

void Processor::sta (admod am) {
  write (getAddr (am), a);
  ccr &= 0x79;
  if (A7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(a & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::sthx (admod am) {
  unsigned addr = getAddr (am);
  write (addr, hx >> 8);
  write (addr + 1, hx);
  ccr &= 0x79;
  if (H7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(hx & 0xffff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::stop () {
}

void Processor::stx (admod am) {
  write (getAddr (am), hx);
  ccr &= 0x79;
  if (X7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(hx & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::wait () {
}


void Processor::sub (admod am) {
  unsigned char m = read (getAddr (am));
  unsigned char r = a - m;
  ccr = (ccr & 0x78) | 0x60;
  if ((A7 && !M7 && !R7) || (!A7 && M7 && R7)) { // V - overflow
    ccr |= VBIT;
  }
  if (R7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(r & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
  if ((!A7 && M7) || (M7 && R7) || (R7 && !A7)) { // C - Carry
    ccr |= CBIT;
  }
  a = r;
}

void Processor::tst (unsigned char m) {
  if (M7) { // N - Negative
    ccr |= NBIT;
  }
  if (!(m & 0xff)) { // Z - Zero
    ccr |= ZBIT;
  }
}

void Processor::tstm (admod am) {
  unsigned addr = getAddr (am);
  tst (read (addr));
}

void Processor::emulate () {
unsigned char opcode;
unsigned addr,addrd;
admod am;
  firstOp = secondOp = -1;
  opcode = read (pc++);
  am = opcodes[opcode].op_mode;
  switch (opcode) {
    case 0x00 : // BRSET0 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x01) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x01 : // BRCLR0 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x01) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x02 : // BRSET1 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x02) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x03 : // BRCLR1 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x02) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x04 : // BRSET2 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x04) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x05 : // BRCLR2 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x04) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x06 : // BRSET3 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x08) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x07 : // BRCLR3 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x08) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x08 : // BRSET4 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x10) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x09 : // BRCLR4 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x10) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x0a : // BRSET5 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x20) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x0b : // BRCLR5 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x20) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x0c : // BRSET6 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x40) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x0d : // BRCLR6 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x40) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x0e : // BRSET7 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x80) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x0f : // BRCLR7 Indirizzamento DIR_REL Lunghezza 3
      if (read (getAddr(am)) & 0x80) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x10 : // BSET0 Indirizzamento DIR Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x01);
      break;
    case 0x11 : // BCLR0 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xfe);
      break;
    case 0x12 : // BSET1 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x02);
      break;
    case 0x13 : // BCLR1 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xfd);
      break;
    case 0x14 : // BSET2 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x04);
      break;
    case 0x15 : // BCLR2 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xfb);
      break;
    case 0x16 : // BSET3 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x08);
      break;
    case 0x17 : // BCLR3 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xf7);
      break;
    case 0x18 : // BSET4 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x10);
      break;
    case 0x19 : // BCLR4 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xef);
      break;
    case 0x1a : // BSET5 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x20);
      break;
    case 0x1b : // BCLR5 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xdf);
      break;
    case 0x1c : // BSET6 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x40);
      break;
    case 0x1d : // BCLR6 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0xbf);
      break;
    case 0x1e : // BSET7 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) | 0x80);
      break;
    case 0x1f : // BCLR7 Indirizzamento DIR_REL Lunghezza 2
      addr = getAddr(am);
      write (addr, readMem (addr) & 0x7f);
      break;
    case 0x20 : // BRA Indirizzamento REL Lunghezza 2
      pc = getAddr(REL);
      break;
    case 0x21 : // BRN Indirizzamento REL Lunghezza 2
      pc++;
      break;
    case 0x22 : // BHI Indirizzamento REL Lunghezza 2
      if ((ccr & 0x3)) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x23 : // BLS Indirizzamento REL Lunghezza 2
      if (ccr & 0x3) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x24 : // BCC Indirizzamento REL Lunghezza 2
      if (ccr & 0x1) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x25 : // BCS Indirizzamento REL Lunghezza 2
      if (ccr & 0x1) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x26 : // BNE Indirizzamento REL Lunghezza 2
      if (ccr & 0x2) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x27 : // BEQ Indirizzamento REL Lunghezza 2
      if (ccr & 0x2) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x28 : // BHCC Indirizzamento REL Lunghezza 2
      if (ccr & 0x4) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x29 : // BHCS Indirizzamento REL Lunghezza 2
      if (ccr & 0x4) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x2a : // BPL Indirizzamento REL Lunghezza 2
      if (ccr & 0x4) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x2b : // BMI Indirizzamento REL Lunghezza 2
      if (ccr & 0x4) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x2c : // BMC Indirizzamento REL Lunghezza 2
      if (ccr & 0x8) {
        pc ++;
      } else {
        pc = getAddr(REL);
      }
      break;
    case 0x2d : // BMS Indirizzamento REL Lunghezza 2
      if (ccr & 0x8) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x2e : // BIL Indirizzamento REL Lunghezza 2
      // if (ccr & 0x8) {    // Testa il piedino "esterno" di "int"
      //  pc ++;
      // } else {
        pc = getAddr(REL);
      // }
      break;
    case 0x2f : // BIH Indirizzamento REL Lunghezza 2
      // if (ccr & 0x8) {    // Testa il piedino "esterno" di "int"
      //  pc = getAddr(REL);
      // } else {
        pc ++;
      // }
      break;
    case 0x30 : // NEG Indirizzamento DIR8 Lunghezza 2
      negm (am);
      break;
    case 0x31 : // CBEQ Indirizzamento DIR8 Lunghezza 3
      if (a == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x32 : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x33 : // COM Indirizzamento DIR8 Lunghezza 2
      comm(am);
      break;
    case 0x34 : // LSR Indirizzamento DIR8 Lunghezza 2
      lsrm (am);
      break;
    case 0x35 : // STHX Indirizzamento DIR8 Lunghezza 2
      sthx (am);
      break;
    case 0x36 : // ROR Indirizzamento DIR8 Lunghezza 2
      rorm (am);
      break;
    case 0x37 : // ASR Indirizzamento DIR8 Lunghezza 2
      addr = getAddr(am);
      write (addr, asr (read(addr)));
      break;
    case 0x38 : // LSL Indirizzamento DIR8 Lunghezza 2
      addr = getAddr(am);
      write (addr, asl (read(addr)));
      break;
    case 0x39 : // ROL Indirizzamento DIR8 Lunghezza 2
      rolm (am);
      break;
    case 0x3a : // DEC Indirizzamento DIR8 Lunghezza 2
      decm (am);
      break;
    case 0x3b : // DBNZ Indirizzamento DIR_REL Lunghezza 3
      if (dnz(am)) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x3c : // INC Indirizzamento DIR8 Lunghezza 2
      incm (am);
      break;
    case 0x3d : // TST Indirizzamento DIR8 Lunghezza 2
      tstm (am);
      break;
    case 0x3e : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x3f : // CLR Indirizzamento DIR8 Lunghezza 2
      write( getAddr(am), 0);
      break;
    case 0x40 : // NEGA Indirizzamento INH Lunghezza 1
      a = neg(a);
      break;
    case 0x41 : // CBEQA Indirizzamento IMM_REL Lunghezza 3
      if (a == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x42 : // MUL Indirizzamento INH Lunghezza 1
      mul ();
      break;
    case 0x43 : // COMA Indirizzamento INH Lunghezza 1
      a = com(a);
      break;
    case 0x44 : // LSRA Indirizzamento INH Lunghezza 1
      a = lsr (a);
      break;
    case 0x45 : // LDHX Indirizzamento IMM16 Lunghezza 3
      ldhx(am);
      pc++;
      break;
    case 0x46 : // RORA Indirizzamento INH Lunghezza 1
      a = ror(a);
      break;
    case 0x47 : // ASRA Indirizzamento INH Lunghezza 1
      a = asr (a);
      break;
    case 0x48 : // LSLA Indirizzamento INH Lunghezza 1
      a = asl (a);
      break;
    case 0x49 : // ROLA Indirizzamento INH Lunghezza 1
      a = rol(a);
      break;
    case 0x4a : // DECA Indirizzamento INH Lunghezza 1
      a = dec(a);
      break;
    case 0x4b : // DBNZA Indirizzamento INH Lunghezza 2
      if (--a) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x4c : // INCA Indirizzamento INH Lunghezza 1
      a = inc(a);
      break;
    case 0x4d : // TSTA Indirizzamento INH Lunghezza 1
      tst (a);
      break;
    case 0x4e : // MOV Indirizzamento DD Lunghezza 3
      addr = getAddr(DIR8);
      addrd = getAddr(DIR8);
      write (addrd, read(addr));
      break;
    case 0x4f : // CLRA Indirizzamento INH Lunghezza 1
      a = 0;
      break;
    case 0x50 : // NEGX Indirizzamento INH Lunghezza 1
      hx = H | (neg(X) & 0xff);
      break;
    case 0x51 : // CBEQX Indirizzamento IMM_REL Lunghezza 3
      if (X == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x52 : // DIV Indirizzamento INH Lunghezza 1
      div ();
      break;
    case 0x53 : // COMX Indirizzamento INH Lunghezza 1
      hx = H | (com(X) & 0xff);
      break;
    case 0x54 : // LSRX Indirizzamento INH Lunghezza 1
      hx = H | (lsr(X) & 0xff);
      break;
    case 0x55 : // LDHX Indirizzamento DIR8 Lunghezza 2
      ldhx(am);
      break;
    case 0x56 : // RORX Indirizzamento INH Lunghezza 1
      hx = H | (ror (X) & 0xff);
      break;
    case 0x57 : // ASRX Indirizzamento INH Lunghezza 1
      hx = H | (asr(X) & 0xff);
      break;
    case 0x58 : // LSLX Indirizzamento INH Lunghezza 1
      hx = H | (asl (X) & 0xff);
      break;
    case 0x59 : // ROLX Indirizzamento INH Lunghezza 1
      hx = H | (rol (X) & 0xff);
      break;
    case 0x5a : // DECX Indirizzamento INH Lunghezza 1
      hx = H | (dec(X) & 0xff);
      break;
    case 0x5b : // DBNZX Indirizzamento INH Lunghezza 2
      hx = H | ((X - 1) & 0xff);
      if (hx&0xff) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x5c : // INCX Indirizzamento INH Lunghezza 1
      hx = H | (inc (X) & 0xff);
      break;
    case 0x5d : // TSTX Indirizzamento INH Lunghezza 1
      tst (hx);
      break;
    case 0x5e : // MOV Indirizzamento DIX_P Lunghezza 2
      addr = getAddr(DIR8);
      addrd = getAddr(IX_P_D);
      write (addrd, read(addr));
      break;
    case 0x5f : // CLRX Indirizzamento INH Lunghezza 1
      hx &= 0xff00;
      break;
    case 0x60 : // NEG Indirizzamento IX1 Lunghezza 2
      negm (am);
      break;
    case 0x61 : // CBEQ Indirizzamento IX1_P_REL Lunghezza 3
      if (a == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x62 : // NSA Indirizzamento INH Lunghezza 1
      a = ((a >> 4) & 0x0f) | ((a << 4) & 0xf0);
      break;
    case 0x63 : // COM Indirizzamento IX1 Lunghezza 2
      comm(am);
      break;
    case 0x64 : // LSR Indirizzamento IX1 Lunghezza 2
      lsrm (am);
      break;
    case 0x65 : // CPHX Indirizzamento IMM16 Lunghezza 3
      cphx (am);
      pc++;
      break;
    case 0x66 : // ROR Indirizzamento IX1 Lunghezza 2
      rorm (am);
      break;
    case 0x67 : // ASR Indirizzamento IX1 Lunghezza 2
      addr = getAddr(am);
      write (addr, asr (read(addr)));
      break;
    case 0x68 : // LSL Indirizzamento IX1 Lunghezza 2
      addr = getAddr(am);
      write (addr, asl (read(addr)));
      break;
    case 0x69 : // ROL Indirizzamento IX1 Lunghezza 2
      rolm (am);
      break;
    case 0x6a : // DEC Indirizzamento IX1 Lunghezza 2
      decm (am);
      break;
    case 0x6b : // DBNZ Indirizzamento IX1 Lunghezza 3
      if (dnz(am)) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x6c : // INC Indirizzamento IX1 Lunghezza 2
      incm (am);
      break;
    case 0x6d : // TST Indirizzamento IX1 Lunghezza 2
      tstm (am);
      break;
    case 0x6e : // MOV Indirizzamento IMD Lunghezza 3
      addr = getAddr(IMM);
      addrd = getAddr(DIR8);
      write (addrd, read(addr));
      break;
    case 0x6f : // CLR Indirizzamento IX1 Lunghezza 2
      write( getAddr(am), 0);
      break;
    case 0x70 : // NEG Indirizzamento IX Lunghezza 1
      negm (am);
      break;
    case 0x71 : // CBEQ Indirizzamento IX_P_REL Lunghezza 2
      if (a == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x72 : // DAA Indirizzamento INH Lunghezza 1
      daa();
      break;
    case 0x73 : // COM Indirizzamento IX Lunghezza 1
      comm(am);
      break;
    case 0x74 : // LSR Indirizzamento IX Lunghezza 1
      lsrm (am);
      break;
    case 0x75 : // CPHX Indirizzamento DIR8 Lunghezza 2
      cphx (am);
      break;
    case 0x76 : // ROR Indirizzamento IX Lunghezza 1
      rorm (am);
      break;
    case 0x77 : // ASR Indirizzamento IX Lunghezza 1
      addr = getAddr(am);
      write (addr, asr (read(addr)));
      break;
    case 0x78 : // LSL Indirizzamento IX Lunghezza 1
      addr = getAddr(am);
      write (addr, asl (read(addr)));
      break;
    case 0x79 : // ROL Indirizzamento IX Lunghezza 1
      rolm (am);
      break;
    case 0x7a : // DEC Indirizzamento IX Lunghezza 1
      decm (am);
      break;
    case 0x7b : // DBNZ Indirizzamento IX Lunghezza 2
      if (dnz(am)) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x7c : // INC Indirizzamento IX Lunghezza 1
      incm (am);
      break;
    case 0x7d : // TST Indirizzamento IX Lunghezza 1
      tstm (am);
      break;
    case 0x7e : // MOV Indirizzamento IX_P_D Lunghezza 2
      addr = getAddr(IX_P_D);
      addrd = getAddr(DIR8);
      write (addrd, read(addr));
      break;
    case 0x7f : // CLR Indirizzamento IX Lunghezza 1
      write( getAddr(am), 0);
      break;
    case 0x80 : // RTI Indirizzamento INH Lunghezza 1
      ccr = pull();
      a = pull();
      hx = H | (pull () & 0xff);
      pc = (pull () << 8) & 0xff00;
      pc |= pull() & 0xff;
      break;
    case 0x81 : // RTS Indirizzamento INH Lunghezza 1
      pc = (pull () << 8) & 0xff00;
      pc |= pull() & 0xff;
      break;
    case 0x82 : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x83 : // SWI Indirizzamento INH Lunghezza 1
      ccr |= IBIT;
      push (pc);
      push (pc >> 8);
      push (hx);
      push (a);
      push (ccr);
      pc = ((read (0xfffc) << 8) | 0xff00) | (read (0xfffd) & 0xff);
      break;
    case 0x84 : // TAP Indirizzamento INH Lunghezza 1
      ccr = a | BASECCR;
      break;
    case 0x85 : // TPA Indirizzamento INH Lunghezzaa = ccr;noop();
      noop ();
      break;
    case 0x86 : // PULA Indirizzamento INH Lunghezza 1
      a = pull();
      break;
    case 0x87 : // PSHA Indirizzamento INH Lunghezza 1
      push(a);
      break;
    case 0x88 : // PULX Indirizzamento INH Lunghezza 1
      hx = H | (pull() & 0xff);
      break;
    case 0x89 : // PSHX Indirizzamento INH Lunghezza 1
      push (X);
      break;
    case 0x8a : // PULH Indirizzamento INH Lunghezza 1
      hx = ((pull() << 8) & 0xff00) | X;
      break;
    case 0x8b : // PSHH Indirizzamento INH Lunghezza 1
      push (H >> 8);
      break;
    case 0x8c : // CLRH Indirizzamento INH Lunghezza 1
      hx &= 0x00ff;
      break;
    case 0x8d : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x8e : // STOP Indirizzamento INH Lunghezza 1
      stop ();
      break;
    case 0x8f : // WAIT Indirizzamento INH Lunghezza 1
      wait ();
      break;
    case 0x90 : // BGE Indirizzamento REL Lunghezza 2
	  // If (N ^ V) = 0 ( N==1&&V==1 || N==0&&V==0)
      if (!(ccr & 0x84) || (ccr & 0x84) == 0x84) {
        pc = getAddr(REL);
      } else {
        pc ++;
	  }
      break;
    case 0x91 : // BLT Indirizzamento REL Lunghezza 2
	  // If (N ^ V) = 1
      if ((ccr & 0x84) == 0x80 || (ccr & 0x84) == 0x04) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x92 : // BGT Indirizzamento REL Lunghezza 2
	  // If (Z) | (N ^ V) = 0
      // if ((ccr & 0x2) || !(ccr & 0x84) || (ccr & 0x84) == 0x84) {
      if (!(ccr & 0x2) && (!(ccr & 0x84) || (ccr & 0x84) == 0x84)) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x93 : // BLE Indirizzamento REL Lunghezza 2
	  // If (Z) | (N ^ V) = 1
      if ((ccr & 0x2) || (ccr & 0x84) == 0x04 || (ccr & 0x84) == 0x80) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x94 : // TXS Indirizzamento INH Lunghezza 1
      sp = hx - 1;
      break;
    case 0x95 : // TSX Indirizzamento INH Lunghezza 1
      hx = sp + 1;
      break;
    case 0x96 : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x97 : // TAX Indirizzamento INH Lunghezza 1
      hx = H | (a & 0xff);
      break;
    case 0x98 : // CLC Indirizzamento INH Lunghezza 1
      ccr &= NOTCBIT;
      break;
    case 0x99 : // SEC Indirizzamento INH Lunghezza 1
      ccr |= CBIT;
      break;
    case 0x9a : // CLI Indirizzamento INH Lunghezza 1
      ccr &= NOTIBIT;
      break;
    case 0x9b : // SEI Indirizzamento INH Lunghezza 1
      ccr |= IBIT;
      break;
    case 0x9c : // RSP Indirizzamento INH Lunghezza 1
      sp |= 0xff;
      break;
    case 0x9d : // NOP Indirizzamento INH Lunghezza 1
      noop();
      break;
    case 0x9e :
      emulate9E ();
      break;
    case 0x9f : // TXA Indirizzamento INH Lunghezza 1
      a = hx;
      break;
    case 0xa0 : // SUB Indirizzamento IMM Lunghezza 2
      sub (am);
      break;
    case 0xa1 : // CMP Indirizzamento IMM Lunghezza 2
      cmp (am);
      break;
    case 0xa2 : // SBC Indirizzamento IMM Lunghezza 2
      sbc (am);
      break;
    case 0xa3 : // CPX Indirizzamento IMM Lunghezza 2
      cpx (am);
      break;
    case 0xa4 : // AND Indirizzamento IMM Lunghezza 2
      andl (am);
      break;
    case 0xa5 : // BIT Indirizzamento IMM Lunghezza 2
      bitl (am);
      break;
    case 0xa6 : // LDA Indirizzamento IMM Lunghezza 2
      lda (am);
      break;
    case 0xa7 : // AIS Indirizzamento IMM Lunghezza 2
      sp += signExtend8(read(getAddr(am)));
      break;
    case 0xa8 : // EOR Indirizzamento IMM Lunghezza 2
      eor (am);
      break;
    case 0xa9 : // ADC Indirizzamento IMM Lunghezza 2
      adc (am);
      break;
    case 0xaa : // ORA Indirizzamento IMM Lunghezza 2
      ora (am);
      break;
    case 0xab : // ADD Indirizzamento IMM Lunghezza 2
      add (am);
      break;
    case 0xac : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0xad : // BSR Indirizzamento REL Lunghezza 2
      addr = getAddr(REL);
      push (pc & 0xff);
      push ((pc >> 8) & 0xff);
      pc = addr;
      break;
    case 0xae : // LDX Indirizzamento IMM Lunghezza 2
      ldx (am);
      break;
    case 0xaf : // AIX Indirizzamento IMM Lunghezza 2
      hx += signExtend8(read(getAddr(am)));
      break;
    case 0xb0 : // SUB Indirizzamento DIR8 Lunghezza 2
      sub (am);
      break;
    case 0xb1 : // CMP Indirizzamento DIR8 Lunghezza 2
      cmp (am);
      break;
    case 0xb2 : // SBC Indirizzamento DIR8 Lunghezza 2
      sbc (am);
      break;
    case 0xb3 : // CPX Indirizzamento DIR8 Lunghezza 2
      cpx (am);
      break;
    case 0xb4 : // AND Indirizzamento DIR8 Lunghezza 2
      andl (am);
      break;
    case 0xb5 : // BIT Indirizzamento DIR8 Lunghezza 2
      bitl (am);
      break;
    case 0xb6 : // LDA Indirizzamento DIR8 Lunghezza 2
      lda (am);
      break;
    case 0xb7 : // STA Indirizzamento DIR8 Lunghezza 2
      sta (am);
      break;
    case 0xb8 : // EOR Indirizzamento DIR8 Lunghezza 2
      eor (am);
      break;
    case 0xb9 : // ADC Indirizzamento DIR8 Lunghezza 2
      adc (am);
      break;
    case 0xba : // ORA Indirizzamento DIR8 Lunghezza 2
      ora (am);
      break;
    case 0xbb : // ADD Indirizzamento DIR8 Lunghezza 2
      add (am);
      break;
    case 0xbc : // JMP Indirizzamento DIR8 Lunghezza 2
      pc = getAddr(am);
      break;
    case 0xbd : // JSR Indirizzamento DIR8 Lunghezza 2
      jsr(am);
      break;
    case 0xbe : // LDX Indirizzamento DIR8 Lunghezza 2
      ldx (am);
      break;
    case 0xbf : // STX Indirizzamento DIR8 Lunghezza 2
      stx (am);
      break;
    case 0xc0 : // SUB Indirizzamento EXT Lunghezza 3
      sub (am);
      break;
    case 0xc1 : // CMP Indirizzamento EXT Lunghezza 3
      cmp (am);
      break;
    case 0xc2 : // SBC Indirizzamento EXT Lunghezza 3
      sbc (am);
      break;
    case 0xc3 : // CPX Indirizzamento EXT Lunghezza 3
      cpx (am);
      break;
    case 0xc4 : // AND Indirizzamento EXT Lunghezza 3
      andl (am);
      break;
    case 0xc5 : // BIT Indirizzamento EXT Lunghezza 3
      bitl (am);
      break;
    case 0xc6 : // LDA Indirizzamento EXT Lunghezza 3
      lda (am);
      break;
    case 0xc7 : // STA Indirizzamento EXT Lunghezza 3
      sta (am);
      break;
    case 0xc8 : // EOR Indirizzamento EXT Lunghezza 3
      eor (am);
      break;
    case 0xc9 : // ADC Indirizzamento EXT Lunghezza 3
      adc (am);
      break;
    case 0xca : // ORA Indirizzamento EXT Lunghezza 3
      ora (am);
      break;
    case 0xcb : // ADD Indirizzamento EXT Lunghezza 3
      add (am);
      break;
    case 0xcc : // JMP Indirizzamento JEXT Lunghezza 3
      pc = getAddr(am);
      break;
    case 0xcd : // JSR Indirizzamento JEXT Lunghezza 3
      jsr(am);
      break;
    case 0xce : // LDX Indirizzamento EXT Lunghezza 3
      ldx (am);
      break;
    case 0xcf : // STX Indirizzamento EXT Lunghezza 3
      stx (am);
      break;
    case 0xd0 : // SUB Indirizzamento IX2 Lunghezza 3
      sub (am);
      break;
    case 0xd1 : // CMP Indirizzamento IX2 Lunghezza 3
      cmp (am);
      break;
    case 0xd2 : // SBC Indirizzamento IX2 Lunghezza 3
      sbc (am);
      break;
    case 0xd3 : // CPX Indirizzamento IX2 Lunghezza 3
      cpx (am);
      break;
    case 0xd4 : // AND Indirizzamento IX2 Lunghezza 3
      andl (am);
      break;
    case 0xd5 : // BIT Indirizzamento IX2 Lunghezza 3
      bitl (am);
      break;
    case 0xd6 : // LDA Indirizzamento IX2 Lunghezza 3
      lda (am);
      break;
    case 0xd7 : // STA Indirizzamento IX2 Lunghezza 3
      sta (am);
      break;
    case 0xd8 : // EOR Indirizzamento IX2 Lunghezza 3
      eor (am);
      break;
    case 0xd9 : // ADC Indirizzamento IX2 Lunghezza 3
      adc (am);
      break;
    case 0xda : // ORA Indirizzamento IX2 Lunghezza 3
      ora (am);
      break;
    case 0xdb : // ADD Indirizzamento IX2 Lunghezza 3
      add (am);
      break;
    case 0xdc : // JMP Indirizzamento IX2 Lunghezza 3
      pc = getAddr(am);
      break;
    case 0xdd : // JSR Indirizzamento IX2 Lunghezza 3
      jsr(am);
      break;
    case 0xde : // LDX Indirizzamento IX2 Lunghezza 3
      ldx (am);
      break;
    case 0xdf : // STX Indirizzamento IX2 Lunghezza 3
      stx (am);
      break;
    case 0xe0 : // SUB Indirizzamento IX1 Lunghezza 2
      sub (am);
      break;
    case 0xe1 : // CMP Indirizzamento IX1 Lunghezza 2
      cmp (am);
      break;
    case 0xe2 : // SBC Indirizzamento IX1 Lunghezza 2
      sbc (am);
      break;
    case 0xe3 : // CPX Indirizzamento IX1 Lunghezza 2
      cpx (am);
      break;
    case 0xe4 : // AND Indirizzamento IX1 Lunghezza 2
      andl (am);
      break;
    case 0xe5 : // BIT Indirizzamento IX1 Lunghezza 2
      bitl (am);
      break;
    case 0xe6 : // LDA Indirizzamento IX1 Lunghezza 2
      lda (am);
      break;
    case 0xe7 : // STA Indirizzamento IX1 Lunghezza 2
      sta (am);
      break;
    case 0xe8 : // EOR Indirizzamento IX1 Lunghezza 2
      eor (am);
      break;
    case 0xe9 : // ADC Indirizzamento IX1 Lunghezza 2
      adc (am);
      break;
    case 0xea : // ORA Indirizzamento IX1 Lunghezza 2
      ora (am);
      break;
    case 0xeb : // ADD Indirizzamento IX1 Lunghezza 2
      add (am);
      break;
    case 0xec : // JMP Indirizzamento IX1 Lunghezza 2
      pc = getAddr(am);
      break;
    case 0xed : // JSR Indirizzamento IX1 Lunghezza 2
      jsr(am);
      break;
    case 0xee : // LDX Indirizzamento IX1 Lunghezza 2
      ldx (am);
      break;
    case 0xef : // STX Indirizzamento IX1 Lunghezza 2
      stx (am);
      break;
    case 0xf0 : // SUB Indirizzamento IX Lunghezza 1
      sub (am);
      break;
    case 0xf1 : // CMP Indirizzamento IX Lunghezza 1
      cmp (am);
      break;
    case 0xf2 : // SBC Indirizzamento IX Lunghezza 1
      sbc (am);
      break;
    case 0xf3 : // CPX Indirizzamento IX Lunghezza 1
      cpx (am);
      break;
    case 0xf4 : // AND Indirizzamento IX Lunghezza 1
      andl (am);
      break;
    case 0xf5 : // BIT Indirizzamento IX Lunghezza 1
      bitl (am);
      break;
    case 0xf6 : // LDA Indirizzamento IX Lunghezza 1
      lda (am);
      break;
    case 0xf7 : // STA Indirizzamento IX Lunghezza 1
      sta (am);
      break;
    case 0xf8 : // EOR Indirizzamento IX Lunghezza 1
      eor (am);
      break;
    case 0xf9 : // ADC Indirizzamento IX Lunghezza 1
      adc (am);
      break;
    case 0xfa : // ORA Indirizzamento IX Lunghezza 1
      ora (am);
      break;
    case 0xfb : // ADD Indirizzamento IX Lunghezza 1
      add (IX);
      break;
    case 0xfc : // JMP Indirizzamento IX Lunghezza 1
      pc = getAddr(am);
      break;
    case 0xfd : // JSR Indirizzamento IX Lunghezza 1
      jsr(am);
      break;
    case 0xfe : // LDX Indirizzamento IX Lunghezza 1
      ldx (am);
      break;
    case 0xff : // STX Indirizzamento IX Lunghezza 1
      stx (am);
      break;
  }
}

void Processor::emulate9E () {
unsigned char opcode;
int addr = INH;
admod am;
  opcode = read (pc++);
  switch (opcode & 0xf0) {
    case 0x60 :
      am = opcodes9E6[opcode & 0xf].op_mode;
      break;
    case 0xd0 :
      am = opcodes9ED[opcode & 0xf].op_mode;
      break;
    case 0xe0 :
      am = opcodes9EE[opcode & 0xf].op_mode;
      break;
  }
  switch (opcode) {
    case 0x60 : // NEG Indirizzamento SP1 Lunghezza 3
      negm (am);
      break;
    case 0x61 : // CBEQ Indirizzamento SP1_REL Lunghezza 4
      if (a == read(getAddr(am))) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x62 : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x63 : // COM Indirizzamento SP1 Lunghezza 3
      comm(am);
      break;
    case 0x64 : // LSR Indirizzamento SP1 Lunghezza 3
      lsrm (am);
      break;
    case 0x65 : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x66 : // ROR Indirizzamento SP1 Lunghezza 3
      rorm (am);
      break;
    case 0x67 : // ASR Indirizzamento SP1 Lunghezza 3
      addr = getAddr(am);
      write (addr, asr (read(addr)));
      break;
    case 0x68 : // LSL Indirizzamento SP1 Lunghezza 3
      addr = getAddr(am);
      write (addr, asl (read(addr)));
      break;
    case 0x69 : // ROL Indirizzamento SP1 Lunghezza 3
      rolm (am);
      break;
    case 0x6a : // DEC Indirizzamento SP1 Lunghezza 3
      decm (am);
      break;
    case 0x6b : // DBNZ Indirizzamento SP1_REL Lunghezza 4
      if (dnz(am)) {
        pc = getAddr(REL);
      } else {
        pc ++;
      }
      break;
    case 0x6c : // INC Indirizzamento SP1 Lunghezza 3
      incm (am);
      break;
    case 0x6d : // TST Indirizzamento SP1 Lunghezza 3
      tstm (am);
      break;
    case 0x6e : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0x6f : // CLR Indirizzamento SP1 Lunghezza 3
      write( getAddr(am), 0);
      break;
    case 0xD0 : // SUB Indirizzamento SP2 Lunghezza 4
      sub (am);
      break;
    case 0xD1 : // CMP Indirizzamento SP2 Lunghezza 4
      cmp (am);
      break;
    case 0xD2 : // SBC Indirizzamento SP2 Lunghezza 4
      sbc (am);
      break;
    case 0xD3 : // CPX Indirizzamento SP2 Lunghezza 4
      cpx (am);
      break;
    case 0xD4 : // AND Indirizzamento SP2 Lunghezza 4
      andl (am);
      break;
    case 0xD5 : // BIT Indirizzamento SP2 Lunghezza 4
      bitl (am);
      break;
    case 0xD6 : // LDA Indirizzamento SP2 Lunghezza 4
      lda (am);
      break;
    case 0xD7 : // STA Indirizzamento SP2 Lunghezza 4
      sta (am);
      break;
    case 0xD8 : // EOR Indirizzamento SP2 Lunghezza 4
      eor (am);
      break;
    case 0xD9 : // ADC Indirizzamento SP2 Lunghezza 4
      adc (am);
      break;
    case 0xDa : // ORA Indirizzamento SP2 Lunghezza 4
      ora (am);
      break;
    case 0xDb : // ADD Indirizzamento SP2 Lunghezza 4
      add (am);
      break;
    case 0xDc : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0xDd : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0xDe : // LDX Indirizzamento SP2 Lunghezza 4
      ldx (am);
      break;
    case 0xDf : // STX Indirizzamento SP2 Lunghezza 4
      stx (am);
      break;
    case 0xE0 : // SUB Indirizzamento SP1 Lunghezza 3
      sub (am);
      break;
    case 0xE1 : // CMP Indirizzamento SP1 Lunghezza 3
      cmp (am);
      break;
    case 0xE2 : // SBC Indirizzamento SP1 Lunghezza 3
      sbc (am);
      break;
    case 0xE3 : // CPX Indirizzamento SP1 Lunghezza 3
      cpx (am);
      break;
    case 0xE4 : // AND Indirizzamento SP1 Lunghezza 3
      andl (am);
      break;
    case 0xE5 : // BIT Indirizzamento SP1 Lunghezza 3
      bitl (am);
      break;
    case 0xE6 : // LDA Indirizzamento SP1 Lunghezza 3
      lda (am);
      break;
    case 0xE7 : // STA Indirizzamento SP1 Lunghezza 3
      sta (am);
      break;
    case 0xE8 : // EOR Indirizzamento SP1 Lunghezza 3
      eor (am);
      break;
    case 0xE9 : // ADC Indirizzamento SP1 Lunghezza 3
      adc (am);
      break;
    case 0xEa : // ORA Indirizzamento SP1 Lunghezza 3
      ora (am);
      break;
    case 0xEb : // ADD Indirizzamento SP1 Lunghezza 3
      add (am);
      break;
    case 0xEc : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0xEd : //  Indirizzamento INH Lunghezza 0
      noop();
      break;
    case 0xEe : // LDX Indirizzamento SP1 Lunghezza 3
      ldx (am);
      break;
    case 0xEf : // STX Indirizzamento SP1 Lunghezza 3
      stx (am);
      break;
    default :
      noop();
      break;
  }
}
