"use strict";
/*
The MIT License (MIT)
Copyright (c) 2014 Martin Maly, http://retrocip.cz, http://www.uelectronics.info,
twitter: @uelectronics

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

var CPU6809 = function() {

var ticks;
var rA,rB,rX,rY,rU,rS,PC,CC,DP,
F_CARRY     =1,
F_OVERFLOW  =2,
F_ZERO      =4,
F_NEGATIVE  =8,
F_IRQMASK   =16,
F_HALFCARRY =32,
F_FIRQMASK  =64,
F_ENTIRE    =128,

vecRESET = 0xFFFE,
vecNMI = 0xFFFC,
vecSWI = 0xFFFA,
vecIRQ = 0xFFF8,
vecFIRQ = 0xFFF6,
vecSWI2 = 0xFFF4,
vecSWI3 = 0xFFF2,

T=0;

var IRQs;

var byteTo, byteAt;

var cycles = [
      6,0,0,6,6,0,6,6,6,6,6,0,6,6,3,6,          /* 00-0F */
      0,0,2,4,0,0,5,9,0,2,3,0,3,2,8,6,          /* 10-1F */
      3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,          /* 20-2F */
      4,4,4,4,5,5,5,5,0,5,3,6,9,11,0,19,        /* 30-3F */
      2,0,0,2,2,0,2,2,2,2,2,0,2,2,0,2,          /* 40-4F */
      2,0,0,2,2,0,2,2,2,2,2,0,2,2,0,2,          /* 50-5F */
      6,0,0,6,6,0,6,6,6,6,6,0,6,6,3,6,          /* 60-6F */
      7,0,0,7,7,0,7,7,7,7,7,0,7,7,4,7,          /* 70-7F */
      2,2,2,4,2,2,2,0,2,2,2,2,4,7,3,0,          /* 80-8F */
      4,4,4,6,4,4,4,4,4,4,4,4,6,7,5,5,          /* 90-9F */
      4,4,4,6,4,4,4,4,4,4,4,4,6,7,5,5,          /* A0-AF */
      5,5,5,7,5,5,5,5,5,5,5,5,7,8,6,6,          /* B0-BF */
      2,2,2,4,2,2,2,0,2,2,2,2,3,0,3,0,          /* C0-CF */
      4,4,4,6,4,4,4,4,4,4,4,4,5,5,5,5,          /* D0-DF */
      4,4,4,6,4,4,4,4,4,4,4,4,5,5,5,5,          /* E0-EF */
      5,5,5,7,5,5,5,5,5,5,5,5,6,6,6,6];         /* F0-FF */

/* Instruction timing for the two-byte opcodes */
var cycles2 = [
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 00-0F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 10-1F */
      0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,          /* 20-2F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,         /* 30-3F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 40-4F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 50-5F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 60-6F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 70-7F */
      0,0,0,5,0,0,0,0,0,0,0,0,5,0,4,0,          /* 80-8F */
      0,0,0,7,0,0,0,0,0,0,0,0,7,0,6,6,          /* 90-9F */
      0,0,0,7,0,0,0,0,0,0,0,0,7,0,6,6,          /* A0-AF */
      0,0,0,8,0,0,0,0,0,0,0,0,8,0,7,7,          /* B0-BF */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,          /* C0-CF */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,          /* D0-DF */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,          /* E0-EF */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7];         /* F0-FF */

/* Negative and zero flags for quicker flag settings */
var flagsNZ = [
      4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 00-0F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 10-1F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 20-2F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 30-3F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 40-4F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 50-5F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 60-6F */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          /* 70-7F */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* 80-8F */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* 90-9F */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* A0-AF */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* B0-BF */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* C0-CF */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* D0-DF */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,          /* E0-EF */
      8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8];         /* F0-FF */

var setV8 = function(a,b,r) {CC |= (((a^b^r^(r>>1))&0x80)>>6);};
var setV16 = function(a,b,r) {CC |= (((a^b^r^(r>>1))&0x8000)>>14);};
var getD = function() {return (rA<<8)+rB;};
var setD = function(v) {rA = (v>>8)& 0xff;rB=v&0xff;};
var PUSHB = function(b) {
    byteTo(--rS, b & 0xff);
};
var PUSHW = function(b) {
    byteTo(--rS, b & 0xff);
    byteTo(--rS, (b>>8) & 0xff);
};

var PUSHBU = function(b) {
    byteTo(--rU, b & 0xff);
};
var PUSHWU = function(b) {
    byteTo(--rU, b & 0xff);
    byteTo(--rU, (b>>8) & 0xff);
};
var PULLB = function(b) {
    return byteAt(rS++);
};
var PULLW = function(b) {
    return byteAt(rS++) * 256 + byteAt(rS++);
};

var PULLBU = function(b) {
    return byteAt(rU++);
};
var PULLWU = function(b) {
    return byteAt(rU++) * 256 + byteAt(rU++);
};

var PSHS = function(ucTemp)  {
      var i = 0;
         if (ucTemp & 0x80) {PUSHW(PC);i += 2;}
         if (ucTemp & 0x40) {PUSHW(rU);i += 2;}
         if (ucTemp & 0x20){PUSHW(rY);i += 2;}
         if (ucTemp & 0x10){PUSHW(rX);i += 2;}
         if (ucTemp & 0x8){PUSHB(DP); i++;}
         if (ucTemp & 0x4){PUSHB(rB); i++;}
         if (ucTemp & 0x2){PUSHB(rA); i++;}
         if (ucTemp & 0x1){PUSHB(CC); i++;}
         T+=i; //timing
};
var PSHU = function(ucTemp)  {
      var i = 0;
         if (ucTemp & 0x80) {PUSHWU(PC);i += 2;}
         if (ucTemp & 0x40) {PUSHWU(rS);i += 2;}
         if (ucTemp & 0x20){PUSHWU(rY);i += 2;}
         if (ucTemp & 0x10){PUSHWU(rX);i += 2;}
         if (ucTemp & 0x8){PUSHBU(DP); i++;}
         if (ucTemp & 0x4){PUSHBU(rB); i++;}
         if (ucTemp & 0x2){PUSHBU(rA); i++;}
         if (ucTemp & 0x1){PUSHBU(CC); i++;}
         T+=i; //timing
};
var PULS = function(ucTemp)  {
      var i = 0;
      if (ucTemp & 0x1){CC = PULLB(); i++;}
      if (ucTemp & 0x2){rA = PULLB(); i++;}
      if (ucTemp & 0x4){rB = PULLB(); i++;}
      if (ucTemp & 0x8){DP = PULLB(); i++;}
      if (ucTemp & 0x10){rX = PULLW();i += 2;}
      if (ucTemp & 0x20){rY = PULLW();i += 2;}
      if (ucTemp & 0x40) {rU = PULLW();i += 2;}
      if (ucTemp & 0x80) {PC = PULLW();i += 2;}
      T+=i; //timing
};
var PULU = function(ucTemp)  {
      var i = 0;
      if (ucTemp & 0x1){CC = PULLBU(); i++;}
      if (ucTemp & 0x2){rA = PULLBU(); i++;}
      if (ucTemp & 0x4){rB = PULLBU(); i++;}
      if (ucTemp & 0x8){DP = PULLBU(); i++;}
      if (ucTemp & 0x10){rX = PULLWU();i += 2;}
      if (ucTemp & 0x20){rY = PULLWU();i += 2;}
      if (ucTemp & 0x40) {rS = PULLWU();i += 2;}
      if (ucTemp & 0x80) {PC = PULLWU();i += 2;}
      T+=i; //timing
};


var getPBR = function(ucPostByte) {
    switch(ucPostByte & 0xf) {
       case 0x00: /* D */
            return getD();
       case 0x1: /* X */
          return rX;
       case 0x2: /* Y */
          return rY;
       case 0x3: /* U */
          return rU;
       case 0x4: /* S */
          return rS;
       case 0x5: /* PC */
          return PC;
       case 0x8: /* A */
          return rA;
       case 0x9: /* B */
          return rB;
       case 0xA: /* CC */
          return CC;
       case 0xB: /* DP */
          return DP;
       default: /* illegal */
          return null;
       }
};
var setPBR = function(ucPostByte, v) {
    switch(ucPostByte & 0xf) /* Get destination register */
       {
       case 0x00: /* D */
            setD(v);return;
       case 0x1: /* X */
          rX = v; return;
       case 0x2: /* Y */
          rY = v; return;
       case 0x3: /* U */
          rU = v; return;
       case 0x4: /* S */
          rS = v; return;
       case 0x5: /* PC */
          PC = v; return;
       case 0x8: /* A */
          rA = v; return;
       case 0x9: /* B */
          rB = v; return;
       case 0xA: /* CC */
          CC = v; return;
       case 0xB: /* DP */
          DP = v; return;
       default: /* illegal */
          return;
       }
};

var TFREXG = function(ucPostByte, bExchange)
{

   var ucTemp = ucPostByte & 0x88;
   if (ucTemp == 0x80 || ucTemp == 0x08)
      ucTemp = 0; /* PROBLEM! */

    if (bExchange)
          {
          ucTemp = getPBR(ucPostByte>>4);
          setPBR(ucPostByte>>4, getPBR(ucPostByte));
          setPBR(ucPostByte, ucTemp);
          }
       else /* Transfer */ {
          setPBR(ucPostByte, getPBR(ucPostByte>>4));
        }
} ;

var signed = function(x) {
    return (x>127)?(x-256):x;
};
var signed16 = function(x) {
    return (x>32767)?(x-65536):x;
};

var fetch = function() {
    var v = byteAt(PC++);
    PC &= 0xffff;
    return v;
};
var fetch16 = function() {
    var v1 = byteAt(PC++);
    PC &= 0xffff;
    var v2 = byteAt(PC++);
    PC &= 0xffff;
    return v1*256+v2;
};

var ReadWord = function(addr) {
    var v1 = byteAt(addr++);
    addr &= 0xffff;
    var v2 = byteAt(addr++);
    addr &= 0xffff;
    return v1*256+v2;
};
var WriteWord = function(addr,v) {
    byteTo(addr++,(v>>8)&0xff);
    addr &= 0xffff;
    byteTo(addr,v&0xff);
};

var PostByte = function() {
    var pb = fetch();
    var preg;
    switch (pb & 0x60) {
        case 0:
            preg = rX; break;
        case 0x20:
            preg = rY; break;
        case 0x40:
            preg = rU; break;
        case 0x60:
            preg = rS; break;
    }

    var xchg = null;
    var addr = null;
    var sTemp;

    if (pb & 0x80) /* Complex stuff */
       {
       switch (pb & 0x0f)
          {
          case 0: /* EA = ,reg+ */
             addr = preg;
             xchg = preg + 1;
             T += 2;
             break;
          case 1: /* EA = ,reg++ */
             addr = preg;
             xchg = preg + 2;
             T += 3;
             break;
          case 2: /* EA = ,-reg */
             xchg = preg - 1;
             addr = xchg;
             T += 2;
             break;
          case 3: /* EA = ,--reg */
             xchg = preg - 2;
             addr = xchg;
             T += 3;
             break;
          case 4: /* EA = ,reg */
             addr = preg;
             break;
          case 5: /* EA = ,reg + B */
             //usAddr = *pReg + (signed short)(signed char)regs->ucRegB;
             addr = preg + signed(rB);
             T += 1;
             break;
          case 6: /* EA = ,reg + A */
              addr = preg + signed(rA);
              T += 1;
             break;
          case 7: /* illegal */
             addr = 0;
             break;
          case 8: /* EA = ,reg + 8-bit offset */
             addr = preg + signed(fetch());
             T += 1;
             break;
          case 9: /* EA = ,reg + 16-bit offset */
             addr = preg + signed16(fetch16());
             T += 4;
             break;
          case 0xA: /* illegal */
             addr = 0;
             break;
          case 0xB: /* EA = ,reg + D */
             T += 4;
             addr = preg + getD();
             break;
          case 0xC: /* EA = PC + 8-bit offset */
             sTemp = signed(fetch());
             addr = PC + sTemp;
             T += 1;
             break;
          case 0xD: /* EA = PC + 16-bit offset */
             sTemp =  signed16(fetch16());
             addr = PC + sTemp;
             T += 5;
             break;
          case 0xe: /* Illegal */
             addr = 0;
             break;
          case 0xF: /* EA = [,address] */
             T += 5;
             addr = fetch16();
             break;
          } /* switch */

       addr &= 0xffff;

       if (pb & 0x10) /* Indirect addressing */
          {
          addr = byteAt(addr)*256+byteAt((addr+1) & 0xffff);
          T += 3;
          }
       }
    else /* Just a 5 bit signed offset + register */
       {
       var sByte = pb & 0x1f;
       if (sByte > 15) /* Two's complement 5-bit value */
          sByte -= 32;
       addr = preg + sByte;
       T += 1;
       }

    if (xchg!==null) {
        switch (pb & 0x60) {
            case 0:
                rX = xchg; break;
            case 0x20:
                rY = xchg; break;
            case 0x40:
                rU = xchg; break;
            case 0x60:
                rS = xchg; break;
        }

    }

    return addr & 0xffff; /* Return the effective address */
};

var flagsNZ16 = function(word) {
    CC &= ~(F_ZERO | F_NEGATIVE);
    if (word===0) CC |= F_ZERO;
    if (word & 0x8000) CC |= F_NEGATIVE;
};

// ============= Operations

var oINC = function(b) {
   b++;
   b &= 0xff;
   CC &= ~(F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[b];
   if (b === 0 || b == 0x80) CC |= F_OVERFLOW;
   return b;
};
var oDEC = function(b) {
   b--;
   b &= 0xff;
   CC &= ~(F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[b];
   if (b === 0x7f || b == 0xff) CC |= F_OVERFLOW;
   return b;
};
var oSUB = function(b,v) {
   var temp = b-v;
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[temp & 0xff];
   if (temp&0x100) CC|=F_CARRY;
   setV8(b,v,temp);
   return temp&0xff;
};
var oSUB16 = function(b,v) {
   var temp = b-v;
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   if ((temp&0xffff)===0) CC|=F_ZERO;
   if (temp&0x8000) CC|=F_NEGATIVE;
   if (temp&0x10000) CC|=F_CARRY;
   setV16(b,v,temp);
   return temp&0xffff;
};
var oADD = function(b,v) {
   var temp = b+v;
   //temp &= 0xff;
   CC &= ~(F_HALFCARRY | F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[temp & 0xff];
   if (temp&0x100) CC|=F_CARRY;
   setV8(b,v,temp);
   if ((temp ^ b ^ v)&0x10) CC |= F_HALFCARRY;
   return temp&0xff;
};
var oADD16 = function(b,v) {
   var temp = b+v;
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   if ((temp&0xffff)===0) CC|=F_ZERO;
   if (temp&0x8000) CC|=F_NEGATIVE;
   if (temp&0x10000) CC|=F_CARRY;
   setV16(b,v,temp);
   return temp&0xffff;
};
var oADC = function(b,v) {
   var temp = b+v+(CC & F_CARRY);
   //temp &= 0xff;
   CC &= ~(F_HALFCARRY | F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[temp & 0xff];
   if (temp&0x100) CC|=F_CARRY;
   setV8(b,v,temp);
   if ((temp ^ b ^ v)&0x10) CC |= F_HALFCARRY;
   return temp&0xff;
};
var oSBC = function(b,v) {
   var temp = b-v-(CC & F_CARRY);
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[temp & 0xff];
   if (temp&0x100) CC|=F_CARRY;
   setV8(b,v,temp);
   return temp&0xff;
};
var oCMP = function(b,v) {
   var temp = b-v;
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   CC |= flagsNZ[temp & 0xff];
   if (temp&0x100) CC|=F_CARRY;
   setV8(b,v,temp);
   return;
};
var oCMP16 = function(b,v) {
   var temp = b-v;
   //temp &= 0xff;
   CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   if ((temp&0xffff)===0) CC|=F_ZERO;
   if (temp&0x8000) CC|=F_NEGATIVE;
   if (temp&0x10000) CC|=F_CARRY;
   setV16(b,v,temp);
   return;
};

var oNEG = function(b) {
    CC &= ~(F_CARRY | F_ZERO | F_OVERFLOW | F_NEGATIVE);
   if (b == 0x80)
      CC |= F_OVERFLOW;
   b = ((~b)&0xff) + 1;
   if (b === 0) CC |= F_ZERO;
   if (b & 0x80) CC |= F_NEGATIVE | F_CARRY;
   return b;
};

var oLSR = function(b) {
    CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
    if (b & 0x01) CC |= F_CARRY;
    b >>= 1;
    if (b === 0) CC |= F_ZERO;
    return b & 0xff;
};
var oASR = function(b) {
    CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
    if (b & 0x01) CC |= F_CARRY;
    b = (b & 0x80) | (b>>1);
    CC |= flagsNZ[b];
    return b;
};
var oASL = function(b) {
    var temp = b;
    CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE | F_OVERFLOW);
    if (b & 0x80) CC |= F_CARRY;
    b <<= 1;
    CC |= flagsNZ[b];
    if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
    return b;
};
var oROL = function(b) {
    var temp = b;
    var oldc = CC&F_CARRY;
    CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE | F_OVERFLOW);
    if (b & 0x80) CC |= F_CARRY;
    b = b<<1 | oldc;
    CC |= flagsNZ[b];
    if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
    return b;
};
var oROR = function(b) {
    var oldc = CC&F_CARRY;
    CC &= ~(F_ZERO | F_CARRY | F_NEGATIVE);
    if (b & 0x01) CC |= F_CARRY;
    b = b>>1 | oldc<<7;
    CC |= flagsNZ[b];
//    if ((b ^ temp) & 0x80) CC|=F_OVERFLOW;
    return b;
};

var oEOR = function(b,v) {
    CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
    b ^= v;
    CC |= flagsNZ[b];
    return b;
};
var oOR = function(b,v) {
    CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
    b |= v;
    CC |= flagsNZ[b];
    return b;
};
var oAND = function(b,v) {
    CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
    b &= v;
    CC |= flagsNZ[b];
    return b;
};
var oCOM = function(b) {
    CC &= ~(F_ZERO | F_NEGATIVE | F_OVERFLOW);
    b ^= 0xff;
    CC |= flagsNZ[b];
    CC |= F_CARRY;
    return b;
};

//----common
var dpadd = function() {
    //direct page + 8bit index
    return DP*256 + fetch();
};

var step = function() {
    var oldT = T;

    var addr = null;
    var pb = null;

    var oldPC = PC;
    var opcode = fetch();
    T+=cycles[opcode];
    switch (opcode) {
        case 0x00: //NEG DP
            addr = dpadd();
            byteTo(addr, oNEG(byteAt(addr)));
            break;
        case 0x03: //COM DP
            addr = dpadd();
            byteTo(addr, oCOM(byteAt(addr)));
            break;
        case 0x04: //LSR DP
            addr = dpadd();
            byteTo(addr, oLSR(byteAt(addr)));
            break;
        case 0x06: //ROR DP
            addr = dpadd();
            byteTo(addr, oROR(byteAt(addr)));
        break;
        case 0x07: //ASR DP
            addr = dpadd();
            byteTo(addr, oASR(byteAt(addr)));
        break;
        case 0x08: //ASL DP
            addr = dpadd();
            byteTo(addr, oASL(byteAt(addr)));
        break;
        case 0x09: //ROL DP
            addr = dpadd();
            byteTo(addr, oROL(byteAt(addr)));
        break;

        case 0x0A: //DEC DP
            addr = dpadd();
            byteTo(addr, oDEC(byteAt(addr)));
        break;
        case 0x0C: //INC DP
            addr = dpadd();
            byteTo(addr, oINC(byteAt(addr)));
        break;

        case 0x0D: //TST DP
            addr = dpadd();
            pb = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[pb];
        break;

        case 0x0E: //JMP DP
            addr = dpadd();
            PC = addr;
        break;
        case 0x0F: //CLR DP
            addr = dpadd();
            byteTo(addr,0);
            CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
            CC |= F_ZERO;
        break;

        case 0x12: //NOP
            break;
        case 0x13: //SYNC
            break;
        case 0x16: //LBRA relative
            addr = signed16(fetch16());
            PC += addr;
            break;
        case 0x17: //LBSR relative
            addr = signed16(fetch16());
            PUSHW(PC);
            PC += addr;
            break;
        case 0x19: //DAA
            var cf = 0;
            var nhi = rA & 0xf0, nlo = rA & 0x0f;
            if( nlo>0x09 || CC & 0x20 ) cf |= 0x06;
            if( nhi>0x80 && nlo>0x09 ) cf |= 0x60;
            if( nhi>0x90 || CC & 0x01 ) cf |= 0x60;
            addr = cf + rA;
            CC  &= ~(F_CARRY | F_NEGATIVE | F_ZERO | F_OVERFLOW);
            if (addr & 0x100)
               CC  |= F_CARRY;
            rA = addr & 0xff;
            CC  |= flagsNZ[rA];
            break;
        case 0x1A: //ORCC
            CC |= fetch();
            break;
        case 0x1C: //ANDCC
            CC &= fetch();
            break;
        case 0x1D: //SEX
            rA = (rB & 0x80)?0xff:0;
            flagsNZ16(getD());
            CC &= ~F_OVERFLOW;
            break;
        case 0x1E: //EXG
            pb = fetch();
            TFREXG(pb,true);
            break;
        case 0x1F: //EXG
            pb = fetch();
            TFREXG(pb,false);
            break;

        case 0x20: //BRA
            addr = signed(fetch());
            PC += addr;
            break;
        case 0x21: //BRN
            addr = signed(fetch());
            break;
        case 0x22: //BHI
            addr = signed(fetch());
            if (!(CC&(F_CARRY | F_ZERO))) PC += addr;
        break;
        case 0x23: //BLS
            addr = signed(fetch());
            if (CC&(F_CARRY | F_ZERO)) PC += addr;
        break;
        case 0x24: //BCC
            addr = signed(fetch());
            if (!(CC&F_CARRY)) PC += addr;
        break;
        case 0x25: //BCS
            addr = signed(fetch());
            if (CC&F_CARRY) PC += addr;
        break;
        case 0x26: //BNE
            addr = signed(fetch());
            if (!(CC&F_ZERO)) PC += addr;
        break;
        case 0x27: //BEQ
            addr = signed(fetch());
            if (CC&F_ZERO) PC += addr;
        break;
        case 0x28: //BVC
            addr = signed(fetch());
            if (!(CC&F_OVERFLOW)) PC += addr;
        break;
        case 0x29: //BVS
            addr = signed(fetch());
            if (CC&F_OVERFLOW) PC += addr;
        break;
        case 0x2A: //BPL
            addr = signed(fetch());
            if (!(CC&F_NEGATIVE)) PC += addr;
        break;
        case 0x2B: //BMI
            addr = signed(fetch());
            if (CC&F_NEGATIVE) PC += addr;
        break;
        case 0x2C: //BGE
            addr = signed(fetch());
            if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2))) PC += addr;
        break;
        case 0x2D: //BLT
            addr = signed(fetch());
            if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2)) PC += addr;
        break;
        case 0x2E: //BGT
            addr = signed(fetch());
            if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO))) PC += addr;
        break;
        case 0x2F: //BLE
            addr = signed(fetch());
            if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO)) PC += addr;
        break;

        case 0x30: //LEAX
            rX = PostByte();
            if (rX===0) CC|=F_ZERO; else CC&=~F_ZERO;
        break;
        case 0x31: //LEAY
            rY = PostByte();
            if (rY===0) CC|=F_ZERO; else CC&=~F_ZERO;
        break;
        case 0x32: //LEAS
            rS = PostByte();
        break;
        case 0x33: //LEAU
            rU = PostByte();
        break;

        case 0x34: //PSHS
            PSHS(fetch());
        break;
        case 0x35: //PULS
            PULS(fetch());
        break;
        case 0x36: //PSHU
            PSHU(fetch());
        break;
        case 0x37: //PULU
            PULU(fetch());
        break;
        case 0x39: //RTS
            PC = PULLW();
        break;
        case 0x3A: //ABX
            rX += rB;
        break;
        case 0x3B: //RTI
            CC = PULLB();
            if (CC & F_ENTIRE) {
                T+=9;
                rA = PULLB();
                rB = PULLB();
                DP = PULLB();
                rX = PULLW();
                rY = PULLW();
                rU = PULLW();
            }
            PC = PULLW();
        break;
        case 0x3C: //CWAI **todo
            CC &= fetch();
        break;
        case 0x3D: //MUL
            addr = rA * rB;
            if (addr===0) CC|=F_ZERO; else CC&=~F_ZERO;
            if (addr&0x80) CC|=F_CARRY; else CC&=~F_CARRY;
            setD(addr);
        break;
        case 0x3F: //SWI
            CC |= F_ENTIRE;
            PUSHW(PC);
            PUSHW(rU);
            PUSHW(rY);
            PUSHW(rX);
            PUSHB(DP);
            PUSHB(rB);
            PUSHB(rA);
            PUSHB(CC);
            CC |= F_IRQMASK | F_FIRQMASK;
            PC = ReadWord(vecSWI);
        break;

        case 0x40:
            rA = oNEG(rA);
        break;
        case 0x43:
            rA = oCOM(rA);
        break;
        case 0x44:
            rA = oLSR(rA);
        break;
        case 0x46:
            rA = oROR(rA);
        break;
        case 0x47:
            rA = oASR(rA);
        break;
        case 0x48:
            rA = oASL(rA);
        break;
        case 0x49:
            rA = oROL(rA);
        break;
        case 0x4A:
            rA = oDEC(rA);
        break;
        case 0x4C:
            rA = oINC(rA);
        break;
        case 0x4D:
            CC &= ~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0x4F:
            rA = 0;
            CC &= ~(F_NEGATIVE|F_OVERFLOW|F_CARRY);
            CC |= F_ZERO;
        break;

        case 0x50:
            rB = oNEG(rB);
        break;
        case 0x53:
            rB = oCOM(rB);
        break;
        case 0x54:
            rB = oLSR(rB);
        break;
        case 0x56:
            rB = oROR(rB);
        break;
        case 0x57:
            rB = oASR(rB);
        break;
        case 0x58:
            rB = oASL(rB);
        break;
        case 0x59:
            rB = oROL(rB);
        break;
        case 0x5A:
            rB = oDEC(rB);
        break;
        case 0x5C:
            rB = oINC(rB);
        break;
        case 0x5D:
            CC &= ~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0x5F:
            rB = 0;
            CC &= ~(F_NEGATIVE|F_OVERFLOW|F_CARRY);
            CC |= F_ZERO;
        break;

        case 0x60: //NEG indexed
            addr = PostByte();
            byteTo(addr, oNEG(byteAt(addr)));
            break;
        case 0x63: //COM indexed
            addr = PostByte();
            byteTo(addr, oCOM(byteAt(addr)));
            break;
        case 0x64: //LSR indexed
            addr = PostByte();
            byteTo(addr, oLSR(byteAt(addr)));
            break;
        case 0x66: //ROR indexed
            addr = PostByte();
            byteTo(addr, oROR(byteAt(addr)));
        break;
        case 0x67: //ASR indexed
            addr = PostByte();
            byteTo(addr, oASR(byteAt(addr)));
        break;
        case 0x68: //ASL indexed
            addr = PostByte();
            byteTo(addr, oASL(byteAt(addr)));
        break;
        case 0x69: //ROL indexed
            addr = PostByte();
            byteTo(addr, oROL(byteAt(addr)));
        break;

        case 0x6A: //DEC indexed
            addr = PostByte();
            byteTo(addr, oDEC(byteAt(addr)));
        break;
        case 0x6C: //INC indexed
            addr = PostByte();
            byteTo(addr, oINC(byteAt(addr)));
        break;

        case 0x6D: //TST indexed
            addr = PostByte();
            pb = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[pb];
        break;

        case 0x6E: //JMP indexed
            addr = PostByte();
            PC = addr;
        break;
        case 0x6F: //CLR indexed
            addr = PostByte();
            byteTo(addr,0);
            CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
            CC |= F_ZERO;
        break;


        case 0x70: //NEG extended
            addr = fetch16();
            byteTo(addr, oNEG(byteAt(addr)));
            break;
        case 0x73: //COM extended
            addr = fetch16();
            byteTo(addr, oCOM(byteAt(addr)));
            break;
        case 0x74: //LSR extended
            addr = fetch16();
            byteTo(addr, oLSR(byteAt(addr)));
            break;
        case 0x76: //ROR extended
            addr = fetch16();
            byteTo(addr, oROR(byteAt(addr)));
        break;
        case 0x77: //ASR extended
            addr = fetch16();
            byteTo(addr, oASR(byteAt(addr)));
        break;
        case 0x78: //ASL extended
            addr = fetch16();
            byteTo(addr, oASL(byteAt(addr)));
        break;
        case 0x79: //ROL extended
            addr = fetch16();
            byteTo(addr, oROL(byteAt(addr)));
        break;

        case 0x7A: //DEC extended
            addr = fetch16();
            byteTo(addr, oDEC(byteAt(addr)));
        break;
        case 0x7C: //INC extended
            addr = fetch16();
            byteTo(addr, oINC(byteAt(addr)));
        break;

        case 0x7D: //TST extended
            addr = fetch16();
            pb = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[pb];
        break;

        case 0x7E: //JMP extended
            addr = fetch16();
            PC = addr;
        break;
        case 0x7F: //CLR extended
            addr = fetch16();
            byteTo(addr,0);
            CC&=~(F_CARRY|F_NEGATIVE|F_OVERFLOW);
            CC |= F_ZERO;
        break;

        // regs A,X

        case 0x80: //SUBA imm
            rA = oSUB(rA, fetch());
        break;
        case 0x81: //CMPA imm
            oCMP(rA, fetch());
        break;
        case 0x82: //SBCA imm
            rA = oSBC(rA, fetch());
        break;
        case 0x83: //SUBD imm
            setD(oSUB16(getD(),fetch16()));
        break;
        case 0x84: //ANDA imm
            rA = oAND(rA, fetch());
        break;
        case 0x85: //BITA imm
            oAND(rA, fetch());
        break;
        case 0x86: //LDA imm
            rA = fetch();
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0x88: //EORA imm
            rA = oEOR(rA, fetch());
        break;
        case 0x89: //ADCA imm
            rA = oADC(rA, fetch());
        break;
        case 0x8A: //ORA imm
            rA = oOR(rA, fetch());
        break;
        case 0x8B: //ADDA imm
            rA = oADD(rA, fetch());
        break;
        case 0x8C: //CMPX imm
            oCMP16(rX, fetch16());
        break;

        case 0x8D: //JSR imm
            addr = signed(fetch());
            PUSHW(PC);
            PC+=addr;
        break;
        case 0x8E: //LDX imm
            rX = fetch16();
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;


        case 0x90: //SUBA direct
            addr = dpadd();
            rA = oSUB(rA, byteAt(addr));
        break;
        case 0x91: //CMPA direct
            addr = dpadd();
            oCMP(rA, byteAt(addr));
        break;
        case 0x92: //SBCA direct
            addr = dpadd();
            rA = oSBC(rA, byteAt(addr));
        break;
        case 0x93: //SUBD direct
            addr = dpadd();
            setD(oSUB16(getD(),ReadWord(addr)));
        break;
        case 0x94: //ANDA direct
            addr = dpadd();
            rA = oAND(rA, byteAt(addr));
        break;
        case 0x95: //BITA direct
            addr = dpadd();
            oAND(rA, byteAt(addr));
        break;
        case 0x96: //LDA direct
            addr = dpadd();
            rA = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0x97: //STA direct
            addr = dpadd();
            byteTo(addr,rA);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0x98: //EORA direct
            addr = dpadd();
            rA = oEOR(rA, byteAt(addr));
        break;
        case 0x99: //ADCA direct
            addr = dpadd();
            rA = oADC(rA, byteAt(addr));
        break;
        case 0x9A: //ORA direct
            addr = dpadd();
            rA = oOR(rA, byteAt(addr));
        break;
        case 0x9B: //ADDA direct
            addr = dpadd();
            rA = oADD(rA, byteAt(addr));
        break;
        case 0x9C: //CMPX direct
            addr = dpadd();
            oCMP16(rX, ReadWord(addr));
        break;

        case 0x9D: //JSR direct
            addr = dpadd();
            PUSHW(PC);
            PC=addr;
        break;
        case 0x9E: //LDX direct
            addr = dpadd();
            rX = ReadWord(addr);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;
        case 0x9F: //STX direct
            addr = dpadd();
            WriteWord(addr,rX);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;
        case 0xA0: //SUBA indexed
            addr = PostByte();
            rA = oSUB(rA, byteAt(addr));
        break;
        case 0xA1: //CMPA indexed
            addr = PostByte();
            oCMP(rA, byteAt(addr));
        break;
        case 0xA2: //SBCA indexed
            addr = PostByte();
            rA = oSBC(rA, byteAt(addr));
        break;
        case 0xA3: //SUBD indexed
            addr = PostByte();
            setD(oSUB16(getD(),ReadWord(addr)));
        break;
        case 0xA4: //ANDA indexed
            addr = PostByte();
            rA = oAND(rA, byteAt(addr));
        break;
        case 0xA5: //BITA indexed
            addr = PostByte();
            oAND(rA, byteAt(addr));
        break;
        case 0xA6: //LDA indexed
            addr = PostByte();
            rA = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0xA7: //STA indexed
            addr = PostByte();
            byteTo(addr,rA);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0xA8: //EORA indexed
            addr = PostByte();
            rA = oEOR(rA, byteAt(addr));
        break;
        case 0xA9: //ADCA indexed
            addr = PostByte();
            rA = oADC(rA, byteAt(addr));
        break;
        case 0xAA: //ORA indexed
            addr = PostByte();
            rA = oOR(rA, byteAt(addr));
        break;
        case 0xAB: //ADDA indexed
            addr = PostByte();
            rA = oADD(rA, byteAt(addr));
        break;
        case 0xAC: //CMPX indexed
            addr = PostByte();
            oCMP16(rX, ReadWord(addr));
        break;

        case 0xAD: //JSR indexed
            addr = PostByte();
            PUSHW(PC);
            PC=addr;
        break;
        case 0xAE: //LDX indexed
            addr = PostByte();
            rX = ReadWord(addr);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;
        case 0xAF: //STX indexed
            addr = PostByte();
            WriteWord(addr,rX);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;


        case 0xB0: //SUBA extended
            addr = fetch16();
            rA = oSUB(rA, byteAt(addr));
        break;
        case 0xB1: //CMPA extended
            addr = fetch16();
            oCMP(rA, byteAt(addr));
        break;
        case 0xB2: //SBCA extended
            addr = fetch16();
            rA = oSBC(rA, byteAt(addr));
        break;
        case 0xB3: //SUBD extended
            addr = fetch16();
            setD(oSUB16(getD(),ReadWord(addr)));
        break;
        case 0xB4: //ANDA extended
            addr = fetch16();
            rA = oAND(rA, byteAt(addr));
        break;
        case 0xB5: //BITA extended
            addr = fetch16();
            oAND(rA, byteAt(addr));
        break;
        case 0xB6: //LDA extended
            addr = fetch16();
            rA = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0xB7: //STA extended
            addr = fetch16();
            byteTo(addr,rA);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rA];
        break;
        case 0xB8: //EORA extended
            addr = fetch16();
            rA = oEOR(rA, byteAt(addr));
        break;
        case 0xB9: //ADCA extended
            addr = fetch16();
            rA = oADC(rA, byteAt(addr));
        break;
        case 0xBA: //ORA extended
            addr = fetch16();
            rA = oOR(rA, byteAt(addr));
        break;
        case 0xBB: //ADDA extended
            addr = fetch16();
            rA = oADD(rA, byteAt(addr));
        break;
        case 0xBC: //CMPX extended
            addr = fetch16();
            oCMP16(rX, ReadWord(addr));
        break;

        case 0xBD: //JSR extended
            addr = fetch16();
            PUSHW(PC);
            PC=addr;
        break;
        case 0xBE: //LDX extended
            addr = fetch16();
            rX = ReadWord(addr);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;
        case 0xBF: //STX extended
            addr = fetch16();
            WriteWord(addr,rX);
            flagsNZ16(rX);
            CC&=~F_OVERFLOW;
        break;

        //Regs B, Y

        case 0xC0: //SUBB imm
            rB = oSUB(rB, fetch());
        break;
        case 0xC1: //CMPB imm
            oCMP(rB, fetch());
        break;
        case 0xC2: //SBCB imm
            rB = oSBC(rB, fetch());
        break;
        case 0xC3: //ADDD imm
            setD(oADD16(getD(),fetch16()));
        break;
        case 0xC4: //ANDB imm
            rB = oAND(rB, fetch());
        break;
        case 0xC5: //BITB imm
            oAND(rB, fetch());
        break;
        case 0xC6: //LDB imm
            rB = fetch();
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xC8: //EORB imm
            rB = oEOR(rB, fetch());
        break;
        case 0xC9: //ADCB imm
            rB = oADC(rB, fetch());
        break;
        case 0xCA: //ORB imm
            rB = oOR(rB, fetch());
        break;
        case 0xCB: //ADDB imm
            rB = oADD(rB, fetch());
        break;
        case 0xCC: //LDD imm
            addr = fetch16();
            setD(addr);
            flagsNZ16(addr);
            CC&=~F_OVERFLOW;
        break;

        case 0xCE: //LDU imm
            rU = fetch16();
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;


        case 0xD0: //SUBB direct
            addr = dpadd();
            rB = oSUB(rB, byteAt(addr));
        break;
        case 0xD1: //CMPB direct
            addr = dpadd();
            oCMP(rB, byteAt(addr));
        break;
        case 0xD2: //SBCB direct
            addr = dpadd();
            rB = oSBC(rB, byteAt(addr));
        break;
        case 0xD3: //ADDD direct
            addr = dpadd();
            setD(oADD16(getD(),ReadWord(addr)));
        break;
        case 0xD4: //ANDB direct
            addr = dpadd();
            rB = oAND(rB, byteAt(addr));
        break;
        case 0xD5: //BITB direct
            addr = dpadd();
            oAND(rB, byteAt(addr));
        break;
        case 0xD6: //LDB direct
            addr = dpadd();
            rB = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xD7: //STB direct
            addr = dpadd();
            byteTo(addr,rB);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xD8: //EORB direct
            addr = dpadd();
            rB = oEOR(rB, byteAt(addr));
        break;
        case 0xD9: //ADCB direct
            addr = dpadd();
            rB = oADC(rB, byteAt(addr));
        break;
        case 0xDA: //ORB direct
            addr = dpadd();
            rB = oOR(rB, byteAt(addr));
        break;
        case 0xDB: //ADDB direct
            addr = dpadd();
            rB = oADD(rB, byteAt(addr));
        break;
        case 0xDC: //LDD direct
            addr = dpadd();
            pb = ReadWord(addr);
            setD(pb);
            flagsNZ16(pb);
            CC&=~F_OVERFLOW;
        break;

        case 0xDD: //STD direct
            addr = dpadd();
            WriteWord(addr, getD());
            CC&=~F_OVERFLOW;
        break;
        case 0xDE: //LDU direct
            addr = dpadd();
            rU = ReadWord(addr);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;
        case 0xDF: //STU direct
            addr = dpadd();
            WriteWord(addr,rU);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;
        case 0xE0: //SUBB indexed
            addr = PostByte();
            rB = oSUB(rB, byteAt(addr));
        break;
        case 0xE1: //CMPB indexed
            addr = PostByte();
            oCMP(rB, byteAt(addr));
        break;
        case 0xE2: //SBCB indexed
            addr = PostByte();
            rB = oSBC(rB, byteAt(addr));
        break;
        case 0xE3: //ADDD indexed
            addr = PostByte();
            setD(oADD16(getD(),ReadWord(addr)));
        break;
        case 0xE4: //ANDB indexed
            addr = PostByte();
            rB = oAND(rB, byteAt(addr));
        break;
        case 0xE5: //BITB indexed
            addr = PostByte();
            oAND(rB, byteAt(addr));
        break;
        case 0xE6: //LDB indexed
            addr = PostByte();
            rB = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xE7: //STB indexed
            addr = PostByte();
            byteTo(addr,rB);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xE8: //EORB indexed
            addr = PostByte();
            rB = oEOR(rB, byteAt(addr));
        break;
        case 0xE9: //ADCB indexed
            addr = PostByte();
            rB = oADC(rB, byteAt(addr));
        break;
        case 0xEA: //ORB indexed
            addr = PostByte();
            rB = oOR(rB, byteAt(addr));
        break;
        case 0xEB: //ADDB indexed
            addr = PostByte();
            rB = oADD(rB, byteAt(addr));
        break;
        case 0xEC: //LDD indexed
            addr = PostByte();
            pb = ReadWord(addr);
            setD(pb);
            flagsNZ16(pb);
            CC&=~F_OVERFLOW;
        break;

        case 0xED: //STD indexed
            addr = PostByte();
            WriteWord(addr, getD());
            CC&=~F_OVERFLOW;
        break;
        case 0xEE: //LDU indexed
            addr = PostByte();
            rU = ReadWord(addr);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;
        case 0xEF: //STU indexed
            addr = PostByte();
            WriteWord(addr,rU);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;


        case 0xF0: //SUBB extended
            addr = fetch16();
            rB = oSUB(rB, byteAt(addr));
        break;
        case 0xF1: //CMPB extended
            addr = fetch16();
            oCMP(rB, byteAt(addr));
        break;
        case 0xF2: //SBCB extended
            addr = fetch16();
            rB = oSBC(rB, byteAt(addr));
        break;
        case 0xF3: //ADDD extended
            addr = fetch16();
            setD(oADD16(getD(),ReadWord(addr)));
        break;
        case 0xF4: //ANDB extended
            addr = fetch16();
            rB = oAND(rB, byteAt(addr));
        break;
        case 0xF5: //BITB extended
            addr = fetch16();
            oAND(rB, byteAt(addr));
        break;
        case 0xF6: //LDB extended
            addr = fetch16();
            rB = byteAt(addr);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xF7: //STB extended
            addr = fetch16();
            byteTo(addr,rB);
            CC&=~(F_ZERO|F_NEGATIVE|F_OVERFLOW);
            CC |= flagsNZ[rB];
        break;
        case 0xF8: //EORB extended
            addr = fetch16();
            rB = oEOR(rB, byteAt(addr));
        break;
        case 0xF9: //ADCB extended
            addr = fetch16();
            rB = oADC(rB, byteAt(addr));
        break;
        case 0xFA: //ORB extended
            addr = fetch16();
            rB = oOR(rB, byteAt(addr));
        break;
        case 0xFB: //ADDB extended
            addr = fetch16();
            rB = oADD(rB, byteAt(addr));
        break;
        case 0xFC: //LDD extended
            addr = fetch16();
            pb = ReadWord(addr);
            setD(pb);
            flagsNZ16(pb);
            CC&=~F_OVERFLOW;
        break;

        case 0xFD: //STD extended
            addr = fetch16();
            WriteWord(addr, getD());
            CC&=~F_OVERFLOW;
        break;
        case 0xFE: //LDU extended
            addr = fetch16();
            rU = ReadWord(addr);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;
        case 0xFF: //STU extended
            addr = fetch16();
            WriteWord(addr,rU);
            flagsNZ16(rU);
            CC&=~F_OVERFLOW;
        break;

        // page 1
        case 0x10: //page 1
            {
                opcode = fetch();
                T+=cycles2[opcode];
                switch(opcode) {
                    case 0x21: //BRN
                        addr = signed16(fetch16());
                        break;
                    case 0x22: //BHI
                        addr = signed16(fetch16());
                        if (!(CC&(F_CARRY | F_ZERO))) PC += addr;
                    break;
                    case 0x23: //BLS
                        addr = signed16(fetch16());
                        if (CC&(F_CARRY | F_ZERO)) PC += addr;
                    break;
                    case 0x24: //BCC
                        addr = signed16(fetch16());
                        if (!(CC&F_CARRY)) PC += addr;
                    break;
                    case 0x25: //BCS
                        addr = signed16(fetch16());
                        if (CC&F_CARRY) PC += addr;
                    break;
                    case 0x26: //BNE
                        addr = signed16(fetch16());
                        if (!(CC&F_ZERO)) PC += addr;
                    break;
                    case 0x27: //BEQ
                        addr = signed16(fetch16());
                        if (CC&F_ZERO) PC += addr;
                    break;
                    case 0x28: //BVC
                        addr = signed16(fetch16());
                        if (!(CC&F_OVERFLOW)) PC += addr;
                    break;
                    case 0x29: //BVS
                        addr = signed16(fetch16());
                        if (CC&F_OVERFLOW) PC += addr;
                    break;
                    case 0x2A: //BPL
                        addr = signed16(fetch16());
                        if (!(CC&F_NEGATIVE)) PC += addr;
                    break;
                    case 0x2B: //BMI
                        addr = signed16(fetch16());
                        if (CC&F_NEGATIVE) PC += addr;
                    break;
                    case 0x2C: //BGE
                        addr = signed16(fetch16());
                        if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2))) PC += addr;
                    break;
                    case 0x2D: //BLT
                        addr = signed16(fetch16());
                        if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2)) PC += addr;
                    break;
                    case 0x2E: //BGT
                        addr = signed16(fetch16());
                        if (!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO))) PC += addr;
                    break;
                    case 0x2F: //BLE
                        addr = signed16(fetch16());
                        if ((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO)) PC += addr;
                    break;
                    case 0x3f: //SWI2
                        CC |= F_ENTIRE;
                        PUSHW(PC);
                        PUSHW(rU);
                        PUSHW(rY);
                        PUSHW(rX);
                        PUSHB(DP);
                        PUSHB(rB);
                        PUSHB(rA);
                        PUSHB(CC);
                        CC |= F_IRQMASK | F_FIRQMASK;
                        PC = ReadWord(vecSWI2);
                    break;
                    case 0x83: //CMPD imm
                        oCMP16(getD(),fetch16());
                    break;
                    case 0x8C: //CMPY imm
                        oCMP16(rY,fetch16());
                    break;
                    case 0x8E: //LDY imm
                        rY = fetch16();
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0x93: //CMPD direct
                        addr = dpadd();
                        oCMP16(getD(),ReadWord(addr));
                    break;
                    case 0x9C: //CMPY direct
                        addr = dpadd();
                        oCMP16(rY,ReadWord(addr));
                    break;
                    case 0x9E: //LDY direct
                        addr = dpadd();
                        rY = ReadWord(addr);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0x9F: //STY direct
                        addr = dpadd();
                        WriteWord(addr,rY);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xA3: //CMPD indexed
                        addr = PostByte();
                        oCMP16(getD(),ReadWord(addr));
                    break;
                    case 0xAC: //CMPY indexed
                        addr = PostByte();
                        oCMP16(rY,ReadWord(addr));
                    break;
                    case 0xAE: //LDY indexed
                        addr = PostByte();
                        rY = ReadWord(addr);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xAF: //STY indexed
                        addr = PostByte();
                        WriteWord(addr,rY);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xB3: //CMPD extended
                        addr = fetch16();
                        oCMP16(getD(),ReadWord(addr));
                    break;
                    case 0xBC: //CMPY extended
                        addr = fetch16();
                        oCMP16(rY,ReadWord(addr));
                    break;
                    case 0xBE: //LDY extended
                        addr = fetch16();
                        rY = ReadWord(addr);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xBF: //STY extended
                        addr = fetch16();
                        WriteWord(addr,rY);
                        flagsNZ16(rY);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xCE: //LDS imm
                        rS = fetch16();
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xDE: //LDS direct
                        addr = dpadd();
                        rS = ReadWord(addr);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xDF: //STS direct
                        addr = dpadd();
                        WriteWord(addr,rS);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xEE: //LDS indexed
                        addr = PostByte();
                        rS = ReadWord(addr);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xEF: //STS indexed
                        addr = PostByte();
                        WriteWord(addr,rS);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xFE: //LDS extended
                        addr = fetch16();
                        rS = ReadWord(addr);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                    case 0xFF: //STS extended
                        addr = fetch16();
                        WriteWord(addr,rS);
                        flagsNZ16(rS);
                        CC&=~F_OVERFLOW;
                    break;
                }
            }
        break;
        // page 2
        case 0x11: //page 2
            {
                opcode = fetch();
                T+=cycles2[opcode];
                switch(opcode) {
                    case 0x3f: //SWI3
                        CC |= F_ENTIRE;
                        PUSHW(PC);
                        PUSHW(rU);
                        PUSHW(rY);
                        PUSHW(rX);
                        PUSHB(DP);
                        PUSHB(rB);
                        PUSHB(rA);
                        PUSHB(CC);
                        CC |= F_IRQMASK | F_FIRQMASK;
                        PC = ReadWord(vecSWI3);
                    break;
                    case 0x83: //CMPU imm
                        oCMP16(rU, fetch16());
                    break;
                    case 0x8C: //CMPS imm
                        oCMP16(rS, fetch16());
                    break;
                    case 0x93: //CMPU imm
                        addr = dpadd();
                        oCMP16(rU, ReadWord(addr));
                    break;
                    case 0x9C: //CMPS imm
                        addr = dpadd();
                        oCMP16(rS, ReadWord(addr));
                    break;
                    case 0xA3: //CMPU imm
                        addr = PostByte();
                        oCMP16(rU, ReadWord(addr));
                    break;
                    case 0xAC: //CMPS imm
                        addr = PostByte();
                        oCMP16(rS, ReadWord(addr));
                    break;
                    case 0xB3: //CMPU imm
                        addr = fetch16();
                        oCMP16(rU, ReadWord(addr));
                    break;
                    case 0xBC: //CMPS imm
                        addr = fetch16();
                        oCMP16(rS, ReadWord(addr));
                    break;

                }
            }
        break;


    }

    rA &= 0xff;
    rB &= 0xff;
    CC &= 0xff;
    DP &= 0xff;
    rX &= 0xffff;
    rY &= 0xffff;
    rU &= 0xffff;
    rS &= 0xffff;
    PC &= 0xffff;
    return T-oldT;

};

var reset = function(){
    PC = ReadWord(vecRESET);
    DP = 0;
    CC |= F_FIRQMASK | F_IRQMASK;
    T=0;
    rA=rB=DP=rX=rY=rU=rS=0;
};

//---------- Disassembler

/*
ILLEGAL 0
DIRECT 1
INHERENT 2
BRANCH_REL_16 3
IMMEDIAT_8 4
BRANCH_REL_8 5
INDEXED 6
EXTENDED 7
IMMEDIAT_16 8

PSHS 10
PSHU 11

EXG, TFR 20
*/
var ds = [
[2,  1,"NEG"],
[1,  0,"???"],
[1,  0,"???"],
[2,  1,"COM"],
[2,  1,"LSR"],
[1,  0,"???"],
[2,  1,"ROR"],
[2,  1,"ASR"],
[2,  1,"LSL"],
[2,  1,"ROL"],
[2,  1,"DEC"],
[1,  0,"???"],
[2,  1,"INC"],
[2,  1,"TST"],
[2,  1,"JMP"],
[2,  1,"CLR"],
[1,  0,"Prefix"],
[1,  0,"Prefix"],
[1,  2,"NOP"],
[1,  2,"SYNC"],
[1,  0,"???"],
[1,  0,"???"],
[3,  3,"LBRA"],
[3,  3,"LBSR"],
[1,  0,"???"],
[1,  2,"DAA"],
[2,  4,"ORCC"],
[1,  0,"???"],
[2,  4,"ANDCC"],
[1,  2,"SEX"],
[2,  20,"EXG"],
[2,  20,"TFR"],
[2,  5,"BRA"],
[2,  5,"BRN"],
[2,  5,"BHI"],
[2,  5,"BLS"],
[2,  5,"BCC"],
[2,  5,"BCS"],
[2,  5,"BNE"],
[2,  5,"BEQ"],
[2,  5,"BVC"],
[2,  5,"BVS"],
[2,  5,"BPL"],
[2,  5,"BMI"],
[2,  5,"BGE"],
[2,  5,"BLT"],
[2,  5,"BGT"],
[2,  5,"BLE"],
[2,  6,"LEAX"],
[2,  6,"LEAY"],
[2,  6,"LEAS"],
[2,  6,"LEAU"],
[2,  10,"PSHS"],
[2,  10,"PULS"],
[2,  11,"PSHU"],
[2,  11,"PULU"],
[1,  0,"???"],
[1,  2,"RTS"],
[1,  2,"ABX"],
[1,  2,"RTI"],
[2,  2,"CWAI"],
[1,  2,"MUL"],
[1,  2,"RESET"],
[1,  2,"SWI1"],
[1,  2,"NEGA"],
[1,  0,"???"],
[1,  0,"???"],
[1,  2,"COMA"],
[1,  2,"LSRA"],
[1,  0,"???"],
[1,  2,"RORA"],
[1,  2,"ASRA"],
[1,  2,"ASLA"],
[1,  2,"ROLA"],
[1,  2,"DECA"],
[1,  0,"???"],
[1,  2,"INCA"],
[1,  2,"TSTA"],
[1,  0,"???"],
[1,  2,"CLRA"],
[1,  2,"NEGB"],
[1,  0,"???"],
[1,  0,"???"],
[1,  2,"COMB"],
[1,  2,"LSRB"],
[1,  0,"???"],
[1,  2,"RORB"],
[1,  2,"ASRB"],
[1,  2,"ASLB"],
[1,  2,"ROLB"],
[1,  2,"DECB"],
[1,  0,"???"],
[1,  2,"INCB"],
[1,  2,"TSTB"],
[1,  0,"???"],
[1,  2,"CLRB"],
[2,  6,"NEG"],
[1,  0,"???"],
[1,  0,"???"],
[2,  6,"COM"],
[2,  6,"LSR"],
[1,  0,"???"],
[2,  6,"ROR"],
[2,  6,"ASR"],
[2,  6,"LSL"],
[2,  6,"ROL"],
[2,  6,"DEC"],
[1,  0,"???"],
[2,  6,"INC"],
[2,  6,"TST"],
[2,  6,"JMP"],
[2,  6,"CLR"],
[3,  7,"NEG"],
[1,  0,"???"],
[1,  0,"???"],
[3,  7,"COM"],
[3,  7,"LSR"],
[1,  0,"???"],
[3,  7,"ROR"],
[3,  7,"ASR"],
[3,  7,"LSL"],
[3,  7,"ROL"],
[3,  7,"DEC"],
[1,  0,"???"],
[3,  7,"INC"],
[3,  7,"TST"],
[3,  7,"JMP"],
[3,  7,"CLR"],
[2,  4,"SUBA"],
[2,  4,"CMPA"],
[2,  4,"SBCA"],
[3,  8,"SUBD"],
[2,  4,"ANDA"],
[2,  4,"BITA"],
[2,  4,"LDA"],
[1,  0,"???"],
[2,  4,"EORA"],
[2,  4,"ADCA"],
[2,  4,"ORA"],
[2,  4,"ADDA"],
[3,  8,"CMPX"],
[2,  5,"BSR"],
[3,  8,"LDX"],
[1,  0,"???"],
[2,  1,"SUBA"],
[2,  1,"CMPA"],
[2,  1,"SBCA"],
[2,  1,"SUBd"],
[2,  1,"ANDA"],
[2,  1,"BITA"],
[2,  1,"LDA"],
[2,  1,"STA"],
[2,  1,"EORA"],
[2,  1,"ADCA"],
[2,  1,"ORA"],
[2,  1,"ADDA"],
[2,  1,"CMPX"],
[2,  1,"JSR"],
[2,  1,"LDX"],
[2,  1,"STX"],
[2,  6,"SUBA"],
[2,  6,"CMPA"],
[2,  6,"SBCA"],
[2,  6,"SUBD"],
[2,  6,"ANDA"],
[2,  6,"BITA"],
[2,  6,"LDA"],
[2,  6,"STA"],
[2,  6,"EORA"],
[2,  6,"ADCA"],
[2,  6,"ORA"],
[2,  6,"ADDA"],
[2,  6,"CMPX"],
[2,  6,"JSR"],
[2,  6,"LDX"],
[2,  6,"STX"],
[3,  7,"SUBA"],
[3,  7,"CMPA"],
[3,  7,"SBCA"],
[3,  7,"SUBD"],
[3,  7,"ANDA"],
[3,  7,"BITA"],
[3,  7,"LDA"],
[3,  7,"STA"],
[3,  7,"EORA"],
[3,  7,"ADCA"],
[3,  7,"ORA"],
[3,  7,"ADDA"],
[3,  7,"CMPX"],
[3,  7,"JSR"],
[3,  7,"LDX"],
[3,  7,"STX"],
[2,  4,"SUBB"],
[2,  4,"CMPB"],
[2,  4,"SBCB"],
[3,  8,"ADDD"],
[2,  4,"ANDB"],
[2,  4,"BITB"],
[2,  4,"LDB"],
[1,  0,"???"],
[2,  4,"EORB"],
[2,  4,"ADCB"],
[2,  4,"ORB"],
[2,  4,"ADDB"],
[3,  8,"LDD"],
[1,  0,"???"],
[3,  8,"LDU"],
[1,  0,"???"],
[2,  1,"SUBB"],
[2,  1,"CMPB"],
[2,  1,"SBCB"],
[2,  1,"ADDD"],
[2,  1,"ANDB"],
[2,  1,"BITB"],
[2,  1,"LDB"],
[2,  1,"STB"],
[2,  1,"EORB"],
[2,  1,"ADCB"],
[2,  1,"ORB "],
[2,  1,"ADDB"],
[2,  1,"LDD "],
[2,  1,"STD "],
[2,  1,"LDU "],
[2,  1,"STU "],
[2,  6,"SUBB"],
[2,  6,"CMPB"],
[2,  6,"SBCB"],
[2,  6,"ADDD"],
[2,  6,"ANDB"],
[2,  6,"BITB"],
[2,  6,"LDB"],
[2,  6,"STB"],
[2,  6,"EORB"],
[2,  6,"ADCB"],
[2,  6,"ORB"],
[2,  6,"ADDB"],
[2,  6,"LDD"],
[2,  6,"STD"],
[2,  6,"LDU"],
[2,  6,"STU"],
[3,  7,"SUBB"],
[3,  7,"CMPB"],
[3,  7,"SBCB"],
[3,  7,"ADDD"],
[3,  7,"ANDB"],
[3,  7,"BITB"],
[3,  7,"LDB"],
[3,  7,"STB"],
[3,  7,"EORB"],
[3,  7,"ADCB"],
[3,  7,"ORB"],
[3,  7,"ADDB"],
[3,  7,"LDD"],
[3,  7,"STD"],
[3,  7,"LDU"],
[3,  7,"STU"]
];

var ds11 = {
0x3F: [2,2,"SWI3"],
0x83: [4,8,"CMPU"],
0x8C: [4,8,"CMPS"],
0x93: [3,1,"CMPU"],
0x9C: [3,1,"CMPS"],
0xA3: [3,6,"CMPU"],
0xAC: [3,6,"CMPS"],
0xB3: [4,7,"CMPU"],
0xBC: [4,7,"CMPS"]
};

var ds10 = {
0x21:[5,3,"LBRN"],
0x22:[5,3,"LBHI"],
0x23:[5,3,"LBLS"],
0x24:[5,3,"LBCC"],
0x25:[5,3,"LBCS"],
0x26:[5,3,"LBNE"],
0x27:[5,3,"LBEQ"],
0x28:[5,3,"LBVC"],
0x29:[5,3,"LBVS"],
0x2a:[5,3,"LBPL"],
0x2b:[5,3,"LBMI"],
0x2c:[5,3,"LBGE"],
0x2d:[5,3,"LBLT"],
0x2e:[5,3,"LBGT"],
0x2f:[5,3,"LBLE"],
0x3F:[2,2,"SWI2"],
0x83:[4,8,"CMPD"],
0x8C:[4,8,"CMPY"],
0x8E:[4,8,"LDY"],
0x93:[3,1,"CMPD"],
0x9C:[3,1,"CMPY"],
0x9E:[3,1,"LDY"],
0x9F:[3,1,"STY"],
0xA3:[3,6,"CMPD"],
0xAC:[3,6,"CMPY"],
0xAE:[3,6,"LDY"],
0xAF:[3,6,"STY"],
0xB3:[4,7,"CMPD"],
0xBC:[4,7,"CMPY"],
0xBE:[4,7,"LDY"],
0xBF:[4,7,"STY"],
0xCE:[4,8,"LDS"],
0xDE:[3,1,"LDS"],
0xDF:[3,1,"STS"],
0xEE:[3,6,"LDS"],
0xEF:[3,6,"STS"],
0xFE:[4,7,"LDS"],
0xFF:[4,7,"STS"]
};
/*
ILLEGAL 0
DIRECT 1
INHERENT 2
BRANCH_REL_16 3
IMMEDIAT_8 4
BRANCH_REL_8 5
INDEXED 6
EXTENDED 7
IMMEDIAT_16 8
*/

var disasm = function(i,a,b,c,d,pc) {
    var toHexN = function(n,d) {
      var s = n.toString(16);
      while (s.length <d) {s = '0'+s;}
      return s.toUpperCase();
    };

    var toHex2 = function(n) {return toHexN(n & 0xff,2);};
    var toHex4 = function(n) {return toHexN(n,4);};
    var rx,ro,j;
      var sx = ds[i];
      if (i===0x10) {
        sx = ds10[a];
        if (sx===undefined) {
            return ["???",2];
        }
        i=a;a=b;b=c;c=d;
      }
      if (i===0x11) {
        sx = ds11[a];
        if (sx===undefined) {
            return ["???",2];
        }
        i=a;a=b;b=c;c=d;
      }
      var bytes = sx[0];
      var mode = sx[1];
      var mnemo = sx[2];

      switch (mode) {
        case 0: //invalid
            break;
        case 1: //direct page
            mnemo+="\t$"+toHex2(a); break;
        case 2: // inherent
            break;
        case 3: //brel16
            mnemo+="\t#$"+toHex4((a*256+b)<32768 ? (a*256+b+pc):(a*256+b+pc-65536)); break;
        case 4: //imm8
            mnemo+="\t#$"+toHex2(a); break;
        case 5: //brel8
            mnemo+="\t#$"+toHex4((a)<128 ? (a+pc+2):(a+pc-254)); break;
        case 6: //indexed, postbyte etc.
            mnemo+='\t';
            var pb = a;
            var ixr = ["X","Y","U","S"][(pb & 0x60)>>5];
            if (!(pb & 0x80)) {
                //direct5
                var disp = pb & 0x1f;
                if (disp>15) disp = disp-32;
                mnemo+=disp+','+ixr;
                break;
            }
            var ind = pb & 0x10;
            var mod = pb & 0x0f;
            var ofs8 = (b>127)?(b-256):b;
            var ofs16 = ((b*256+c)>32767)?((b*256+c)-65536):(b*256+c);
            if (!ind) {
                switch (mod) {
                    case 0: mnemo += ","+ixr+'+'; break;
                    case 1: mnemo += ","+ixr+'++'; break;
                    case 2: mnemo += ",-"+ixr; break;
                    case 3: mnemo += ",--"+ixr; break;
                    case 4: mnemo += ","+ixr; break;
                    case 5: mnemo += "B,"+ixr; break;
                    case 6: mnemo += "A,"+ixr; break;
                    case 7: mnemo += "???"; break;
                    case 8: mnemo += ofs8+","+ixr; bytes++; break;
                    case 9: mnemo += ofs16+","+ixr; bytes+=2; break;
                    case 10: mnemo += "???"; break;
                    case 11: mnemo += "D,"+ixr; break;
                    case 12: mnemo += ofs8+",PC"; bytes++; break;
                    case 13: mnemo += ofs16+",PC"; bytes+=2; break;
                    case 14: mnemo += "???"; break;
                    case 15: mnemo += "$"+toHex4((b*256+c)); bytes+=2; break;
                }
            }  else {
                switch (mod) {
                    case 0: mnemo += "???"; break;
                    case 1: mnemo += "[,"+ixr+'++]'; break;
                    case 2: mnemo += "???"; break;
                    case 3: mnemo += "[,--"+ixr+']'; break;
                    case 4: mnemo += "[,"+ixr+']'; break;
                    case 5: mnemo += "[B,"+ixr+']'; break;
                    case 6: mnemo += "[A,"+ixr+']'; break;
                    case 7: mnemo += "???"; break;
                    case 8: mnemo += "["+ofs8+","+ixr+']'; bytes++; break;
                    case 9: mnemo += "["+ofs16+","+ixr+']'; bytes+=2; break;
                    case 10: mnemo += "???"; break;
                    case 11: mnemo += "[D,"+ixr+']'; break;
                    case 12: mnemo += "["+ofs8+",PC]"; bytes++; break;
                    case 13: mnemo += "["+ofs16+",PC]"; bytes+=2; break;
                    case 14: mnemo += "???"; break;
                    case 15: mnemo += "[$"+toHex4((b*256+c))+']'; bytes+=2; break;
                }
            }

            break;
        case 7: //extended
            mnemo+="\t$"+toHex4(a*256+b); break;
        case 8: //imm16
            mnemo+="\t#$"+toHex4(a*256+b); break;

        case 10: //pshs, puls
            rx = ['PC','U','Y','X','DP','B','A','CC'];
            ro = [];
            for (j=0;j<8;j++) {
                if ((a & 1)!==0) {ro.push(rx[7-j]);}
                a>>=1;
            }
            mnemo += '\t'+ro.join(',');
            break;
        case 11: //pshs, puls
            rx = ['PC','S','Y','X','DP','B','A','CC'];
            ro = [];
            for (j=0;j<8;j++) {
                if ((a & 1)!==0) {ro.push(rx[7-j]);}
                a>>=1;
            }
            mnemo += '\t'+ro.join(',');
            break;
        case 20: //TFR etc
            rx = ['D','X','Y','U','S','PC','?','?','A','B','CC','DP','?','?','?','?'];
            mnemo += '\t'+rx[a>>4]+','+rx[a&0x0f];
            break;
      }

      return {line:mnemo,nbytes:bytes};
    };


//---------- Exports

return {
    steps: function(Ts){
        //T=0;
        while (Ts>0){
            Ts-=step();
        }
    },
    runFrame: function(Tt){
        while (T<Tt){
          step();
        }
    },
    T:function(){return T;},
    getTstates:function(){return T;},
    setTstates:function(t){T=t;},
    reset: reset,
    init: function(bt,ba,tck){
        byteTo=bt;
        byteAt=ba;
        ticks=tck;
        reset();
    },
    getPC: function() { return PC; },
    saveState: function() {
        return {
            PC:PC,
            SP:rS,
            U:rU,
            A:rA,
            B:rB,
            X:rX,
            Y:rY,
            DP:DP,
            CC:CC,
            T:T
        };
    },
    loadState: function(s) {
      PC=s.PC;
      rS=s.SP;
      rU=s.U;
      rA=s.A;
      rB=s.B;
      rX=s.X;
      rY=s.Y;
      DP=s.DP;
      CC=s.CC;
      T=s.T;
    },
    firq: function() {
      if (CC & F_FIRQMASK) return;
      PUSHW(PC);
      CC &= ~F_ENTIRE;
      PUSHB(CC);
      CC |= F_IRQMASK | F_FIRQMASK;
      PC = ReadWord(vecFIRQ);
      T += 9;
    },
    interrupt: function() {
      if (CC & F_IRQMASK) return;
      PUSHW(PC);
      PUSHW(rU);
      PUSHW(rY);
      PUSHW(rX);
      PUSHB(DP);
      PUSHB(rB);
      PUSHB(rA);
      CC |= F_ENTIRE;
      PUSHB(CC);
      CC |= F_IRQMASK;
      PC = ReadWord(vecIRQ);
      T += 18;
    },
    nmi: function() {
      PUSHW(PC);
      PUSHW(rU);
      PUSHW(rY);
      PUSHW(rX);
      PUSHB(DP);
      PUSHB(rB);
      PUSHB(rA);
      CC |= F_ENTIRE;
      PUSHB(CC);
      CC |= F_IRQMASK | F_FIRQMASK;
      PC = ReadWord(vecNMI);
      T += 18;
    },
    set:function(reg,value) {
        switch (reg.toUpperCase()) {
            case "PC": PC=value;return;
            case "A": rA=value;return;
            case "B": rB=value;return;
            case "X": rX=value;return;
            case "Y": rY=value;return;
            case "SP": rS=value;return;
            case "U": rU=value;return;
            case "FLAGS": CC=value;return;
        }
    },
    flagsToString: function() {
        var f='',fx = "EFHINZVC";
        for (var i=0;i<8;i++) {
            var n = CC&(0x80>>i);
            if (n===0) {f+=fx[i].toLowerCase();} else {f+=fx[i];}
        }
        return f;
    },
    disasm: disasm
};

};
