/***************************************************************************

 h83002.c: Hitachi H8/3002 microcontroller emulator

 Original by The_Author & DynaChicken for the ZiNc emulator.

 Rewrite for MAME by R. Belmont, including...
   - Changed types to MAME standards
   - Added MAME cpuintrf glue
   - Put all per-CPU state in a struct
   - Fixed ADD flag calcs
   - Added support for all 8 flag bits
   - Added cycle timing (probably not right yet)
   - Fixed and optimized interrupt handling
   - Optimized main execution loop
   - Added new opcodes for ND-1 and System 23 BIOS programs
   - Improved I/O and timer support
   - Fixed major error in 7Cxx/7Dxx series bit opcodes where the wrong
     instructions were being picked.

 TS 20060412 Added exts.l, sub.l, divxs.w (buggy), jsr @reg, rotxl.l reg, mov.l @(adr, reg), reg

 Note: The H8/3000 series is normally back-compatible to the 8-bit H8/300,
 but the 3002 does not include "emulation mode" - it always runs in full
 16/32-bit ("advanced") mode.  So this core is not suitable for general
 H8/300 emulation.

****************************************************************************/

#include "debugger.h"
#include "h83002.h"
#include "h8priv.h"

#define H8_SP	(7)

#define h8_mem_read8(x) program_read_byte_16be(x)
#define h8_mem_read16(x) program_read_word_16be(x)
#define h8_mem_write8(x, y)  program_write_byte_16be(x, y)
#define h8_mem_write16(x, y) program_write_word_16be(x, y)

// timing macros
// note: we assume a system 12 - type setup where external access is 3+1 states
// timing will be off somewhat for other configurations.
#define H8_IFETCH_TIMING(x)	h8_cyccnt -= (x) * 4;
#define H8_BRANCH_TIMING(x)	h8_cyccnt -= (x) * 4;
#define H8_STACK_TIMING(x)	h8_cyccnt -= (x) * 4;
#define H8_BYTE_TIMING(x, adr)	if (address24 >= 0xffff10) h8_cyccnt -= (x) * 3; else h8_cyccnt -= (x) * 4;
#define H8_WORD_TIMING(x, adr)	if (address24 >= 0xffff10) h8_cyccnt -= (x) * 3; else h8_cyccnt -= (x) * 4;
#define H8_IOP_TIMING(x)	h8_cyccnt -= (x);

extern UINT8 h8_register_read8(UINT32 address);
extern void h8_register_write8(UINT32 address, UINT8 val);

INLINE UINT32 h8_mem_read32(offs_t address)
{
	UINT32 result = program_read_word_16be(address) << 16;
	return result | program_read_word_16be(address + 2);
}

INLINE void h8_mem_write32(offs_t address, UINT32 data)
{
	program_write_word_16be(address, data >> 16);
	program_write_word_16be(address + 2, data);
}


h83002_state h8;

static INT32 h8_cyccnt;

static UINT32 udata32, address24;
static INT32 sdata32;
static UINT16 udata16, ext16;
static INT16 sdata16;
static UINT8 udata8;
static INT8 sdata8;
static UINT8 srcreg, dstreg;

/* internal functions */

static void h8_check_irqs(void);

static void h8_group0(UINT16 opcode);
static void h8_group1(UINT16 opcode);
static void h8_group5(UINT16 opcode);
static void h8_group6(UINT16 opcode);
static void h8_group7(UINT16 opcode);

static int h8_branch(UINT8 condition);

static UINT8 h8_mov8(UINT8 src);
static UINT16 h8_mov16(UINT16 src);
static UINT32 h8_mov32(UINT32 src);

static UINT8 h8_add8(UINT8 src, UINT8 dst);
static UINT16 h8_add16(UINT16 src, UINT16 dst);
static UINT32 h8_add32(UINT32 src, UINT32 dst);

static UINT8 h8_sub8(UINT8 src, UINT8 dst);
static UINT16 h8_sub16(UINT16 src, UINT16 dst);
static UINT32 h8_sub32(UINT32 src, UINT32 dst);

static UINT8 h8_addx8(UINT8 src, UINT8 dst);

static void h8_cmp8(UINT8 src, UINT8 dst);
static void h8_cmp16(UINT16 src, UINT16 dst);
static void h8_cmp32(UINT32 src, UINT32 dst);
static UINT8 h8_subx8(UINT8 src, UINT8 dst);

static UINT8 h8_or8(UINT8 src, UINT8 dst);
static UINT16 h8_or16(UINT16 src, UINT16 dst);

static UINT8 h8_xor8(UINT8 src, UINT8 dst);
static UINT16 h8_xor16(UINT16 src, UINT16 dst);
static UINT32 h8_xor32(UINT32 src, UINT32 dst);

static UINT8 h8_and8(UINT8 src, UINT8 dst);
static UINT16 h8_and16(UINT16 src, UINT16 dst);
static UINT32 h8_and32(UINT32 src, UINT32 dst);

static INT8 h8_neg8(INT8 src);
static INT16 h8_neg16(INT16 src);

static UINT16 h8_divxu8 (UINT16 dst, UINT8  src);
static UINT32 h8_divxu16(UINT32 dst, UINT16 src);

static UINT8 h8_not8(UINT8 src);
static UINT16 h8_not16(UINT16 src);

static UINT8 h8_rotl8(UINT8 src);
static UINT16 h8_rotl16(UINT16 src);

static UINT8 h8_rotxl8(UINT8 src);
static UINT16 h8_rotxl16(UINT16 src);
static UINT32 h8_rotxl32(UINT32 src);

static UINT8 h8_rotxr8(UINT8 src);
static UINT16 h8_rotxr16(UINT16 src);

static UINT8 h8_shll8(UINT8 src);
static UINT16 h8_shll16(UINT16 src);
static UINT32 h8_shll32(UINT32 src);

static UINT8 h8_shlr8(UINT8 src);
static UINT16 h8_shlr16(UINT16 src);
static UINT32 h8_shlr32(UINT32 src);

static INT8 h8_shal8(INT8 src);
static INT16 h8_shal16(INT16 src);

static INT8 h8_shar8(INT8 src);
static INT16 h8_shar16(INT16 src);
static INT32 h8_shar32(INT32 src);

static UINT8 h8_dec8(UINT8 src);
static UINT16 h8_dec16(UINT16 src);
static UINT32 h8_dec32(UINT32 src);

static UINT8 h8_inc8(UINT8 src);
static UINT16 h8_inc16(UINT16 src);
static UINT32 h8_inc32(UINT32 src);

//static UINT8 h8_bnot8(UINT8 src, UINT8 dst);
static UINT8 h8_bst8(UINT8 src, UINT8 dst);
static UINT8 h8_bist8(UINT8 src, UINT8 dst);
static UINT8 h8_bset8(UINT8 src, UINT8 dst);
static UINT8 h8_bclr8(UINT8 src, UINT8 dst);
static void h8_btst8(UINT8 src, UINT8 dst);
static void h8_bld8(UINT8 src, UINT8 dst); // loads to carry
static void h8_bor8(UINT8 src, UINT8 dst); // result in carry
//static void h8_bxor8(UINT8 src, UINT8 dst);

static INT32 h8_mulxs16(INT16 src, INT16 dst);
static UINT32 h8_divxs16(INT16 src, INT32 dst);

/* implementation */

#ifdef MAME_DEBUG
extern offs_t h8_disasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
#endif /* MAME_DEBUG */

void h8_3002_InterruptRequest(UINT8 source)
{
	if(source>31)
	{
		h8.h8_IRQrequestH |= (1<<(source-32));
	}
	else
	{
		h8.h8_IRQrequestL |= (1<<source);
	}
}


static UINT8 h8_get_ccr(void)
{
	h8.ccr = 0;
	if(h8.h8nflag)h8.ccr |= NFLAG;
	if(h8.h8zflag)h8.ccr |= ZFLAG;
	if(h8.h8vflag)h8.ccr |= VFLAG;
	if(h8.h8cflag)h8.ccr |= CFLAG;
	if(h8.h8uflag)h8.ccr |= UFLAG;
	if(h8.h8hflag)h8.ccr |= HFLAG;
	if(h8.h8uiflag)h8.ccr |= UIFLAG;
	if(h8.h8iflag)h8.ccr |= IFLAG;
	return h8.ccr;
}

static char *h8_get_ccr_str(void)
{
	static char res[8];

	memset(res, 0, 8);
	if(h8.h8iflag) strcat(res, "I"); else strcat(res, "i");
	if(h8.h8uiflag)strcat(res, "U"); else strcat(res, "u");
	if(h8.h8hflag) strcat(res, "H"); else strcat(res, "h");
	if(h8.h8uflag) strcat(res, "U"); else strcat(res, "u");
	if(h8.h8nflag) strcat(res, "N"); else strcat(res, "n");
	if(h8.h8zflag) strcat(res, "Z"); else strcat(res, "z");
	if(h8.h8vflag) strcat(res, "V"); else strcat(res, "v");
	if(h8.h8cflag) strcat(res, "C"); else strcat(res, "c");

	return res;
}

static void h8_set_ccr(UINT8 data)
{
	h8.ccr = data;

	h8.h8nflag = 0;
	h8.h8zflag = 0;
	h8.h8vflag = 0;
	h8.h8cflag = 0;
	h8.h8hflag = 0;
	h8.h8iflag = 0;
	h8.h8uflag = 0;
	h8.h8uiflag = 0;

	if(h8.ccr & NFLAG) h8.h8nflag = 1;
	if(h8.ccr & ZFLAG) h8.h8zflag = 1;
	if(h8.ccr & VFLAG) h8.h8vflag = 1;
	if(h8.ccr & CFLAG) h8.h8cflag = 1;
	if(h8.ccr & HFLAG) h8.h8hflag = 1;
	if(h8.ccr & UFLAG) h8.h8uflag = 1;
	if(h8.ccr & UIFLAG) h8.h8uiflag = 1;
	if(h8.ccr & IFLAG) h8.h8iflag = 1;

	h8_check_irqs();
}

static INT16 h8_getreg16(UINT8 reg)
{
	if(reg > 7)
	{
		return h8.regs[reg-8]>>16;
	}
	else
	{
		return h8.regs[reg];
	}
}

static void h8_setreg16(UINT8 reg, UINT16 data)
{
	if(reg > 7)
	{
		h8.regs[reg-8] &= 0xffff;
		h8.regs[reg-8] |= data<<16;
	}
	else
	{
		h8.regs[reg] &= 0xffff0000;
		h8.regs[reg] |= data;
	}
}

static UINT8 h8_getreg8(UINT8 reg)
{
	if(reg > 7)
	{
		return h8.regs[reg-8];
	}
	else
	{
		return h8.regs[reg]>>8;
	}
}

static void h8_setreg8(UINT8 reg, UINT8 data)
{
	if(reg > 7)
	{
		h8.regs[reg-8] &= 0xffffff00;
		h8.regs[reg-8] |= data;
	}
	else
	{
		h8.regs[reg] &= 0xffff00ff;
		h8.regs[reg] |= data<<8;
	}
}

static UINT32 h8_getreg32(UINT8 reg)
{
	return h8.regs[reg];
}

static void h8_setreg32(UINT8 reg, UINT32 data)
{
	h8.regs[reg] = data;
}

static void h8_onstateload(void)
{
	h8_set_ccr(h8.ccr);
}

static void h8_init(int index, int clock, const void *config, int (*irqcallback)(int))
{
	memset(&h8, 0, sizeof(h8));
	h8.h8iflag = 1;

	h8.irq_cb = irqcallback;

	state_save_register_item("H8/3002", index, h8.h8err);
	state_save_register_item_array("H8/3002", index, h8.regs);
	state_save_register_item("H8/3002", index, h8.pc);
	state_save_register_item("H8/3002", index, h8.ppc);
	state_save_register_item("H8/3002", index, h8.h8_IRQrequestH);
	state_save_register_item("H8/3002", index, h8.h8_IRQrequestL);
	state_save_register_item("H8/3002", index, h8.ccr);

	state_save_register_item_array("H8/3002", index, h8.per_regs);
	state_save_register_item("H8/3002", index, h8.h8TSTR);
	state_save_register_item("H8/3002", index, h8.h8TCNT0);
	state_save_register_item("H8/3002", index, h8.h8TCNT1);
	state_save_register_item("H8/3002", index, h8.h8TCNT2);
	state_save_register_item("H8/3002", index, h8.h8TCNT3);
	state_save_register_item("H8/3002", index, h8.h8TCNT4);

	state_save_register_func_postload(h8_onstateload);

	h8_itu_init();
}

static void h8_reset(void)
{
	h8.h8err = 0;
	h8.pc = h8_mem_read32(0) & 0xffffff;
	change_pc(h8.pc);

	// disable timers
	h8.h8TSTR = 0;

	h8_itu_reset();
}

static void h8_GenException(UINT8 vectornr)
{
	// push PC on stack
	// extended mode stack push!
	h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
	h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
	// push ccr
	h8_setreg32(H8_SP, h8_getreg32(H8_SP)-2);
	h8_mem_write16(h8_getreg32(H8_SP), h8_get_ccr());

	// generate address from vector
	h8_set_ccr(h8_get_ccr() | 0x80);
	h8.pc = h8_mem_read32(vectornr * 4) & 0xffffff;
	change_pc(h8.pc);

	// I couldn't find timing info for exceptions, so this is a guess (based on JSR/BSR)
	H8_IFETCH_TIMING(2);
	H8_STACK_TIMING(2);
}

static int h8_get_priority(UINT8 bit)
{
	int res = 0;
	switch(bit)
	{
	case 12: // IRQ0
		if (h8.per_regs[0xF8]&0x80) res = 1; break;
	case 13: // IRQ1
		if (h8.per_regs[0xF8]&0x40) res = 1; break;
	case 14: // IRQ2
	case 15: // IRQ3
		if (h8.per_regs[0xF8]&0x20) res = 1; break;
	case 16: // IRQ4
	case 17: // IRQ5
		if (h8.per_regs[0xF8]&0x10) res = 1; break;
	}
	return res;
}

static void h8_check_irqs(void)
{
	int lv = -1;
	if (h8.h8iflag == 0)
	{
		lv = 0;
	}
	else
	{
		if ((h8.per_regs[0xF2]&0x08)/*SYSCR*/ == 0)
		{
			if (h8.h8uiflag == 0)
				lv = 1;
		}
	}

	// any interrupts wanted and can accept ?
	if(((h8.h8_IRQrequestH != 0) || (h8.h8_IRQrequestL != 0)) && (lv >= 0))
	{
		UINT8 bit, source;
		// which one ?
		for(bit = 0, source = 0xff; source == 0xff && bit < 32; bit++)
		{
			if( h8.h8_IRQrequestL & (1<<bit) )
			{
				if (h8_get_priority(bit) >= lv)
				{
					// mask off
					h8.h8_IRQrequestL &= ~(1<<bit);
					source = bit;
				}
			}
		}
		// which one ?
		for(bit = 0; source == 0xff && bit < 32; bit++)
		{
			if( h8.h8_IRQrequestH & (1<<bit) )
			{
				if (h8_get_priority(bit + 32) >= lv)
				{
					// mask off
					h8.h8_IRQrequestH &= ~(1<<bit);
					source = bit + 32;
				}
			}
		}

		// call the MAME callback if it's one of the 6
		// external IRQs
		if (source >= 12 && source <= 17)
		{
			(*h8.irq_cb)(source - 12 + H8_IRQ0);
		}

		if (source != 0xff)
			h8_GenException(source);
	}
}

static int h8_execute(int cycles)
{
	UINT16 opcode=0;

	h8_cyccnt = cycles;

 	h8_check_irqs();

	while ((h8_cyccnt > 0) && (!h8.h8err))
	{
		h8.ppc = h8.pc;

#ifdef MAME_DEBUG
		CALL_MAME_DEBUG;
#endif
		opcode = cpu_readop16(h8.pc);
//      mame_printf_debug("[%06x]: %04x => %x\n", h8.pc, opcode, (opcode>>12)&0xf);
		h8.pc += 2;

		switch((opcode>>12) & 0xf)
		{
		case 0x0:
			h8_group0(opcode);
			break;
		case 0x1:
			h8_group1(opcode);
			break;
		case 0x2:
			// mov.b @xx:8, Rd (abs)
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_mem_read8(0xffff00+(opcode & 0xff));
			h8_mov8(udata8); // flags calculation, dont care about others
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x3: // pass
			// mov.b Rs, @xx:8 (abs)
			srcreg = (opcode>>8) & 0xf;
			udata8 = h8_getreg8(srcreg);
			h8_mov8(udata8); // flags calculation, dont care about others
			h8_mem_write8(0xffff00+(opcode & 0xff), udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, 0xffff00+(opcode & 0xff));
			break;
		case 0x4:
			// bcc @xx:8
			sdata8 = (opcode & 0xff);
			if( h8_branch((opcode >> 8) & 0xf) == 1)h8.pc += sdata8;
			change_pc(h8.pc);
			break;
		case 0x5:
			h8_group5(opcode);
			break;
		case 0x6:
			h8_group6(opcode);
			break;
		case 0x7:
			h8_group7(opcode);
			break;
		case 0x8:
			// add.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_add8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1)
			break;
		case 0x9:
			// addx.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_addx8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1)
			break;
		case 0xa:
			// cmp.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			h8_cmp8(opcode & 0xff, h8_getreg8(dstreg));
			H8_IFETCH_TIMING(1);
			break;
		case 0xb:
			// subx.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_subx8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0xc:
			// or.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_or8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0xd:
			// xor.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_xor8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0xe: // pass
			// and.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_and8(opcode & 0xff, h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1)
			break;
		case 0xf: // pass
			// mov.b #xx:8, Rd
			dstreg = (opcode>>8) & 0xf;
			udata8 = h8_mov8(opcode & 0xff);
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		}
	}

	if (h8.h8err)
	{
		fatalerror("H8/3002: Unknown opcode (PC=%x)  %x", h8.ppc, opcode);

	}

	return cycles - h8_cyccnt;
}

static void h8_group0(UINT16 opcode)
{
	switch((opcode>>8)&0xf)
	{
	case 0:
		// nop
		H8_IFETCH_TIMING(1);
		break;
	case 0x1:
		// 010x  where x should always be 0!
		if((opcode & 0xf) != 0)
		{
			h8.h8err = 1;
			break;
		}
		switch((opcode>>4) & 0xf)
		{
			// 0100 mov.l prefix
		case 0xf:     // and.l Rn, Rn
			ext16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			if (ext16 & 0x88)
			{
				h8.h8err = 1;
			}
			else
			{
				switch((ext16>>8)&0xff)
				{
				case 0x65:
					dstreg = ext16 & 0x7;
					udata32 = h8_xor32(h8_getreg32((ext16>>4) & 0x7), h8_getreg32(dstreg));
					h8_setreg32(dstreg, udata32);
					H8_IFETCH_TIMING(2);
					break;
				case 0x66:
					dstreg = ext16 & 0x7;
					udata32 = h8_and32(h8_getreg32((ext16>>4) & 0x7), h8_getreg32(dstreg));
					h8_setreg32(dstreg, udata32);
					H8_IFETCH_TIMING(2);
					break;
				default:
					h8.h8err = 1;
					break;
				}
			}
			break;

		case 0:
			ext16 = h8_mem_read16(h8.pc);
			h8.pc+=2;
			switch((ext16 >> 8) & 0xff)
			{
			case 0x69:
				if((ext16 & 0x80) == 0x80)
				{
					// mov.l rx, @rx
					udata32 = h8_mov32(h8_getreg32(ext16 & 7));
					h8_mem_write32(h8_getreg32((ext16 >> 4) & 7), udata32);
					H8_IFETCH_TIMING(2);
					H8_WORD_TIMING(2, h8_getreg32((ext16 >> 4) & 7));
				}
				else
				{
					// mov.l @rx, rx
					udata32 = h8_mem_read32(h8_getreg32( (ext16 >> 4) &7));
					h8_mov32(udata32);
					h8_setreg32(ext16 & 7, udata32);
					H8_IFETCH_TIMING(2);
					H8_WORD_TIMING(2, h8_getreg32( (ext16 >> 4) &7));
				}
				break;
			case 0x6b:
				// mov.l rx, @xx / mov.l @xx, rx
				switch((ext16 >> 4)&0xf)
				{
				case 0x2:
					// mov.l @aa:24, erx
					address24=h8_mem_read32(h8.pc);
					h8.pc += 4;
					udata32=h8_mem_read32(address24);
					h8_mov32(udata32); // flags only
					h8_setreg32(ext16 & 0x7, udata32);
					H8_IFETCH_TIMING(4);
					H8_WORD_TIMING(2, address24);
					break;
				case 0xa:
					// mov.l erx, @aa:24
					address24=h8_mem_read32(h8.pc);
					h8.pc += 4;
					udata32=h8_getreg32(ext16 & 0x7);
					h8_mov32(udata32); // flags only
					h8_mem_write32(address24, udata32);
					H8_IFETCH_TIMING(4);
					H8_WORD_TIMING(2, address24);
					break;
				default:
					h8.h8err = 1;
					break;
				}
				break;
			case 0x6d:
				if(ext16 & 0x80)
				{
					// mov.l rs, @-erd
					srcreg = (ext16>>4)&7;
					h8_setreg32(srcreg, h8_getreg32(srcreg)-4);
					address24 = h8_getreg32(srcreg) & 0xffffff;
					udata32 = h8_getreg32(ext16 & 0x7);
					h8_mem_write32(address24, udata32);
					H8_IFETCH_TIMING(2);
					H8_WORD_TIMING(2, address24);
					H8_IOP_TIMING(2);
				}
				else
				{
					// mov.l @ers+, rd
					srcreg = (ext16 >>4)&7;
					address24 = h8_getreg32(srcreg) & 0xffffff;
					h8_setreg32(srcreg, h8_getreg32(srcreg)+4);
					udata32 = h8_mem_read32(address24);
					h8_setreg32(ext16 & 0x7, udata32);
					H8_IFETCH_TIMING(2);
					H8_WORD_TIMING(2, address24);
					H8_IOP_TIMING(2);
				}
				h8_mov32(udata32);
				break;
			case 0x6f:
				// mov.l @(displ16 + Rs), rd
				sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
				h8.pc += 2;
				address24 = (h8_getreg32((ext16 >> 4)&7)) & 0xffffff;
				address24 += sdata16;
				H8_IFETCH_TIMING(3);
				H8_WORD_TIMING(2, address24);
				if(ext16 & 0x80)
				{
					udata32 = h8_getreg32(ext16 & 0x7);
					h8_mem_write32(address24, udata32);
				}
				else
				{
					udata32 = h8_mem_read32(address24);
					h8_setreg32(ext16 & 0x7, udata32);
				}
				h8_mov32(udata32);
				break;
			case 0x78:
				// prefix for
				// mov.l (@aa:x, rx), Rx
				//00000A10 010078606B2600201AC2 MOV.L   @($00201AC2,ER6),ER6
				// mov.l @(displ24 + Rs), rd
				srcreg = (ext16 >> 4) & 7;

				// 6b20
				udata16 = h8_mem_read16(h8.pc);
				h8.pc += 2;
				dstreg = udata16 & 7;

				address24 = h8_mem_read32(h8.pc);
				h8.pc += 4;
				address24 += h8_getreg32(srcreg);
				address24 &= 0xffffff;

				if ( (ext16 & 0x80) && ((udata16 & ~7) == 0x6ba0) )
				{
					udata32 = h8_getreg32(dstreg);
					h8_mem_write32(address24, udata32);
				}
				else if ( (!(ext16 & 0x80)) && ((udata16 & ~7) == 0x6b20) )
				{
					udata32 = h8_mem_read32(address24);
					h8_setreg32(dstreg, udata32);
				}
				else
				{
					h8.h8err = 1;
				}

				h8_mov32(udata32);

				H8_IFETCH_TIMING(5);
				H8_WORD_TIMING(2, address24);

				break;
			default:
				h8.h8err = 1;
				break;
			}
			break;
		case 0xc:
			// mulxs
			ext16 = h8_mem_read16(h8.pc);
			h8.pc+=2;
			if(((ext16>>8) & 0xf) == 0)
			{
				h8.h8err = 1;
			}
			else if(((ext16>>8) & 0xf) == 2)
			{
				sdata32 = h8_getreg32(ext16 & 0x7);
				sdata16 = h8_getreg16((ext16>>4) & 0xf);
				sdata32 = h8_mulxs16(sdata16, sdata32);
				h8_setreg32(ext16 & 0x7, sdata32);
				H8_IFETCH_TIMING(2);
				H8_IOP_TIMING(20);
			}
			else
			{
				logerror("H8/3002: Unk. group 0 mulxs %x\n", opcode);
				h8.h8err = 1;
			}
			break;

		case 0xd:
			//divxs - probbaly buggy (flags?)
			ext16 = h8_mem_read16(h8.pc);
			h8.pc+=2;
			if(((ext16>>8) & 0xf) == 0)
			{
				h8.h8err = 1;
			}
			else if(((ext16>>8) & 0xf) == 3)
			{
				sdata32 = h8_getreg32(ext16 & 0x7);
				sdata16 = h8_getreg16((ext16>>4) & 0xf);
				sdata32 = h8_divxs16(sdata16, sdata32);
				h8_setreg32(ext16 & 0x7, sdata32);
				H8_IFETCH_TIMING(2);
				H8_IOP_TIMING(20);
			}
			else
			{
				h8.h8err = 1;
			}


		break;

		default:
			h8.h8err = 1;
			break;
		}
		break;
	case 0x2:
		// stc ccr, rd
		if(((opcode>>4) & 0xf) == 0)
		{
			h8_setreg8(opcode & 0xf, h8_get_ccr());
			H8_IFETCH_TIMING(1);
		}
		else
		{
			logerror("H8/3002: Unk. group 0 2 %x\n", opcode);
			h8.h8err = 1;
		}
		break;
	case 0x3:
		// ldc rd, ccr
		if(((opcode>>4) & 0xf) == 0)
		{
			udata8 = h8_getreg8(opcode & 0xf);
			h8_set_ccr(udata8);
			H8_IFETCH_TIMING(1);
		}
		else
		{
			logerror("H8/3002: Unk. group 0 3 %x\n", opcode);
			h8.h8err = 1;
		}
		break;
	case 0x4: // pass
		// orc
		udata8 = h8_or8(opcode & 0xff, h8_get_ccr());
		h8_set_ccr(udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0x6:
		// andc
		udata8 = h8_and8(opcode & 0xff, h8_get_ccr());
		h8_set_ccr(udata8);
		H8_IFETCH_TIMING(1)
		break;
		// ldc
	case 0x8:
		// add.b rx, ry
		dstreg = opcode & 0xf;
		udata8 = h8_add8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1)
		break;
		// add.w rx, ry
	case 0x9:
		dstreg = opcode & 0xf;
		udata16 = h8_add16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(dstreg));
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1)
		break;
		// inc.b rx
	case 0xA:
		if(opcode&0x80)
		{
			if(opcode & 0x8)
			{
				logerror("H8/3002: Unk. group 0 a %x\n", opcode);
				h8.h8err = 1;
			}
			else
			{
				dstreg = opcode & 0x7;
				udata32 = h8_add32(h8_getreg32((opcode>>4) &0x7), h8_getreg32(dstreg));
				h8_setreg32(dstreg, udata32);
				H8_IFETCH_TIMING(1)
			}
		}
		else
		{
			if(opcode & 0xf0)
			{
			logerror("H8/3002: Unk. group 0 a2 %x\n", opcode);
				h8.h8err =1;
			}
			else
			{
				dstreg = opcode & 0xf;
				udata8 = h8_inc8(h8_getreg8(dstreg));
				h8_setreg8(dstreg, udata8);
				H8_IFETCH_TIMING(1);
			}
		}
		break;
	case 0xb:
		switch((opcode>>4)& 0xf)
		{
		case 0:
			if(opcode & 8)
			{
				h8.h8err = 1;
			}
			else
			{
				dstreg = opcode & 7;
				udata32 = h8_getreg32(dstreg) + 1;
				h8_setreg32(dstreg, udata32);
				H8_IFETCH_TIMING(1)
			}
			break;
		case 5:
			dstreg = opcode & 0xf;
			udata16 = h8_inc16(h8_getreg16(dstreg));
			h8_setreg16(dstreg, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 7:
			dstreg = opcode & 0x7;
			udata32 = h8_inc32(h8_getreg32(dstreg));
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 8:
			if(opcode & 8)
			{
				h8.h8err = 1;
			}
			else
			{
				dstreg = opcode & 7;
				udata32 = h8_getreg32(dstreg) + 2;
				h8_setreg32(dstreg, udata32);
				H8_IFETCH_TIMING(1)
			}
			break;
		case 9:
			if(opcode & 8)
			{
				h8.h8err = 1;
			}
			else
			{
				dstreg = opcode & 7;
				udata32 = h8_getreg32(dstreg) + 4;
				h8_setreg32(dstreg, udata32);
				H8_IFETCH_TIMING(1)
			}
			break;
		case 0xd:
			dstreg = opcode & 0xf;
			udata16 = h8_inc16(h8_getreg16(dstreg));
			if(h8.h8vflag)
			{
				udata16 = h8_inc16(udata16); // slow and easy
				h8.h8vflag = 1;
			}
			else
				udata16 = h8_inc16(udata16); // slow and easy
			h8_setreg16(dstreg, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 0xf:
			dstreg = opcode & 0x7;
			udata32 = h8_inc32(h8_getreg32(dstreg));
			if(h8.h8vflag)
			{
				udata32 = h8_inc32(udata32); // slow and easy
				h8.h8vflag = 1;
			}
			else
				udata32 = h8_inc32(udata32); // slow and easy
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		default:
			logerror("H8/3002: Unk. group 0 b %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
		// mov.b rx, ry
	case 0xc: // pass
		dstreg = opcode & 0xf;
		udata8 = h8_mov8(h8_getreg8((opcode>>4) &0xf));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0xd:
		// mov.w rx, ry
		dstreg = opcode & 0xf;
		udata16 = h8_mov16(h8_getreg16((opcode>>4) &0xf));
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1);
		break;
	case 0xf:
		if(opcode & 0x80)
		{
			if(opcode & 8)
			{
			logerror("H8/3002: Unk. group 0 f %x\n", opcode);
				h8.h8err = 1;
			}
			else
			{
				dstreg = opcode & 0x7;
				udata32 = h8_mov32(h8_getreg32((opcode>>4) &0x7));
				h8_setreg32(dstreg, udata32);
				H8_IFETCH_TIMING(1);
			}
		}
		else
		{
			h8.h8err = 1;
			logerror("H8/3002: Unk. group 0 f2 %x\n", opcode);
			if((opcode & 0xf0) !=0)
			{
				h8.h8err = 1;
			}
			else
			{
				h8.h8err = 1;
			}
		}
		break;
	default:
		logerror("H8/3002: Unk. group 0 tdef %x\n", opcode);
		h8.h8err = 1;
		break;
	}
}

static void h8_group1(UINT16 opcode)
{
	switch((opcode>>8)&0xf)
	{
	case 0x0:
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			// shll.b Rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_shll8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x1:
			// shll.w Rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_shll16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 0x3:
			// shal.l Rx
			udata32 = h8_getreg32(opcode & 0x7);
			udata32 = h8_shll32(udata32);
			h8_setreg32(opcode & 0x7, udata32);
			H8_IFETCH_TIMING(1);
			break;

		case 0x8:
			// shal.b Rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_shal8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
			// shal.w Rx
		case 0x9:
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_shal16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;

		default:
			logerror("H8/3002: Unk. group 1 0 %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0x1:
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			// shlr.b rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_shlr8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x1:
			// shlr.w rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_shlr16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;
			// shlr.l rx
		case 0x3:
			udata32 = h8_getreg32(opcode & 0x7);
			udata32 = h8_shlr32(udata32);
			h8_setreg32(opcode & 0x7, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 0x8:
			// shar.b rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_shar8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x9:
			// shar.w rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_shar16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 0xb:
			// shar.l rx
			udata32 = h8_getreg32(opcode & 0x7);
			udata32 = h8_shar32(udata32);
			h8_setreg32(opcode & 0x7, udata32);
			H8_IFETCH_TIMING(1);
			break;
		default:
			logerror("H8/3002: Unk. group 1 1 %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0x2:
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			// rotxl.b Rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_rotxl8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x1:
			// rotxl.w Rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_rotxl16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;

		case 0x3:
			// rotxl.l Rx
			udata32 = h8_getreg32(opcode & 0x7);
			udata32 = h8_rotxl32(udata32);
			h8_setreg32(opcode & 0xf, udata32);
			H8_IFETCH_TIMING(1);
			break;

		case 0x8:
			// rotl.b Rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_rotl8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x9:
			// rotl.w Rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_rotl16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;
			// rotl.l Rx
		default:
			logerror("H8/3002: Unk. group 1 2 %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0x3:
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			// rotxr.b Rx
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_rotxr8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x1:
			// rotxr.w Rx
			udata16 = h8_getreg16(opcode & 0xf);
			udata16 = h8_rotxr16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			break;
		default:
			logerror("H8/3002: Unk. group 1 3 %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0x4:
		// or.b rs, rd
		dstreg = opcode & 0xf;
		udata8 = h8_or8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0x5:
		// xor.b rs, rd
		dstreg = opcode & 0xf;
		udata8 = h8_xor8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0x6:
		// and.b rs, rd
		dstreg = opcode & 0xf;
		udata8 = h8_and8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1)
		break;
		// not
	case 0x7:
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			// not.b Rx
			dstreg = opcode & 0xf;
			udata8 = h8_not8(h8_getreg8(dstreg));
			h8_setreg8(dstreg, udata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x1:
			// not.w Rx
			dstreg = opcode & 0xf;
			udata16 = h8_not16(h8_getreg16(dstreg));
			h8_setreg16(dstreg, udata16);
			H8_IFETCH_TIMING(1);
			break;

		case 0x5:
			// extu.w Rx
			dstreg = opcode & 0xf;
			udata16 = h8_getreg16(dstreg) & 0x00ff;
			h8_setreg16(dstreg, udata16);
			h8.h8nflag = 0;
			h8.h8vflag = 0;
			h8.h8zflag = ((udata16 == 0) ? 1 : 0);
			H8_IFETCH_TIMING(1);
			break;
		case 0x7:
			// extu.l Rx
			dstreg = opcode & 0x7;
			udata32 = h8_getreg32(dstreg) & 0x0000ffff;
			h8_setreg32(dstreg, udata32);
			h8.h8nflag = 0;
			h8.h8vflag = 0;
			h8.h8zflag = ((udata32 == 0) ? 1 : 0);
			H8_IFETCH_TIMING(1);
			break;
		case 0x8:
			// neg.b Rx
			//sprintf(output, "%4.4x neg.b %s", opcode, reg_names8[opcode & 0xf]);
			dstreg = opcode & 0xf;
			sdata8 = h8_neg8(h8_getreg8(dstreg));
			h8_setreg8(dstreg, sdata8);
			H8_IFETCH_TIMING(1);
			break;
		case 0x9:
			// neg.w Rx
			//sprintf(output, "%4.4x neg.w %s", opcode, reg_names16[opcode & 0xf]);
			dstreg = opcode & 0xf;
			sdata16 = h8_neg16(h8_getreg16(dstreg));
			h8_setreg16(dstreg, sdata16);
			H8_IFETCH_TIMING(1);
			break;
		case 0xf:
			// exts.l Rx
			dstreg = opcode & 0xf;
			udata32=h8_getreg32(dstreg)&0xffff;
			if(udata32&0x8000)
			{
				udata32|=0xffff0000;
			}
			h8_setreg32(dstreg, udata32);

			h8.h8vflag = 0;
			h8.h8nflag = (udata32 & 0xffff0000) ? 1 : 0;
			h8.h8zflag = (udata32) ? 0 : 1;

			H8_IFETCH_TIMING(1);
			break;

		default:
			logerror("H8/3002: Unk. group 1 7-9 %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0x8:
		// sub.b rs, rd
		dstreg = opcode & 0xf;
		udata8 = h8_sub8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0x9:
		// sub.w rs, rd
		dstreg = opcode & 0xf;
		udata16 = h8_sub16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(dstreg));
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1);
		break;
		// sub.b rx
	case 0xA:
		if(opcode&0x80)
		{
			//logerror("H8/3002: Unk. group 1 A %x\n", opcode);

			// sub.l rs,rd
			dstreg = opcode & 0x7;
			udata32=h8_sub32(h8_getreg32((opcode>>4) &0x7), h8_getreg32(dstreg));
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(2);
			break;

		}
		else
		{
			if(opcode & 0xf0)
			{
				logerror("H8/3002: Unk. group A2 0 %x\n", opcode);
				h8.h8err = 1;
			}
			else
			{
				udata8 = h8_getreg8(opcode & 0xf);
				udata8 = h8_dec8(udata8);
				h8_setreg8(opcode & 0xf, udata8);
				H8_IFETCH_TIMING(1);
			}
		}
		break;
		//
	case 0xb:
		switch((opcode>>4)& 0xf)
		{
		case 0:	// subs.l #1, rN (decrement without touching flags)
			dstreg = opcode & 0x7;
			udata32 = h8_getreg32(dstreg);
			udata32--;
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 5:	// dec.w #1, rN
			dstreg = opcode & 0xf;
			udata16 = h8_dec16(h8_getreg16(dstreg));
			h8_setreg16(dstreg, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 7:	// dec.l #1, rN
			dstreg = opcode & 0x7;
			udata32 = h8_dec32(h8_getreg32(dstreg));
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 8:	// subs.l #2, rN (decrement without touching flags)
			dstreg = opcode & 0x7;
			udata32 = h8_getreg32(dstreg);
			udata32-=2;
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 9:	// subs.l #4, rN (decrement without touching flags)
			dstreg = opcode & 0x7;
			udata32 = h8_getreg32(dstreg);
			udata32-=4;
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;
		case 0xd:	// dec.w #2, rN
			dstreg = opcode & 0xf;
			udata16 = h8_dec16(h8_getreg16(dstreg));
			if (h8.h8vflag)
			{
				udata16 = h8_dec16(udata16);
				h8.h8vflag = 1;
			}
			else
				udata16 = h8_dec16(udata16);
			h8_setreg16(dstreg, udata16);
			H8_IFETCH_TIMING(1);
			break;
		case 0xf:	// dec.l #2, rN
			dstreg = opcode & 0x7;
			udata32 = h8_dec32(h8_getreg32(dstreg));
			if (h8.h8vflag)
			{
				udata32 = h8_dec32(udata32);
				h8.h8vflag = 1;
			}
			else
				udata32 = h8_dec32(udata32);
			h8_setreg32(dstreg, udata32);
			H8_IFETCH_TIMING(1);
			break;

		default:
			logerror("H8/3002: Unk. group 1 B %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0xc:
		// cmp.b rs, rd
		h8_cmp8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(opcode & 0xf));
		H8_IFETCH_TIMING(1);
		break;
	case 0xd:
		// cmp.w rx, ry
		h8_cmp16(h8_getreg16((opcode>>4) &0xf), h8_getreg16(opcode & 0xf));
		H8_IFETCH_TIMING(1);
		break;
	case 0xe:
		// subx.b rx, ry
		dstreg = opcode & 0xf;
		udata8 = h8_subx8(h8_getreg8((opcode>>4) &0xf), h8_getreg8(dstreg));
		h8_setreg8(dstreg, udata8);
		H8_IFETCH_TIMING(1);
		break;
	case 0xf:
		if(opcode & 0x80)
		{
			if(opcode & 8)
			{
				logerror("H8/3002: Unk. group 1 f %x\n", opcode);
				h8.h8err = 1;
			}
			else
			{
				h8_cmp32(h8_getreg32((opcode>>4) & 0x7), h8_getreg32(opcode & 0x7));
				H8_IFETCH_TIMING(1);
			}
		}
		else
		{
			logerror("H8/3002: Unk. group 1 f2 %x\n", opcode);
			h8.h8err = 1;
		}
		break;
	default:
		logerror("H8/3002: Unk. group 1 def %x\n", opcode);
		h8.h8err = 1;
		break;
	}
}


static void h8_group5(UINT16 opcode)
{
	switch((opcode>>8)&0xf)
	{
	case 0x0:
		// mulxu.b
		udata8 = h8_getreg8((opcode>>4)&0xf);
		udata16 = h8_getreg16(opcode & 0xf);
		udata16 &= 0xff;
		udata16 = udata16*udata8;
		// no flags modified!
		h8_setreg16(opcode & 0xf, udata16);
		H8_IFETCH_TIMING(1);
		H8_IOP_TIMING(12);
		break;
	case 0x1:
		// divxu.b
		udata8 = h8_getreg8((opcode>>4)&0xf);
		udata16 = h8_getreg16(opcode & 0x0f);
		udata16 = h8_divxu8(udata16,udata8);
		h8_setreg16(opcode & 0xf, udata16);
		H8_IFETCH_TIMING(1);
		H8_IOP_TIMING(12);
		break;
	case 0x2:
		// mulxu.w
		udata16 = h8_getreg16((opcode>>4)&0xf);
		udata32 = h8_getreg32(opcode & 7);
		udata32 &= 0xffff;
		udata32 = udata32*udata16;
		// no flags modified!
		h8_setreg32(opcode & 7, udata32);
		H8_IFETCH_TIMING(1);
		H8_IOP_TIMING(20);
		break;
	case 0x3:
		// divxu.w
		udata16 = h8_getreg16((opcode>>4)&0xf);
		udata32 = h8_getreg32(opcode & 7);
		udata32 = h8_divxu16(udata32,udata16);
		h8_setreg32(opcode & 7, udata32);
		H8_IFETCH_TIMING(1);
		H8_IOP_TIMING(20);
		break;
	case 0x4:
		if(opcode == 0x5470)
		{
			// rts
			udata32 = h8_mem_read32(h8_getreg32(H8_SP));
			h8_setreg32(H8_SP, h8_getreg32(H8_SP)+4);
			// extended mode
			h8.pc = udata32;
			change_pc(h8.pc);
			H8_IFETCH_TIMING(2);
			H8_STACK_TIMING(2);
			H8_IOP_TIMING(2);
		}
		else
		{
			logerror("H8/3002: Unk. group 5 1 %x\n", opcode);
			h8.h8err = 1;
		}
		break;
	case 0x5:
		// bsr 8
		sdata8 = opcode & 0xff;
		// extended mode stack push!
		h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
		h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
		h8.pc = h8.pc + sdata8;
		change_pc(h8.pc);
		H8_IFETCH_TIMING(2); H8_STACK_TIMING(2);
		break;
	case 0x6:
		// rte
		if(opcode == 0x5670)
		{
			// restore CCR
			udata16 = h8_mem_read16(h8_getreg32(H8_SP));
			h8_setreg32(H8_SP, h8_getreg32(H8_SP)+2);
			// extended mode restore PC
			udata32 = h8_mem_read32(h8_getreg32(H8_SP));
			h8_setreg32(H8_SP, h8_getreg32(H8_SP)+4);
			// extended mode
			h8.pc = udata32;
			change_pc(h8.pc);
			// must do this last, because set_ccr() does a check_irq()
			h8_set_ccr((UINT8)udata16);
			H8_IFETCH_TIMING(2);
			H8_STACK_TIMING(2);
			H8_IOP_TIMING(2);
		}
		else
		{
			logerror("H8/3002: Unk. group 5 6 %x\n", opcode);
			h8.h8err = 1;
		}
		break;
		// trapa
	case 0x7:
		logerror("H8/3002: Unk. group 5 7 %x\n", opcode);
		h8.h8err = 1;
		break;
	case 0x8:
		// bcc @xx:16
		if(opcode & 0xf)
		{
			logerror("H8/3002: Unk. group 5 8 %x\n", opcode);
			h8.h8err = 1;
		}
		else
		{
			sdata16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			if( h8_branch((opcode >> 4) & 0xf) == 1)h8.pc += sdata16;
			change_pc(h8.pc);
			H8_IOP_TIMING(2)
		}
		break;
	case 0x9:
		// jmp @erd
		address24 = h8_getreg32((opcode>>4)&7);
		address24 &= 0xffffff;
		h8.pc = address24;
		change_pc(h8.pc);
		H8_IFETCH_TIMING(2);
		break;
		// jmp @aa:24
	case 0xa:
		address24=h8_mem_read32(h8.pc-2);
		address24 &= 0xffffff;
		h8.pc = address24;
		change_pc(h8.pc);
		H8_IFETCH_TIMING(2);
		H8_IOP_TIMING(2);
		break;
		// jmp @aa:8
	case 0xc:
		if(opcode & 0xff)
		{
			logerror("H8/3002: Unk. group 5 c %x\n", opcode);
			h8.h8err = 1;
		}
		else
		{
			// bsr d:16
			sdata16=h8_mem_read16(h8.pc);
			h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
			h8_mem_write32(h8_getreg32(H8_SP), h8.pc+2);
			h8.pc += sdata16 + 2;
			change_pc(h8.pc);
			H8_IFETCH_TIMING(2); H8_STACK_TIMING(2); H8_IOP_TIMING(2);
		}
		break;
	case 0xd:
		// jsr @reg
		address24=h8_getreg32((opcode>>4)&7);
		address24 &= 0xffffff;
		// extended mode stack push!
		h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
		h8_mem_write32(h8_getreg32(H8_SP), h8.pc);
		h8.pc = address24;
		change_pc(h8.pc);
		H8_STACK_TIMING(2);
		H8_IOP_TIMING(2);
		break;
	case 0xe:
		// jsr @aa:24
		address24=h8_mem_read32(h8.pc-2);
		address24 &= 0xffffff;
		// extended mode stack push!
		h8_setreg32(H8_SP, h8_getreg32(H8_SP)-4);
		h8_mem_write32(h8_getreg32(H8_SP), h8.pc+2);
		h8.pc = address24;
		change_pc(h8.pc);
		H8_IFETCH_TIMING(2);
		H8_STACK_TIMING(2);
		H8_IOP_TIMING(2);
		break;
		// jsr @aa:8
	default:
		logerror("H8/3002: Unk. group 5 def %x\n", opcode);
		h8.h8err = 1;
		break;
	}
}

static void h8_group6(UINT16 opcode)
{
	switch((opcode>>8)&0xf)
	{
	case 0:case 1:case 2:case 3:
		{
			UINT8 bitnr;

			dstreg = opcode & 0xf;
			udata8 = h8_getreg8(dstreg);
			bitnr = h8_getreg8((opcode>>4)& 0xf)&7;

			switch((opcode>>8)&0xf)
			{
			case 0:	udata8 = h8_bset8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
			case 2:	udata8 = h8_bclr8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
			case 3:	h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
			default:
				logerror("H8/3002: Unk. group 6 def 0-3-0 %x\n", opcode);
				h8.h8err = 1;
				break;
			}
		}
		break;
	case 0x4:
		// or.w rs, rd
		dstreg = opcode & 0xf;
		udata16 = h8_getreg16(dstreg);
		udata16 = h8_or16(h8_getreg16((opcode>>4) & 0xf), udata16);
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1);
		break;
	case 0x5:
		// xor.w rs, rd
		dstreg = opcode & 0xf;
		udata16 = h8_getreg16(dstreg);
		udata16 = h8_xor16(h8_getreg16((opcode>>4) & 0xf), udata16);
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1);
		break;
	case 0x6:
		// and.w rs, rd
		dstreg = opcode & 0xf;
		udata16 = h8_getreg16(dstreg);
		udata16 = h8_and16(h8_getreg16((opcode>>4) & 0xf), udata16);
		h8_setreg16(dstreg, udata16);
		H8_IFETCH_TIMING(1)
		break;
	case 0x7:
		// bst/bist #imm, rd
		if(opcode & 0x80)
		{
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_bist8((opcode>>4) & 7, udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
		}
		else
		{
			udata8 = h8_getreg8(opcode & 0xf);
			udata8 = h8_bst8((opcode>>4) & 7, udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
		}
		break;
	case 0x8:
		if(opcode & 0x80)
		{
			// mov.b rx, @rx
			udata8 = h8_getreg8(opcode & 0xf);
			address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
			h8_mov8(udata8);
			h8_mem_write8(address24, udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
		}
		else
		{
			// mov.b @rx, rx
			address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
			udata8 = h8_mem_read8(address24);
			h8_mov8(udata8);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
		}
		break;
	case 0x9:
		if(opcode & 0x80)
		{
			// mov.w rx, @rx
			address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
			udata16 = h8_getreg16(opcode & 0xf);
			h8_mov16(udata16);
			h8_mem_write16(address24, udata16);
			H8_IFETCH_TIMING(1);
			H8_WORD_TIMING(1, address24);
		}
		else
		{
			// mov.w @rx, rx
			address24 = h8_getreg32((opcode>>4)&7) & 0xffffff;
			udata16 = h8_mem_read16(address24);
			h8_mov16(udata16);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			H8_WORD_TIMING(1, address24);
		}
		break;
	case 0xa:
		// mov.b rx, @xx
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			sdata16=h8_mem_read16(h8.pc);
			h8.pc += 2;
			address24 = sdata16 & 0xffffff;
			udata8=h8_mem_read8(address24);
			h8_mov8(udata8); // flags only
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
			break;
		case 0x2:
			address24=h8_mem_read32(h8.pc);
			h8.pc += 4;
			udata8=h8_mem_read8(address24);
			h8_mov8(udata8); // flags only
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(2);
			H8_BYTE_TIMING(1, address24);
			break;
		case 0x8:
			sdata16=h8_mem_read16(h8.pc);
			h8.pc += 2;
			address24 = sdata16 & 0xffffff;
			udata8=h8_getreg8(opcode & 0xf);
			h8_mov8(udata8); // flags only
			h8_mem_write8(address24, udata8);
			H8_IFETCH_TIMING(3);
			H8_BYTE_TIMING(1, address24);
			break;
		case 0xa: // pass
			address24=h8_mem_read32(h8.pc);
			h8.pc += 4;
			udata8=h8_getreg8(opcode & 0xf);
			h8_mov8(udata8); // flags only
			h8_mem_write8(address24, udata8);
			H8_IFETCH_TIMING(3);
			H8_BYTE_TIMING(1, address24);
			break;
		default:
			logerror("H8/3002: Unk. group 6 a %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0xb:
		// mov.w rx, @xx / mov.w @xx, rx
		switch((opcode>>4)&0xf)
		{
		case 0x0:
			sdata16=h8_mem_read16(h8.pc);
			address24 = sdata16;
			address24 &= 0xffffff;
			h8.pc += 2;
			udata16=h8_mem_read16(address24);
			h8_mov16(udata16); // flags only
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(2);
			H8_WORD_TIMING(1, address24);
			break;
		case 0x2:
			address24=h8_mem_read32(h8.pc);
			h8.pc += 4;
			udata16=h8_mem_read16(address24);
			h8_mov16(udata16); // flags only
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(4);
			H8_WORD_TIMING(1, address24);
			break;
		case 0x8:
			sdata16=h8_mem_read16(h8.pc);
			address24 = sdata16;
			address24 &= 0xffffff;
			h8.pc += 2;
			udata16=h8_getreg16(opcode & 0xf);
			h8_mov16(udata16); // flags only
			h8_mem_write16(address24, udata16);
			H8_IFETCH_TIMING(2);
			H8_WORD_TIMING(1, address24);
			break;
		case 0xa: // pass
			address24=h8_mem_read32(h8.pc);
			h8.pc += 4;
			udata16=h8_getreg16(opcode & 0xf);
			h8_mov16(udata16); // flags only
			h8_mem_write16(address24, udata16);
			H8_IFETCH_TIMING(4);
			H8_WORD_TIMING(1, address24);
			break;
		default:
			logerror("H8/3002: Unk. group 6b %x\n", opcode);
			h8.h8err = 1;
			break;
		}
		break;
	case 0xc:
		if(opcode & 0x80)
		{
			// mov.b rx, @-erx
			srcreg = (opcode>>4)&7;
			h8_setreg32(srcreg, h8_getreg32(srcreg)-1);
			address24 = h8_getreg32(srcreg) & 0xffffff;
			udata8 = h8_getreg8(opcode & 0xf);
			h8_mem_write8(address24, udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
			H8_IOP_TIMING(2);
		}
		else
		{
			// mov.b @erx+,rx
			srcreg = (opcode>>4)&7;
			address24 = h8_getreg32(srcreg) & 0xffffff;
			h8_setreg32(srcreg, h8_getreg32(srcreg)+1);
			udata8 = h8_mem_read8(address24);
			h8_setreg8(opcode & 0xf, udata8);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
			H8_IOP_TIMING(2);
		}
		h8_mov8(udata8);
		break;
	case 0xd:
		if(opcode & 0x80)
		{
			// mov.w rs, @-erd
			srcreg = (opcode>>4)&7;
			h8_setreg32(srcreg, h8_getreg32(srcreg)-2);
			address24 = h8_getreg32(srcreg) & 0xffffff;
			udata16 = h8_getreg16(opcode & 0xf);
			h8_mem_write16(address24, udata16);
			H8_IFETCH_TIMING(1);
			H8_WORD_TIMING(1, address24);
			H8_IOP_TIMING(2);
		}
		else
		{
			// mov.w @ers+, rd
			srcreg = (opcode>>4)&7;
			address24 = h8_getreg32(srcreg) & 0xffffff;
			h8_setreg32(srcreg, h8_getreg32(srcreg)+2);
			udata16 = h8_mem_read16(address24);
			h8_setreg16(opcode & 0xf, udata16);
			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING(1, address24);
			H8_IOP_TIMING(2);
		}
		h8_mov16(udata16);
		break;
	case 0xe: // pass
		// mov.b @(displ16 + Rs), rd
		sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
		h8.pc += 2;
		address24 = (h8_getreg32((opcode>>4)&7)) & 0xffffff;
		address24 += sdata16;
		if(opcode & 0x80)
		{
			udata8 = h8_getreg8(opcode & 0xf);
			h8_mem_write8(address24, udata8);
		}
		else
		{
			udata8 = h8_mem_read8(address24);
			h8_setreg8(opcode & 0xf, udata8);
		}
		h8_mov8(udata8);
		H8_IFETCH_TIMING(2);
		H8_BYTE_TIMING(1, address24);
		break;
	case 0xf:
		// mov.w @(displ16 + Rs), rd
		sdata16=h8_mem_read16(h8.pc); // sign extend displacements !
		h8.pc += 2;
		address24 = (h8_getreg32((opcode>>4)&7)) & 0xffffff;
		address24 += sdata16;
		if(opcode & 0x80)
		{
			udata16 = h8_getreg16(opcode & 0xf);
			h8_mem_write16(address24, udata16);
		}
		else
		{
			udata16 = h8_mem_read16(address24);
			h8_setreg16(opcode & 0xf, udata16);
		}
		h8_mov16(udata16);
		H8_IFETCH_TIMING(2);
		H8_WORD_TIMING(1, address24);
		break;
	default:
		logerror("H8/3002: Unk. group 6 def %x\n", opcode);
		h8.h8err = 1;
		break;
	}
}

static void h8_group7(UINT16 opcode)
{
	switch((opcode>>8)&0xf)
	{
	case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
		{
			UINT8 bitnr;

			dstreg = opcode & 0xf;
			udata8 = h8_getreg8(dstreg);
			bitnr = (opcode>>4)&7;

			if(((opcode>>4)&0x8) == 0)
			{
				switch((opcode>>8)&7)
				{
				case 0:	udata8 = h8_bset8(bitnr, udata8); h8_setreg8(dstreg, udata8); H8_IFETCH_TIMING(1); break;
				case 2:	udata8 = h8_bclr8(bitnr, udata8); h8_setreg8(dstreg, udata8);H8_IFETCH_TIMING(1);break;
				case 3:	h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
				case 7:	h8_bld8(bitnr, udata8); H8_IFETCH_TIMING(1); break;
				default:
					logerror("H8/3002: Unk. group 7 0-7 def %x\n", opcode);
					h8.h8err = 1;
					break;
				}
			}
			else
			{
				switch((opcode>>8)&7)
				{
				default:
					logerror("H8/3002: Unk. group 7 0-7-1 def %x\n", opcode);
					h8.h8err = 1;
					break;
				}
			}
		}
		break;
	case 0x8:
		ext16 = h8_mem_read16(h8.pc);
		h8.pc += 2;
		udata32 = h8_mem_read32(h8.pc);
		h8.pc += 4;

		if(((ext16>>8) & 0xf) == 0xa)
		{
			if(((ext16>>4) & 0xf) == 0xa)
			{
				udata8 = h8_getreg8(ext16 & 0xf);
				h8_mov8(udata8); // update flags !
				udata32 += h8_getreg32((opcode >> 4) & 7);
				h8_mem_write8(udata32, udata8);
			}
			else
			{
				udata32 += h8_getreg32((opcode >> 4) & 7);
				udata8 = h8_mem_read8(udata32);
				h8_mov8(udata8); // update flags !
				h8_setreg8(ext16 & 0xf, udata8);
			}
			H8_BYTE_TIMING(1, udata32);
			H8_IFETCH_TIMING(4);
		}
		else if ((ext16 & 0xfff0) == 0x6b20) // mov.w @(24-bit direct, rN), rM
		{
			udata32 += h8_getreg32((opcode >> 4) & 7);
			udata16 = h8_mem_read16(udata32);
			h8_setreg16(ext16 & 0xf, udata16);
			h8_mov16(udata16); // update flags !
			H8_WORD_TIMING(1, udata32);
			H8_IFETCH_TIMING(4);
		}
		else if ((ext16 & 0xfff0) == 0x6ba0) // mov.w rM, @(24-bit direct, rN)
		{
			udata32 += h8_getreg32((opcode >> 4) & 7);
			udata16 = h8_getreg16(ext16 & 0xf);
			h8_mem_write16(udata32, udata16);
			h8_mov16(udata16); // update flags !
			H8_WORD_TIMING(1, udata32);
			H8_IFETCH_TIMING(4);
		}
		else
		{
			logerror("H8/3002: Unk. group 7 8 %x\n", opcode);
			h8.h8err = 1;
		}
		break;


		// xxx.w #aa:16, rd
	case 0x9:
		if( ((opcode>>4) & 0xf) > 0x6)
		{
			logerror("H8/3002: Unk. group 7 9 %x\n", opcode);
			h8.h8err = 1;
		}
		else
		{
			UINT16 dst16;
			udata16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			dstreg = opcode&0xf;
			dst16 = h8_getreg16(dstreg);

			switch((opcode>>4)&7)
			{
			case 0:	dst16 = h8_mov16(udata16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2);break;
			case 1: dst16 = h8_add16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
			case 2: h8_cmp16(udata16, dst16); H8_IFETCH_TIMING(2); break;
			case 3: dst16 = h8_sub16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
			case 4: dst16 = h8_or16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
			case 5: dst16 = h8_xor16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
			case 6: dst16 = h8_and16(udata16, dst16); h8_setreg16(dstreg, dst16); H8_IFETCH_TIMING(2); break;
			default:
				logerror("H8/3002: Unk. group 7 9 %x\n", opcode);
				h8.h8err = 1;
				break;
			}
		}
		break;
		// xxx.l #aa:32, erd
	case 0xa:
		if( (((opcode>>4) & 0xf) > 0x6) || (opcode & 0x8))
		{
			logerror("H8/3002: Unk. group 7 a %x\n", opcode);
			h8.h8err = 1;
		}
		else
		{
			UINT32 dst32;
			udata32 = h8_mem_read32(h8.pc);
			dstreg = opcode&0x7;
			h8.pc +=4;
			dst32 = h8_getreg32(dstreg);

			switch((opcode>>4)&7)
			{
			case 0:	dst32 = h8_mov32(udata32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
			case 1: dst32 = h8_add32(udata32, dst32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
			case 2: h8_cmp32(udata32, dst32); H8_IFETCH_TIMING(3); break;
			case 6: dst32 = h8_and32(udata32, dst32); h8_setreg32(dstreg, dst32); H8_IFETCH_TIMING(3); break;
			default:
				logerror("H8/3002: Unk. group 7 a2 %x\n", opcode);
				h8.h8err = 1;
				break;
			}
		}
		break;
		// eepmov
	case 0xb:
		if ((opcode & 0xff) == 0xd4)
		{
			UINT16 cnt = h8_getreg16(4);

			H8_IFETCH_TIMING(1);
			H8_BYTE_TIMING((2*cnt)+2, h8.regs[5]);

			// eepmov.w
			while (cnt > 0)
			{
				h8_mem_write8(h8.regs[6], h8_mem_read8(h8.regs[5]));
				h8.regs[5]++;
				h8.regs[6]++;
				cnt--;
			}
			h8_setreg16(4, 0);
			h8.pc += 2;
		}
		else
		{
			logerror("H8/3002: Unk. eepmov form\n");
			h8.h8err = 1;
		}
		break;
		// bxx.b #xx:3, @rd
	case 0xc:
		{
			UINT8 bitnr;

			address24 = h8_getreg32((opcode>>4) & 0x7);
			udata8 = h8_mem_read8(address24);
			H8_BYTE_TIMING(1, address24);

			ext16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			H8_IFETCH_TIMING(2);

			switch(ext16>>8)
			{
				// BTST Rn,@ERd
				case 0x63:
					srcreg = (ext16>>4)&0xf;
					bitnr = h8_getreg8(srcreg)&7;
					h8_btst8(bitnr, udata8);
					break;
				// btst.b #imm, @Rn
				case 0x73:
					bitnr = (ext16>>4)&7;
					h8_btst8(bitnr, udata8);
					break;
				default:
					h8.h8err=1;
			}
		}
		break;
	case 0xd:
		{
			UINT8 bitnr;
			sdata16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			address24 = h8_getreg32((opcode>>4) & 0x7);
			udata8 = h8_mem_read8(address24);
			bitnr = (sdata16>>4)&7;

			if(((sdata16>>4)&0x8) == 0)
			{
				switch ((sdata16>>8)&0xff)
				{
					// bset.b #imm, @Rn
					case 0x70: udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24); break;
					// bclr.b #imm, @Rn
					case 0x72: udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24); break;
					default:
					h8.h8err=1;
					logerror("H8/3002: Unk. group 7 cd-1 %x (%x)\n", opcode, (sdata16>>4)&7);
					break;
				}
			}
			else
			{
				switch ((sdata16>>8)&7)
				{
					default:
					h8.h8err=1;
					logerror("H8/3002: Unk. group 7 cd-2 %x %x\n", opcode, sdata16);
					break;
				}
			}
		}
		break;
		// bxxx.b #imm, @aa:8
	case 0xe:
	case 0xf:
		{
			UINT8 bitnr=0;
			ext16 = h8_mem_read16(h8.pc);
			h8.pc += 2;
			address24 = 0xffff00 + (opcode & 0xff);
			udata8 = h8_mem_read8(address24);

			switch((ext16>>8)&0xff)
			{
			case 0x30:
			case 0x60:
				bitnr = (ext16>>4)&7;
				udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				break;
			case 0x70:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80) h8.h8err = 1;
				udata8 = h8_bset8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				break;
			case 0x32:
			case 0x62:
				bitnr = h8_getreg8((ext16>>4)&0xf)&7;
				udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				break;
			case 0x72:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80) h8.h8err = 1;
				udata8 = h8_bclr8(bitnr, udata8); h8_mem_write8(address24, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				break;
			case 0x63:
				bitnr = h8_getreg8((ext16>>4)&0xf)&7;
				h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
				break;
			case 0x73:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80) h8.h8err = 1;
				h8_btst8(bitnr, udata8); H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
				break;
			case 0x74:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80)
				{
					// bior
					h8.h8err = 1;
				}
				else
				{
					h8_bor8(bitnr, udata8);  H8_IFETCH_TIMING(2); H8_BYTE_TIMING(1, address24);
				}
				break;
			case 0x67:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80)
				{
					// bist
					h8.h8err = 1;
				}
				else
				{
					h8_bst8(bitnr, udata8);  H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				}
				break;
			case 0x77:
				bitnr = (ext16>>4)&7;
				if(ext16&0x80)
				{
					// bild
					h8.h8err = 1;
				}
				else
				{
					h8_bld8(bitnr, udata8);  H8_IFETCH_TIMING(2); H8_BYTE_TIMING(2, address24);
				}
				break;
			default:
				h8.h8err = 1;
				break;
			}
			if(h8.h8err)
				logerror("H8/3002: Unk. group 7 e %x\n", opcode);
		}
		break;
	default:
		logerror("H8/3002: Unk. group 7 def %x\n", opcode);
		h8.h8err = 1;
		break;
	}
}


static UINT8 h8_mov8(UINT8 src)
{
	// N and Z modified
	h8.h8nflag = (src>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(src==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return src;
}

static UINT16 h8_mov16(UINT16 src)
{
	// N and Z modified
	h8.h8nflag = (src>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(src==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}
	return src;
}

static UINT32 h8_mov32(UINT32 src)
{
	// N and Z modified
	h8.h8nflag = (src>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(src==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return src;
}

static UINT8 h8_sub8(UINT8 src, UINT8 dst)
{
	UINT16 res;

	res = (UINT16)dst - src;
	// H,N,Z,V,C modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = (((src^dst) & (res^dst))>>7) & 1;
	h8.h8cflag = (res >> 8) & 1;

	// zflag
	if((res&0xff)==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;

	return res;
}

static UINT16 h8_sub16(UINT16 src, UINT16 dst)
{
	UINT32 res;

	res = (UINT32)dst - src;
	// H,N,Z,V,C modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = (((src^dst) & (res^dst))>>15) & 1;
	h8.h8cflag = (res >> 16) & 1;
	//  h8.h8hflag = (res>>28) & 1;

	// zflag
	if((res&0xffff)==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;

	return res;
}

static UINT32 h8_sub32(UINT32 src, UINT32 dst)
{
	UINT64 res;

	res = (UINT64)dst - src;
	// H,N,Z,V,C modified
	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = (((src^dst) & (res^dst))>>31) & 1;
	h8.h8cflag = (res >> 32) & 1;
	//  h8.h8hflag = (res>>28) & 1;

	// zflag
	if((res&0xffffffff)==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;

	return res;
}




static UINT8 h8_add8(UINT8 src, UINT8 dst)
{
	UINT16 res;

	res = (UINT16)src + dst;
	// H,N,Z,V,C modified
	h8.h8nflag = (res & 0x80) ? 1 : 0;
	h8.h8vflag = ((src^res) & (dst^res) & 0x80) ? 1 : 0;
	h8.h8cflag = (res & 0x100) ? 1 : 0;
	h8.h8zflag = (res & 0xff) ? 0 : 1;
	h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;

	return (UINT8)res;
}

static UINT16 h8_add16(UINT16 src, UINT16 dst)
{
	UINT32 res;

	res = (UINT32)src + dst;
	// H,N,Z,V,C modified
	h8.h8nflag = (res & 0x8000) ? 1 : 0;
	h8.h8vflag = ((src^res) & (dst^res) & 0x8000) ? 1 : 0;
	h8.h8cflag = (res & 0x10000) ? 1 : 0;
	h8.h8zflag = (res & 0xffff) ? 0 : 1;
	h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;

	return res;
}

static UINT32 h8_add32(UINT32 src, UINT32 dst)
{
	UINT64 res;

	res = (UINT64)src + dst;
	// H,N,Z,V,C modified
	h8.h8nflag = (res & 0x80000000) ? 1 : 0;
	h8.h8vflag = (((src^res) & (dst^res)) & 0x80000000) ? 1 : 0;
	h8.h8cflag = ((res) & (((UINT64)1) << 32)) ? 1 : 0;
	h8.h8zflag = (res & 0xffffffff) ? 0 : 1;
	h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;

	return res;
}


static UINT8 h8_addx8(UINT8 src, UINT8 dst)
{
	UINT16 res;

	res = (UINT16)src + dst + h8.h8cflag;
	// H,N,Z,V,C modified
	h8.h8nflag = (res & 0x80) ? 1 : 0;
	h8.h8vflag = ((src^res) & (dst^res) & 0x80) ? 1 : 0;
	h8.h8cflag = (res >> 8) & 1;
	h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
	h8.h8zflag = (res & 0xff) ? 0 : h8.h8zflag;

	return (UINT8)res;
}

static void h8_cmp8(UINT8 src, UINT8 dst)
{
	UINT16 res = (UINT16)dst - src;

	h8.h8cflag = (res & 0x100) ? 1 : 0;
	h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x80) ? 1 : 0;
	h8.h8zflag = ((res & 0xff) == 0) ? 1 : 0;
	h8.h8nflag = (res & 0x80) ? 1 : 0;
	h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;
}

static void h8_cmp16(UINT16 src, UINT16 dst)
{
	UINT32 res = (UINT32)dst - src;

	h8.h8cflag = (res & 0x10000) ? 1 : 0;
	h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x8000) ? 1 : 0;
	h8.h8zflag = ((res & 0xffff) == 0) ? 1 : 0;
	h8.h8nflag = (res & 0x8000) ? 1 : 0;
	h8.h8hflag = ((src^dst^res) & 0x1000) ? 1 : 0;
}

static void h8_cmp32(UINT32 src, UINT32 dst)
{
	UINT64 res = (UINT64)dst - src;

	h8.h8cflag = (res & (UINT64)U64(0x100000000)) ? 1 : 0;
	h8.h8vflag = (((dst) ^ (src)) & ((dst) ^ (res)) & 0x80000000) ? 1 : 0;
	h8.h8zflag = ((res & 0xffffffff) == 0) ? 1 : 0;
	h8.h8nflag = (res & 0x80000000) ? 1 : 0;
	h8.h8hflag = ((src^dst^res) & 0x10000000) ? 1 : 0;
}


static UINT8 h8_subx8(UINT8 src, UINT8 dst)
{
	UINT16 res;

	res = (UINT16)dst - src - (h8.h8cflag) ? 1 : 0;
	// H,N,Z,V,C modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = (((src^dst) & (res^dst))>>7) & 1;
	h8.h8cflag = (res >> 8) & 1;

	// zflag
	if((res&0xff)==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src^dst^res) & 0x10) ? 1 : 0;

	return res;
}

static UINT8 h8_or8(UINT8 src, UINT8 dst)
{
	UINT8 res;
	res = src | dst;

	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_or16(UINT16 src, UINT16 dst)
{
	UINT16 res;
	res = src | dst;

	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_xor8(UINT8 src, UINT8 dst)
{
	UINT8 res;
	res = src ^ dst;

	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_xor16(UINT16 src, UINT16 dst)
{
	UINT16 res;
	res = src ^ dst;

	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_xor32(UINT32 src, UINT32 dst)
{
	UINT32 res;
	res = src ^ dst;

	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_and8(UINT8 src, UINT8 dst)
{
	UINT8 res;

	res = src & dst;
	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_and16(UINT16 src, UINT16 dst)
{
	UINT16 res;

	res = src & dst;
	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_and32(UINT32 src, UINT32 dst)
{
	UINT32 res;

	res = src & dst;
	// N and Z modified
	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static void h8_btst8(UINT8 bit, UINT8 dst)
{
	// test single bit and update Z flag
	if( (dst & (1<<bit)) == 0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}
}

static void h8_bld8(UINT8 bit, UINT8 dst)
{
	// load bit to carry
	h8.h8cflag = (dst >> bit) & 1;
}

#ifdef UNUSED_FUNCTION
static UINT8 h8_bnot8(UINT8 src, UINT8 dst)
{
	UINT8 res;

	// invert single bit, no effect on C flag
	res = dst ^ (1<<src);

	return res;
}
#endif

static UINT8 h8_bst8(UINT8 src, UINT8 dst)
{
	UINT8 res;

	// store carry flag in bit position
	if(h8.h8cflag == 1)
	{
		res = dst | (1<<src);
	}
	else
	{
		res = dst & ~(1<<src); // mask off
	}
	return res;
}

static UINT8 h8_bist8(UINT8 src, UINT8 dst)
{
	UINT8 res;

	// store inverse of carry flag in bit position
	if(h8.h8cflag == 0)
	{
		res = dst | (1<<src);
	}
	else
	{
		res = dst & ~(1<<src); // mask off
	}
	return res;
}

static UINT8 h8_bset8(UINT8 src, UINT8 dst)
{
	// pass
	UINT8 res;
	res = dst | (1<<src);
	return res;
}

// does not affect result, res in C flag only
static void h8_bor8(UINT8 src, UINT8 dst)
{
	// pass
	UINT8 res;

	res = dst & (1<<src);
	h8.h8cflag |= res ? 1 : 0;
}

#ifdef UNUSED_FUNCTION
static void h8_bxor8(UINT8 src, UINT8 dst)
{
	dst >>= src;
	dst &= 0x1;
	h8.h8cflag ^= dst;
}
#endif

static UINT8 h8_bclr8(UINT8 src, UINT8 dst)
{
	// pass
	UINT8 res;
	res = dst & ~(1<<src);
	return res;
}

static INT8 h8_neg8(INT8 src)
{
	INT8 res;

	if((UINT8)src == 0x80)
	{
		// overflow !
		h8.h8vflag = 1;
		res = 0x80;
	}
	else
	{
		h8.h8vflag = 0;
		res = 0-src;
	}

	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src|res)&0x08) ? 1 : 0;
	h8.h8cflag = ((src|res)&0x80) ? 1 : 0;

	return res;
}

static INT16 h8_neg16(INT16 src)
{
	INT16 res;

	if((UINT16)src == 0x8000)
	{
		// overflow !
		h8.h8vflag = 1;
		res = 0x8000;
	}
	else
	{
		h8.h8vflag = 0;
		res = 0-src;
	}

	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	h8.h8hflag = ((src|res)&0x0800) ? 1 : 0;
	h8.h8cflag = ((src|res)&0x8000) ? 1 : 0;

	return res;
}

static UINT8 h8_not8(UINT8 src)
{
	UINT8 res;

	res = ~src;

	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_not16(UINT16 src)
{
	UINT16 res;

	res = ~src;

	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_rotxr8(UINT8 src)
{
	UINT8 res;

	// rotate through carry right
	res = src>>1;
	if(h8.h8cflag)res |= 0x80; // put cflag in upper bit
	h8.h8cflag = src & 1;

	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_rotxr16(UINT16 src)
{
	UINT16 res;

	// rotate through carry right
	res = src>>1;
	if(h8.h8cflag)res |= 0x8000; // put cflag in upper bit
	h8.h8cflag = src & 1;

	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_rotxl8(UINT8 src)
{
	UINT8 res;

	// rotate through carry
	res = src<<1;
	res |= (h8.h8cflag & 1);
	h8.h8cflag = (src>>7) & 1;

	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_rotxl16(UINT16 src)
{
	UINT16 res;

	// rotate through carry
	res = src<<1;
	res |= (h8.h8cflag & 1);
	h8.h8cflag = (src>>15) & 1;

	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_rotxl32(UINT32 src)
{
	UINT32 res;

	// rotate through carry
	res = src<<1;
	res |= (h8.h8cflag & 1);
	h8.h8cflag = (src>>31) & 1;

	// N and Z modified
	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}


static UINT8 h8_rotl8(UINT8 src)
{
	UINT8 res;

	// rotate
	res = src<<1;
	h8.h8cflag = (src>>7) & 1;
	res |= (h8.h8cflag & 1);

	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_rotl16(UINT16 src)
{
	UINT16 res;

	// rotate
	res = src<<1;
	h8.h8cflag = (src>>15) & 1;
	res |= (h8.h8cflag & 1);

	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_shll8(UINT8 src)
{
	UINT8 res;
	h8.h8cflag = (src>>7) & 1;
	res = src<<1;
	// N and Z modified
	h8.h8nflag = (res>>7) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_shll16(UINT16 src)
{
	UINT16 res;
	h8.h8cflag = (src>>15) & 1;
	res = src<<1;
	// N and Z modified
	h8.h8nflag = (res>>15) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_shll32(UINT32 src)
{
	UINT32 res;
	h8.h8cflag = (src>>31) & 1;
	res = src<<1;
	// N and Z modified
	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_shlr8(UINT8 src)
{
	UINT8 res;
	h8.h8cflag = src&1;
	res = src>>1;
	// N and Z modified
	h8.h8nflag = 0;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_shlr16(UINT16 src)
{
	UINT16 res;
	h8.h8cflag = src&1;
	res = src>>1;
	// N and Z modified
	h8.h8nflag = 0;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_shlr32(UINT32 src)
{
	UINT32 res;
	h8.h8cflag = src&1;
	res = src>>1;

	// N and Z modified, V always cleared
	h8.h8nflag = 0;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT8 h8_shar8(INT8 src)
{
	INT8 res;
	h8.h8cflag = src&1;
	res = (src>>1)|(src&0x80);
	// N and Z modified
	h8.h8nflag = (res>>7)&1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT16 h8_shar16(INT16 src)
{
	INT16 res;
	h8.h8cflag = src&1;
	res = (src>>1)|(src&0x8000);
	// N and Z modified
	h8.h8nflag = (res>>15)&1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT32 h8_shar32(INT32 src)
{
	INT32 res;

	h8.h8cflag = src&1;
	res = (src>>1)|(src&0x80000000);
	// N and Z modified
	h8.h8nflag = (res>>31) & 1;
	h8.h8vflag = 0;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT8 h8_shal8(INT8 src)
{
	INT8 res;

	h8.h8cflag = (src>>7)&1;
	res = src<<1;
	// N and Z modified
	h8.h8nflag = (res>>7)&1;
	h8.h8vflag = (((src>>7)&(~src>>6)) | ((~src>>7)&(~src>>6)))&1;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT16 h8_shal16(INT16 src)
{
	INT16 res;

	h8.h8cflag = (src>>15)&1;
	res = src<<1;
	// N and Z modified
	h8.h8nflag = (res>>15)&1;
	h8.h8vflag = (((src>>15)&(~src>>14)) | ((~src>>15)&(~src>>14)))&1;

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_dec8(UINT8 src)
{
	UINT8 res;

	res = src - 1;
	// N and Z modified
	h8.h8nflag = (res>>7)&1;
	if(src == 0x80)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_dec16(UINT16 src)
{
	UINT16 res;

	res = src - 1;
	// N and Z modified
	h8.h8nflag = (res>>15)&1;
	if(src == 0x8000)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_dec32(UINT32 src)
{
	UINT32 res;

	res = src - 1;
	// N and Z modified
	h8.h8nflag = (res>>31)&1;
	if(src == 0x80000000)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT8 h8_inc8(UINT8 src)
{
	UINT8 res;

	res = src + 1;
	// N and Z modified
	h8.h8nflag = (res>>7)&1;
	if(src == 0x7f)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT16 h8_inc16(UINT16 src)
{
	UINT16 res;

	res = src + 1;
	// N and Z modified
	h8.h8nflag = (res>>15)&1;
	if(src == 0x7fff)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static UINT32 h8_inc32(UINT32 src)
{
	UINT32 res;

	res = src + 1;
	// N and Z modified
	h8.h8nflag = (res>>31)&1;
	if(src == 0x7fffffff)
	{
		h8.h8vflag = 1;
	}
	else
	{
		h8.h8vflag = 0;
	}

	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}

	return res;
}

static INT32 h8_mulxs16(INT16 src, INT16 dst)
{
	INT32 res;

	res = (INT32)src * dst;

	// N and Z modified
	h8.h8nflag = (res>>31)&1;
	// zflag
	if(res==0)
	{
		h8.h8zflag = 1;
	}
	else
	{
		h8.h8zflag = 0;
	}
	return res;
}

static UINT32 h8_divxs16(INT16 src, INT32 dst)
{
	// NOT tested !
	UINT32 res,r1,r2;
	INT16 remainder, quotient;

	if(src!=0)
	{
		quotient = dst/src;
		h8.h8zflag = 0;
	}
	else
	{
		quotient = 0;
		h8.h8zflag = 1;
	}
	remainder = dst%src;

	r1=*(&quotient);
	r2=*(&remainder);
	res=(r2<<16)|r1;

	h8.h8nflag = (quotient<0)?1:0;

	return res;

}

static UINT16 h8_divxu8(UINT16 dst, UINT8 src)
{
	UINT8 remainder, quotient;
	UINT16 res = 0;
	// N and Z modified
	h8.h8nflag = (src>>7)&1;
	// zflag
	if(src==0)
	{
		h8.h8zflag = 1;
		// dont do anything on division by zero !
	}
	else
	{
		h8.h8zflag = 0;
		quotient = dst / src;
		remainder = dst % src;
		res = (remainder << 8) | quotient;
	}
	return res;
}

static UINT32 h8_divxu16(UINT32 dst, UINT16 src)
{
	UINT16 remainder, quotient;
	UINT32 res = 0;
	// N and Z modified
	h8.h8nflag = (src>>15)&1;
	// zflag
	if(src==0)
	{
		h8.h8zflag = 1;
		// dont do anything on division by zero !
	}
	else
	{
		h8.h8zflag = 0;
		quotient = dst / src;
		remainder = dst % src;
		res = (remainder << 16) | quotient;
	}
	return res;
}

// input: branch condition
// output: 1 if condition met, 0 if not condition met
static int h8_branch(UINT8 condition)
{
	int taken = 0;

	// a branch always eats 2 ifetch states, regardless of if it's taken
	H8_IFETCH_TIMING(2)

	switch(condition)
	{
	case 0: // bt
		taken = 1;
		break;
	case 1: // bf
		break;
	case 2: // bhi (C | Z) == 0)
		if((h8.h8cflag | h8.h8zflag) == 0)taken = 1;
		break;
	case 3: // bls
		if((h8.h8cflag | h8.h8zflag) == 1)taken = 1;
		break;
	case 4: // bcc C = 0
		if(h8.h8cflag == 0)taken = 1;
		break;
	case 5: // bcs C = 1
		if(h8.h8cflag == 1)taken = 1;
		break;
	case 6: // bne Z = 0
		if(h8.h8zflag == 0)taken = 1;
		break;
	case 7: // beq Z = 1
		if(h8.h8zflag == 1)taken = 1;
		break;
	case 8: // bvc V = 0
		h8.h8err = 1;
		if(h8.h8vflag == 0)taken = 1;
		break;
	case 9: // bvs V = 1
		h8.h8err = 1;
		if(h8.h8vflag == 1)taken = 1;
		break;
	case 0xa: // bpl N = 0
		if(h8.h8nflag == 0)taken = 1;
		break;
	case 0xb: // bmi N = 1
		if(h8.h8nflag == 1)taken = 1;
		break;
	case 0xc: // bge (N ^ V) = 0
		if((h8.h8nflag ^ h8.h8vflag) == 0)taken = 1;
		break;
	case 0xd: // blt (N ^ V) = 1
		if((h8.h8nflag ^ h8.h8vflag) == 1)taken = 1;
		break;
	case 0xe: // bgt (Z | (N ^ V)) = 0
		if((h8.h8zflag | (h8.h8nflag ^ h8.h8vflag)) == 0)taken = 1;
		break;
	case 0xf: // ble (Z | (N ^ V)) = 1
		if((h8.h8zflag | (h8.h8nflag ^ h8.h8vflag)) == 1)taken = 1;
		break;
	}
	return taken;
}

// MAME interface stuff

static void h8_get_context(void *context)
{
	*(h83002_state *)context = h8;
}

static void h8_set_context(void *context)
{
	h8 = *(h83002_state *)context;
}

static void h8_set_info(UINT32 state, cpuinfo *info)
{
	switch(state) {
	case CPUINFO_INT_PC:						h8.pc = info->i; change_pc(h8.pc);				break;
	case CPUINFO_INT_REGISTER + H8_PC:			h8.pc = info->i; change_pc(h8.pc);				break;
	case CPUINFO_INT_REGISTER + H8_CCR:			h8_set_ccr(info->i);							break;

	case CPUINFO_INT_REGISTER + H8_E0:			h8.regs[0] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E1:			h8.regs[1] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E2:			h8.regs[2] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E3:			h8.regs[3] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E4:			h8.regs[4] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E5:			h8.regs[5] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E6:			h8.regs[6] = info->i;							break;
	case CPUINFO_INT_REGISTER + H8_E7:			h8.regs[7] = info->i;							break;

	case CPUINFO_INT_INPUT_STATE + H8_IRQ0:		if (info->i) h8_3002_InterruptRequest(12);		break;
	case CPUINFO_INT_INPUT_STATE + H8_IRQ1:		if (info->i) h8_3002_InterruptRequest(13);		break;
	case CPUINFO_INT_INPUT_STATE + H8_IRQ2:		if (info->i) h8_3002_InterruptRequest(14);		break;
	case CPUINFO_INT_INPUT_STATE + H8_IRQ3:		if (info->i) h8_3002_InterruptRequest(15);		break;
	case CPUINFO_INT_INPUT_STATE + H8_IRQ4:		if (info->i) h8_3002_InterruptRequest(16);		break;
	case CPUINFO_INT_INPUT_STATE + H8_IRQ5:		if (info->i) h8_3002_InterruptRequest(17);		break;

	default:
		fatalerror("h8_set_info unknown request %x", state);
		break;
	}
}

static READ16_HANDLER( h8_itu_r )
{
	if (mem_mask == 0)
	{
		// 16-bit read
		return h8_register_read8(offset*2 + 0xffff10)<<8 | h8_register_read8((offset*2) + 1 + 0xffff10);
	}
	else if (mem_mask == 0xff)
	{
		return h8_register_read8(offset*2 + 0xffff10)<<8;
	}
	else if (mem_mask == 0xff00)
	{
		return h8_register_read8((offset*2) + 1 + 0xffff10);
	}

	return 0;
}

static WRITE16_HANDLER( h8_itu_w )
{
	if (mem_mask == 0)
	{
		// 16-bit write
		h8_register_write8(offset*2 + 0xffff10, data>>8);
		h8_register_write8((offset*2) + 1 + 0xffff10, data&0xff);
	}
	else if (mem_mask == 0xff)
	{
		h8_register_write8(offset*2 + 0xffff10, data>>8);
	}
	else if (mem_mask == 0xff00)
	{
		h8_register_write8((offset*2) + 1 + 0xffff10, data&0xff);
	}
}

// On-board RAM and peripherals
static ADDRESS_MAP_START( h8_internal_map, ADDRESS_SPACE_PROGRAM, 16 )
	AM_RANGE(0xfffd10, 0xffff0f) AM_RAM
	AM_RANGE(0xffff10, 0xffffff) AM_READWRITE( h8_itu_r, h8_itu_w )
ADDRESS_MAP_END

void h8_3002_get_info(UINT32 state, cpuinfo *info)
{
	switch(state) {
	// Interface functions and variables
	case CPUINFO_PTR_SET_INFO:					info->setinfo     = h8_set_info;				break;
	case CPUINFO_PTR_GET_CONTEXT:				info->getcontext  = h8_get_context;				break;
	case CPUINFO_PTR_SET_CONTEXT:				info->setcontext= h8_set_context;				break;
	case CPUINFO_PTR_INIT:						info->init        = h8_init;					break;
	case CPUINFO_PTR_RESET:						info->reset       = h8_reset;					break;
	case CPUINFO_PTR_EXIT:						info->exit        = 0;							break;
	case CPUINFO_PTR_EXECUTE:					info->execute     = h8_execute;					break;
	case CPUINFO_PTR_BURN:						info->burn        = 0;							break;
#ifdef MAME_DEBUG
	case CPUINFO_PTR_DISASSEMBLE:				info->disassemble = h8_disasm;					break;
#endif /* MAME_DEBUG */
	case CPUINFO_PTR_INSTRUCTION_COUNTER:		info->icount      = &h8_cyccnt;					break;
	case CPUINFO_INT_CONTEXT_SIZE:				info->i           = sizeof(h83002_state);		break;
	case CPUINFO_INT_MIN_INSTRUCTION_BYTES:		info->i           = 2;							break;
	case CPUINFO_INT_MAX_INSTRUCTION_BYTES:		info->i           = 10;							break;

		// Bus sizes
	case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 16;						break;
	case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 24;						break;
	case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM:	info->i = 0;						break;
	case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA:	info->i = 0;						break;
	case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA:	info->i = 0;						break;
	case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA:	info->i = 0;						break;
	case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO:		info->i = 8;						break;
	case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO:		info->i = 16;						break;
	case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO:		info->i = 0;						break;

		// Internal maps
	case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_h8_internal_map; break;
	case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA:    info->internal_map = 0;		break;
	case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO:      info->internal_map = 0;		break;

		// CPU misc parameters
	case CPUINFO_STR_NAME:						strcpy(info->s, "H8/3002");						break;
	case CPUINFO_STR_CORE_FILE:					strcpy(info->s, __FILE__);						break;
	case CPUINFO_STR_FLAGS:						strcpy(info->s, h8_get_ccr_str());				break;
	case CPUINFO_INT_ENDIANNESS:				info->i = CPU_IS_BE;							break;
	case CPUINFO_INT_INPUT_LINES:				info->i = 16;									break;
	case CPUINFO_INT_DEFAULT_IRQ_VECTOR:		info->i = -1;									break;

		// CPU main state
	case CPUINFO_INT_PC:						info->i = h8.pc;								break;
	case CPUINFO_INT_PREVIOUSPC:				info->i = h8.ppc;								break;

	case CPUINFO_INT_REGISTER + H8_PC:			info->i = h8.pc;								break;
	case CPUINFO_INT_REGISTER + H8_CCR:			info->i = h8_get_ccr();							break;

	case CPUINFO_INT_REGISTER + H8_E0:			info->i = h8.regs[0];							break;
	case CPUINFO_INT_REGISTER + H8_E1:			info->i = h8.regs[1];							break;
	case CPUINFO_INT_REGISTER + H8_E2:			info->i = h8.regs[2];							break;
	case CPUINFO_INT_REGISTER + H8_E3:			info->i = h8.regs[3];							break;
	case CPUINFO_INT_REGISTER + H8_E4:			info->i = h8.regs[4];							break;
	case CPUINFO_INT_REGISTER + H8_E5:			info->i = h8.regs[5];							break;
	case CPUINFO_INT_REGISTER + H8_E6:			info->i = h8.regs[6];							break;
	case CPUINFO_INT_REGISTER + H8_E7:			info->i = h8.regs[7];							break;

	// CPU debug stuff
	case CPUINFO_STR_REGISTER + H8_PC:			sprintf(info->s, "PC   :%08x", h8.pc);			break;
	case CPUINFO_STR_REGISTER + H8_CCR:			sprintf(info->s, "CCR  :%08x", h8_get_ccr());	break;

	case CPUINFO_STR_REGISTER + H8_E0:			sprintf(info->s, "ER0  :%08x", h8.regs[0]);		break;
	case CPUINFO_STR_REGISTER + H8_E1:			sprintf(info->s, "ER1  :%08x", h8.regs[1]);		break;
	case CPUINFO_STR_REGISTER + H8_E2:			sprintf(info->s, "ER2  :%08x", h8.regs[2]);		break;
	case CPUINFO_STR_REGISTER + H8_E3:			sprintf(info->s, "ER3  :%08x", h8.regs[3]);		break;
	case CPUINFO_STR_REGISTER + H8_E4:			sprintf(info->s, "ER4  :%08x", h8.regs[4]);		break;
	case CPUINFO_STR_REGISTER + H8_E5:			sprintf(info->s, "ER5  :%08x", h8.regs[5]);		break;
	case CPUINFO_STR_REGISTER + H8_E6:			sprintf(info->s, "ER6  :%08x", h8.regs[6]);		break;
	case CPUINFO_STR_REGISTER + H8_E7:			sprintf(info->s, " SP  :%08x", h8.regs[7]);		break;
	}
}
