summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mcs96/mcs96.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mcs96/mcs96.c')
-rw-r--r--src/devices/cpu/mcs96/mcs96.c751
1 files changed, 751 insertions, 0 deletions
diff --git a/src/devices/cpu/mcs96/mcs96.c b/src/devices/cpu/mcs96/mcs96.c
new file mode 100644
index 00000000000..4c4cf849b88
--- /dev/null
+++ b/src/devices/cpu/mcs96/mcs96.c
@@ -0,0 +1,751 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ mcs96.h
+
+ MCS96, 8098/8398/8798 branch
+
+***************************************************************************/
+
+#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;
+}
+
+void mcs96_device::recompute_bcount(UINT64 event_time)
+{
+ if(!event_time || event_time >= total_cycles() + icount) {
+ bcount = 0;
+ return;
+ }
+ bcount = total_cycles() + icount - event_time;
+}
+
+void mcs96_device::check_irq()
+{
+ irq_requested = (PSW & pending_irq) && (PSW & F_I);
+}
+
+void mcs96_device::execute_run()
+{
+ internal_update(total_cycles());
+
+ // if(inst_substate)
+ // do_exec_partial();
+
+ while(icount > 0) {
+ while(icount > bcount) {
+ int picount = inst_state >= 0x200 ? -1 : icount;
+ do_exec_full();
+ if(icount == picount) {
+ fatalerror("Unhandled %x (%04x)\n", inst_state, PPC);
+ }
+ }
+ while(bcount && icount <= bcount)
+ internal_update(total_cycles() + icount - bcount);
+ // if(inst_substate)
+ // do_exec_partial();
+ }
+}
+
+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, std::string &str)
+{
+ switch(entry.index()) {
+ case STATE_GENFLAGS:
+ case MCS96_PSW:
+ strprintf(str, "%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;
+ }
+}
+
+std::string 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]).c_str(), (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]).c_str(), (pc+3+delta) & 0xffff);
+ flags |= 3;
+ break;
+ }
+
+ case DASM_direct_1:
+ sprintf(buffer, " %s", regname(oprom[1]).c_str());
+ flags |= 2;
+ break;
+
+ case DASM_direct_2:
+ sprintf(buffer, " %s, %s", regname(oprom[2]).c_str(), regname(oprom[1]).c_str());
+ flags |= 3;
+ break;
+
+ case DASM_direct_3:
+ sprintf(buffer, " %s, %s, %s", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]).c_str());
+ 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]).c_str(), oprom[1]);
+ flags |= 3;
+ break;
+
+ case DASM_immed_or_reg_2b:
+ if(oprom[1] >= 0x10)
+ sprintf(buffer, " %s, %s", regname(oprom[2]).c_str(), regname(oprom[1]).c_str());
+ else
+ sprintf(buffer, " %s, #%02x", regname(oprom[2]).c_str(), oprom[1]);
+ flags |= 3;
+ break;
+
+ case DASM_immed_3b:
+ sprintf(buffer, " %s, %s, #%02x", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), 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]).c_str(), oprom[2], oprom[1]);
+ flags |= 4;
+ break;
+
+ case DASM_immed_3w:
+ sprintf(buffer, " %s, %s, #%02x%02x", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), oprom[2], oprom[1]);
+ flags |= 5;
+ break;
+
+ case DASM_indirect_1n:
+ sprintf(buffer, " [%s]", regname(oprom[1]).c_str());
+ flags |= 2;
+ break;
+
+ case DASM_indirect_1:
+ if(oprom[1] & 0x01) {
+ sprintf(buffer, " [%s]+", regname(oprom[1]-1).c_str());
+ flags |= 2;
+ } else {
+ sprintf(buffer, " [%s]", regname(oprom[1]).c_str());
+ flags |= 2;
+ }
+ break;
+
+ case DASM_indirect_2:
+ if(oprom[1] & 0x01) {
+ sprintf(buffer, " %s, [%s]+", regname(oprom[2]).c_str(), regname(oprom[1]-1).c_str());
+ flags |= 3;
+ } else {
+ sprintf(buffer, " %s, [%s]", regname(oprom[2]).c_str(), regname(oprom[1]).c_str());
+ flags |= 3;
+ }
+ break;
+
+ case DASM_indirect_3:
+ if(oprom[1] & 0x01) {
+ sprintf(buffer, " %s, %s, [%s]+", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]-1).c_str());
+ flags |= 4;
+ } else {
+ sprintf(buffer, " %s, %s, [%s]", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]).c_str());
+ 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).c_str());
+ 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]).c_str());
+ else
+ sprintf(buffer, " %02x[%s]", delta, regname(oprom[1]).c_str());
+ }
+ flags |= 3;
+ }
+ break;
+
+ case DASM_indexed_2:
+ if(oprom[1] & 0x01) {
+ if(oprom[1] == 0x01)
+ sprintf(buffer, " %s, %02x%02x", regname(oprom[4]).c_str(), oprom[3], oprom[2]);
+ else
+ sprintf(buffer, " %s, %02x%02x[%s]", regname(oprom[4]).c_str(), oprom[3], oprom[2], regname(oprom[1]-1).c_str());
+ 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]).c_str(), delta & 0xffff);
+ else
+ sprintf(buffer, " %s, %02x", regname(oprom[3]).c_str(), delta);
+ } else {
+ if(delta < 0)
+ sprintf(buffer, " %s, -%02x[%s]", regname(oprom[3]).c_str(), -delta, regname(oprom[1]).c_str());
+ else
+ sprintf(buffer, " %s, %02x[%s]", regname(oprom[3]).c_str(), delta, regname(oprom[1]).c_str());
+ }
+ flags |= 4;
+ }
+ break;
+
+ case DASM_indexed_3:
+ if(oprom[1] & 0x01) {
+ if(oprom[1] == 0x01)
+ sprintf(buffer, " %s, %s, %02x%02x", regname(oprom[5]).c_str(), regname(oprom[4]).c_str(), oprom[3], oprom[2]);
+ else
+ sprintf(buffer, " %s, %s, %02x%02x[%s]", regname(oprom[5]).c_str(), regname(oprom[4]).c_str(), oprom[3], oprom[2], regname(oprom[1]-1).c_str());
+ 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]).c_str(), regname(oprom[3]).c_str(), delta & 0xffff);
+ else
+ sprintf(buffer, " %s, %s, %02x", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), delta);
+ } else {
+ if(delta < 0)
+ sprintf(buffer, " %s, %s, -%02x[%s]", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), -delta, regname(oprom[1]).c_str());
+ else
+ sprintf(buffer, " %s, %s, %02x[%s]", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), delta, regname(oprom[1]).c_str());
+ }
+ 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"