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

    mcs96.h

    MCS96, 8098/8398/8798 branch

****************************************************************************

    Copyright Olivier Galibert
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY OLIVIER GALIBERT ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

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

#include "emu.h"
#include "debugger.h"
#include "mcs96.h"

mcs96_device::mcs96_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int data_width, const char *shortname, const char *source) :
	cpu_device(mconfig, type, name, tag, owner, clock, shortname, source),
	program_config("program", ENDIANNESS_LITTLE, data_width, 16)
{
}

void mcs96_device::device_start()
{
	program = &space(AS_PROGRAM);
	direct = &program->direct();
	m_icountptr = &icount;

	state_add(STATE_GENPC,     "GENPC",     PC).noshow();
	state_add(STATE_GENPCBASE, "GENPCBASE", PPC).noshow();
	state_add(STATE_GENSP,     "GENSP",     R[0]).noshow();
	state_add(STATE_GENFLAGS,  "GENFLAGS",  PSW).formatstr("%16s").noshow();
	state_add(MCS96_PC,        "PC",        PC);
	state_add(MCS96_PSW,       "PSW",       PSW);
	state_add(MCS96_R,         "SP",        R[0]);
	for(int i=1; i<0x74; i++) {
		char buf[10];
		sprintf(buf, "R%02x", i*2+0x18);
		state_add(MCS96_R+i,   buf,         R[i]);
	}

	memset(R, 0, sizeof(R));
}

void mcs96_device::device_reset()
{
	PC = 0x2080;
	PPC = PC;
	PSW = 0;
	pending_irq = 0x00;
	irq_requested = false;
	inst_state = STATE_FETCH;
}

UINT32 mcs96_device::execute_min_cycles() const
{
	return 4;
}

UINT32 mcs96_device::execute_max_cycles() const
{
	return 33;
}

UINT32 mcs96_device::execute_input_lines() const
{
	return 1;
}

UINT64 mcs96_device::get_cycle()
{
	return end_cycles == 0 || icount <= 0 ? machine().time().as_ticks(clock()) : end_cycles - icount;
}

void mcs96_device::recompute_bcount(UINT64 event_time)
{
	if(!event_time || event_time >= end_cycles) {
		bcount = 0;
		return;
	}
	bcount = end_cycles - event_time;
}

void mcs96_device::check_irq()
{
	irq_requested = (PSW & pending_irq) && (PSW & F_I);
}

void mcs96_device::execute_run()
{
	UINT64 start_cycles = machine().time().as_ticks(clock());
	end_cycles = start_cycles + icount;

	internal_update(start_cycles);

	if(/*inst_substate*/ 0)
		do_exec_partial();

	while(icount > 0) {
		while(icount > bcount) {
			int picount = inst_state >= 0x200 ? -1 : icount;
			do_exec_full();
			if(icount == picount) {
				fprintf(stderr, "Unhandled %x (%04x)\n", inst_state, PPC);
				exit(0);
			}
		}
		while(bcount && icount <= bcount)
			internal_update(end_cycles - bcount);
	}
	end_cycles = 0;
}

void mcs96_device::execute_set_input(int inputnum, int state)
{
	switch(inputnum) {
	case EXINT_LINE:
		if(state)
			pending_irq |= 0x80;
		else
			pending_irq &= 0x7f;
		check_irq();
		break;
	}
}

const address_space_config *mcs96_device::memory_space_config(address_spacenum spacenum) const
{
	return (spacenum == AS_PROGRAM) ? &program_config : NULL;
}

void mcs96_device::state_import(const device_state_entry &entry)
{
}

void mcs96_device::state_export(const device_state_entry &entry)
{
}

void mcs96_device::state_string_export(const device_state_entry &entry, astring &string)
{
	switch(entry.index()) {
	case STATE_GENFLAGS:
	case MCS96_PSW:
		string.printf("%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c",
						PSW & F_Z  ? 'Z' : '.',
						PSW & F_N  ? 'N' : '.',
						PSW & F_V  ? 'V' : '.',
						PSW & F_VT ? 'v' : '.',
						PSW & F_C  ? 'C' : '.',
						PSW & F_I  ? 'I' : '.',
						PSW & F_ST ? 'S' : '.',
						PSW & 0x80 ? '7' : '.',
						PSW & 0x40 ? '6' : '.',
						PSW & 0x20 ? '5' : '.',
						PSW & 0x10 ? '4' : '.',
						PSW & 0x08 ? '3' : '.',
						PSW & 0x04 ? '2' : '.',
						PSW & 0x02 ? '1' : '.',
						PSW & 0x01 ? '0' : '.');
		break;
	}
}

astring mcs96_device::regname(UINT8 reg)
{
	char res[32];
	switch(reg) {
	case 0x18:
		strcpy(res, "sp");
		break;

	case 0x19:
		strcpy(res, "sph");
		break;

	default:
		sprintf(res, "%02x", reg);
		break;
	}
	return res;
}

offs_t mcs96_device::disasm_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *entries)
{
	bool prefix_fe = false;
	int off = 0;
	if(oprom[0] == 0xfe && entries[oprom[1]].opcode_fe) {
		prefix_fe = true;
		pc++;
		off++;
		oprom++;
	}
	const disasm_entry &e = entries[oprom[0]];
	UINT32 flags = e.flags | DASMFLAG_SUPPORTED;
	buffer += sprintf(buffer, "%s", prefix_fe ? e.opcode_fe : e.opcode);

	switch(e.mode) {
	case DASM_none:
		flags |= 1;
		break;

	case DASM_nop_2:
		sprintf(buffer, " %02x", oprom[1]);
		flags |= 2;
		break;

	case DASM_rel8: {
		int delta = oprom[1];
		if(delta & 0x80)
			delta -= 0x100;
		sprintf(buffer, " %04x", (pc+2+delta) & 0xffff);
		flags |= 2;
		break;
	}

	case DASM_rel11: {
		int delta = ((oprom[0] << 8) | oprom[1]) & 0x7ff;
		if(delta & 0x400)
			delta -= 0x800;
		sprintf(buffer, " %04x", (pc+2+delta) & 0xffff);
		flags |= 2;
		break;
	}

	case DASM_rel16: {
		int delta = oprom[1] | (oprom[2] << 8);
		sprintf(buffer, " %04x", (pc+3+delta) & 0xffff);
		flags |= 3;
		break;
	}

	case DASM_rrel8: {
		int delta = oprom[2];
		if(delta & 0x80)
			delta -= 0x100;
		sprintf(buffer, " %s, %04x", regname(oprom[1]).cstr(), (pc+3+delta) & 0xffff);
		flags |= 3;
		break;
	}

	case DASM_brrel8: {
		int delta = oprom[2];
		if(delta & 0x80)
			delta -= 0x100;
		sprintf(buffer, " %d, %s, %04x", oprom[0] & 7, regname(oprom[1]).cstr(), (pc+3+delta) & 0xffff);
		flags |= 3;
		break;
	}

	case DASM_direct_1:
		sprintf(buffer, " %s", regname(oprom[1]).cstr());
		flags |= 2;
		break;

	case DASM_direct_2:
		sprintf(buffer, " %s, %s", regname(oprom[2]).cstr(), regname(oprom[1]).cstr());
		flags |= 3;
		break;

	case DASM_direct_3:
		sprintf(buffer, " %s, %s, %s", regname(oprom[3]).cstr(), regname(oprom[2]).cstr(), regname(oprom[1]).cstr());
		flags |= 4;
		break;

	case DASM_immed_1b:
		sprintf(buffer, " #%02x", oprom[1]);
		flags |= 2;
		break;

	case DASM_immed_2b:
		sprintf(buffer, " %s, #%02x", regname(oprom[2]).cstr(), oprom[1]);
		flags |= 3;
		break;

	case DASM_immed_or_reg_2b:
		if(oprom[1] >= 0x10)
			sprintf(buffer, " %s, %s", regname(oprom[2]).cstr(), regname(oprom[1]).cstr());
		else
			sprintf(buffer, " %s, #%02x", regname(oprom[2]).cstr(), oprom[1]);
		flags |= 3;
		break;

	case DASM_immed_3b:
		sprintf(buffer, " %s, %s, #%02x", regname(oprom[3]).cstr(), regname(oprom[2]).cstr(), oprom[1]);
		flags |= 4;
		break;

	case DASM_immed_1w:
		sprintf(buffer, " #%02x%02x", oprom[2], oprom[1]);
		flags |= 3;
		break;

	case DASM_immed_2w:
		sprintf(buffer, " %s, #%02x%02x", regname(oprom[3]).cstr(), oprom[2], oprom[1]);
		flags |= 4;
		break;

	case DASM_immed_3w:
		sprintf(buffer, " %s, %s, #%02x%02x", regname(oprom[4]).cstr(), regname(oprom[3]).cstr(), oprom[2], oprom[1]);
		flags |= 5;
		break;

	case DASM_indirect_1n:
		sprintf(buffer, " [%s]", regname(oprom[1]).cstr());
		flags |= 2;
		break;

	case DASM_indirect_1:
		if(oprom[1] & 0x01) {
			sprintf(buffer, " [%s]+", regname(oprom[1]-1).cstr());
			flags |= 2;
		} else {
			sprintf(buffer, " [%s]", regname(oprom[1]).cstr());
			flags |= 2;
		}
		break;

	case DASM_indirect_2:
		if(oprom[1] & 0x01) {
			sprintf(buffer, " %s, [%s]+", regname(oprom[2]).cstr(), regname(oprom[1]-1).cstr());
			flags |= 3;
		} else {
			sprintf(buffer, " %s, [%s]", regname(oprom[2]).cstr(), regname(oprom[1]).cstr());
			flags |= 3;
		}
		break;

	case DASM_indirect_3:
		if(oprom[1] & 0x01) {
			sprintf(buffer, " %s, %s, [%s]+", regname(oprom[3]).cstr(), regname(oprom[2]).cstr(), regname(oprom[1]-1).cstr());
			flags |= 4;
		} else {
			sprintf(buffer, " %s, %s, [%s]", regname(oprom[3]).cstr(), regname(oprom[2]).cstr(), regname(oprom[1]).cstr());
			flags |= 4;
		}
		break;

	case DASM_indexed_1:
		if(oprom[1] & 0x01) {
			if(oprom[1] == 0x01)
				sprintf(buffer, " %02x%02x", oprom[3], oprom[2]);
			else
				sprintf(buffer, " %02x%02x[%s]", oprom[3], oprom[2], regname(oprom[1]-1).cstr());
			flags |= 4;
		} else {
			int delta = oprom[2];
			if(delta & 0x80)
				delta -= 0x100;
			if(oprom[1] == 0x00) {
				if(delta < 0)
					sprintf(buffer, " %04x", delta & 0xffff);
				else
					sprintf(buffer, " %02x", delta);
			} else {
				if(delta < 0)
					sprintf(buffer, " -%02x[%s]", -delta, regname(oprom[1]).cstr());
				else
					sprintf(buffer, " %02x[%s]", delta, regname(oprom[1]).cstr());
			}
			flags |= 3;
		}
		break;

	case DASM_indexed_2:
		if(oprom[1] & 0x01) {
			if(oprom[1] == 0x01)
				sprintf(buffer, " %s, %02x%02x", regname(oprom[4]).cstr(), oprom[3], oprom[2]);
			else
				sprintf(buffer, " %s, %02x%02x[%s]", regname(oprom[4]).cstr(), oprom[3], oprom[2], regname(oprom[1]-1).cstr());
			flags |= 5;
		} else {
			int delta = oprom[2];
			if(delta & 0x80)
				delta -= 0x100;
			if(oprom[1] == 0x00) {
				if(delta < 0)
					sprintf(buffer, " %s, %04x", regname(oprom[3]).cstr(), delta & 0xffff);
				else
					sprintf(buffer, " %s, %02x", regname(oprom[3]).cstr(), delta);
			} else {
				if(delta < 0)
					sprintf(buffer, " %s, -%02x[%s]", regname(oprom[3]).cstr(), -delta, regname(oprom[1]).cstr());
				else
					sprintf(buffer, " %s, %02x[%s]", regname(oprom[3]).cstr(), delta, regname(oprom[1]).cstr());
			}
			flags |= 4;
		}
		break;

	case DASM_indexed_3:
		if(oprom[1] & 0x01) {
			if(oprom[1] == 0x01)
				sprintf(buffer, " %s, %s, %02x%02x", regname(oprom[5]).cstr(),  regname(oprom[4]).cstr(), oprom[3], oprom[2]);
			else
				sprintf(buffer, " %s, %s, %02x%02x[%s]", regname(oprom[5]).cstr(), regname(oprom[4]).cstr(), oprom[3], oprom[2], regname(oprom[1]-1).cstr());
			flags |= 6;
		} else {
			int delta = oprom[2];
			if(delta & 0x80)
				delta -= 0x100;
			if(oprom[1] == 0x00) {
				if(delta < 0)
					sprintf(buffer, " %s, %s, %04x", regname(oprom[4]).cstr(), regname(oprom[3]).cstr(), delta & 0xffff);
				else
					sprintf(buffer, " %s, %s, %02x", regname(oprom[4]).cstr(), regname(oprom[3]).cstr(), delta);
			} else {
				if(delta < 0)
					sprintf(buffer, " %s, %s, -%02x[%s]", regname(oprom[4]).cstr(), regname(oprom[3]).cstr(), -delta, regname(oprom[1]).cstr());
				else
					sprintf(buffer, " %s, %s, %02x[%s]", regname(oprom[4]).cstr(), regname(oprom[3]).cstr(), delta, regname(oprom[1]).cstr());
			}
			flags |= 5;
		}
		break;

	default:
		fprintf(stderr, "Unhandled dasm mode %d\n", e.mode);
		abort();
	};

	return flags+off;
}

UINT32 mcs96_device::disasm_min_opcode_bytes() const
{
	return 1;
}

UINT32 mcs96_device::disasm_max_opcode_bytes() const
{
	return 7;
}

void mcs96_device::io_w8(UINT8 adr, UINT8 data)
{
	switch(adr) {
	case 0x02:
		logerror("%s: ad_command %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x03:
		logerror("%s: hsi_mode %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x04:
		logerror("%s: hso_time.l %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x05:
		logerror("%s: hso_time.h %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x06:
		logerror("%s: hso_command %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x07:
		logerror("%s: sbuf %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x08:
		PSW = (PSW & 0xff00) | data;
		break;
	case 0x09:
		logerror("%s: int_pending %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x0a:
		logerror("%s: watchdog %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x0e:
		logerror("%s: baud rate %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x0f:
		logerror("%s: io port 1 %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x10:
		logerror("%s: io port 2 %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x11:
		logerror("%s: sp con %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x15:
		logerror("%s: ioc0 %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x16:
		logerror("%s: ioc1 %02x (%04x)\n", tag(), data, PPC);
		break;
	case 0x17:
		logerror("%s: pwm control %02x (%04x)\n", tag(), data, PPC);
		break;
	}
	return;
}

void mcs96_device::io_w16(UINT8 adr, UINT16 data)
{
	switch(adr) {
	case 0:
		break;
	case 4:
		logerror("%s: hso_time %04x (%04x)\n", tag(), data, PPC);
		break;
	default:
		io_w8(adr, data);
		io_w8(adr+1, data>>8);
		break;
	}
	return;
}

UINT8 mcs96_device::io_r8(UINT8 adr)
{
	switch(adr) {
	case 0x00:
		return 0x00;
	case 0x01:
		return 0x00;
	case 0x08:
		return PSW;
	}
	UINT8 data = 0x00;
	logerror("%s: io_r8 %02x, %02x (%04x)\n", tag(), adr, data, PPC);
	return data;
}

UINT16 mcs96_device::io_r16(UINT8 adr)
{
	if(adr < 2)
		return 0x0000;
	UINT16 data = 0x0000;
	logerror("%s: io_r16 %02x, %04x (%04x)\n", tag(), adr, data, PPC);
	return data;
}

void mcs96_device::reg_w8(UINT8 adr, UINT8 data)
{
	if(adr < 0x18)
		io_w8(adr, data);
	else {
		UINT16 &r = R[(adr - 0x18) >> 1];
		if(adr & 0x01)
			r = (r & 0x00ff) | (data << 8);
		else
			r = (r & 0xff00) | data;
	}
}

void mcs96_device::reg_w16(UINT8 adr, UINT16 data)
{
	adr &= 0xfe;
	if(adr < 0x18)
		io_w16(adr, data);
	else
		R[(adr-0x18) >> 1] = data;
}

UINT8 mcs96_device::reg_r8(UINT8 adr)
{
	if(adr < 0x18)
		return io_r8(adr);

	UINT16 data = R[(adr - 0x18) >> 1];
	if(adr & 0x01)
		return data >> 8;
	else
		return data;
}

UINT16 mcs96_device::reg_r16(UINT8 adr)
{
	adr &= 0xfe;
	if(adr < 0x18)
		return io_r16(adr);

	return R[(adr-0x18) >> 1];
}

void mcs96_device::any_w8(UINT16 adr, UINT8 data)
{
	if(adr < 0x18)
		io_w8(adr, data);
	else if(adr < 0x100) {
		UINT16 &r = R[(adr - 0x18) >> 1];
		if(adr & 0x01)
			r = (r & 0x00ff) | (data << 8);
		else
			r = (r & 0xff00) | data;
	} else
		program->write_byte(adr, data);
}

void mcs96_device::any_w16(UINT16 adr, UINT16 data)
{
	adr &= 0xfffe;
	if(adr < 0x18)
		io_w16(adr, data);
	else if(adr < 0x100)
		R[(adr-0x18) >> 1] = data;
	else
		program->write_word(adr, data);
}

UINT8 mcs96_device::any_r8(UINT16 adr)
{
	if(adr < 0x18)
		return io_r8(adr);
	else if(adr < 0x100) {
		UINT16 data = R[(adr - 0x18) >> 1];
		if(adr & 0x01)
			return data >> 8;
		else
			return data;
	} else
		return program->read_byte(adr);
}

UINT16 mcs96_device::any_r16(UINT16 adr)
{
	adr &= 0xfffe;
	if(adr < 0x18)
		return io_r16(adr);
	else if(adr < 0x100)
		return R[(adr-0x18) >> 1];
	else
		return program->read_word(adr);
}

UINT8 mcs96_device::do_addb(UINT8 v1, UINT8 v2)
{
	UINT16 sum = v1+v2;
	PSW &= ~(F_Z|F_N|F_C|F_V);
	if(!UINT8(sum))
		PSW |= F_Z;
	else if(INT8(sum) < 0)
		PSW |= F_N;
	if(~(v1^v2) & (v1^sum) & 0x80)
		PSW |= F_V|F_VT;
	if(sum & 0xff00)
		PSW |= F_C;
	return sum;
}

UINT16 mcs96_device::do_add(UINT16 v1, UINT16 v2)
{
	UINT32 sum = v1+v2;
	PSW &= ~(F_Z|F_N|F_C|F_V);
	if(!UINT16(sum))
		PSW |= F_Z;
	else if(INT16(sum) < 0)
		PSW |= F_N;
	if(~(v1^v2) & (v1^sum) & 0x8000)
		PSW |= F_V|F_VT;
	if(sum & 0xffff0000)
		PSW |= F_C;
	return sum;
}

UINT8 mcs96_device::do_subb(UINT8 v1, UINT8 v2)
{
	UINT16 diff = v1 - v2;
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!UINT8(diff))
		PSW |= F_Z;
	else if(INT8(diff) < 0)
		PSW |= F_N;
	if((v1^v2) & (v1^diff) & 0x80)
		PSW |= F_V;
	if(!(diff & 0xff00))
		PSW |= F_C;
	return diff;
}

UINT16 mcs96_device::do_sub(UINT16 v1, UINT16 v2)
{
	UINT32 diff = v1 - v2;
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!UINT16(diff))
		PSW |= F_Z;
	else if(INT16(diff) < 0)
		PSW |= F_N;
	if((v1^v2) & (v1^diff) & 0x8000)
		PSW |= F_V;
	if(!(diff & 0xffff0000))
		PSW |= F_C;
	return diff;
}

UINT8 mcs96_device::do_addcb(UINT8 v1, UINT8 v2)
{
	UINT16 sum = v1+v2+(PSW & F_C ? 1 : 0);
	PSW &= ~(F_Z|F_N|F_C|F_V);
	if(!UINT8(sum))
		PSW |= F_Z;
	else if(INT8(sum) < 0)
		PSW |= F_N;
	if(~(v1^v2) & (v1^sum) & 0x80)
		PSW |= F_V|F_VT;
	if(sum & 0xff00)
		PSW |= F_C;
	return sum;
}

UINT16 mcs96_device::do_addc(UINT16 v1, UINT16 v2)
{
	UINT32 sum = v1+v2+(PSW & F_C ? 1 : 0);
	PSW &= ~(F_Z|F_N|F_C|F_V);
	if(!UINT16(sum))
		PSW |= F_Z;
	else if(INT16(sum) < 0)
		PSW |= F_N;
	if(~(v1^v2) & (v1^sum) & 0x8000)
		PSW |= F_V|F_VT;
	if(sum & 0xffff0000)
		PSW |= F_C;
	return sum;
}

UINT8 mcs96_device::do_subcb(UINT8 v1, UINT8 v2)
{
	UINT16 diff = v1 - v2 - (PSW & F_C ? 0 : 1);
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!UINT8(diff))
		PSW |= F_Z;
	else if(INT8(diff) < 0)
		PSW |= F_N;
	if((v1^v2) & (v1^diff) & 0x80)
		PSW |= F_V;
	if(!(diff & 0xff00))
		PSW |= F_C;
	return diff;
}

UINT16 mcs96_device::do_subc(UINT16 v1, UINT16 v2)
{
	UINT32 diff = v1 - v2 - (PSW & F_C ? 0 : 1);
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!UINT16(diff))
		PSW |= F_Z;
	else if(INT16(diff) < 0)
		PSW |= F_N;
	if((v1^v2) & (v1^diff) & 0x8000)
		PSW |= F_V;
	if(!(diff & 0xffff0000))
		PSW |= F_C;
	return diff;
}

void mcs96_device::set_nz8(UINT8 v)
{
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!v)
		PSW |= F_Z;
	else if(INT8(v) < 0)
		PSW |= F_N;
}

void mcs96_device::set_nz16(UINT16 v)
{
	PSW &= ~(F_N|F_V|F_Z|F_C);
	if(!v)
		PSW |= F_Z;
	else if(INT16(v) < 0)
		PSW |= F_N;
}

#include "cpu/mcs96/mcs96.inc"
