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


#include <stdio.h>
#include "types.h"
#include "vmachine.h"
//#include "voice.h"
#include "vdc.h"
//#include "vpp.h"
#include "cpu.h"


Byte acc;		/* Accumulator */
ADDRESS pc;     /* Program counter */
long clk;		/* clock */

Byte itimer;	/* Internal timer */
Byte reg_pnt;	/* pointer to register bank */
Byte timer_on;  /* 0=timer off/1=timer on */
Byte count_on;  /* 0=count off/1=count on */
Byte psw;		/* Processor status word */
Byte sp;		/* Stack pointer (part of psw) */

Byte p1;		/* I/O port 1 */
Byte p2; 		/* I/O port 2 */
Byte xirq_pend; /* external IRQ pending */
Byte tirq_pend; /* timer IRQ pending */
Byte t_flag;    /* Timer flag */

static ADDRESS lastpc;
static ADDRESS A11;		/* PC bit 11 */
static ADDRESS A11ff;
static Byte bs; 		/* Register Bank (part of psw) */
static Byte f0;			/* Flag Bit (part of psw) */
static Byte f1;			/* Flag Bit 1 */
static Byte ac;			/* Aux Carry (part of psw) */
static Byte cy;	    	/* Carry flag (part of psw) */
static Byte xirq_en;	/* external IRQ's enabled */
static Byte tirq_en;	/* Timer IRQ enabled */
static Byte irq_ex;		/* IRQ executing */

static int master_count;


#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);}


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();
}



void cpu_exec(void) {
	Byte op;
	ADDRESS adr;
	Byte dat;
	int temp;
	
	for (;;) {

		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);
			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 */
				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];
//JMH				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];
// JMH				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) acc+=6;
				dat = (acc & 0xF0) >> 4;
				if ((dat > 9) || cy) {
					dat+=6;
					cy=1;
				}
				else {
					cy=0;
				}
				/* if (dat > 0x0F) 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 */
				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;
				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;
				break;
			case 0xA9: /* MOV Rr,A */
				intRAM[reg_pnt+1] = acc;
				break;
			case 0xAA: /* MOV Rr,A */
				intRAM[reg_pnt+2] = acc;
				break;
			case 0xAB: /* MOV Rr,A */
				intRAM[reg_pnt+3] = acc;
				break;
			case 0xAC: /* MOV Rr,A */
				intRAM[reg_pnt+4] = acc;
				break;
			case 0xAD: /* MOV Rr,A */
				intRAM[reg_pnt+5] = acc;
				break;
			case 0xAE: /* MOV Rr,A */
				intRAM[reg_pnt+6] = acc;
				break;
			case 0xAF: /* MOV Rr,A */
				intRAM[reg_pnt+7] = acc;
				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();
					if (!ccolflag) {
						clear_collision();
						ccolflag=1;
					}
					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();
			break;
		}

		if (app_data.debug) break;
	}

}

