
/*
 *   O2EM Free Odyssey2 / Videopac+ Emulator
 *
 *   Created by Daniel Boris <dboris@comcast.net>  (c) 1997,1998
 *
 **   Developed by Andre de la Rocha   <adlroc@users.sourceforge.net>
 *             Arlindo M. de Oliveira <dgtec@users.sourceforge.net>
 *
 *   http://o2em.sourceforge.net
 *
 *
 *
 *   8048 microcontroller emulation
 */


#include <stdio.h>
#include <stdint.h>
#include "vmachine.h"
#include "keyboard.h"
#include "voice.h"
#include "vdc.h"
#include "vpp.h"
#include "cpu.h"

#define push(d) {intRAM[sp++] = (d); if (sp > 23) sp = 8;}
#define pull() (sp--, (sp < 8)?(sp=23):0, intRAM[sp])
#define make_psw() {psw = (cy << 7) | ac | f0 | bs | 0x08; psw = psw | ((sp - 8) >> 1);}
#define illegal(o) {}
#define undef(i) {printf("** unimplemented instruction %x, %x**\n",i,pc);}
#define ROM(adr) (rom[(adr) & 0xfff])


void init_cpu(void){
	pc=0;
	sp=8;
	bs=0;
	p1=p2=0xFF;
	ac=cy=f0=0;
	A11=A11ff=0;
	timer_on=0;
	count_on=0;
	reg_pnt=0;
	tirq_en=xirq_en=irq_ex=xirq_pend=tirq_pend=0;
}


void ext_IRQ(void){
	int_clk = 5; /* length of pulse on /INT */
	if (xirq_en && !irq_ex) {
		irq_ex=1;
		xirq_pend=0;
		clk+=2;
		make_psw();
		push(pc & 0xFF);
		push(((pc & 0xF00) >> 8) | (psw & 0xF0));
		pc = 0x03;
		A11ff=A11;
		A11=0;
	}
	if (pendirq && (!xirq_en)) xirq_pend=1;
}


void tim_IRQ(void){
	if (tirq_en && !irq_ex) {
		irq_ex=2;
		tirq_pend=0;
		clk+=2;
		make_psw();
		push(pc & 0xFF);
		push(((pc & 0xF00) >> 8) | (psw & 0xF0));
		pc = 0x07;
		A11ff=A11;
		A11=0;
	}
	if (pendirq && (!tirq_en)) tirq_pend=1;
}


void make_psw_debug(void){
	make_psw();
}

extern int RLOOP;

void cpu_exec(void)
{
	uint16_t adr;
	uint8_t dat;
	int temp;

	while(RLOOP == 1)
   {
      uint8_t op;

      clk=0;	

      lastpc=pc;
      op=ROM(pc++);

      switch (op)
      {
         case 0x00: /* NOP */
            clk++;
            break;
         case 0x01: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0x02: /* OUTL BUS,A */
            clk+=2;
            undef(0x02);
            break;
         case 0x03: /* ADD A,#data */
            clk+=2;
            cy=ac=0;
            dat = ROM(pc++);
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x04:	/* JMP */
            pc=ROM(pc) | A11;
            clk+=2;
            break;
         case 0x05: /* EN I */
            xirq_en=1;
            clk++;
            break;
         case 0x06: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x07: /* DEC A */
            acc--;
            clk++;
            break;
         case 0x08: /* INS A,BUS*/
            clk+=2;
            acc=in_bus();
            break;
         case 0x09: /* IN A,Pp */
            acc=p1;
            clk+=2;
            break;
         case 0x0A: /* IN A,Pp */
            acc=read_P2();
            clk+=2;
            break;
         case 0x0B: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x0C: /* MOVD A,P4 */
            clk+=2;
            acc=read_PB(0);
            break;
         case 0x0D: /* MOVD A,P5 */
            clk+=2;
            acc=read_PB(1);
            break;
         case 0x0E: /* MOVD A,P6 */
            clk+=2;
            acc=read_PB(2);
            break;
         case 0x0F: /* MOVD A,P7 */
            clk+=2;
            acc=read_PB(3);
            break;
         case 0x10: /* INC @Ri */
            intRAM[intRAM[reg_pnt] & 0x3F]++;
            clk++;
            break;
         case 0x11: /* INC @Ri */
            intRAM[intRAM[reg_pnt+1] & 0x3F]++;
            clk++;
            break;
         case 0x12: /* JBb address */
            clk+=2;
            dat = ROM(pc);
            if (acc & 0x01)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x13: /* ADDC A,#data */
            clk+=2;
            dat=ROM(pc++);
            ac=0;
            if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;

         case 0x14: /* CALL */
            make_psw();
            adr = ROM(pc) | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0x15: /* DIS I */
            xirq_en=0;
            clk++;
            break;
         case 0x16: /* JTF */
            clk+=2;
            dat = ROM(pc);
            if (t_flag)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            t_flag=0;
            break;
         case 0x17: /* INC A */
            acc++;
            clk++;
            break;
         case 0x18: /* INC Rr */
            intRAM[reg_pnt]++;
            clk++;
            break;
         case 0x19: /* INC Rr */
            intRAM[reg_pnt+1]++;
            clk++;
            break;
         case 0x1A: /* INC Rr */
            intRAM[reg_pnt+2]++;
            clk++;
            break;
         case 0x1B: /* INC Rr */
            intRAM[reg_pnt+3]++;
            clk++;
            break;
         case 0x1C: /* INC Rr */
            intRAM[reg_pnt+4]++;
            clk++;
            break;
         case 0x1D: /* INC Rr */
            intRAM[reg_pnt+5]++;
            clk++;
            break;
         case 0x1E: /* INC Rr */
            intRAM[reg_pnt+6]++;
            clk++;
            break;
         case 0x1F: /* INC Rr */
            intRAM[reg_pnt+7]++;
            clk++;
            break;
         case 0x20: /* XCH A,@Ri */
            clk++;
            dat=acc;
            acc=intRAM[intRAM[reg_pnt] & 0x3F];
            intRAM[intRAM[reg_pnt] & 0x3F] = dat;
            break;
         case 0x21: /* XCH A,@Ri */
            clk++;
            dat=acc;
            acc=intRAM[intRAM[reg_pnt+1] & 0x3F];
            intRAM[intRAM[reg_pnt+1] & 0x3F] = dat;
            break;
         case 0x22: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x23:  /* MOV a,#data */
            clk+=2;
            acc = ROM(pc++);
            break;

         case 0x24:  /* JMP */
            pc=ROM(pc) | 0x100 | A11;
            clk+=2;
            break;
         case 0x25: /* EN TCNTI */
            tirq_en=1;
            clk++;
            break;
         case 0x26:  /* JNT0 */
            clk+=2;
            dat = ROM(pc);
            if (!get_voice_status())
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x27:  /* CLR A */
            clk++;
            acc=0;
            break;
         case 0x28: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt];
            intRAM[reg_pnt]=dat;
            clk++;
            break;
         case 0x29: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+1];
            intRAM[reg_pnt+1]=dat;
            clk++;
            break;
         case 0x2A: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+2];
            intRAM[reg_pnt+2]=dat;
            clk++;
            break;
         case 0x2B: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+3];
            intRAM[reg_pnt+3]=dat;
            clk++;
            break;
         case 0x2C: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+4];
            intRAM[reg_pnt+4]=dat;
            clk++;
            break;
         case 0x2D: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+5];
            intRAM[reg_pnt+5]=dat;
            clk++;
            break;
         case 0x2E: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+6];
            intRAM[reg_pnt+6]=dat;
            clk++;
            break;
         case 0x2F: /* XCH A,Rr */
            dat=acc;
            acc=intRAM[reg_pnt+7];
            intRAM[reg_pnt+7]=dat;
            clk++;
            break;
         case 0x30: /* XCHD A,@Ri */
            clk++;
            adr=intRAM[reg_pnt] & 0x3F;
            dat=acc & 0x0F;
            acc=acc & 0xF0;
            acc=acc | (intRAM[adr] & 0x0F);
            intRAM[adr] &= 0xF0;
            intRAM[adr] |= dat;
            break;
         case 0x31: /* XCHD A,@Ri */
            clk++;
            adr=intRAM[reg_pnt+1] & 0x3F;
            dat=acc & 0x0F;
            acc=acc & 0xF0;
            acc=acc | (intRAM[adr] & 0x0F);
            intRAM[adr] &= 0xF0;
            intRAM[adr] |= dat;
            break;
         case 0x32: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x02)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x33: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x34: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x100 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0x35: /* DIS TCNTI */
            tirq_en=0;
            tirq_pend=0;
            clk++;
            break;
         case 0x36: /* JT0 */
            clk+=2;
            dat=ROM(pc);
            if (get_voice_status())
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x37: /* CPL A */
            acc = acc ^ 0xFF;
            clk++;
            break;
         case 0x38: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x39: /* OUTL P1,A */
            clk+=2;
            write_p1(acc);
            break;
         case 0x3A: /* OUTL P2,A */
            clk+=2;
            p2=acc;
            break;
         case 0x3B: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x3C: /* MOVD P4,A */
            clk+=2;
            write_PB(0,acc);
            break;
         case 0x3D: /* MOVD P5,A */
            clk+=2;
            write_PB(1,acc);
            break;
         case 0x3E: /* MOVD P6,A */
            clk+=2;
            write_PB(2,acc);
            break;
         case 0x3F: /* MOVD P7,A */
            clk+=2;
            write_PB(3,acc);
            break;
         case 0x40: /* ORL A,@Ri */
            clk++;
            acc = acc | intRAM[intRAM[reg_pnt] & 0x3F];
            break;
         case 0x41: /* ORL A,@Ri */
            clk++;
            acc = acc | intRAM[intRAM[reg_pnt+1] & 0x3F];
            break;
         case 0x42: /* MOV A,T */
            clk++;
            acc = itimer;
            break;
         case 0x43: /* ORL A,#data */
            clk+=2;
            acc = acc | ROM(pc++);
            break;
         case 0x44:  /* JMP */
            pc=ROM(pc) | 0x200 | A11;
            clk+=2;
            break;
         case 0x45: /* STRT CNT */
            /* printf("START: %d=%d\n",master_clk/22,itimer); */
            count_on=1;
            clk++;
            break;
         case 0x46:  /* JNT1 */
            clk+=2;
            dat = ROM(pc);
            if (!read_t1())
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x47: /* SWAP A */
            clk++;
            dat=(acc & 0xF0) >> 4;
            acc = acc << 4;
            acc = acc | dat;
            break;
         case 0x48: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt];
            break;
         case 0x49: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+1];
            break;
         case 0x4A: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+2];
            break;
         case 0x4B: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+3];
            break;
         case 0x4C: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+4];
            break;
         case 0x4D: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+5];
            break;
         case 0x4E: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+6];
            break;
         case 0x4F: /* ORL A,Rr */
            clk++;
            acc = acc | intRAM[reg_pnt+7];
            break;

         case 0x50:	/* ANL A,@Ri */
            acc = acc & intRAM[intRAM[reg_pnt] & 0x3F];
            clk++;
            break;
         case 0x51:	/* ANL A,@Ri */
            acc = acc & intRAM[intRAM[reg_pnt+1] & 0x3F];
            clk++;
            break;
         case 0x52: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x04)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x53:  /* ANL A,#data */
            clk+=2;
            acc = acc & ROM(pc++);
            break;
         case 0x54: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x200 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0x55: /* STRT T */
            timer_on=1;
            clk++;
            break;
         case 0x56: /* JT1 */
            clk+=2;
            dat = ROM(pc);
            if (read_t1())
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x57: /* DA A */
            clk++;
            if (((acc & 0x0F) > 0x09) || ac) {
               if (acc>0xf9) cy=1;
               acc += 6;
            }
            dat = (acc & 0xF0) >> 4;
            if ((dat > 9) || cy) {
               dat+=6;
               cy=1;
            }
            acc = (acc & 0x0F) | (dat << 4);
            break;
         case 0x58: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt];
            break;
         case 0x59: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+1];
            break;
         case 0x5A: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+2];
            break;
         case 0x5B: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+3];
            break;
         case 0x5C: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+4];
            break;
         case 0x5D: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+5];
            break;
         case 0x5E: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+6];
            break;
         case 0x5F: /* ANL A,Rr */
            clk++;
            acc = acc & intRAM[reg_pnt+7];
            break;

         case 0x60: /* ADD A,@Ri */
            clk++;
            cy=ac=0;
            dat=intRAM[intRAM[reg_pnt] & 0x3F];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x61: /* ADD A,@Ri */
            clk++;
            cy=ac=0;
            dat=intRAM[intRAM[reg_pnt+1] & 0x3F];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x62: /* MOV T,A */
            clk++;
            itimer=acc;
            break;
         case 0x63: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x64:  /* JMP */
            pc=ROM(pc) | 0x300 | A11;
            clk+=2;
            break;
         case 0x65: /* STOP TCNT */
            clk++;
            /* printf("STOP %d\n",master_clk/22); */
            count_on=timer_on=0;
            break;
         case 0x66: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x67: /* RRC A */
            dat=cy;
            cy=acc & 0x01;
            acc = acc >> 1;
            if (dat)
               acc = acc | 0x80;
            else
               acc = acc & 0x7F;
            clk++;
            break;
         case 0x68: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x69: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+1];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6A: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+2];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6B: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+3];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6C: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+4];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6D: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+5];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6E: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+6];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x6F: /* ADD A,Rr */
            clk++;
            cy=ac=0;
            dat=intRAM[reg_pnt+7];
            if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) ac=0x40;
            temp=acc+dat;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x70: /* ADDC A,@Ri */
            clk++;
            ac=0;
            dat=intRAM[intRAM[reg_pnt] & 0x3F];
            if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x71: /* ADDC A,@Ri */
            clk++;
            ac=0;
            dat=intRAM[intRAM[reg_pnt+1] & 0x3F];
            if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;

         case 0x72: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x08)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x73: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x74: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x300 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0x75: /* EN CLK */
            clk++;
            undef(op);
            break;
         case 0x76: /* JF1 address */
            clk+=2;
            dat=ROM(pc);
            if (f1)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x77: /* RR A */
            clk++;
            dat=acc & 0x01;
            acc = acc >> 1;
            if (dat)
               acc = acc | 0x80;
            else
               acc = acc & 0x7f;
            break;

         case 0x78: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x79: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+1];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7A: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+2];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7B: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+3];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7C: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+4];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7D: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+5];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7E: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+6];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;
         case 0x7F: /* ADDC A,Rr */
            clk++;
            ac=0;
            dat=intRAM[reg_pnt+7];
            if (((acc & 0x0f) + (dat & 0x0f)+cy) > 0x0f) ac=0x40;
            temp=acc+dat+cy;
            cy=0;
            if (temp > 0xFF) cy=1;
            acc=(temp & 0xFF);
            break;

         case 0x80:  /* MOVX  A,@Ri */
            acc=ext_read(intRAM[reg_pnt]);
            clk+=2;
            break;
         case 0x81:  /* MOVX A,@Ri */
            acc=ext_read(intRAM[reg_pnt+1]);
            clk+=2;
            break;
         case 0x82: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0x83:  /* RET */
            clk+=2;
            pc = ((pull() & 0x0F) << 8);
            pc = pc | pull();
            break;
         case 0x84:  /* JMP */
            pc=ROM(pc) | 0x400 | A11;
            clk+=2;
            break;
         case 0x85: /* CLR F0 */
            clk++;
            f0=0;
            break;
         case 0x86: /* JNI address */
            clk+=2;
            dat=ROM(pc);
            if (int_clk > 0)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x87: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0x88: /* BUS,#data */
            clk+=2;
            undef(op);
            break;
         case 0x89: /* ORL Pp,#data */
            write_p1(p1 | ROM(pc++));
            clk+=2;
            break;
         case 0x8A: /* ORL Pp,#data */
            p2 = p2 | ROM(pc++);
            clk+=2;
            break;
         case 0x8B: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0x8C: /* ORLD P4,A */
            write_PB(0,read_PB(0)|acc);
            clk+=2;
            break;
         case 0x8D: /* ORLD P5,A */
            write_PB(1,read_PB(1)|acc);
            clk+=2;
            break;
         case 0x8E: /* ORLD P6,A */
            write_PB(2,read_PB(2)|acc);
            clk+=2;
            break;
         case 0x8F: /* ORLD P7,A */
            write_PB(3,read_PB(3)|acc);
            clk+=2;
            break;
         case 0x90:  /* MOVX @Ri,A */
            ext_write(acc,intRAM[reg_pnt]);
            clk+=2;
            break;
         case 0x91:  /* MOVX @Ri,A */
            ext_write(acc,intRAM[reg_pnt+1]);
            clk+=2;
            break;
         case 0x92: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x10)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x93:  /* RETR*/
            /* printf("RETR %d\n",master_clk/22); */
            clk+=2;
            dat=pull();
            pc = (dat & 0x0F) << 8;
            cy = (dat & 0x80) >> 7;
            ac = dat & 0x40;
            f0 = dat & 0x20;
            bs = dat & 0x10;
            if (bs)
               reg_pnt=24;
            else
               reg_pnt=0;
            pc = pc | pull();
            irq_ex=0;
            A11=A11ff; 
            break;
         case 0x94: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x400 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0x95: /* CPL F0 */
            f0 = f0 ^ 0x20;
            clk++;
            break;
         case 0x96: /* JNZ address */
            clk+=2;
            dat=ROM(pc);
            if (acc != 0)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0x97: /* CLR C */
            cy=0;
            clk++;
            break;
         case 0x98: /* ANL BUS,#data */
            clk+=2;
            undef(op);
            break;
         case 0x99: /* ANL Pp,#data */
            write_p1(p1 & ROM(pc++));
            clk+=2;
            break;
         case 0x9A: /* ANL Pp,#data */
            p2 = p2 & ROM(pc++);
            clk+=2;
            break;
         case 0x9B: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0x9C: /* ANLD P4,A */
            write_PB(0,read_PB(0)&acc);
            clk+=2;
            break;
         case 0x9D: /* ANLD P5,A */
            write_PB(1,read_PB(1)&acc);
            clk+=2;
            break;
         case 0x9E: /* ANLD P6,A */
            write_PB(2,read_PB(2)&acc);
            clk+=2;
            break;
         case 0x9F: /* ANLD P7,A */
            write_PB(3,read_PB(3)&acc);
            clk+=2;
            break;
         case 0xA0: /* MOV @Ri,A */
            intRAM[intRAM[reg_pnt] & 0x3F]=acc;
            clk++;
            break;
         case 0xA1: /* MOV @Ri,A */
            intRAM[intRAM[reg_pnt+1] & 0x3F]=acc;
            clk++;
            break;
         case 0xA2: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0xA3: /* MOVP A,@A */
            acc=ROM((pc & 0xF00) | acc);
            clk+=2;
            break;
         case 0xA4:  /* JMP */
            pc=ROM(pc) | 0x500 | A11;
            clk+=2;
            break;
         case 0xA5:  /* CLR F1 */
            clk++;
            f1=0;
            break;
         case 0xA6: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xA7: /* CPL C */
            cy = cy ^ 0x01;
            clk++;
            break;
         case 0xA8: /* MOV Rr,A */
            intRAM[reg_pnt] = acc;
            clk++;
            break;
         case 0xA9: /* MOV Rr,A */
            intRAM[reg_pnt+1] = acc;
            clk++;
            break;
         case 0xAA: /* MOV Rr,A */
            intRAM[reg_pnt+2] = acc;
            clk++;
            break;
         case 0xAB: /* MOV Rr,A */
            intRAM[reg_pnt+3] = acc;
            clk++;
            break;
         case 0xAC: /* MOV Rr,A */
            intRAM[reg_pnt+4] = acc;
            clk++;
            break;
         case 0xAD: /* MOV Rr,A */
            intRAM[reg_pnt+5] = acc;
            clk++;
            break;
         case 0xAE: /* MOV Rr,A */
            intRAM[reg_pnt+6] = acc;
            clk++;
            break;
         case 0xAF: /* MOV Rr,A */
            intRAM[reg_pnt+7] = acc;
            clk++;
            break;
         case 0xB0: /* MOV @Ri,#data */
            intRAM[intRAM[reg_pnt] & 0x3F]=ROM(pc++);
            clk+=2;
            break;
         case 0xB1: /* MOV @Ri,#data */
            intRAM[intRAM[reg_pnt+1] & 0x3F]=ROM(pc++);
            clk+=2;
            break;
         case 0xB2: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x20)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xB3: /* JMPP @A */
            adr = (pc & 0xF00) | acc;
            pc=(pc & 0xF00) | ROM(adr);
            clk+=2;
            break;
         case 0xB4: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x500 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0xB5: /* CPL F1 */
            f1 = f1 ^ 0x01;
            clk++;
            break;
         case 0xB6: /* JF0 address */
            clk+=2;
            dat=ROM(pc);
            if (f0)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xB7: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0xB8: /* MOV Rr,#data */
            intRAM[reg_pnt]=ROM(pc++);
            clk+=2;
            break;
         case 0xB9: /* MOV Rr,#data */
            intRAM[reg_pnt+1]=ROM(pc++);
            clk+=2;
            break;
         case 0xBA: /* MOV Rr,#data */
            intRAM[reg_pnt+2]=ROM(pc++);
            clk+=2;
            break;
         case 0xBB: /* MOV Rr,#data */
            intRAM[reg_pnt+3]=ROM(pc++);
            clk+=2;
            break;
         case 0xBC: /* MOV Rr,#data */
            intRAM[reg_pnt+4]=ROM(pc++);
            clk+=2;
            break;
         case 0xBD: /* MOV Rr,#data */
            intRAM[reg_pnt+5]=ROM(pc++);
            clk+=2;
            break;
         case 0xBE: /* MOV Rr,#data */
            intRAM[reg_pnt+6]=ROM(pc++);
            clk+=2;
            break;
         case 0xBF: /* MOV Rr,#data */
            intRAM[reg_pnt+7]=ROM(pc++);
            clk+=2;
            break;
         case 0xC0: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xC1: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xC2: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xC3: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xC4:  /* JMP */
            pc=ROM(pc) | 0x600 | A11;
            clk+=2;
            break;
         case 0xC5: /* SEL RB0 */
            bs=reg_pnt=0;
            clk++;
            break;
         case 0xC6: /* JZ address */
            clk+=2;
            dat=ROM(pc);
            if (acc == 0)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xC7: /* MOV A,PSW */
            clk++;
            make_psw();
            acc=psw;
            break;
         case 0xC8: /* DEC Rr */
            intRAM[reg_pnt]--;
            clk++;
            break;
         case 0xC9: /* DEC Rr */
            intRAM[reg_pnt+1]--;
            clk++;
            break;
         case 0xCA: /* DEC Rr */
            intRAM[reg_pnt+2]--;
            clk++;
            break;
         case 0xCB: /* DEC Rr */
            intRAM[reg_pnt+3]--;
            clk++;
            break;
         case 0xCC: /* DEC Rr */
            intRAM[reg_pnt+4]--;
            clk++;
            break;
         case 0xCD: /* DEC Rr */
            intRAM[reg_pnt+5]--;
            clk++;
            break;
         case 0xCE: /* DEC Rr */
            intRAM[reg_pnt+6]--;
            clk++;
            break;
         case 0xCF: /* DEC Rr */
            intRAM[reg_pnt+7]--;
            clk++;
            break;
         case 0xD0:	/* XRL A,@Ri */
            acc = acc ^ intRAM[intRAM[reg_pnt] & 0x3F];
            clk++;
            break;
         case 0xD1:	/* XRL A,@Ri */
            acc = acc ^ intRAM[intRAM[reg_pnt+1] & 0x3F];
            clk++;
            break;
         case 0xD2: /* JBb address */
            clk+=2;
            dat = ROM(pc);
            if (acc & 0x40)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xD3: /* XRL A,#data */
            clk+=2;
            acc = acc ^ ROM(pc++);
            break;
         case 0xD4: /* CALL */
            make_psw();
            adr = ROM(pc) | 0x600 | A11;
            pc++;
            clk+=2;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0xD5: /* SEL RB1 */
            bs=0x10;
            reg_pnt=24;
            clk++;
            break;
         case 0xD6: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xD7: /* MOV PSW,A */
            psw=acc;
            clk++;
            cy = (psw & 0x80) >> 7;
            ac = psw & 0x40;
            f0 = psw & 0x20;
            bs = psw & 0x10;
            if (bs)
               reg_pnt = 24;
            else
               reg_pnt = 0;
            sp = (psw & 0x07) << 1;
            sp+=8;
            break;
         case 0xD8: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt];
            clk++;
            break;
         case 0xD9: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+1];
            clk++;
            break;
         case 0xDA: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+2];
            clk++;
            break;
         case 0xDB: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+3];
            clk++;
            break;
         case 0xDC: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+4];
            clk++;
            break;
         case 0xDD: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+5];
            clk++;
            break;
         case 0xDE: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+6];
            clk++;
            break;
         case 0xDF: /* XRL A,Rr */
            acc = acc ^ intRAM[reg_pnt+7];
            clk++;
            break;
         case 0xE0: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0xE1: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0xE2: /* ILL */
            clk++;
            illegal(op);
            break;
         case 0xE3: /* MOVP3 A,@A */

            adr = 0x300 | acc;
            acc=ROM(adr);
            clk+=2;
            break;
         case 0xE4:  /* JMP */
            pc=ROM(pc) | 0x700 | A11;
            clk+=2;
            break;
         case 0xE5: /* SEL MB0 */
            A11=0;
            A11ff = 0;
            clk++;
            break;
         case 0xE6: /* JNC address */
            clk+=2;
            dat=ROM(pc);
            if (!cy)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xE7: /* RL A */
            clk++;
            dat=acc & 0x80;
            acc = acc << 1;
            if (dat)
               acc = acc | 0x01;
            else
               acc = acc & 0xFE;
            break;
         case 0xE8: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xE9: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+1]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+1] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xEA: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+2]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+2] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xEB: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+3]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+3] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xEC: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+4]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+4] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xED: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+5]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+5] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xEE: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+6]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+6] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xEF: /* DJNZ Rr,address */
            clk+=2;
            intRAM[reg_pnt+7]--;
            dat=ROM(pc);
            if (intRAM[reg_pnt+7] != 0) {
               pc = pc & 0xF00;
               pc = pc | dat;
            } else pc++;
            break;
         case 0xF0: /* MOV A,@Ri */
            clk++;
            acc=intRAM[intRAM[reg_pnt] & 0x3F];
            break;
         case 0xF1: /* MOV A,@Ri */
            clk++;
            acc=intRAM[intRAM[reg_pnt + 1] & 0x3F];
            break;
         case 0xF2: /* JBb address */
            clk+=2;
            dat=ROM(pc);
            if (acc & 0x80)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xF3: /* ILL */
            illegal(op);
            clk++;
            break;
         case 0xF4: /* CALL */
            clk+=2;
            make_psw();
            adr = ROM(pc) | 0x700 | A11;
            pc++;
            push(pc & 0xFF);
            push(((pc & 0xF00) >> 8) | (psw & 0xF0));
            pc = adr;
            break;
         case 0xF5: /* SEL MB1 */
            if (irq_ex) {
               A11ff = 0x800;
            }
            else
            {
               A11=0x800;
               A11ff = 0x800;
            }
            clk++;
            break;
         case 0xF6: /* JC address */
            clk+=2;
            dat=ROM(pc);
            if (cy)
               pc=(pc & 0xF00) | dat;
            else
               pc++;
            break;
         case 0xF7: /* RLC A */
            dat=cy;
            cy=(acc & 0x80) >> 7;
            acc = acc << 1;
            if (dat)
               acc = acc | 0x01;
            else
               acc = acc & 0xFE;
            clk++;
            break;
         case 0xF8: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt];
            break;
         case 0xF9: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 1];
            break;
         case 0xFA: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 2];
            break;
         case 0xFB: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 3];
            break;
         case 0xFC: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 4];
            break;
         case 0xFD: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 5];
            break;
         case 0xFE: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 6];
            break;
         case 0xFF: /* MOV A,Rr */
            clk++;
            acc = intRAM[reg_pnt + 7];
            break;
      }


      master_clk+=clk;
      h_clk+=clk;
      clk_counter+=clk;

      /* flag for JNI */
      if (int_clk > clk)
         int_clk -= clk;
      else
         int_clk = 0;

      /* pending IRQs */
      if (xirq_pend)
         ext_IRQ();
      if (tirq_pend)
         tim_IRQ();

      if (h_clk > LINECNT-1)
      {
         h_clk-=LINECNT;
         if (enahirq && (VDCwrite[0xA0] & 0x01))
            ext_IRQ();

         if (count_on && mstate == 0)
         {
            itimer++;
            if (itimer == 0)
            {
               t_flag=1;
               tim_IRQ();
               draw_region();
            }
         }
      }

      if (timer_on)
      {
         master_count+=clk;
         if (master_count > 31)
         {
            master_count-=31;
            itimer++;
            if (itimer == 0)
            {
               t_flag=1;
               tim_IRQ();
            }
         }
      }

      if ((mstate==0) && (master_clk > VBLCLK))
      {
         handle_vbl();
      }	
      if ((mstate==1) && (master_clk > evblclk))
      {
         handle_evbl();
         if (app_data.crc == 0xA7344D1F) handle_evbll(); /* Atlantis */
         break;
      }

      if (app_data.debug)
         break;
      if (pc==app_data.breakpoint)
         break;
   }
}
