summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/upd7725
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
commitf88cefad27a1737c76e09d99c9fb43e173506081 (patch)
tree2d8167d03579c46e226471747eb4407bd00ed6fa /src/devices/cpu/upd7725
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/devices/cpu/upd7725')
-rw-r--r--src/devices/cpu/upd7725/dasm7725.c234
-rw-r--r--src/devices/cpu/upd7725/upd7725.c622
-rw-r--r--src/devices/cpu/upd7725/upd7725.h264
3 files changed, 1120 insertions, 0 deletions
diff --git a/src/devices/cpu/upd7725/dasm7725.c b/src/devices/cpu/upd7725/dasm7725.c
new file mode 100644
index 00000000000..987002412ac
--- /dev/null
+++ b/src/devices/cpu/upd7725/dasm7725.c
@@ -0,0 +1,234 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont,byuu
+/***************************************************************************
+
+ dasm7725.c
+ Disassembler for the portable uPD7725 emulator.
+ Written by byuu
+ MAME conversion by R. Belmont
+
+***************************************************************************/
+
+#include "emu.h"
+#include "upd7725.h"
+
+CPU_DISASSEMBLE( upd7725 )
+{
+ static char output[256];
+ UINT32 opcode = oprom[2] | (oprom[1] << 8) | (oprom[0] << 16);
+ UINT32 type = (opcode >> 22);
+
+// printf("dasm: PC %x opcode %08x\n", pc, opcode);
+
+ memset(output, 0, sizeof(output));
+
+ if(type == 0 || type == 1) { //OP,RT
+ UINT8 pselect = (opcode >> 20)&0x3; //P select
+ UINT8 alu = (opcode >> 16)&0xf; //ALU operation mode
+ UINT8 asl = (opcode >> 15)&0x1; //accumulator select
+ UINT8 dpl = (opcode >> 13)&0x3; //DP low modify
+ UINT8 dphm = (opcode >> 9)&0xf; //DP high XOR modify
+ UINT8 rpdcr = (opcode >> 8)&0x1; //RP decrement
+ UINT8 src = (opcode >> 4)&0xf; //move source
+ UINT8 dst = (opcode >> 0)&0xf; //move destination
+
+ switch(alu) {
+ case 0: strcat(output, "nop "); break;
+ case 1: strcat(output, "or "); break;
+ case 2: strcat(output, "and "); break;
+ case 3: strcat(output, "xor "); break;
+ case 4: strcat(output, "sub "); break;
+ case 5: strcat(output, "add "); break;
+ case 6: strcat(output, "sbb "); break;
+ case 7: strcat(output, "adc "); break;
+ case 8: strcat(output, "dec "); break;
+ case 9: strcat(output, "inc "); break;
+ case 10: strcat(output, "cmp "); break;
+ case 11: strcat(output, "shr1 "); break;
+ case 12: strcat(output, "shl1 "); break;
+ case 13: strcat(output, "shl2 "); break;
+ case 14: strcat(output, "shl4 "); break;
+ case 15: strcat(output, "xchg "); break;
+ }
+
+ if(alu < 8) {
+ switch(pselect) {
+ case 0: strcat(output, "ram,"); break;
+ case 1: strcat(output, "idb,"); break;
+ case 2: strcat(output, "m,"); break;
+ case 3: strcat(output, "n,"); break;
+ }
+ }
+
+ switch(asl) {
+ case 0: strcat(output, "a"); break;
+ case 1: strcat(output, "b"); break;
+ }
+
+ if(dst) {
+ strcat(output, " | mov ");
+
+ switch(src) {
+ case 0: strcat(output, "trb,"); break;
+ case 1: strcat(output, "a,"); break;
+ case 2: strcat(output, "b,"); break;
+ case 3: strcat(output, "tr,"); break;
+ case 4: strcat(output, "dp,"); break;
+ case 5: strcat(output, "rp,"); break;
+ case 6: strcat(output, "ro,"); break;
+ case 7: strcat(output, "sgn,"); break;
+ case 8: strcat(output, "dr,"); break;
+ case 9: strcat(output, "drnf,"); break;
+ case 10: strcat(output, "sr,"); break;
+ case 11: strcat(output, "sim,"); break;
+ case 12: strcat(output, "sil,"); break;
+ case 13: strcat(output, "k,"); break;
+ case 14: strcat(output, "l,"); break;
+ case 15: strcat(output, "mem,"); break;
+ }
+
+ switch(dst) {
+ case 0: strcat(output, "non"); break;
+ case 1: strcat(output, "a"); break;
+ case 2: strcat(output, "b"); break;
+ case 3: strcat(output, "tr"); break;
+ case 4: strcat(output, "dp"); break;
+ case 5: strcat(output, "rp"); break;
+ case 6: strcat(output, "dr"); break;
+ case 7: strcat(output, "sr"); break;
+ case 8: strcat(output, "sol"); break;
+ case 9: strcat(output, "som"); break;
+ case 10: strcat(output, "k"); break;
+ case 11: strcat(output, "klr"); break;
+ case 12: strcat(output, "klm"); break;
+ case 13: strcat(output, "l"); break;
+ case 14: strcat(output, "trb"); break;
+ case 15: strcat(output, "mem"); break;
+ }
+ }
+
+ if(dpl) {
+ switch(dpl) {
+ case 0: strcat(output, " | dpnop"); break;
+ case 1: strcat(output, " | dpinc"); break;
+ case 2: strcat(output, " | dpdec"); break;
+ case 3: strcat(output, " | dpclr"); break;
+ }
+ }
+
+ if(dphm) {
+ switch(dphm) {
+ case 0: strcat(output, " | m0"); break;
+ case 1: strcat(output, " | m1"); break;
+ case 2: strcat(output, " | m2"); break;
+ case 3: strcat(output, " | m3"); break;
+ case 4: strcat(output, " | m4"); break;
+ case 5: strcat(output, " | m5"); break;
+ case 6: strcat(output, " | m6"); break;
+ case 7: strcat(output, " | m7"); break;
+ case 8: strcat(output, " | m8"); break;
+ case 9: strcat(output, " | m9"); break;
+ case 10: strcat(output, " | ma"); break;
+ case 11: strcat(output, " | mb"); break;
+ case 12: strcat(output, " | mc"); break;
+ case 13: strcat(output, " | md"); break;
+ case 14: strcat(output, " | me"); break;
+ case 15: strcat(output, " | mf"); break;
+ }
+ }
+
+ if(rpdcr == 1) {
+ strcat(output, " | rpdec");
+ }
+
+ if(type == 1) {
+ strcat(output, " | ret");
+ }
+ }
+
+ if(type == 2) { //JP
+ UINT16 brch = (opcode >> 13) & 0x1ff; //branch
+ UINT16 na = (opcode >> 2) & 0x7ff; //next address
+
+ switch(brch) {
+ case 0x000: strcat(output, "jmpso "); break;
+ case 0x080: strcat(output, "jnca "); break;
+ case 0x082: strcat(output, "jca "); break;
+ case 0x084: strcat(output, "jncb "); break;
+ case 0x086: strcat(output, "jcb "); break;
+ case 0x088: strcat(output, "jnza "); break;
+ case 0x08a: strcat(output, "jza "); break;
+ case 0x08c: strcat(output, "jnzb "); break;
+ case 0x08e: strcat(output, "jzb "); break;
+ case 0x090: strcat(output, "jnova0 "); break;
+ case 0x092: strcat(output, "jova0 "); break;
+ case 0x094: strcat(output, "jnovb0 "); break;
+ case 0x096: strcat(output, "jovb0 "); break;
+ case 0x098: strcat(output, "jnova1 "); break;
+ case 0x09a: strcat(output, "jova1 "); break;
+ case 0x09c: strcat(output, "jnovb1 "); break;
+ case 0x09e: strcat(output, "jovb1 "); break;
+ case 0x0a0: strcat(output, "jnsa0 "); break;
+ case 0x0a2: strcat(output, "jsa0 "); break;
+ case 0x0a4: strcat(output, "jnsb0 "); break;
+ case 0x0a6: strcat(output, "jsb0 "); break;
+ case 0x0a8: strcat(output, "jnsa1 "); break;
+ case 0x0aa: strcat(output, "jsa1 "); break;
+ case 0x0ac: strcat(output, "jnsb1 "); break;
+ case 0x0ae: strcat(output, "jsb1 "); break;
+ case 0x0b0: strcat(output, "jdpl0 "); break;
+ case 0x0b1: strcat(output, "jdpln0 "); break;
+ case 0x0b2: strcat(output, "jdplf "); break;
+ case 0x0b3: strcat(output, "jdplnf "); break;
+ case 0x0b4: strcat(output, "jnsiak "); break;
+ case 0x0b6: strcat(output, "jsiak "); break;
+ case 0x0b8: strcat(output, "jnsoak "); break;
+ case 0x0ba: strcat(output, "jsoak "); break;
+ case 0x0bc: strcat(output, "jnrqm "); break;
+ case 0x0be: strcat(output, "jrqm "); break;
+ case 0x100: strcat(output, "ljmp "); break;
+ case 0x101: strcat(output, "hjmp "); break;
+ case 0x140: strcat(output, "lcall "); break;
+ case 0x141: strcat(output, "hcall "); break;
+ default: strcat(output, "?????? "); break;
+ }
+
+ char temp[16];
+
+ sprintf(temp, "$%x", na);
+ strcat(output, temp);
+ }
+
+ if(type == 3) { //LD
+ strcat(output, "ld ");
+ UINT16 id = opcode >> 6;
+ UINT8 dst = (opcode >> 0) & 0xf; //destination
+
+ char temp[16];
+ sprintf(temp, "$%x,", id);
+ strcat(output, temp);
+
+ switch(dst) {
+ case 0: strcat(output, "non"); break;
+ case 1: strcat(output, "a"); break;
+ case 2: strcat(output, "b"); break;
+ case 3: strcat(output, "tr"); break;
+ case 4: strcat(output, "dp"); break;
+ case 5: strcat(output, "rp"); break;
+ case 6: strcat(output, "dr"); break;
+ case 7: strcat(output, "sr"); break;
+ case 8: strcat(output, "sol"); break;
+ case 9: strcat(output, "som"); break;
+ case 10: strcat(output, "k"); break;
+ case 11: strcat(output, "klr"); break;
+ case 12: strcat(output, "klm"); break;
+ case 13: strcat(output, "l"); break;
+ case 14: strcat(output, "trb"); break;
+ case 15: strcat(output, "mem"); break;
+ }
+ }
+
+ strcpy(buffer, output);
+
+ return 1 | DASMFLAG_SUPPORTED;
+}
diff --git a/src/devices/cpu/upd7725/upd7725.c b/src/devices/cpu/upd7725/upd7725.c
new file mode 100644
index 00000000000..d422eae21b0
--- /dev/null
+++ b/src/devices/cpu/upd7725/upd7725.c
@@ -0,0 +1,622 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont,byuu
+/***************************************************************************
+
+ upd7725.c
+
+ Core implementation for the portable NEC uPD7725/uPD96050 emulator
+
+ Original by byuu in the public domain.
+ MAME conversion by R. Belmont
+
+****************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "upd7725.h"
+
+
+//**************************************************************************
+// DEVICE INTERFACE
+//**************************************************************************
+
+// device type definition
+const device_type UPD7725 = &device_creator<upd7725_device>;
+const device_type UPD96050 = &device_creator<upd96050_device>;
+
+necdsp_device::necdsp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, UINT32 abits, UINT32 dbits, const char *name, const char *shortname, const char *source)
+ : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_program_config("program", ENDIANNESS_BIG, 32, abits, -2), // data bus width, address bus width, -2 means DWORD-addressable
+ m_data_config("data", ENDIANNESS_BIG, 16, dbits, -1), // -1 for WORD-addressable
+ m_irq(0),
+ m_program(NULL),
+ m_data(NULL),
+ m_direct(NULL),
+ m_in_int_cb(*this),
+ //m_in_si_cb(*this),
+ //m_in_sck_cb(*this),
+ //m_in_sien_cb(*this),
+ //m_in_soen_cb(*this),
+ //m_in_dack_cb(*this),
+ m_out_p0_cb(*this),
+ m_out_p1_cb(*this)
+ //m_out_so_cb(*this),
+ //m_out_sorq_cb(*this),
+ //m_out_drq_cb(*this)
+{
+}
+
+
+upd7725_device::upd7725_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : necdsp_device(mconfig, UPD7725, tag, owner, clock, 11, 11, "uPD7725", "upd7725", __FILE__)
+{
+}
+
+upd96050_device::upd96050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : necdsp_device(mconfig, UPD96050, tag, owner, clock, 14, 12, "uPD96050", "upd96050", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - start up the device
+//-------------------------------------------------
+
+void necdsp_device::device_start()
+{
+ // get our address spaces
+ m_program = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ m_direct = &m_program->direct();
+
+ // register our state for the debugger
+ std::string tempstr;
+ state_add(STATE_GENPC, "GENPC", regs.pc).noshow();
+ state_add(UPD7725_PC, "PC", regs.pc);
+ state_add(UPD7725_RP, "RP", regs.rp);
+ state_add(UPD7725_DP, "DP", regs.dp);
+ state_add(UPD7725_SP, "SP", regs.sp);
+ state_add(UPD7725_K, "K", regs.k);
+ state_add(UPD7725_L, "L", regs.l);
+ state_add(UPD7725_M, "M", regs.m);
+ state_add(UPD7725_N, "N", regs.n);
+ state_add(UPD7725_A, "A", regs.a);
+ state_add(UPD7725_B, "B", regs.b);
+ state_add(UPD7725_TR, "TR", regs.tr);
+ state_add(UPD7725_TRB, "TRB", regs.trb);
+ state_add(UPD7725_DR, "DR", regs.dr);
+ state_add(UPD7725_SI, "SI", regs.si);
+ state_add(UPD7725_SO, "SO", regs.so);
+ state_add(UPD7725_IDB, "IDB", regs.idb);
+
+ // resolve callbacks
+ m_in_int_cb.resolve_safe(0);
+ //m_in_si_cb.resolve_safe(0);
+ //m_in_sck_cb.resolve_safe(0);
+ //m_in_sien_cb.resolve_safe(0);
+ //m_in_soen_cb.resolve_safe(0);
+ //m_in_dack_cb.resolve_safe(0);
+ m_out_p0_cb.resolve_safe();
+ m_out_p1_cb.resolve_safe();
+ //m_out_so_cb.resolve_safe();
+ //m_out_sorq_cb.resolve_safe();
+ //m_out_drq_cb.resolve_safe();
+
+ // save state registrations
+ save_item(NAME(regs.pc));
+ save_item(NAME(regs.rp));
+ save_item(NAME(regs.dp));
+ save_item(NAME(regs.sp));
+ save_item(NAME(regs.k));
+ save_item(NAME(regs.l));
+ save_item(NAME(regs.m));
+ save_item(NAME(regs.n));
+ save_item(NAME(regs.a));
+ save_item(NAME(regs.b));
+ save_item(NAME(regs.tr));
+ save_item(NAME(regs.trb));
+ save_item(NAME(regs.dr));
+ save_item(NAME(regs.so));
+ save_item(NAME(regs.idb));
+ save_item(NAME(regs.sr.rqm));
+ save_item(NAME(regs.sr.usf0));
+ save_item(NAME(regs.sr.usf1));
+ save_item(NAME(regs.sr.drs));
+ save_item(NAME(regs.sr.dma));
+ save_item(NAME(regs.sr.drc));
+ save_item(NAME(regs.sr.soc));
+ save_item(NAME(regs.sr.sic));
+ save_item(NAME(regs.sr.ei));
+ save_item(NAME(regs.sr.p0));
+ save_item(NAME(regs.sr.p1));
+ save_item(NAME(regs.stack));
+ save_item(NAME(dataRAM));
+
+ m_icountptr = &m_icount;
+}
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void necdsp_device::device_reset()
+{
+ for (unsigned i = 0; i < 2048; i++)
+ {
+ dataRAM[i] = 0x0000;
+ }
+
+ regs.pc = 0x0000;
+ regs.rp = 0x0000;
+ regs.dp = 0x0000;
+ regs.sp = 0x0;
+ regs.k = 0x0000;
+ regs.l = 0x0000;
+ regs.m = 0x0000;
+ regs.n = 0x0000;
+ regs.a = 0x0000;
+ regs.b = 0x0000;
+ regs.flaga = 0x00;
+ regs.flagb = 0x00;
+ regs.tr = 0x0000;
+ regs.trb = 0x0000;
+ regs.sr = 0x0000;
+ regs.dr = 0x0000;
+ regs.si = 0x0000;
+ regs.so = 0x0000;
+ regs.idb = 0x0000;
+}
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the specified address space, or NULL if
+// the space doesn't exist
+//-------------------------------------------------
+
+const address_space_config *necdsp_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_PROGRAM) ? &m_program_config : &m_data_config;
+}
+
+
+//-------------------------------------------------
+// state_import - import state into the device,
+// after it has been set
+//-------------------------------------------------
+
+void necdsp_device::state_import(const device_state_entry &entry)
+{
+}
+
+
+//-------------------------------------------------
+// state_export - export state from the device,
+// to a known location where it can be read
+//-------------------------------------------------
+
+void necdsp_device::state_export(const device_state_entry &entry)
+{
+}
+
+
+//-------------------------------------------------
+// state_string_export - export state as a string
+// for the debugger
+//-------------------------------------------------
+
+void necdsp_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case UPD7725_FLAGA:
+ strprintf(str, "%s %s %c%c %s %s %s %s",
+ regs.flaga.s1 ? "S1" : "s1",
+ regs.flaga.s0 ? "S0" : "s0",
+ regs.flaga.c ? 'C' : 'c',
+ regs.flaga.z ? 'Z' : 'z',
+ regs.flaga.ov1 ? "OV1" : "ov1",
+ regs.flaga.ov0 ? "OV0" : "ov0",
+ regs.flaga.ov0p ? "OV0P" : "ov0p",
+ regs.flaga.ov0pp ? "OV0PP" : "ov0pp");
+ break;
+
+ case UPD7725_FLAGB:
+ strprintf(str, "%s %s %c%c %s %s %s %s",
+ regs.flagb.s1 ? "S1" : "s1",
+ regs.flagb.s0 ? "S0" : "s0",
+ regs.flagb.c ? 'C' : 'c',
+ regs.flagb.z ? 'Z' : 'z',
+ regs.flagb.ov1 ? "OV1" : "ov1",
+ regs.flagb.ov0 ? "OV0" : "ov0",
+ regs.flagb.ov0p ? "OV0P" : "ov0p",
+ regs.flagb.ov0pp ? "OV0PP" : "ov0pp");
+ break;
+ }
+}
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+UINT32 necdsp_device::execute_min_cycles() const
+{
+ return 4;
+}
+
+
+//-------------------------------------------------
+// execute_max_cycles - return maximum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+UINT32 necdsp_device::execute_max_cycles() const
+{
+ return 4;
+}
+
+
+//-------------------------------------------------
+// execute_input_lines - return the number of
+// input/interrupt lines
+//-------------------------------------------------
+
+UINT32 necdsp_device::execute_input_lines() const
+{
+ return 3; // TODO: there should be 11: INT, SCK, /SIEN, /SOEN, SI, and /DACK, plus SO, /SORQ and DRQ; for now, just INT, P0, and P1 are enough.
+}
+
+
+//-------------------------------------------------
+// execute_set_input -
+//-------------------------------------------------
+
+void necdsp_device::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case NECDSP_INPUT_LINE_INT:
+ //TODO: detect rising edge; if rising edge found AND IE = 1, push PC, pc = 0x100; else do nothing
+ m_irq = state; // set old state to current state
+ break;
+ // add more when needed
+ }
+}
+
+//-------------------------------------------------
+// disasm_min_opcode_bytes - return the length
+// of the shortest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 necdsp_device::disasm_min_opcode_bytes() const
+{
+ return 4;
+}
+
+
+//-------------------------------------------------
+// disasm_max_opcode_bytes - return the length
+// of the longest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 necdsp_device::disasm_max_opcode_bytes() const
+{
+ return 4;
+}
+
+//-------------------------------------------------
+// disasm_disassemble - call the disassembly
+// helper function
+//-------------------------------------------------
+
+offs_t necdsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( upd7725 );
+ return CPU_DISASSEMBLE_NAME(upd7725)(this, buffer, pc, oprom, opram, options);
+}
+
+void necdsp_device::execute_run()
+{
+ UINT32 opcode;
+
+ do
+ {
+ // call debugger hook if necessary
+ if (device_t::machine().debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debugger_instruction_hook(this, regs.pc);
+ }
+
+ opcode = m_direct->read_dword(regs.pc<<2)>>8;
+ regs.pc++;
+ switch(opcode >> 22)
+ {
+ case 0: exec_op(opcode); break;
+ case 1: exec_rt(opcode); break;
+ case 2: exec_jp(opcode); break;
+ case 3: exec_ld(opcode); break;
+ }
+
+ INT32 result = (INT32)regs.k * regs.l; //sign + 30-bit result
+ regs.m = result >> 15; //store sign + top 15-bits
+ regs.n = result << 1; //store low 15-bits + zero
+
+ m_icount--;
+
+ } while (m_icount > 0);
+}
+
+void necdsp_device::exec_op(UINT32 opcode) {
+ UINT8 pselect = (opcode >> 20)&0x3; //P select
+ UINT8 alu = (opcode >> 16)&0xf; //ALU operation mode
+ UINT8 asl = (opcode >> 15)&0x1; //accumulator select
+ UINT8 dpl = (opcode >> 13)&0x3; //DP low modify
+ UINT8 dphm = (opcode >> 9)&0xf; //DP high XOR modify
+ UINT8 rpdcr = (opcode >> 8)&0x1; //RP decrement
+ UINT8 src = (opcode >> 4)&0xf; //move source
+ UINT8 dst = (opcode >> 0)&0xf; //move destination
+
+ switch(src) {
+ case 0: regs.idb = regs.trb; break;
+ case 1: regs.idb = regs.a; break;
+ case 2: regs.idb = regs.b; break;
+ case 3: regs.idb = regs.tr; break;
+ case 4: regs.idb = regs.dp; break;
+ case 5: regs.idb = regs.rp; break;
+ case 6: regs.idb = m_data->read_word(regs.rp<<1); break;
+ case 7: regs.idb = 0x8000 - regs.flaga.s1; break; //SGN
+ case 8: regs.idb = regs.dr; regs.sr.rqm = 1; break;
+ case 9: regs.idb = regs.dr; break;
+ case 10: regs.idb = regs.sr; break;
+ case 11: regs.idb = regs.si; break; //MSB
+ case 12: regs.idb = regs.si; break; //LSB
+ case 13: regs.idb = regs.k; break;
+ case 14: regs.idb = regs.l; break;
+ case 15: regs.idb = dataRAM[regs.dp]; break;
+ }
+
+ if(alu) {
+ UINT16 p=0, q=0, r=0;
+ Flag flag;
+ bool c=0;
+
+ flag.c = 0;
+ flag.s1 = 0;
+ flag.ov0 = 0;
+ flag.ov1 = 0;
+ flag.ov0p = 0;
+ flag.ov0pp = 0;
+
+ switch(pselect) {
+ case 0: p = dataRAM[regs.dp]; break;
+ case 1: p = regs.idb; break;
+ case 2: p = regs.m; break;
+ case 3: p = regs.n; break;
+ }
+
+ switch(asl) {
+ case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
+ case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
+ }
+
+ switch(alu) {
+ case 1: r = q | p; break; //OR
+ case 2: r = q & p; break; //AND
+ case 3: r = q ^ p; break; //XOR
+ case 4: r = q - p; break; //SUB
+ case 5: r = q + p; break; //ADD
+ case 6: r = q - p - c; break; //SBB
+ case 7: r = q + p + c; break; //ADC
+ case 8: r = q - 1; p = 1; break; //DEC
+ case 9: r = q + 1; p = 1; break; //INC
+ case 10: r = ~q; break; //CMP
+ case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR)
+ case 12: r = (q << 1) | (c ? 1 : 0); break; //SHL1 (ROL)
+ case 13: r = (q << 2) | 3; break; //SHL2
+ case 14: r = (q << 4) | 15; break; //SHL4
+ case 15: r = (q << 8) | (q >> 8); break; //XCHG
+ }
+
+ flag.s0 = (r & 0x8000);
+ flag.z = (r == 0);
+ flag.ov0pp = flag.ov0p;
+ flag.ov0p = flag.ov0;
+
+ switch(alu) {
+ case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
+ flag.c = 0;
+ flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero
+ break;
+ }
+ case 4: case 5: case 6: case 7: case 8: case 9: {
+ if(alu & 1) {
+ //addition
+ flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
+ flag.c = (r < q);
+ } else {
+ //subtraction
+ flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
+ flag.c = (r > q);
+ }
+ break;
+ }
+ case 11: {
+ flag.c = q & 1;
+ flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero
+ break;
+ }
+ case 12: {
+ flag.c = q >> 15;
+ flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero
+ break;
+ }
+ }
+ // flag.ov1 is only set if the number of overflows of the past 3 opcodes (of type 4,5,6,7,8,9) is odd
+ flag.ov1 = (flag.ov0 + flag.ov0p + flag.ov0pp) & 1;
+ // flag.s1 is based on ov1: s1 = ov1 ^ s0;
+ flag.s1 = flag.ov1 ^ flag.s0;
+
+ switch(asl) {
+ case 0: regs.a = r; regs.flaga = flag; break;
+ case 1: regs.b = r; regs.flagb = flag; break;
+ }
+ }
+
+ exec_ld((regs.idb << 6) + dst);
+
+ switch(dpl) {
+ case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
+ case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
+ case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
+ }
+
+ regs.dp ^= dphm << 4;
+
+ if(rpdcr) regs.rp--;
+}
+
+void necdsp_device::exec_rt(UINT32 opcode) {
+ exec_op(opcode);
+ regs.pc = regs.stack[--regs.sp];
+ regs.sp &= 0xf;
+}
+
+void necdsp_device::exec_jp(UINT32 opcode) {
+ UINT16 brch = (opcode >> 13) & 0x1ff; //branch
+ UINT16 na = (opcode >> 2) & 0x7ff; //next address
+ UINT16 bank = (opcode >> 0) & 0x3; //bank address
+
+ UINT16 jps = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
+ UINT16 jpl = (bank << 11) | (na << 0);
+
+ switch(brch) {
+ case 0x000: regs.pc = regs.so; return; //JMPSO
+
+ case 0x080: if(regs.flaga.c == 0) regs.pc = jps; return; //JNCA
+ case 0x082: if(regs.flaga.c == 1) regs.pc = jps; return; //JCA
+ case 0x084: if(regs.flagb.c == 0) regs.pc = jps; return; //JNCB
+ case 0x086: if(regs.flagb.c == 1) regs.pc = jps; return; //JCB
+
+ case 0x088: if(regs.flaga.z == 0) regs.pc = jps; return; //JNZA
+ case 0x08a: if(regs.flaga.z == 1) regs.pc = jps; return; //JZA
+ case 0x08c: if(regs.flagb.z == 0) regs.pc = jps; return; //JNZB
+ case 0x08e: if(regs.flagb.z == 1) regs.pc = jps; return; //JZB
+
+ case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jps; return; //JNOVA0
+ case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jps; return; //JOVA0
+ case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jps; return; //JNOVB0
+ case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jps; return; //JOVB0
+
+ case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jps; return; //JNOVA1
+ case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jps; return; //JOVA1
+ case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jps; return; //JNOVB1
+ case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jps; return; //JOVB1
+
+ case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jps; return; //JNSA0
+ case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jps; return; //JSA0
+ case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jps; return; //JNSB0
+ case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jps; return; //JSB0
+
+ case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jps; return; //JNSA1
+ case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jps; return; //JSA1
+ case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jps; return; //JNSB1
+ case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jps; return; //JSB1
+
+ case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jps; return; //JDPL0
+ case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jps; return; //JDPLN0
+ case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jps; return; //JDPLF
+ case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jps; return; //JDPLNF
+
+ case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jps; return; //JNRQM
+ case 0x0be: if(regs.sr.rqm == 1) regs.pc = jps; return; //JRQM
+
+ case 0x100: regs.pc = 0x0000 | jpl; return; //LJMP
+ case 0x101: regs.pc = 0x2000 | jpl; return; //HJMP
+
+ case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x0000 | jpl; regs.sp &= 0xf; return; //LCALL
+ case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x2000 | jpl; regs.sp &= 0xf; return; //HCALL
+ }
+}
+
+void necdsp_device::exec_ld(UINT32 opcode) {
+ UINT16 id = opcode >> 6; //immediate data
+ UINT8 dst = (opcode >> 0) & 0xf; //destination
+
+ regs.idb = id;
+
+ switch(dst) {
+ case 0: break;
+ case 1: regs.a = id; break;
+ case 2: regs.b = id; break;
+ case 3: regs.tr = id; break;
+ case 4: regs.dp = id; break;
+ case 5: regs.rp = id; break;
+ case 6: regs.dr = id; regs.sr.rqm = 1; break;
+ case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c);
+ m_out_p0_cb(regs.sr&0x1);
+ m_out_p1_cb((regs.sr&0x2)>>1);
+ break;
+ case 8: regs.so = id; break; //LSB
+ case 9: regs.so = id; break; //MSB
+ case 10: regs.k = id; break;
+ case 11: regs.k = id; regs.l = m_data->read_word(regs.rp<<1); break;
+ case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
+ case 13: regs.l = id; break;
+ case 14: regs.trb = id; break;
+ case 15: dataRAM[regs.dp] = id; break;
+ }
+}
+
+UINT8 necdsp_device::snesdsp_read(bool mode) {
+ if (!mode)
+ {
+ return regs.sr >> 8;
+ }
+
+ if (regs.sr.drc == 0)
+ {
+ //16-bit
+ if(regs.sr.drs == 0)
+ {
+ regs.sr.drs = 1;
+ return regs.dr >> 0;
+ }
+ else
+ {
+ regs.sr.rqm = 0;
+ regs.sr.drs = 0;
+ return regs.dr >> 8;
+ }
+ }
+ else
+ {
+ //8-bit
+ regs.sr.rqm = 0;
+ return regs.dr >> 0;
+ }
+}
+
+void necdsp_device::snesdsp_write(bool mode, UINT8 data) {
+ if (!mode) return;
+
+ if (regs.sr.drc == 0)
+ {
+ //16-bit
+ if (regs.sr.drs == 0)
+ {
+ regs.sr.drs = 1;
+ regs.dr = (regs.dr & 0xff00) | (data << 0);
+ }
+ else
+ {
+ regs.sr.rqm = 0;
+ regs.sr.drs = 0;
+ regs.dr = (data << 8) | (regs.dr & 0x00ff);
+ }
+ }
+ else
+ {
+ //8-bit
+ regs.sr.rqm = 0;
+ regs.dr = (regs.dr & 0xff00) | (data << 0);
+ }
+}
diff --git a/src/devices/cpu/upd7725/upd7725.h b/src/devices/cpu/upd7725/upd7725.h
new file mode 100644
index 00000000000..d10094073c3
--- /dev/null
+++ b/src/devices/cpu/upd7725/upd7725.h
@@ -0,0 +1,264 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont,byuu
+/***************************************************************************
+
+ upd7725.h
+
+ Core implementation for the portable NEC uPD7725/uPD96050 emulator
+
+****************************************************************************/
+
+#pragma once
+
+#ifndef __UPD7725_H__
+#define __UPD7725_H__
+
+//**************************************************************************
+// ENUMERATIONS
+//**************************************************************************
+
+// input lines
+enum
+{
+ NECDSP_INPUT_LINE_INT = 0
+ // add more here as needed
+};
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class necdsp_device;
+class upd7725_device;
+class upd96050_device;
+
+
+#define MCFG_NECDSP_IN_INT_CB(_devcb) \
+ devcb = &necdsp_device::set_in_int_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_IN_SI_CB(_devcb) \
+ devcb = &necdsp_device::set_in_si_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_IN_SCK_CB(_devcb) \
+ devcb = &necdsp_device::set_in_sck_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_IN_SIEN_CB(_devcb) \
+ devcb = &necdsp_device::set_in_sien_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_IN_SOEN_CB(_devcb) \
+ devcb = &necdsp_device::set_in_soen_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_IN_DACK_CB(_devcb) \
+ devcb = &necdsp_device::set_in_dack_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_OUT_P0_CB(_devcb) \
+ devcb = &necdsp_device::set_out_p0_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_OUT_P1_CB(_devcb) \
+ devcb = &necdsp_device::set_out_p1_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_OUT_SO_CB(_devcb) \
+ devcb = &necdsp_device::set_out_so_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_OUT_SORQ_CB(_devcb) \
+ devcb = &necdsp_device::set_out_sorq_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_NECDSP_OUT_DRQ_CB(_devcb) \
+ devcb = &necdsp_device::set_out_drq_callback(*device, DEVCB_##_devcb);
+
+
+// ======================> necdsp_device
+
+class necdsp_device : public cpu_device
+{
+protected:
+ // construction/destruction
+ necdsp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, UINT32 abits, UINT32 dbits, const char *name, const char *shortname, const char *source);
+
+public:
+
+ template<class _Object> static devcb_base &set_in_int_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_int_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_in_si_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_si_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_in_sck_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_sck_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_in_sien_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_sien_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_in_soen_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_soen_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_in_dack_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_in_dack_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_out_p0_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_out_p0_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_out_p1_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_out_p1_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_out_so_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_out_so_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_out_sorq_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_out_sorq_cb.set_callback(object); }
+ //template<class _Object> static devcb_base &set_out_drq_callback(device_t &device, _Object object) { return downcast<necdsp_device &>(device).m_out_drq_cb.set_callback(object); }
+
+ UINT8 snesdsp_read(bool mode);
+ void snesdsp_write(bool mode, UINT8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_execute_interface overrides
+ virtual UINT32 execute_min_cycles() const;
+ virtual UINT32 execute_max_cycles() const;
+ virtual UINT32 execute_input_lines() const;
+ virtual void execute_run();
+ virtual void execute_set_input(int inputnum, int state);
+
+ // device_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // device_state_interface overrides
+ virtual void state_import(const device_state_entry &entry);
+ virtual void state_export(const device_state_entry &entry);
+ virtual void state_string_export(const device_state_entry &entry, std::string &str);
+
+ // device_disasm_interface overrides
+ virtual UINT32 disasm_min_opcode_bytes() const;
+ virtual UINT32 disasm_max_opcode_bytes() const;
+ virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
+
+ // inline data
+ const address_space_config m_program_config, m_data_config;
+
+ UINT16 dataRAM[2048];
+
+private:
+ struct Flag
+ {
+ bool s1, s0, c, z, ov1, ov0, ov0p, ov0pp;
+
+ inline operator unsigned() const
+ {
+ return (s1 << 7) + (s0 << 6) + (c << 5) + (z << 4) + (ov1 << 3) + (ov0 << 2) + (ov0p << 1) + (ov0pp << 0);
+ }
+
+ inline unsigned operator=(unsigned d)
+ {
+ s1 = d & 0x80; s0 = d & 0x40; c = d & 0x20; z = d & 0x10; ov1 = d & 0x08; ov0 = d & 0x04; ov0p = d & 0x02; ov0pp = d & 0x01;
+ return d;
+ }
+ };
+
+ struct Status
+ {
+ bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0;
+
+ inline operator unsigned() const
+ {
+ return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12)
+ + (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8)
+ + (ei << 7) + (p1 << 1) + (p0 << 0);
+ }
+
+ inline unsigned operator=(unsigned d)
+ {
+ rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000;
+ dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100;
+ ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001;
+ return d;
+ }
+ };
+
+ struct Regs
+ {
+ UINT16 pc; //program counter
+ UINT16 stack[16]; //LIFO
+ UINT16 rp; //ROM pointer
+ UINT16 dp; //data pointer
+ UINT8 sp; //stack pointer
+ INT16 k;
+ INT16 l;
+ INT16 m;
+ INT16 n;
+ INT16 a; //accumulator
+ INT16 b; //accumulator
+ Flag flaga;
+ Flag flagb;
+ UINT16 tr; //temporary register
+ UINT16 trb; //temporary register
+ Status sr; //status register
+ UINT16 dr; //data register
+ UINT16 si;
+ UINT16 so;
+ UINT16 idb;
+ } regs;
+
+ void exec_op(UINT32 opcode);
+ void exec_rt(UINT32 opcode);
+ void exec_jp(UINT32 opcode);
+ void exec_ld(UINT32 opcode);
+
+ void stack_push();
+ void stack_pull();
+
+ int m_icount;
+ int m_irq; // old irq line state, for detecting rising edges.
+
+ address_space *m_program, *m_data;
+ direct_read_data *m_direct;
+
+protected:
+// device callbacks
+ devcb_read_line m_in_int_cb;
+ //devcb_read8 m_in_si_cb;
+ //devcb_read_line m_in_sck_cb;
+ //devcb_read_line m_in_sien_cb;
+ //devcb_read_line m_in_soen_cb;
+ //devcb_read_line m_in_dack_cb;
+ devcb_write_line m_out_p0_cb;
+ devcb_write_line m_out_p1_cb;
+ //devcb_write8 m_out_so_cb;
+ //devcb_write_line m_out_sorq_cb;
+ //devcb_write_line m_out_drq_cb;
+};
+
+class upd7725_device : public necdsp_device
+{
+public:
+ // construction/destruction
+ upd7725_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class upd96050_device : public necdsp_device
+{
+public:
+ // construction/destruction
+ upd96050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ UINT16 dataram_r(UINT16 addr) { return dataRAM[addr]; }
+ void dataram_w(UINT16 addr, UINT16 data) { dataRAM[addr] = data; }
+};
+
+// device type definition
+extern const device_type UPD7725;
+extern const device_type UPD96050;
+
+//**************************************************************************
+// ENUMERATIONS
+//**************************************************************************
+
+// registers
+enum
+{
+ UPD7725_PC = 1,
+ UPD7725_RP,
+ UPD7725_DP,
+ UPD7725_K,
+ UPD7725_L,
+ UPD7725_M,
+ UPD7725_N,
+ UPD7725_A,
+ UPD7725_B,
+ UPD7725_FLAGA,
+ UPD7725_FLAGB,
+ UPD7725_SR,
+ UPD7725_DR,
+ UPD7725_SP,
+ UPD7725_TR,
+ UPD7725_TRB,
+ UPD7725_SI,
+ UPD7725_SO,
+ UPD7725_IDB
+};
+
+#endif /* __UPD7725_H__ */