summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/i4004/4004dasm.cpp133
-rw-r--r--src/devices/cpu/i4004/i4004.cpp529
-rw-r--r--src/devices/cpu/i4004/i4004.h107
-rw-r--r--src/devices/cpu/mcs40/mcs40.cpp1022
-rw-r--r--src/devices/cpu/mcs40/mcs40.h307
-rw-r--r--src/devices/cpu/mcs40/mcs40dasm.cpp189
-rw-r--r--src/mame/drivers/4004clk.cpp133
-rw-r--r--src/mame/drivers/busicom.cpp27
-rw-r--r--src/mame/drivers/flicker.cpp83
-rw-r--r--src/mame/includes/busicom.h24
-rw-r--r--src/tools/unidasm.cpp2
11 files changed, 1638 insertions, 918 deletions
diff --git a/src/devices/cpu/i4004/4004dasm.cpp b/src/devices/cpu/i4004/4004dasm.cpp
deleted file mode 100644
index 09cef4a9873..00000000000
--- a/src/devices/cpu/i4004/4004dasm.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
-/*****************************************************************************
- *
- * 4004dasm.c
- *
- * Intel 4004 CPU Disassembly
- *
- *****************************************************************************/
-
-#include "emu.h"
-
-#define OP(A) oprom[(A) - PC]
-#define ARG(A) opram[(A) - PC]
-
-CPU_DISASSEMBLE(i4004)
-{
- uint32_t flags = 0;
- uint8_t op;
- unsigned PC = pc;
- uint16_t page = PC & 0x0f00;
- switch (op = OP(pc++))
- {
- case 0x00: util::stream_format(stream, "nop"); break;
- case 0x11: util::stream_format(stream, "jnt $%03x",page | ARG(pc)); pc++; break;
- case 0x12: util::stream_format(stream, "jc $%03x",page | ARG(pc)); pc++; break;
- case 0x14: util::stream_format(stream, "jz $%03x",page | ARG(pc)); pc++; break;
- case 0x19: util::stream_format(stream, "jt $%03x",page | ARG(pc)); pc++; break;
- case 0x1a: util::stream_format(stream, "jnc $%03x",page | ARG(pc)); pc++; break;
- case 0x1c: util::stream_format(stream, "jnz $%03x",page | ARG(pc)); pc++; break;
- case 0x10: case 0x13: case 0x15: case 0x16:
- case 0x17: case 0x18: case 0x1b: case 0x1d:
- case 0x1e: case 0x1f:
- util::stream_format(stream, "jcn $%01x,$%03x",op & 0x0f,page | ARG(pc)); pc++; break;
- case 0x20: case 0x22: case 0x24: case 0x26:
- case 0x28: case 0x2a: case 0x2c: case 0x2e:
- util::stream_format(stream, "fim $%01x,$%02x",op & 0x0f,OP(pc)); pc++; break;
- case 0x21: case 0x23: case 0x25: case 0x27:
- case 0x29: case 0x2b: case 0x2d: case 0x2f:
- util::stream_format(stream, "src $%01x",(op & 0x0f)-1); break;
- case 0x30: case 0x32: case 0x34: case 0x36:
- case 0x38: case 0x3a: case 0x3c: case 0x3e:
- util::stream_format(stream, "fin $%01x",op & 0x0f); break;
- case 0x31: case 0x33: case 0x35: case 0x37:
- case 0x39: case 0x3b: case 0x3d: case 0x3f:
- util::stream_format(stream, "jin $%01x",(op & 0x0f)-1); break;
- case 0x40: case 0x41: case 0x42: case 0x43:
- case 0x44: case 0x45: case 0x46: case 0x47:
- case 0x48: case 0x49: case 0x4a: case 0x4b:
- case 0x4c: case 0x4d: case 0x4e: case 0x4f:
- util::stream_format(stream, "jun $%01x%02x",op & 0x0f,ARG(pc)); pc++; break;
- case 0x50: case 0x51: case 0x52: case 0x53:
- case 0x54: case 0x55: case 0x56: case 0x57:
- case 0x58: case 0x59: case 0x5a: case 0x5b:
- case 0x5c: case 0x5d: case 0x5e: case 0x5f:
- util::stream_format(stream, "jms $%01x%02x",op & 0x0f,ARG(pc)); pc++; break;
- case 0x60: case 0x61: case 0x62: case 0x63:
- case 0x64: case 0x65: case 0x66: case 0x67:
- case 0x68: case 0x69: case 0x6a: case 0x6b:
- case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- util::stream_format(stream, "inc $%01x",op & 0x0f); break;
- case 0x70: case 0x71: case 0x72: case 0x73:
- case 0x74: case 0x75: case 0x76: case 0x77:
- case 0x78: case 0x79: case 0x7a: case 0x7b:
- case 0x7c: case 0x7d: case 0x7e: case 0x7f:
- util::stream_format(stream, "isz $%01x,%03x",op & 0x0f,page | ARG(pc)); pc++; break;
- case 0x80: case 0x81: case 0x82: case 0x83:
- case 0x84: case 0x85: case 0x86: case 0x87:
- case 0x88: case 0x89: case 0x8a: case 0x8b:
- case 0x8c: case 0x8d: case 0x8e: case 0x8f:
- util::stream_format(stream, "add $%01x",op & 0x0f); break;
- case 0x90: case 0x91: case 0x92: case 0x93:
- case 0x94: case 0x95: case 0x96: case 0x97:
- case 0x98: case 0x99: case 0x9a: case 0x9b:
- case 0x9c: case 0x9d: case 0x9e: case 0x9f:
- util::stream_format(stream, "sub $%01x",op & 0x0f); break;
- case 0xa0: case 0xa1: case 0xa2: case 0xa3:
- case 0xa4: case 0xa5: case 0xa6: case 0xa7:
- case 0xa8: case 0xa9: case 0xaa: case 0xab:
- case 0xac: case 0xad: case 0xae: case 0xaf:
- util::stream_format(stream, "ld $%01x",op & 0x0f); break;
- case 0xb0: case 0xb1: case 0xb2: case 0xb3:
- case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb:
- case 0xbc: case 0xbd: case 0xbe: case 0xbf:
- util::stream_format(stream, "xch $%01x",op & 0x0f); break;
- case 0xc0: case 0xc1: case 0xc2: case 0xc3:
- case 0xc4: case 0xc5: case 0xc6: case 0xc7:
- case 0xc8: case 0xc9: case 0xca: case 0xcb:
- case 0xcc: case 0xcd: case 0xce: case 0xcf:
- util::stream_format(stream, "bbl $%01x",op & 0x0f); break;
- case 0xd0: case 0xd1: case 0xd2: case 0xd3:
- case 0xd4: case 0xd5: case 0xd6: case 0xd7:
- case 0xd8: case 0xd9: case 0xda: case 0xdb:
- case 0xdc: case 0xdd: case 0xde: case 0xdf:
- util::stream_format(stream, "ldm $%01x",op & 0x0f); break;
-
- case 0xe0: util::stream_format(stream, "wrm"); break;
- case 0xe1: util::stream_format(stream, "wmp"); break;
- case 0xe2: util::stream_format(stream, "wrr"); break;
- case 0xe3: util::stream_format(stream, "wpm"); break;
- case 0xe4: util::stream_format(stream, "wr0"); break;
- case 0xe5: util::stream_format(stream, "wr1"); break;
- case 0xe6: util::stream_format(stream, "wr2"); break;
- case 0xe7: util::stream_format(stream, "wr3"); break;
- case 0xe8: util::stream_format(stream, "sbm"); break;
- case 0xe9: util::stream_format(stream, "rdm"); break;
- case 0xea: util::stream_format(stream, "rdr"); break;
- case 0xeb: util::stream_format(stream, "adm"); break;
- case 0xec: util::stream_format(stream, "rd0"); break;
- case 0xed: util::stream_format(stream, "rd1"); break;
- case 0xee: util::stream_format(stream, "rd2"); break;
- case 0xef: util::stream_format(stream, "rd3"); break;
-
- case 0xf0: util::stream_format(stream, "clb"); break;
- case 0xf1: util::stream_format(stream, "clc"); break;
- case 0xf2: util::stream_format(stream, "iac"); break;
- case 0xf3: util::stream_format(stream, "cmc"); break;
- case 0xf4: util::stream_format(stream, "cma"); break;
- case 0xf5: util::stream_format(stream, "ral"); break;
- case 0xf6: util::stream_format(stream, "rar"); break;
- case 0xf7: util::stream_format(stream, "tcc"); break;
- case 0xf8: util::stream_format(stream, "dac"); break;
- case 0xf9: util::stream_format(stream, "tcs"); break;
- case 0xfa: util::stream_format(stream, "stc"); break;
- case 0xfb: util::stream_format(stream, "daa"); break;
- case 0xfc: util::stream_format(stream, "kbp"); break;
- case 0xfd: util::stream_format(stream, "dcl"); break;
-
- default : util::stream_format(stream, "illegal"); break;
- }
- return (pc - PC) | flags | DASMFLAG_SUPPORTED;
-}
diff --git a/src/devices/cpu/i4004/i4004.cpp b/src/devices/cpu/i4004/i4004.cpp
deleted file mode 100644
index 782e59d6d84..00000000000
--- a/src/devices/cpu/i4004/i4004.cpp
+++ /dev/null
@@ -1,529 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
-/*****************************************************************************
- *
- * i4004.c
- *
- * Intel 4004 CPU
- *
- *****************************************************************************/
-#include "emu.h"
-#include "i4004.h"
-#include "debugger.h"
-
-
-static const uint8_t kbp_table[] = { 0x00,0x01,0x02,0x0f,0x03,0x0f,0x0f,0x0f,0x04,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f };
-
-
-/***************************************************************************
- MACROS
-***************************************************************************/
-#define GET_PC (m_ADDR[m_pc_pos])
-
-
-DEFINE_DEVICE_TYPE(I4004, i4004_cpu_device, "i4004", "Intel 4004")
-
-
-i4004_cpu_device::i4004_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : cpu_device(mconfig, I4004, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0)
- , m_io_config("io", ENDIANNESS_LITTLE, 8, 6, 0)
- , m_data_config("data", ENDIANNESS_LITTLE, 8, 12, 0), m_A(0), m_C(0), m_TEST(0), m_flags(0), m_program(nullptr), m_direct(nullptr), m_data(nullptr), m_io(nullptr), m_icount(0), m_pc_pos(0), m_addr_mask(0)
-{
- m_program_config.m_is_octal = true;
- m_io_config.m_is_octal = true;
- m_data_config.m_is_octal = true;
-}
-
-
-uint8_t i4004_cpu_device::ROP()
-{
- uint8_t retVal = m_direct->read_byte(GET_PC.w.l);
- GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff;
- m_PC = GET_PC;
- return retVal;
-}
-
-uint8_t i4004_cpu_device::READ_ROM()
-{
- return m_direct->read_byte((GET_PC.w.l & 0x0f00) | m_R[0]);
-}
-
-void i4004_cpu_device::WPM()
-{
- uint8_t t = (m_program->read_byte(m_RAM.d) << 4) | m_A;
- m_program->write_byte((GET_PC.w.l & 0x0f00) | m_RAM.d, t);
-}
-
-
-uint8_t i4004_cpu_device::ARG()
-{
- uint8_t retVal = m_direct->read_byte(GET_PC.w.l);
- GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff;
- m_PC = GET_PC;
- return retVal;
-}
-
-uint8_t i4004_cpu_device::RM()
-{
- return m_data->read_byte(m_RAM.d) & 0x0f;
-}
-
-uint8_t i4004_cpu_device::RMS(uint32_t a)
-{
- return m_data->read_byte((m_RAM.d & 0xff0) + a) >> 4;
-}
-
-void i4004_cpu_device::WM(uint8_t v)
-{
- uint8_t t = m_data->read_byte(m_RAM.d);
- m_data->write_byte(m_RAM.d, (t & 0xf0) | v);
-}
-
-
-void i4004_cpu_device::WMP(uint8_t v)
-{
- m_io->write_byte((m_RAM.d >> 6) | 0x10, v & 0x0f);
-}
-
-void i4004_cpu_device::WMS(uint32_t a, uint8_t v)
-{
- uint8_t t = m_data->read_byte((m_RAM.d & 0xff0) + a);
- m_data->write_byte((m_RAM.d & 0xff0) + a, (t & 0x0f) | (v<<4));
-}
-
-uint8_t i4004_cpu_device::RIO()
-{
- return m_io->read_byte(m_RAM.b.l >> 4) & 0x0f;
-}
-
-void i4004_cpu_device::WIO(uint8_t v)
-{
- m_io->write_byte(m_RAM.b.l >> 4, v & 0x0f);
-}
-
-uint8_t i4004_cpu_device::GET_REG(uint8_t num)
-{
- uint8_t r = m_R[num>>1];
- if (num & 1) {
- return r & 0x0f;
- } else {
- return (r >> 4) & 0x0f;
- }
-}
-
-void i4004_cpu_device::SET_REG(uint8_t num, uint8_t val)
-{
- if (num & 1) {
- m_R[num>>1] = (m_R[num>>1] & 0xf0) + (val & 0x0f);
- } else {
- m_R[num>>1] = (m_R[num>>1] & 0x0f) + ((val & 0x0f) << 4);
- }
-}
-
-void i4004_cpu_device::PUSH_STACK()
-{
- m_pc_pos = (m_pc_pos + 1) & m_addr_mask;
-}
-
-void i4004_cpu_device::POP_STACK()
-{
- m_ADDR[m_pc_pos].d = 0;
- m_pc_pos = (m_pc_pos - 1) & m_addr_mask;
-}
-
-void i4004_cpu_device::set_test(uint8_t val)
-{
- m_TEST = val;
-}
-
-void i4004_cpu_device::execute_one(int opcode)
-{
- m_icount -= 8;
- switch (opcode)
- {
- case 0x00: /* NOP */
- /* no op */
- break;
- case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x15: case 0x16: case 0x17:
- case 0x18: case 0x19: case 0x1a: case 0x1b:
- case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* JCN */
- {
- uint8_t arg = ARG();
-
- uint8_t C1 = BIT(opcode,3);
- uint8_t C2 = BIT(opcode,2);
- uint8_t C3 = BIT(opcode,1);
- uint8_t C4 = BIT(opcode,0);
- uint8_t JUMP = (((m_A == 0) ? 1 : 0) & C2) | ((m_C) & C3) | ((m_TEST ^ 1) & C4);
- m_icount -= 8;
-
- if(((C1 ^ 1) & JUMP) | (C1 & (JUMP ^ 1))) {
- GET_PC.w.l = (GET_PC.w.l & 0x0f00) | arg;
- m_PC = GET_PC;
- }
- }
- break;
- case 0x20: case 0x22: case 0x24: case 0x26:
- case 0x28: case 0x2a: case 0x2c: case 0x2e: /* FIM */
- m_icount -= 8;
- m_R[(opcode & 0x0f)>>1] = ROP();
- break;
- case 0x21: case 0x23: case 0x25: case 0x27:
- case 0x29: case 0x2b: case 0x2d: case 0x2f: /* SRC */
- m_RAM.b.l = m_R[(opcode & 0x0f)>>1];
- break;
- case 0x30: case 0x32: case 0x34: case 0x36:
- case 0x38: case 0x3a: case 0x3c: case 0x3e: /* FIN */
- m_icount -= 8;
- m_R[(opcode & 0x0f)>>1] = READ_ROM();
- break;
- case 0x31: case 0x33: case 0x35: case 0x37:
- case 0x39: case 0x3b: case 0x3d: case 0x3f: /* JIN */
- GET_PC.w.l = (GET_PC.w.l & 0x0f00) | m_R[(opcode & 0x0f)>>1];
- m_PC = GET_PC;
- break;
- case 0x40: case 0x41: case 0x42: case 0x43:
- case 0x44: case 0x45: case 0x46: case 0x47:
- case 0x48: case 0x49: case 0x4a: case 0x4b:
- case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* JUN */
- m_icount -= 8;
- GET_PC.w.l = ((opcode & 0x0f) << 8) | ARG();
- m_PC = GET_PC;
- break;
- case 0x50: case 0x51: case 0x52: case 0x53:
- case 0x54: case 0x55: case 0x56: case 0x57:
- case 0x58: case 0x59: case 0x5a: case 0x5b:
- case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* JMS */
- {
- uint16_t newPC = ((opcode & 0x0f) << 8) | ARG();
- m_icount -= 8;
- PUSH_STACK();
- GET_PC.w.l = newPC;
- m_PC = GET_PC;
- }
- break;
- case 0x60: case 0x61: case 0x62: case 0x63:
- case 0x64: case 0x65: case 0x66: case 0x67:
- case 0x68: case 0x69: case 0x6a: case 0x6b:
- case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* INC */
- SET_REG(opcode & 0x0f, GET_REG(opcode & 0x0f) + 1);
- break;
- case 0x70: case 0x71: case 0x72: case 0x73:
- case 0x74: case 0x75: case 0x76: case 0x77:
- case 0x78: case 0x79: case 0x7a: case 0x7b:
- case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ISZ */
- {
- uint8_t val = (GET_REG(opcode & 0x0f) + 1) & 0xf;
- uint16_t addr = ARG();
- m_icount -= 8;
- SET_REG(opcode & 0x0f, val);
- if (val!=0) {
- GET_PC.w.l = (GET_PC.w.l & 0x0f00) | addr;
- }
- m_PC = GET_PC;
- }
- break;
- case 0x80: case 0x81: case 0x82: case 0x83:
- case 0x84: case 0x85: case 0x86: case 0x87:
- case 0x88: case 0x89: case 0x8a: case 0x8b:
- case 0x8c: case 0x8d: case 0x8e: case 0x8f: /* ADD */
- {
- uint8_t acc = m_A + GET_REG(opcode & 0x0f) + m_C;
- m_A = acc & 0x0f;
- m_C = (acc >> 4) & 1;
- }
- break;
- case 0x90: case 0x91: case 0x92: case 0x93:
- case 0x94: case 0x95: case 0x96: case 0x97:
- case 0x98: case 0x99: case 0x9a: case 0x9b:
- case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* SUB */
- {
- uint8_t acc = m_A + (GET_REG(opcode & 0x0f) ^ 0x0f) + (m_C ^ 1);
- m_A = acc & 0x0f;
- m_C = (acc >> 4) & 1;
- }
- break;
- case 0xa0: case 0xa1: case 0xa2: case 0xa3:
- case 0xa4: case 0xa5: case 0xa6: case 0xa7:
- case 0xa8: case 0xa9: case 0xaa: case 0xab:
- case 0xac: case 0xad: case 0xae: case 0xaf: /* LD */
- m_A = GET_REG(opcode & 0x0f);
- break;
- case 0xb0: case 0xb1: case 0xb2: case 0xb3:
- case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb:
- case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* XCH */
- {
- uint8_t temp = m_A;
- m_A = GET_REG(opcode & 0x0f);
- SET_REG(opcode & 0x0f, temp);
- }
- break;
- case 0xc0: case 0xc1: case 0xc2: case 0xc3:
- case 0xc4: case 0xc5: case 0xc6: case 0xc7:
- case 0xc8: case 0xc9: case 0xca: case 0xcb:
- case 0xcc: case 0xcd: case 0xce: case 0xcf: /* BBL */
- POP_STACK();
- m_A = opcode & 0x0f;
- m_PC = GET_PC;
- break;
- case 0xd0: case 0xd1: case 0xd2: case 0xd3:
- case 0xd4: case 0xd5: case 0xd6: case 0xd7:
- case 0xd8: case 0xd9: case 0xda: case 0xdb:
- case 0xdc: case 0xdd: case 0xde: case 0xdf: /* LDM */
- m_A = opcode & 0x0f;
- break;
- case 0xe0: /* WRM */
- WM(m_A);
- break;
- case 0xe1: /* WMP */
- WMP(m_A);
- break;
- case 0xe2: /* WRR */
- WIO(m_A);
- break;
- case 0xe3: /* WPM */
- WPM();
- break;
- case 0xe4: /* WR0 */
- WMS(0,m_A);
- break;
- case 0xe5: /* WR1 */
- WMS(1,m_A);
- break;
- case 0xe6: /* WR2 */
- WMS(2,m_A);
- break;
- case 0xe7: /* WR3 */
- WMS(3,m_A);
- break;
- case 0xe8: /* SBM */
- m_A = m_A + (RM() ^ 0x0f) + (m_C ^ 1);
- m_C = m_A >> 4;
- m_A &= 0x0f;
- break;
- case 0xe9: /* RDM */
- m_A = RM();
- break;
- case 0xea: /* RDR */
- m_A = RIO();
- break;
- case 0xeb: /* ADM */
- m_A += RM() + m_C;
- m_C = m_A >> 4;
- m_A &= 0x0f;
- break;
- case 0xec: /* RD0 */
- m_A = RMS(0);
- break;
- case 0xed: /* RD1 */
- m_A = RMS(1);
- break;
- case 0xee: /* RD2 */
- m_A = RMS(2);
- break;
- case 0xef: /* RD3 */
- m_A = RMS(3);
- break;
-
- case 0xf0: /* CLB */
- m_A = 0;
- m_C = 0;
- break;
- case 0xf1: /* CLC */
- m_C = 0;
- break;
- case 0xf2: /* IAC */
- m_A += 1;
- m_C = m_A >> 4;
- m_A &= 0x0f;
- break;
- case 0xf3: /* CMC */
- m_C ^= 1;
- break;
- case 0xf4: /* CMA */
- m_A ^= 0x0f;
- break;
- case 0xf5: /* RAL */
- m_A = (m_A << 1) | m_C;
- m_C = m_A >> 4;
- m_A &= 0x0f;
- break;
- case 0xf6: /* RAR */
- {
- uint8_t c = m_A & 1;
- m_A = (m_A >> 1) | (m_C << 3);
- m_C = c;
- }
- break;
- case 0xf7: /* TCC */
- m_A = m_C;
- m_C = 0;
- break;
- case 0xf8: /* DAC */
- m_A = m_A + 0x0f;
- m_C = m_A >> 4;
- m_A &= 0x0f;
- break;
- case 0xf9: /* TCS */
- m_A = m_C ? 10 : 9;
- m_C = 0;
- break;
- case 0xfa: /* STC */
- m_C = 1;
- break;
- case 0xfb: /* DAA */
- if (m_C || (m_A > 9)) {
- m_A += 6;
- }
- if (m_A > 0x0f) {
- // it is unaffected if it is in range
- m_C = 1;
- }
- m_A &= 0x0f;
- break;
- case 0xfc: /* KBP */
- m_A = kbp_table[m_A];
- break;
- case 0xfd: /* DCL */
- m_RAM.b.h = m_A;
- break;
- }
-}
-
-
-/***************************************************************************
- COMMON EXECUTION
-***************************************************************************/
-
-void i4004_cpu_device::execute_run()
-{
- do
- {
- debugger_instruction_hook(this, GET_PC.d);
- execute_one(ROP());
-
- } while (m_icount > 0);
-}
-
-/***************************************************************************
- CORE INITIALIZATION
-***************************************************************************/
-
-void i4004_cpu_device::device_start()
-{
- /* set up the state table */
- {
- state_add(I4004_PC, "PC", m_PC.w.l).mask(0x0fff);
- state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x0fff).noshow();
- state_add(STATE_GENPCBASE,"CURPC", m_PC.w.l).mask(0x0fff).noshow();
- state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s");
- state_add(I4004_A, "A", m_A).mask(0x0f);
-
- for (int regnum = 0; regnum < 8; regnum++)
- {
- state_add(I4004_R01 + regnum, string_format("R%X%X", regnum * 2, regnum * 2 + 1).c_str(), m_R[regnum]);
- }
-
- for (int addrnum = 0; addrnum < 4; addrnum++)
- {
- state_add(I4004_ADDR1 + addrnum, string_format("ADDR%d", addrnum + 1).c_str(), m_ADDR[addrnum].w.l).mask(0xfff);
- }
-
- state_add(I4004_RAM, "RAM", m_RAM.w.l).mask(0x0fff);
- }
-
- m_program = &space(AS_PROGRAM);
- m_direct = &m_program->direct();
- m_data = &space(AS_DATA);
- m_io = &space(AS_IO);
-
- save_item(NAME(m_PC));
- save_item(NAME(m_A));
- save_item(NAME(m_C));
- save_item(NAME(m_TEST));
- save_item(NAME(m_pc_pos));
- save_item(NAME(m_ADDR[0]));
- save_item(NAME(m_ADDR[1]));
- save_item(NAME(m_ADDR[2]));
- save_item(NAME(m_ADDR[3]));
- save_item(NAME(m_R[0]));
- save_item(NAME(m_R[1]));
- save_item(NAME(m_R[2]));
- save_item(NAME(m_R[3]));
- save_item(NAME(m_R[4]));
- save_item(NAME(m_R[5]));
- save_item(NAME(m_R[6]));
- save_item(NAME(m_R[7]));
- save_item(NAME(m_RAM));
-
- m_icountptr = &m_icount;
-}
-
-
-/***************************************************************************
- COMMON RESET
-***************************************************************************/
-
-void i4004_cpu_device::device_reset()
-{
- m_addr_mask = 3;
- m_C = 0;
- m_pc_pos = 0;
- m_A = 0;
- memset(m_R,0,8);
- memset(m_ADDR,0,sizeof(m_ADDR));
- m_RAM.d = 0;
- m_PC = GET_PC;
-
-}
-
-
-
-/***************************************************************************
- COMMON STATE IMPORT/EXPORT
-***************************************************************************/
-
-void i4004_cpu_device::state_import(const device_state_entry &entry)
-{
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- m_C = (m_flags >> 1) & 1;
- m_TEST = (m_flags >> 0) & 1;
- break;
- }
-}
-
-void i4004_cpu_device::state_export(const device_state_entry &entry)
-{
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- m_flags = ((m_A == 0) ? 0x04 : 0x00) |
- (m_C ? 0x02 : 0x00) |
- (m_TEST ? 0x01 : 0x00);
- break;
- }
-}
-
-void i4004_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
-{
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- str = string_format(".%c%c%c",
- (m_A==0) ? 'Z':'.',
- m_C ? 'C':'.',
- m_TEST ? 'T':'.');
- break;
- }
-}
-
-offs_t i4004_cpu_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
-{
- extern CPU_DISASSEMBLE( i4004 );
- return CPU_DISASSEMBLE_NAME(i4004)(this, stream, pc, oprom, opram, options);
-}
diff --git a/src/devices/cpu/i4004/i4004.h b/src/devices/cpu/i4004/i4004.h
deleted file mode 100644
index 42dd51cd0ca..00000000000
--- a/src/devices/cpu/i4004/i4004.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
-#ifndef MAME_CPU_I4004_I4004_H
-#define MAME_CPU_I4004_I4004_H
-
-#pragma once
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-enum
-{
- I4004_PC,
- I4004_A,
- I4004_R01, I4004_R23, I4004_R45, I4004_R67, I4004_R89, I4004_RAB, I4004_RCD, I4004_REF,
- I4004_ADDR1,I4004_ADDR2,I4004_ADDR3,I4004_ADDR4,I4004_RAM
-};
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-class i4004_cpu_device : public cpu_device
-{
-public:
- // construction/destruction
- i4004_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock);
-
- void set_test(uint8_t val);
-
-protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // device_execute_interface overrides
- virtual uint32_t execute_min_cycles() const override { return 8; }
- virtual uint32_t execute_max_cycles() const override { return 16; }
- virtual void execute_run() override;
-
- // device_memory_interface overrides
- virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override
- {
- switch (spacenum)
- {
- case AS_PROGRAM: return &m_program_config;
- case AS_IO: return &m_io_config;
- case AS_DATA: return &m_data_config;
- default: return nullptr;
- }
- }
-
- // device_state_interface overrides
- virtual void state_import(const device_state_entry &entry) override;
- virtual void state_export(const device_state_entry &entry) override;
- virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
-
- // device_disasm_interface overrides
- virtual uint32_t disasm_min_opcode_bytes() const override { return 1; }
- virtual uint32_t disasm_max_opcode_bytes() const override { return 2; }
- virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
-
- uint8_t ROP();
- uint8_t READ_ROM();
- void WPM();
- uint8_t ARG();
- uint8_t RM();
- uint8_t RMS(uint32_t a);
- void WM(uint8_t v);
- void WMP(uint8_t v);
- void WMS(uint32_t a, uint8_t v);
- uint8_t RIO();
- void WIO(uint8_t v);
- uint8_t GET_REG(uint8_t num);
- void SET_REG(uint8_t num, uint8_t val);
- void PUSH_STACK();
- void POP_STACK();
- void execute_one(int opcode);
-
- address_space_config m_program_config;
- address_space_config m_io_config;
- address_space_config m_data_config;
-
- uint8_t m_A; // Accumulator
- uint8_t m_R[8];
- PAIR m_ADDR[4]; // Address registers
- PAIR m_RAM;
- uint8_t m_C; // Carry flag
- uint8_t m_TEST; // Test PIN status
- PAIR m_PC; // It is in fact one of ADDR regs
- uint8_t m_flags; // used for I/O only
-
- address_space *m_program;
- direct_read_data *m_direct;
- address_space *m_data;
- address_space *m_io;
- int m_icount;
- int m_pc_pos; // PC position in ADDR
- int m_addr_mask;
-};
-
-
-DECLARE_DEVICE_TYPE(I4004, i4004_cpu_device)
-
-#endif // MAME_CPU_I4004_I4004_H
diff --git a/src/devices/cpu/mcs40/mcs40.cpp b/src/devices/cpu/mcs40/mcs40.cpp
new file mode 100644
index 00000000000..8efce9710ea
--- /dev/null
+++ b/src/devices/cpu/mcs40/mcs40.cpp
@@ -0,0 +1,1022 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*****************************************************************************
+ *
+ * i4004.cpp
+ *
+ * Intel MCS-40 CPU family
+ *
+ *****************************************************************************/
+#include "emu.h"
+#include "mcs40.h"
+#include "debugger.h"
+
+
+/*
+MCS-40 uses an unusual scheme for memory. RAMs contain four registers,
+each of which has 16 memory characters and 4 status characters (all
+characters are 4 bits wide). We represent a register as 16 bytes,
+storing memory characters in the low nybbles and status characters in
+the high nybbles of the first four bytes. This necessitates a
+read/modify/write on each write, as MAME doesn't cater for nybble lane
+select.
+
+I/O is similarly unusual. It's assumed that there's one 4-bit I/O port
+per 256 bytes of ROM. The upper four bits of RC select the ROM I/O port
+for WRR and RDR instructions (along with the selected ROM bank for the
+4040). It's assumed that there's one output-only port per RAM. The
+upper two bits of RC along with the lower three bits of CR select the
+RAM output port for WMP instructions. This isn't too bad, but it's
+complicated by the GPIO peripherals. These chips respond to WRR/RDR,
+but can be wired to the CM-RAM lines, so they can be selected by the
+combination of the lower three bits of RC along with the upper four bits
+of RC. On top of this, the 4289 latches the entire RC value on its A
+outputs at X1, allowing for a flat 8-bit I/O space using the WRR/RDR
+instructions, as well as having CM lines for devices selection. This
+means we need 12 bits to represent the entire range of possibilities
+using the WRR/RDR instructions. At this point, we're placing the
+ROM/RAM select in bit 12, CR in bits 11-8, and RC in bits 7-0. Ideally
+we'd be able to put the RAM output ports in a separate address space,
+but we're already running out.
+
+ CR RC
+4001: 0 B--- RRRR----
+4002: 1 -CCC RR------
+4207: 0 BCCC 11PP----
+4209: 0 BCCC 11PP----
+4211: 0 BCCC 11PP----
+4289: 0 B--- AAAAAAAA
+4308: 0 B--- RRPP----
+
+TODO: WPM, HLT, BBS, EIN, DIN, RPM instructions
+TODO: 4040 halt/interrupt support
+TODO: expose 4289 lines
+TODO: expose data bus
+*/
+
+
+ALLOW_SAVE_TYPE(mcs40_cpu_device_base::phase);
+ALLOW_SAVE_TYPE(mcs40_cpu_device_base::cycle);
+
+
+DEFINE_DEVICE_TYPE(I4004, i4004_cpu_device, "i4004", "Intel 4004")
+DEFINE_DEVICE_TYPE(I4040, i4040_cpu_device, "i4040", "Intel 4040")
+
+
+mcs40_cpu_device_base::mcs40_cpu_device_base(
+ const machine_config &mconfig,
+ device_type type,
+ const char *tag,
+ device_t *owner,
+ uint32_t clock,
+ bool extended_cm,
+ unsigned rom_width,
+ unsigned stack_ptr_mask,
+ unsigned index_reg_cnt,
+ unsigned cr_mask)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, rom_width, 0)
+ , m_data_config("data", ENDIANNESS_LITTLE, 8, 11, 0)
+ , m_io_config("io", ENDIANNESS_LITTLE, 8, 13, 0)
+ , m_program(nullptr), m_data(nullptr), m_io(nullptr), m_direct(nullptr)
+ , m_sync_cb(*this)
+ , m_cm_rom_cb{ { *this }, { *this } }
+ , m_cm_ram_cb{ { *this }, { *this }, { *this }, { *this }, }
+ , m_cy_cb(*this)
+ , m_extended_cm(extended_cm)
+ , m_stack_ptr_mask(stack_ptr_mask), m_index_reg_cnt(index_reg_cnt), m_cr_mask(cr_mask)
+ , m_pc_mask((1U << rom_width) - 1)
+ , m_phase(phase::A1), m_cycle(cycle::OP)
+ , m_rom_addr(0U), m_opr(0U), m_opa(0U), m_arg(0U)
+ , m_a(0U), m_c(0U)
+ , m_addr_stack(), m_stack_ptr(0U)
+ , m_index_regs(), m_index_reg_bank(0U)
+ , m_cr(0U), m_pending_cr3(0U), m_latched_rc(0U), m_new_rc(0U), m_src(0U), m_rc_pending(false)
+ , m_test(CLEAR_LINE)
+ , m_cm_rom(0U), m_cm_ram(0U), m_cy(0U)
+ , m_pc(0U), m_pcbase(0U), m_genflags(0U)
+{
+ assert(!((1 & sp_mask) | sp_mask));
+ assert((16U == index_reg_cnt) || (24U == index_reg_cnt));
+}
+
+
+/***********************************************************************
+ device_t implementation
+***********************************************************************/
+
+void mcs40_cpu_device_base::device_start()
+{
+ m_icountptr = &m_icount;
+
+ m_program = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ m_io = &space(AS_IO);
+ m_direct = &m_program->direct();
+
+ m_sync_cb.resolve_safe();
+ m_cm_rom_cb[0].resolve_safe();
+ m_cm_rom_cb[1].resolve_safe();
+ m_cm_ram_cb[0].resolve_safe();
+ m_cm_ram_cb[1].resolve_safe();
+ m_cm_ram_cb[2].resolve_safe();
+ m_cm_ram_cb[3].resolve_safe();
+ m_cy_cb.resolve_safe();
+
+ m_rom_addr = 0U;
+ m_opr = m_opa = m_arg = 0U;
+
+ m_a = m_c = 0U;
+
+ m_addr_stack.reset(new u16[m_stack_ptr_mask + 1]);
+ std::fill(&m_addr_stack[0], &m_addr_stack[m_stack_ptr_mask + 1], 0U);
+ m_stack_ptr = 0U;
+
+ m_index_regs.reset(new u8[m_index_reg_cnt >> 1]);
+ std::fill(&m_index_regs[0], &m_index_regs[m_index_reg_cnt >> 1], 0U);
+
+ m_latched_rc = m_new_rc = m_src = 0U;
+
+ m_test = CLEAR_LINE;
+ m_cm_rom = 0x03U;
+ m_cm_ram = 0x0fU;
+ m_cy = 0x00U;
+
+ m_pc = m_pcbase = 0U;
+ m_genflags = 0U;
+
+ state_add(STATE_GENPC, "PC", m_pc).mask(m_pc_mask).callimport().callexport();
+ state_add(STATE_GENPCBASE, "CURPC", m_pcbase).mask(m_pc_mask).noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_genflags).mask(0x07U).noshow().callimport().callexport().formatstr("%3s");
+ state_add(I4004_A, "A", m_a).mask(0x0fU);
+ for (unsigned i = 0; (m_index_reg_cnt >> 1) > i; ++i)
+ {
+ state_add(
+ I4004_R01 + i,
+ string_format("R%X%X%s", (i << 1) & 0x0fU, ((i << 1) + 1) & 0x0fU, BIT(i, 3) ? "*" : "").c_str(),
+ m_index_regs[i]);
+ }
+ for (unsigned i = 0; m_stack_ptr_mask >= i; ++i)
+ state_add(I4004_ADDR0 + i, string_format("ADDR%d", i).c_str(), m_addr_stack[i]).mask(0x0fff);
+ state_add(I4004_CR, "CR", m_cr).mask(m_cr_mask);
+ state_add(I4004_RC, "RC", m_latched_rc);
+ state_add(I4004_RCN, "RC'", m_new_rc);
+ // TODO: export SRC for 4040
+ // TODO: export register bank for 4040
+
+ save_item(NAME(m_phase));
+ save_item(NAME(m_cycle));
+ save_item(NAME(m_rom_addr));
+ save_item(NAME(m_opr));
+ save_item(NAME(m_opa));
+ save_item(NAME(m_arg));
+ save_item(NAME(m_a));
+ save_item(NAME(m_c));
+ save_pointer(NAME(m_addr_stack.get()), m_stack_ptr_mask + 1);
+ save_item(NAME(m_stack_ptr));
+ save_pointer(NAME(m_index_regs.get()), m_index_reg_cnt >> 1);
+ save_item(NAME(m_index_reg_bank));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_pending_cr3));
+ save_item(NAME(m_latched_rc));
+ save_item(NAME(m_new_rc));
+ save_item(NAME(m_src));
+ save_item(NAME(m_rc_pending));
+ save_item(NAME(m_test));
+ save_item(NAME(m_cm_ram));
+ save_item(NAME(m_cm_rom));
+ save_item(NAME(m_cy));
+ save_item(NAME(m_pcbase));
+}
+
+void mcs40_cpu_device_base::device_reset()
+{
+ m_phase = phase::A1;
+ m_cycle = cycle::OP;
+
+ m_rom_addr = 0U;
+ pc() = 0U;
+
+ m_c = 0U;
+
+ m_index_reg_bank = 0U;
+
+ m_cr = 0U;
+ m_pending_cr3 = 0U;
+ m_rc_pending = false;
+
+ update_cm_rom(0x03U);
+ update_cm_ram(0x0fU);
+
+ // TODO: it actually takes multiple cycles with reset asserted for everything to get cleared
+ m_a = m_c = 0U;
+ std::fill(&m_addr_stack[0], &m_addr_stack[m_stack_ptr_mask + 1], 0U);
+ std::fill(&m_index_regs[0], &m_index_regs[m_index_reg_cnt >> 1], 0U);
+}
+
+
+/***********************************************************************
+ device_execute_interface implementation
+***********************************************************************/
+
+void mcs40_cpu_device_base::execute_run()
+{
+ static constexpr u8 cm_ram_table[8] = { 0x0eU, 0x0dU, 0x0bU, 0x07U, 0x09U, 0x05U, 0x03U, 0x01U };
+ while (m_icount > 0)
+ {
+ switch (m_phase)
+ {
+ case phase::A1:
+ m_pending_cr3 = (m_pending_cr3 << 1) | BIT(m_cr, 3);
+ m_cr = (m_cr & 0x07U) | (m_pending_cr3 & 0x08U);
+ if (cycle::OP == m_cycle)
+ {
+ m_pcbase = rom_bank() | m_rom_addr;
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ debugger_instruction_hook(this, pc());
+ }
+ m_sync_cb(1);
+ // low nybble of ROM address is output here
+ // STOPACK is asserted here
+ m_phase = phase::A2;
+ break;
+ case phase::A2:
+ // mid nybble of ROM address is output here
+ m_phase = phase::A3;
+ break;
+ case phase::A3:
+ // high nybble of ROM address is output here
+ update_cm_rom(BIT(m_cr, 3) ? 0x01U : 0x02U);
+ m_phase = phase::M1;
+ break;
+ case phase::M1:
+ // OPR is read here
+ {
+ if (!m_extended_cm || (cycle::OP != m_cycle))
+ update_cm_rom(0x03);
+ else
+ update_cm_ram(cm_ram_table[m_cr & 0x07U]);
+ // TODO: split this up into two nybble reads - MAME doesn't support this
+ u8 const read = m_direct->read_byte(rom_bank() | m_rom_addr);
+ if (cycle::OP == m_cycle)
+ {
+ m_opr = read >> 4;
+ m_opa = read & 0x0f;
+ m_io_pending = is_io_op(m_opr);
+ }
+ else
+ {
+ m_arg = read;
+ }
+ }
+ m_phase = phase::M2;
+ break;
+ case phase::M2:
+ // OPA is read here
+ if (m_io_pending)
+ {
+ update_cm_rom(BIT(m_cr, 3) ? 0x01U : 0x02U);
+ update_cm_ram(cm_ram_table[m_cr & 0x07U]);
+ }
+ if (cycle::IN != m_cycle)
+ m_rom_addr = pc() = (pc() + 1) & 0x0fff;
+ m_phase = phase::X1;
+ break;
+ case phase::X1:
+ // A or OPA is output here
+ update_cy(m_c);
+ update_cm_rom(0x03U);
+ update_cm_ram(0x0fU);
+ if (cycle::OP == m_cycle)
+ {
+ m_cycle = do_cycle1(m_opr, m_opa);
+ }
+ else
+ {
+ do_cycle2(m_opr, m_opa, m_arg);
+ m_cycle = cycle::OP;
+ }
+ m_phase = phase::X2;
+ break;
+ case phase::X2:
+ if (m_io_pending)
+ {
+ assert(phase::X2 == m_phase);
+ assert(m_latched_rc == m_new_rc);
+ assert(!m_rc_pending);
+ do_io(m_opr, m_opa);
+ m_io_pending = false;
+ }
+ if (m_rc_pending)
+ {
+ update_cm_rom(BIT(m_cr, 3) ? 0x01U : 0x02U);
+ update_cm_ram(cm_ram_table[m_cr & 0x07U]);
+ m_latched_rc = (m_latched_rc & 0x0fU) | (m_new_rc & 0xf0U);
+ }
+ else
+ {
+ assert(m_latched_rc == m_new_rc);
+ }
+ m_phase = phase::X3;
+ break;
+ case phase::X3:
+ m_sync_cb(0);
+ update_cm_rom(0x03U);
+ update_cm_ram(0x0fU);
+ if (m_rc_pending)
+ {
+ m_latched_rc = (m_latched_rc & 0xf0U) | (m_new_rc & 0x0fU);
+ m_rc_pending = false;
+ }
+ else
+ {
+ assert(m_latched_rc == m_new_rc);
+ }
+ m_phase = phase::A1;
+ break;
+ }
+ --m_icount;
+ }
+}
+
+
+/***********************************************************************
+ device_memory_interface implementation
+***********************************************************************/
+
+address_space_config const *mcs40_cpu_device_base::memory_space_config(address_spacenum spacenum) const
+{
+ switch (spacenum)
+ {
+ case AS_PROGRAM: return &m_program_config;
+ case AS_DATA: return &m_data_config;
+ case AS_IO: return &m_io_config;
+ default: return nullptr;
+ }
+}
+
+
+/***********************************************************************
+ device_state_interface implementation
+***********************************************************************/
+
+void mcs40_cpu_device_base::state_import(device_state_entry const &entry)
+{
+ switch (entry.index())
+ {
+ case STATE_GENPC:
+ pc() = m_pc_mask & m_pc & 0x0fffU;
+ if (BIT(m_pc, 12))
+ m_cr |= 0x08;
+ else
+ m_cr &= 0x07;
+ m_rom_bank = m_pc_mask & m_pc & 0xf000U;
+ if ((cycle::OP == m_cycle) && (phase::M1 > m_phase))
+ {
+ m_rom_addr = pc();
+ m_pcbase = m_pc;
+ }
+ break;
+ case STATE_GENFLAGS:
+ m_c = BIT(m_genflags, 1);
+ m_test = BIT(m_genflags, 0) ? ASSERT_LINE : CLEAR_LINE;
+ break;
+ }
+}
+
+void mcs40_cpu_device_base::state_export(device_state_entry const &entry)
+{
+ switch (entry.index())
+ {
+ case STATE_GENPC:
+ m_pc = rom_bank() | pc();
+ break;
+ case STATE_GENFLAGS:
+ m_genflags = (m_a ? 0x00 : 0x04) | (m_c ? 0x02 : 0x00) | ((CLEAR_LINE != m_test) ? 0x01 : 0x00);
+ break;
+ }
+}
+
+void mcs40_cpu_device_base::state_string_export(device_state_entry const &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = util::string_format("%c%c%c", m_a ? '.' : 'Z', m_c ? 'C' : '.', (CLEAR_LINE != m_test) ? 'T' : '.');
+ break;
+ }
+}
+
+
+/***********************************************************************
+ device_disasm_interface implementation
+***********************************************************************/
+
+u32 mcs40_cpu_device_base::disasm_min_opcode_bytes() const
+{
+ return 1U;
+}
+
+u32 mcs40_cpu_device_base::disasm_max_opcode_bytes() const
+{
+ return 2U;
+}
+
+
+/***********************************************************************
+ register access
+***********************************************************************/
+
+inline u8 mcs40_cpu_device_base::get_a() const
+{
+ return m_a;
+}
+
+inline u8 mcs40_cpu_device_base::get_c() const
+{
+ return m_c;
+}
+
+inline void mcs40_cpu_device_base::set_a(u8 val)
+{
+ m_a = val & 0x0fU;
+}
+
+inline void mcs40_cpu_device_base::set_c(u8 val)
+{
+ m_c = val & 0x01U;
+}
+
+inline void mcs40_cpu_device_base::set_a_c(u8 val)
+{
+ m_a = val & 0x0fU;
+ m_c = BIT(val, 4);
+}
+
+inline void mcs40_cpu_device_base::set_pc(u16 addr, u16 mask)
+{
+ set_rom_addr(pc() = (addr & mask) | (pc() & ~mask), 0x0fffU);
+}
+
+inline void mcs40_cpu_device_base::push_pc()
+{
+ m_stack_ptr = (m_stack_ptr + 1) & m_stack_ptr_mask;
+}
+
+inline void mcs40_cpu_device_base::pop_pc()
+{
+ m_stack_ptr = (m_stack_ptr - 1) & m_stack_ptr_mask;
+ set_rom_addr(pc(), 0x0fffU);
+}
+
+inline u8 &mcs40_cpu_device_base::index_reg_pair(unsigned n)
+{
+ return m_index_regs[(BIT(n, 2) ? 0 : m_index_reg_bank) | (n & 0x7U)];
+}
+
+inline u8 mcs40_cpu_device_base::get_index_reg(unsigned n)
+{
+ return (index_reg_pair(n >> 1) >> (BIT(n, 0) ? 0 : 4)) & 0x0fU;
+}
+
+inline void mcs40_cpu_device_base::set_index_reg(unsigned n, u8 val)
+{
+ u8 &reg_pair(index_reg_pair(n >> 1));
+ bool const lsn(BIT(n, 0));
+ reg_pair = (reg_pair & (lsn ? 0xf0U : 0x0fU)) | ((val & 0x0fU) << (lsn ? 0 : 4));
+}
+
+inline void mcs40_cpu_device_base::set_index_reg_bank(u8 val)
+{
+ m_index_reg_bank = BIT(val, 0) << 3;
+}
+
+
+/***********************************************************************
+ register access
+***********************************************************************/
+
+inline void mcs40_cpu_device_base::set_rom_addr(u16 addr, u16 mask)
+{
+ m_rom_addr = (addr & mask) | (m_rom_addr & ~mask);
+}
+
+inline u8 mcs40_cpu_device_base::get_cr()
+{
+ return m_cr;
+}
+
+inline void mcs40_cpu_device_base::set_cr(u8 val, u8 mask)
+{
+ m_cr = (val & mask) | (m_cr & ~mask);
+}
+
+inline void mcs40_cpu_device_base::set_pending_rom_bank(u8 val)
+{
+ m_pending_cr3 = (m_pending_cr3 & 0x0eU) | (val & 0x01U);
+}
+
+inline void mcs40_cpu_device_base::set_rc(u8 val)
+{
+ m_rc_pending = true;
+ m_new_rc = val;
+ m_src = val; // TODO: lock out during interrupt processing
+}
+
+inline u8 mcs40_cpu_device_base::read_memory()
+{
+ return m_data->read_byte((u16(m_cr & 0x7U) << 8) | m_latched_rc) & 0x0fU;
+}
+
+inline void mcs40_cpu_device_base::write_memory(u8 val)
+{
+ u16 const addr((u16(m_cr & 0x7U) << 8) | m_latched_rc);
+ m_data->write_byte(addr, (m_data->read_byte(addr) & 0xf0U) | (val & 0x0fU));
+}
+
+inline u8 mcs40_cpu_device_base::read_status()
+{
+ u16 const addr((((u16(m_cr) << 8) | m_latched_rc) & 0x07f0U) | (m_opa & 0x0003U));
+ return (m_data->read_byte(addr) >> 4) & 0x0fU;
+}
+
+inline void mcs40_cpu_device_base::write_status(u8 val)
+{
+ u16 const addr((((u16(m_cr) << 8) | m_latched_rc) & 0x07f0U) | (m_opa & 0x0003U));
+ m_data->write_byte(addr, (m_data->read_byte(addr) & 0x0fU) | (val << 4));
+}
+
+inline u8 mcs40_cpu_device_base::read_rom_port()
+{
+ return m_io->read_byte((u16(m_cr) << 8) | m_latched_rc) & 0x0fU;
+}
+
+inline void mcs40_cpu_device_base::write_rom_port(u8 val)
+{
+ m_io->write_byte((u16(m_cr) << 8) | m_latched_rc, val & 0x0fU);
+}
+
+inline void mcs40_cpu_device_base::write_memory_port(u8 val)
+{
+ m_io->write_byte(0x1000U | (u16(m_cr) << 8) | m_latched_rc, val & 0x0fU);
+}
+
+
+/***********************************************************************
+ input lines
+***********************************************************************/
+
+inline bool mcs40_cpu_device_base::get_test()
+{
+ bool const result(CLEAR_LINE != m_test);
+ if (ASSERT_LINE != m_test)
+ m_test = CLEAR_LINE;
+ return result;
+}
+
+inline void mcs40_cpu_device_base::set_test(int state)
+{
+ m_test = ((ASSERT_LINE == state) || (HOLD_LINE == state)) ? state : CLEAR_LINE;
+}
+
+
+/***********************************************************************
+ internal helpers
+***********************************************************************/
+
+inline void mcs40_cpu_device_base::update_cm_rom(u8 val)
+{
+ u8 const diff(val ^ m_cm_rom);
+ m_cm_rom = val;
+ if (BIT(diff, 0))
+ m_cm_rom_cb[0](BIT(val, 0));
+ if (BIT(diff, 1))
+ m_cm_rom_cb[1](BIT(val, 1));
+}
+
+inline void mcs40_cpu_device_base::update_cm_ram(u8 val)
+{
+ u8 const diff(val ^ m_cm_ram);
+ m_cm_ram = val;
+ if (BIT(diff, 0))
+ m_cm_ram_cb[0](BIT(val, 0));
+ if (BIT(diff, 1))
+ m_cm_ram_cb[1](BIT(val, 1));
+ if (BIT(diff, 2))
+ m_cm_ram_cb[2](BIT(val, 2));
+ if (BIT(diff, 3))
+ m_cm_ram_cb[3](BIT(val, 3));
+}
+
+inline void mcs40_cpu_device_base::update_cy(u8 val)
+{
+ u8 const diff(val ^ m_cy);
+ if (BIT(diff, 0))
+ m_cy_cb(BIT(val, 0));
+}
+
+
+
+i4004_cpu_device::i4004_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+ : mcs40_cpu_device_base(mconfig, I4004, tag, owner, clock, false, 12U, 0x3U, 16U, 0x7U)
+{
+}
+
+
+/***********************************************************************
+ device_execute_interface implementation
+***********************************************************************/
+
+u32 i4004_cpu_device::execute_input_lines() const
+{
+ return 1U;
+}
+
+void i4004_cpu_device::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case I4004_TEST_LINE:
+ set_test(state);
+ break;
+ default:
+ mcs40_cpu_device_base::execute_set_input(inputnum, state);
+ }
+}
+
+
+/***********************************************************************
+ device_disasm_interface implementation
+***********************************************************************/
+
+offs_t i4004_cpu_device::disasm_disassemble(
+ std::ostream &stream,
+ offs_t pc,
+ uint8_t const *oprom,
+ uint8_t const *opram,
+ uint32_t options)
+{
+ extern CPU_DISASSEMBLE(i4004);
+ return CPU_DISASSEMBLE_NAME(i4004)(this, stream, pc, oprom, opram, options);
+}
+
+
+/***********************************************************************
+ mcs40_cpu_device_base implementation
+***********************************************************************/
+
+bool i4004_cpu_device::is_io_op(u8 opr)
+{
+ return 0x0e == opr;
+}
+
+i4004_cpu_device::cycle i4004_cpu_device::do_cycle1(u8 opr, u8 opa)
+{
+ static constexpr uint8_t kbp_table[] = { 0x0, 0x1, 0x2, 0xf, 0x3, 0xf, 0xf, 0xf, 0x4, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf };
+
+ switch (opr)
+ {
+ case 0x0:
+ switch (opa)
+ {
+ case 0x0: // NOP
+ return cycle::OP;
+ default:
+ break;
+ }
+ break;
+
+ case 0x1: // JCN
+ case 0x4: // JUN
+ case 0x5: // JMS
+ case 0x7: // ISZ
+ return cycle::IM;
+
+ case 0x2:
+ if (BIT(opa, 0))
+ {
+ // SRC
+ set_rc(index_reg_pair(opa >> 1));
+ return cycle::OP;
+ }
+ else
+ {
+ // FIM
+ return cycle::IM;
+ }
+
+ case 0x3:
+ if (BIT(opa, 0))
+ {
+ // JIN
+ set_pc(index_reg_pair(opa >> 1), 0x00ffU);
+ return cycle::OP;
+ }
+ else
+ {
+ // FIN
+ set_rom_addr(index_reg_pair(0), 0x00ffU);
+ return cycle::IN;
+ }
+
+ case 0x6: // INC
+ set_index_reg(opa, get_index_reg(opa) + 1U);
+ return cycle::OP;
+
+ case 0x8: // ADD
+ set_a_c(get_a() + get_index_reg(opa) + get_c());
+ return cycle::OP;
+
+ case 0x9: // SUB
+ set_a_c(get_a() + (get_index_reg(opa) ^ 0x0fU) + (get_c() ^ 0x01U));
+ return cycle::OP;
+
+ case 0xa: // LD
+ set_a(get_index_reg(opa));
+ return cycle::OP;
+
+ case 0xb: // XCH
+ {
+ u8 const val = get_a();
+ set_a(get_index_reg(opa));
+ set_index_reg(opa, val);
+ }
+ return cycle::OP;
+
+ case 0xc: // BBL
+ pop_pc();
+ set_a(opa);
+ return cycle::OP;
+
+ case 0xd: // LDM
+ set_a(opa);
+ return cycle::OP;
+
+ case 0xe: // WRM/WMP/WRR/WPM/WR0/WR1/WR2/WR3/SBM/RDM/RDR/ADM/RD0/RD1/RD2/RD3
+ return cycle::OP;
+
+ case 0xf:
+ switch (opa)
+ {
+ case 0x0: // CLB
+ set_a(0U);
+ set_c(0U);
+ return cycle::OP;
+ case 0x1: // CLC
+ set_c(0U);
+ return cycle::OP;
+ case 0x2: // IAC
+ set_a_c(get_a() + 1U);
+ return cycle::OP;
+ case 0x3: // CMC
+ set_c(get_c() ^ 0x01U);
+ return cycle::OP;
+ case 0x4: // CMA
+ set_a(get_a() ^ 0x0fU);
+ return cycle::OP;
+ case 0x5: // RAL
+ set_a_c((get_a() << 1) | get_c());
+ return cycle::OP;
+ case 0x6: // RAR
+ {
+ u8 const c(BIT(get_a(), 0));
+ set_a((get_a() >> 1) | (get_c() << 3));
+ set_c(c);
+ }
+ return cycle::OP;
+ case 0x7: // TCC
+ set_a(get_c());
+ set_c(0U);
+ return cycle::OP;
+ case 0x8: // DAC
+ set_a_c(get_a() + 0x0fU);
+ return cycle::OP;
+ case 0x9: // TCS
+ set_a(9U + get_c());
+ set_c(0U);
+ return cycle::OP;
+ case 0xa: // STC
+ set_c(1U);
+ return cycle::OP;
+ case 0xb: // DAA
+ if (get_c() || (9U < get_a()))
+ {
+ u8 const val(get_a() + 6U);
+ set_a(val);
+ if (BIT(val, 4))
+ set_c(1U);
+ }
+ return cycle::OP;
+ case 0xc: // KBP
+ set_a(kbp_table[get_a()]);
+ return cycle::OP;
+ case 0xd: // DCL
+ set_cr(get_a(), 0x07U);
+ return cycle::OP;
+ default:
+ break;
+ }
+ break;
+
+ default: // something is badly wrong if we get here
+ throw false;
+ }
+
+ logerror("MCS-40: unhandled instruction OPR=%X OPA=%X\n", opr, opa);
+ return cycle::OP;
+}
+
+void i4004_cpu_device::do_cycle2(u8 opr, u8 opa, u8 arg)
+{
+ switch (opr)
+ {
+ case 0x1: // JCN
+ {
+ // FIXME: on which cycle is TEST sampled?
+ // order of expression is important because of how HOLD_LINE is consumed for TEST input
+ bool const jump((BIT(opa, 0) && !get_test()) || (BIT(opa, 1) && get_c()) || (BIT(opa, 2) && !get_a()));
+ if (bool(BIT(opa, 3)) != jump)
+ set_pc(arg, 0x00ff);
+ }
+ break;
+
+ case 0x2: // FIM
+ assert(!BIT(opa, 0));
+ index_reg_pair(opa >> 1) = arg;
+ break;
+
+ case 0x3: // FIN
+ assert(BIT(opa, 0));
+ index_reg_pair(opa >> 1) = arg;
+ break;
+
+ case 0x4: // JUN
+ set_pc((u16(opa) << 8) | arg, 0x0fffU);
+ break;
+
+ case 0x5: // JMS
+ push_pc();
+ set_pc((u16(opa) << 8) | arg, 0x0fffU);
+ break;
+
+ case 0x7: // ISZ
+ {
+ u8 const val((get_index_reg(opa) + 1U) & 0x0fU);
+ set_index_reg(opa, val);
+ if (val)
+ set_pc(arg, 0x00ffU);
+ }
+ break;
+
+ default: // something is badly wrong if we get here
+ throw false;
+ }
+}
+
+void i4004_cpu_device::do_io(u8 opr, u8 opa)
+{
+ assert(0xe == opr);
+ switch (opa)
+ {
+ case 0x0: // WRM
+ write_memory(get_a());
+ break;
+ case 0x1: // WMP
+ write_memory_port(get_a());
+ break;
+ case 0x2: // WRR
+ write_rom_port(get_a());
+ break;
+ case 0x4: // WR0
+ case 0x5: // WR1
+ case 0x6: // WR2
+ case 0x7: // WR3
+ write_status(get_a());
+ break;
+ case 0x8: // SBM
+ set_a_c(get_a() + (read_memory() ^ 0x0fU) + (get_c() ^ 0x01U));
+ break;
+ case 0x9: // RDM
+ set_a(read_memory());
+ break;
+ case 0xa: // RDR
+ set_a(read_rom_port());
+ break;
+ case 0xb: // ADM
+ set_a_c(get_a() + read_memory() + get_c());
+ break;
+ case 0xc: // RD0
+ case 0xd: // RD1
+ case 0xe: // RD2
+ case 0xf: // RD3
+ set_a(read_status());
+ break;
+ default:
+ logerror("MCS-40: unhandled instruction OPR=%X OPA=%X\n", opr, opa);
+ }
+}
+
+
+
+i4040_cpu_device::i4040_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+ : i4004_cpu_device(mconfig, I4040, tag, owner, clock, true, 13U, 0x7U, 24U, 0xfU)
+{
+}
+
+
+/***********************************************************************
+ device_disasm_interface implementation
+***********************************************************************/
+
+offs_t i4040_cpu_device::disasm_disassemble(
+ std::ostream &stream,
+ offs_t pc,
+ uint8_t const *oprom,
+ uint8_t const *opram,
+ uint32_t options)
+{
+ extern CPU_DISASSEMBLE(i4040);
+ return CPU_DISASSEMBLE_NAME(i4040)(this, stream, pc, oprom, opram, options);
+}
+
+
+/***********************************************************************
+ mcs40_cpu_device_base implementation
+***********************************************************************/
+
+i4040_cpu_device::cycle i4040_cpu_device::do_cycle1(u8 opr, u8 opa)
+{
+ switch (opr)
+ {
+ case 0x0:
+ switch (opa)
+ {
+ case 0x3: // LCR
+ set_a(get_cr());
+ break;
+ case 0x4: // OR4
+ case 0x5: // OR5
+ set_a(get_a() | get_index_reg(4U | BIT(opa, 0)));
+ return cycle::OP;
+ case 0x6: // AN6
+ case 0x7: // AN7
+ set_a(get_a() & get_index_reg(6U | BIT(opa, 0)));
+ return cycle::OP;
+ case 0x8: // DB0
+ case 0x9: // DB1
+ set_pending_rom_bank(BIT(opa, 0));
+ return cycle::OP;
+ case 0xa: // SB0
+ case 0xb: // SB1
+ set_index_reg_bank(BIT(opa, 0));
+ return cycle::OP;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return i4004_cpu_device::do_cycle1(opr, opa);
+}
+
+
+#if 0
+void i4004_cpu_device::WPM()
+{
+ uint8_t t = (m_program->read_byte(m_RAM.d) << 4) | m_A;
+ m_program->write_byte((GET_PC.w.l & 0x0f00) | m_RAM.d, t);
+}
+
+
+void i4004_cpu_device::execute_one(unsigned opcode)
+{
+ m_icount -= 8;
+ switch ((opcode >> 4) & 0x0f)
+ {
+ case 0xe:
+ switch (opcode & 0x0f)
+ {
+ case 0x3: WPM(); break; // WPM
+ }
+ return;
+ }
+}
+
+
+void i4040_cpu_device::execute_one(unsigned opcode)
+{
+ switch (opcode)
+ {
+ case 0x01: // HLT
+ case 0x02: // BBS
+ case 0x0a: // SB0
+ case 0x0b: // SB1
+ case 0x0c: // EIN
+ case 0x0d: // DIN
+ case 0x0e: // RPM
+ default:
+ i4004_cpu_device::execute_one(opcode);
+ }
+}
+#endif
diff --git a/src/devices/cpu/mcs40/mcs40.h b/src/devices/cpu/mcs40/mcs40.h
new file mode 100644
index 00000000000..fe7c9e3352e
--- /dev/null
+++ b/src/devices/cpu/mcs40/mcs40.h
@@ -0,0 +1,307 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#ifndef MAME_CPU_I4004_I4004_H
+#define MAME_CPU_I4004_I4004_H
+
+#pragma once
+
+
+/***********************************************************************
+ CONSTANTS
+***********************************************************************/
+
+enum
+{
+ I4004_A = 1,
+ I4004_R01, I4004_R23, I4004_R45, I4004_R67, I4004_R89, I4004_RAB, I4004_RCD, I4004_REF,
+ I4040_RGH, I4040_RIJ, I4040_RKL, I4040_RMN,
+ I4004_ADDR0, I4004_ADDR1, I4004_ADDR2, I4004_ADDR3,
+ I4040_ADDR4, I4040_ADDR5, I4040_ADDR6, I4040_ADDR7,
+ I4004_CR, I4004_RC, I4004_RCN,
+ I4040_SRC
+};
+
+enum
+{
+ I4004_TEST_LINE = 0,
+
+ I4040_TEST_LINE = I4004_TEST_LINE,
+ I4040_INT_LINE = 1,
+ I4040_STP_LINE = 2
+};
+
+
+
+/***********************************************************************
+ CONFIGURATION MACROS
+***********************************************************************/
+
+#define MCFG_I4004_SYNC_CB(obj) \
+ devcb = &i4004_cpu_device::set_sync_cb(*device, DEVCB_##obj);
+
+#define MCFG_I4004_CM_ROM_CB(obj) \
+ devcb = &i4004_cpu_device::set_cm_rom_cb(*device, DEVCB_##obj);
+
+#define MCFG_I4004_CM_RAM0_CB(obj) \
+ devcb = &i4004_cpu_device::set_cm_ram_cb<0>(*device, DEVCB_##obj);
+
+#define MCFG_I4004_CM_RAM1_CB(obj) \
+ devcb = &i4004_cpu_device::set_cm_ram_cb<1>(*device, DEVCB_##obj);
+
+#define MCFG_I4004_CM_RAM2_CB(obj) \
+ devcb = &i4004_cpu_device::set_cm_ram_cb<2>(*device, DEVCB_##obj);
+
+#define MCFG_I4004_CM_RAM3_CB(obj) \
+ devcb = &i4004_cpu_device::set_cm_ram_cb<3>(*device, DEVCB_##obj);
+
+
+#define MCFG_I4040_SYNC_CB(obj) \
+ devcb = &i4040_cpu_device::set_sync_cb(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_ROM0_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_rom_cb<0>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_ROM1_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_rom_cb<1>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_RAM0_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_ram_cb<0>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_RAM1_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_ram_cb<1>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_RAM2_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_ram_cb<2>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CM_RAM3_CB(obj) \
+ devcb = &i4040_cpu_device::set_cm_ram_cb<3>(*device, DEVCB_##obj);
+
+#define MCFG_I4040_CY_CB(obj) \
+ devcb = &i4040_cpu_device::set_cy_cb(*device, DEVCB_##obj);
+
+
+
+/***********************************************************************
+ TYPE DEFINITIONS
+***********************************************************************/
+
+class mcs40_cpu_device_base : public cpu_device
+{
+protected:
+ enum class cycle { OP, IM, IN };
+
+ mcs40_cpu_device_base(
+ machine_config const &mconfig,
+ device_type type,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock,
+ bool extended_cm,
+ unsigned rom_width,
+ unsigned stack_ptr_mask,
+ unsigned index_reg_cnt,
+ unsigned cr_mask);
+
+ // device_t implementation
+ void device_start() override;
+ void device_reset() override;
+
+ // device_execute_interface implementation
+ virtual void execute_run() override;
+
+ // device_memory_interface configuration
+ virtual address_space_config const *memory_space_config(address_spacenum spacenum) const override;
+
+ // device_state_interface implementation
+ virtual void state_import(device_state_entry const &entry) override;
+ virtual void state_export(device_state_entry const &entry) override;
+ virtual void state_string_export(device_state_entry const &entry, std::string &str) const override;
+
+ // device_disasm_interface implementation
+ virtual u32 disasm_min_opcode_bytes() const override;
+ virtual u32 disasm_max_opcode_bytes() const override;
+
+ // instruction execution
+ virtual bool is_io_op(u8 opr) = 0;
+ virtual cycle do_cycle1(u8 opr, u8 opa) = 0;
+ virtual void do_cycle2(u8 opr, u8 opa, u8 arg) = 0;
+ virtual void do_io(u8 opr, u8 opa) = 0;
+
+ // register access
+ u8 get_a() const;
+ u8 get_c() const;
+ void set_a(u8 val);
+ void set_c(u8 val);
+ void set_a_c(u8 val);
+ void set_pc(u16 addr, u16 mask);
+ void push_pc();
+ void pop_pc();
+ u8 &index_reg_pair(unsigned n);
+ u8 get_index_reg(unsigned n);
+ void set_index_reg(unsigned n, u8 val);
+ void set_index_reg_bank(u8 val);
+
+ // I/O control
+ void set_rom_addr(u16 addr, u16 mask);
+ u8 get_cr();
+ void set_cr(u8 val, u8 mask);
+ void set_pending_rom_bank(u8 val);
+ void set_rc(u8 val);
+ u8 read_memory();
+ void write_memory(u8 val);
+ u8 read_status();
+ void write_status(u8 val);
+ u8 read_rom_port();
+ void write_rom_port(u8 val);
+ void write_memory_port(u8 val);
+
+ // input lines
+ bool get_test();
+ void set_test(int state);
+
+ // configuration helpers
+ template <typename Obj> devcb_base &set_sync_cb(Obj &&cb)
+ { return m_sync_cb.set_callback(std::forward<Obj>(cb)); }
+ template <unsigned N, typename Obj> devcb_base &set_cm_rom_cb(Obj &&cb)
+ { return m_cm_rom_cb[N].set_callback(std::forward<Obj>(cb)); }
+ template <unsigned N, typename Obj> devcb_base &set_cm_ram_cb(Obj &&cb)
+ { return m_cm_ram_cb[N].set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base &set_cy_cb(Obj &&cb)
+ { return m_cy_cb.set_callback(std::forward<Obj>(cb)); }
+
+private:
+ enum class phase { A1, A2, A3, M1, M2, X1, X2, X3 };
+
+ // internal helpers
+ u16 &pc() { return m_addr_stack[m_stack_ptr]; }
+ u16 rom_bank() const { return BIT(m_cr, 3) ? 0x1000U : 0x0000U; }
+ void update_cm_rom(u8 val);
+ void update_cm_ram(u8 val);
+ void update_cy(u8 val);
+
+ // address spaces
+ address_space_config m_program_config, m_data_config, m_io_config;
+ address_space *m_program, *m_data, *m_io;
+ direct_read_data *m_direct;
+
+ // output callbacks
+ devcb_write_line m_sync_cb;
+ devcb_write_line m_cm_rom_cb[2], m_cm_ram_cb[4];
+ devcb_write_line m_cy_cb;
+
+ // configuration
+ bool const m_extended_cm;
+ u8 const m_stack_ptr_mask;
+ u8 const m_index_reg_cnt;
+ u8 const m_cr_mask;
+ u16 const m_pc_mask;
+
+ // machine/instruction phase
+ int m_icount;
+ phase m_phase;
+ cycle m_cycle;
+ bool m_io_pending;
+
+ // instruction ROM fetch/decode
+ u16 m_rom_bank, m_rom_addr;
+ u8 m_opr, m_opa, m_arg;
+
+ // ALU registers
+ u8 m_a, m_c;
+
+ // address stack
+ std::unique_ptr<u16 []> m_addr_stack;
+ u8 m_stack_ptr;
+
+ // index registers
+ std::unique_ptr<u8 []> m_index_regs;
+ u8 m_index_reg_bank;
+
+ // RAM/I/O control
+ u8 m_cr, m_pending_cr3, m_latched_rc, m_new_rc, m_src;
+ bool m_rc_pending;
+
+ // input/output lines
+ int m_test;
+ u8 m_cm_rom, m_cm_ram, m_cy;
+
+ // state export/import
+ u16 m_pc, m_pcbase;
+ u8 m_genflags;
+};
+
+
+class i4004_cpu_device : public mcs40_cpu_device_base
+{
+public:
+ // configuration helpers
+ template <typename Obj> static devcb_base &set_sync_cb(device_t &device, Obj &&cb)
+ { return downcast<i4004_cpu_device &>(device).set_sync_cb(std::forward<Obj>(cb)); }
+ template <typename Obj> static devcb_base &set_cm_rom_cb(device_t &device, Obj &&cb)
+ { return downcast<i4004_cpu_device &>(device).set_cm_rom_cb<0>(std::forward<Obj>(cb)); }
+ template <unsigned N, typename Obj> static devcb_base &set_cm_ram_cb(device_t &device, Obj &&cb)
+ { return downcast<i4004_cpu_device &>(device).set_cm_ram_cb<N>(std::forward<Obj>(cb)); }
+
+ i4004_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ using mcs40_cpu_device_base::mcs40_cpu_device_base;
+
+ // device_execute_interface implementation
+ u32 execute_input_lines() const override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_disasm_interface implementation
+ virtual offs_t disasm_disassemble(
+ std::ostream &stream,
+ offs_t pc,
+ uint8_t const *oprom,
+ uint8_t const *opram,
+ uint32_t options) override;
+
+ // mcs40_cpu_device_base implementation
+ virtual bool is_io_op(u8 opr) override;
+ virtual cycle do_cycle1(u8 opr, u8 opa) override;
+ virtual void do_cycle2(u8 opr, u8 opa, u8 arg) override;
+ virtual void do_io(u8 opr, u8 opa) override;
+};
+
+
+class i4040_cpu_device : public i4004_cpu_device
+{
+public:
+ // configuration helpers
+ template <typename Obj> static devcb_base &set_sync_cb(device_t &device, Obj &&cb)
+ { return downcast<i4040_cpu_device &>(device).set_sync_cb(std::forward<Obj>(cb)); }
+ template <unsigned N, typename Obj> static devcb_base &set_cm_rom_cb(device_t &device, Obj &&cb)
+ { return downcast<i4040_cpu_device &>(device).set_cm_rom_cb<N>(std::forward<Obj>(cb)); }
+ template <unsigned N, typename Obj> static devcb_base &set_cm_ram_cb(device_t &device, Obj &&cb)
+ { return downcast<i4040_cpu_device &>(device).set_cm_ram_cb<N>(std::forward<Obj>(cb)); }
+ template <typename Obj> static devcb_base &set_cy_cb(device_t &device, Obj &&cb)
+ { return downcast<i4040_cpu_device &>(device).set_cy_cb(std::forward<Obj>(cb)); }
+
+ i4040_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device_disasm_interface implementation
+ virtual offs_t disasm_disassemble(
+ std::ostream &stream,
+ offs_t pc,
+ uint8_t const *oprom,
+ uint8_t const *opram,
+ uint32_t options) override;
+
+ // mcs40_cpu_device_base implementation
+ virtual cycle do_cycle1(u8 opr, u8 opa) override;
+};
+
+
+
+/***********************************************************************
+ DEVICE TYPE DECLARATIONS
+***********************************************************************/
+
+DECLARE_DEVICE_TYPE(I4004, i4004_cpu_device)
+DECLARE_DEVICE_TYPE(I4040, i4040_cpu_device)
+
+#endif // MAME_CPU_I4004_I4004_H
diff --git a/src/devices/cpu/mcs40/mcs40dasm.cpp b/src/devices/cpu/mcs40/mcs40dasm.cpp
new file mode 100644
index 00000000000..7e3f3d68a44
--- /dev/null
+++ b/src/devices/cpu/mcs40/mcs40dasm.cpp
@@ -0,0 +1,189 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*****************************************************************************
+ *
+ * 4004dasm.cpp
+ *
+ * Intel MCS-40 CPU Disassembly
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+
+namespace {
+
+enum class format
+{
+ ILL,
+ SIMPLE,
+ IMM4,
+ REG,
+ REGPAGE,
+ PAIR,
+ PAIRIMM,
+ ABS,
+ PAGE,
+ COND
+};
+
+enum class level
+{
+ I4004,
+ I4040
+};
+
+struct op
+{
+ format m_format;
+ level m_level;
+ char const *m_name;
+};
+
+#define OP(fmt, lvl, name) { format::fmt, level::lvl, #name }
+
+op const f_ops[256] = {
+ OP(SIMPLE, I4004, nop), OP(SIMPLE, I4040, hlt), OP(SIMPLE, I4040, bbs), OP(SIMPLE, I4040, lcr),
+ OP(SIMPLE, I4040, or4), OP(SIMPLE, I4040, or5), OP(SIMPLE, I4040, an6), OP(SIMPLE, I4040, an7),
+ OP(SIMPLE, I4040, db0), OP(SIMPLE, I4040, db1), OP(SIMPLE, I4040, sb0), OP(SIMPLE, I4040, sb1),
+ OP(SIMPLE, I4040, ein), OP(SIMPLE, I4040, din), OP(SIMPLE, I4040, rpm), OP(ILL, I4004, ill),
+
+ OP(COND, I4004, jcn), OP(PAGE, I4004, jnt), OP(PAGE, I4004, jc ), OP(COND, I4004, jcn),
+ OP(PAGE, I4004, jz ), OP(COND, I4004, jcn), OP(COND, I4004, jcn), OP(COND, I4004, jcn),
+ OP(COND, I4004, jcn), OP(PAGE, I4004, jt), OP(PAGE, I4004, jnc), OP(COND, I4004, jcn),
+ OP(PAGE, I4004, jnz), OP(COND, I4004, jcn), OP(COND, I4004, jcn), OP(COND, I4004, jcn),
+
+ OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
+ OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
+ OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
+ OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
+
+ OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
+ OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
+ OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
+ OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
+
+ OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun),
+ OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun),
+ OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun),
+ OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun), OP(ABS, I4004, jun),
+
+ OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms),
+ OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms),
+ OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms),
+ OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms), OP(ABS, I4004, jms),
+
+ OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc),
+ OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc),
+ OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc),
+ OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc), OP(REG, I4004, inc),
+
+ OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz),
+ OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz),
+ OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz),
+ OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz), OP(REGPAGE, I4004, isz),
+
+ OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add),
+ OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add),
+ OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add),
+ OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add), OP(REG, I4004, add),
+
+ OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub),
+ OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub),
+ OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub),
+ OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub), OP(REG, I4004, sub),
+
+ OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ),
+ OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ),
+ OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ),
+ OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ), OP(REG, I4004, ld ),
+
+ OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch),
+ OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch),
+ OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch),
+ OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch), OP(REG, I4004, xch),
+
+ OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl),
+ OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl),
+ OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl),
+ OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl), OP(IMM4, I4004, bbl),
+
+ OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm),
+ OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm),
+ OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm),
+ OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm), OP(IMM4, I4004, ldm),
+
+ OP(SIMPLE, I4004, wrm), OP(SIMPLE, I4004, wmp), OP(SIMPLE, I4004, wrr), OP(SIMPLE, I4004, wpm),
+ OP(SIMPLE, I4004, wr0), OP(SIMPLE, I4004, wr1), OP(SIMPLE, I4004, wr2), OP(SIMPLE, I4004, wr3),
+ OP(SIMPLE, I4004, sbm), OP(SIMPLE, I4004, rdm), OP(SIMPLE, I4004, rdr), OP(SIMPLE, I4004, adm),
+ OP(SIMPLE, I4004, rd0), OP(SIMPLE, I4004, rd1), OP(SIMPLE, I4004, rd2), OP(SIMPLE, I4004, rd3),
+
+ OP(SIMPLE, I4004, clb), OP(SIMPLE, I4004, clc), OP(SIMPLE, I4004, iac), OP(SIMPLE, I4004, cmc),
+ OP(SIMPLE, I4004, cma), OP(SIMPLE, I4004, ral), OP(SIMPLE, I4004, rar), OP(SIMPLE, I4004, tcc),
+ OP(SIMPLE, I4004, dac), OP(SIMPLE, I4004, tcs), OP(SIMPLE, I4004, stc), OP(SIMPLE, I4004, daa),
+ OP(SIMPLE, I4004, kbp), OP(SIMPLE, I4004, dcl), OP(ILL, I4004, ill), OP(ILL, I4004, ill) };
+
+offs_t disassemble(
+ cpu_device *device,
+ std::ostream &stream,
+ offs_t pc,
+ u8 const *oprom,
+ u8 const *opram,
+ int options,
+ level lvl,
+ unsigned pcmask)
+{
+ offs_t npc(pc + 1);
+ u8 const opcode(oprom[0]);
+ op const &desc(f_ops[(f_ops[opcode].m_level > lvl) ? 0xffU : opcode]);
+
+ switch (desc.m_format)
+ {
+ case format::ILL:
+ util::stream_format(stream, "%-3s $%02x", desc.m_name, opcode);
+ break;
+ case format::SIMPLE:
+ util::stream_format(stream, "%s", desc.m_name);
+ break;
+ case format::IMM4:
+ case format::REG:
+ util::stream_format(stream, "%-3s $%01x", desc.m_name, opcode & 0x0fU);
+ break;
+ case format::REGPAGE:
+ case format::COND:
+ npc++;
+ util::stream_format(stream, "%-3s $%01x,$%03x", desc.m_name, opcode & 0x0fU, opram[1] | (npc & 0x0f00U));
+ break;
+ case format::PAIR:
+ util::stream_format(stream, "%-3s $%01x", desc.m_name, opcode & 0x0eU);
+ break;
+ case format::PAIRIMM:
+ npc++;
+ util::stream_format(stream, "%-3s $%01x,$%02x", desc.m_name, opcode & 0x0eU, opram[1]);
+ break;
+ case format::ABS:
+ npc++;
+ util::stream_format(stream, "%-3s $%03x", desc.m_name, ((u16(opcode) & 0x0fU) << 8) | opram[1]);
+ break;
+ case format::PAGE:
+ npc++;
+ util::stream_format(stream, "%-3s $%03x", desc.m_name, opram[1] | (npc & 0x0f00U));
+ break;
+ }
+
+ offs_t flags(0U);
+ if (format::ILL != desc.m_format)
+ {
+ if (0x50U == (opcode & 0xf0U)) // JMS
+ flags = DASMFLAG_STEP_OVER;
+ else if ((0xc0 == (opcode & 0xf0)) || (0x02 == opcode)) // BBL/BBS
+ flags = DASMFLAG_STEP_OUT;
+ }
+
+ return (npc - pc) | flags | DASMFLAG_SUPPORTED;
+}
+
+} // anonymous namespace
+
+
+CPU_DISASSEMBLE(i4004) { return disassemble(device, stream, pc, oprom, opram, options, level::I4004, 0x0fffU); }
+CPU_DISASSEMBLE(i4040) { return disassemble(device, stream, pc, oprom, opram, options, level::I4040, 0x1fffU); }
diff --git a/src/mame/drivers/4004clk.cpp b/src/mame/drivers/4004clk.cpp
index c9cb98538cb..acf35c9b837 100644
--- a/src/mame/drivers/4004clk.cpp
+++ b/src/mame/drivers/4004clk.cpp
@@ -9,7 +9,8 @@
****************************************************************************/
#include "emu.h"
-#include "cpu/i4004/i4004.h"
+#include "cpu/mcs40/mcs40.h"
+#include "machine/clock.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"
#include "speaker.h"
@@ -19,73 +20,61 @@
class nixieclock_state : public driver_device
{
public:
- nixieclock_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_input(*this, "INPUT")
- { }
-
- required_device<i4004_cpu_device> m_maincpu;
- required_ioport m_input;
- DECLARE_READ8_MEMBER( data_r );
+ nixieclock_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) { }
+
DECLARE_WRITE8_MEMBER( nixie_w );
DECLARE_WRITE8_MEMBER( neon_w );
- uint16_t m_nixie[16];
- uint8_t m_timer;
- virtual void machine_start() override;
- TIMER_DEVICE_CALLBACK_MEMBER(timer_callback);
- uint8_t nixie_to_num(uint16_t val);
- inline void output_set_nixie_value(int index, int value);
- inline void output_set_neon_value(int index, int value);
-};
-READ8_MEMBER(nixieclock_state::data_r)
-{
- return m_input->read() & 0x0f;
-}
-
-uint8_t nixieclock_state::nixie_to_num(uint16_t val)
-{
- if (BIT(val,0)) return 0;
- if (BIT(val,1)) return 1;
- if (BIT(val,2)) return 2;
- if (BIT(val,3)) return 3;
- if (BIT(val,4)) return 4;
- if (BIT(val,5)) return 5;
- if (BIT(val,6)) return 6;
- if (BIT(val,7)) return 7;
- if (BIT(val,8)) return 8;
- if (BIT(val,9)) return 9;
- return 10;
-}
+protected:
+ virtual void machine_start() override;
-inline void nixieclock_state::output_set_nixie_value(int index, int value)
-{
- output().set_indexed_value("nixie", index, value);
-}
+private:
+ static constexpr uint8_t nixie_to_num(uint16_t val)
+ {
+ return
+ (BIT(val, 0)) ? 0 :
+ (BIT(val, 1)) ? 1 :
+ (BIT(val, 2)) ? 2 :
+ (BIT(val, 3)) ? 3 :
+ (BIT(val, 4)) ? 4 :
+ (BIT(val, 5)) ? 5 :
+ (BIT(val, 6)) ? 6 :
+ (BIT(val, 7)) ? 7 :
+ (BIT(val, 8)) ? 8 :
+ (BIT(val, 9)) ? 9 :
+ 10;
+ }
+
+ void output_set_nixie_value(int index, int value)
+ {
+ output().set_indexed_value("nixie", index, value);
+ }
+
+ void output_set_neon_value(int index, int value)
+ {
+ output().set_indexed_value("neon", index, value);
+ }
-inline void nixieclock_state::output_set_neon_value(int index, int value)
-{
- output().set_indexed_value("neon", index, value);
-}
+ uint16_t m_nixie[16];
+};
WRITE8_MEMBER(nixieclock_state::nixie_w)
{
- m_nixie[offset] = data;
- output_set_nixie_value(5,nixie_to_num(((m_nixie[2] & 3)<<8) | (m_nixie[1] << 4) | m_nixie[0]));
- output_set_nixie_value(4,nixie_to_num((m_nixie[4] << 6) | (m_nixie[3] << 2) | (m_nixie[2] >>2)));
- output_set_nixie_value(3,nixie_to_num(((m_nixie[7] & 3)<<8) | (m_nixie[6] << 4) | m_nixie[5]));
- output_set_nixie_value(2,nixie_to_num((m_nixie[9] << 6) | (m_nixie[8] << 2) | (m_nixie[7] >>2)));
- output_set_nixie_value(1,nixie_to_num(((m_nixie[12] & 3)<<8) | (m_nixie[11] << 4) | m_nixie[10]));
- output_set_nixie_value(0,nixie_to_num((m_nixie[14] << 6) | (m_nixie[13] << 2) | (m_nixie[12] >>2)));
+ m_nixie[offset >> 4] = data;
+ output_set_nixie_value(5, nixie_to_num(((m_nixie[2] & 3)<<8) | (m_nixie[1] << 4) | m_nixie[0]));
+ output_set_nixie_value(4, nixie_to_num((m_nixie[4] << 6) | (m_nixie[3] << 2) | (m_nixie[2] >>2)));
+ output_set_nixie_value(3, nixie_to_num(((m_nixie[7] & 3)<<8) | (m_nixie[6] << 4) | m_nixie[5]));
+ output_set_nixie_value(2, nixie_to_num((m_nixie[9] << 6) | (m_nixie[8] << 2) | (m_nixie[7] >>2)));
+ output_set_nixie_value(1, nixie_to_num(((m_nixie[12] & 3)<<8) | (m_nixie[11] << 4) | m_nixie[10]));
+ output_set_nixie_value(0, nixie_to_num((m_nixie[14] << 6) | (m_nixie[13] << 2) | (m_nixie[12] >>2)));
}
WRITE8_MEMBER(nixieclock_state::neon_w)
{
- output_set_neon_value(0,BIT(data,3));
- output_set_neon_value(1,BIT(data,2));
- output_set_neon_value(2,BIT(data,1));
- output_set_neon_value(3,BIT(data,0));
+ output_set_neon_value(0, BIT(data,3));
+ output_set_neon_value(1, BIT(data,2));
+ output_set_neon_value(2, BIT(data,1));
+ output_set_neon_value(3, BIT(data,0));
}
static ADDRESS_MAP_START(4004clk_rom, AS_PROGRAM, 8, nixieclock_state)
@@ -99,10 +88,10 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( 4004clk_io, AS_IO, 8, nixieclock_state)
ADDRESS_MAP_UNMAP_HIGH
- AM_RANGE(0x00, 0x0e) AM_WRITE(nixie_w)
- AM_RANGE(0x00, 0x00) AM_READ(data_r)
- AM_RANGE(0x0f, 0x0f) AM_WRITE(neon_w)
- AM_RANGE(0x10, 0x10) AM_DEVWRITE("dac", dac_bit_interface, write)
+ AM_RANGE(0x0000, 0x000f) AM_MIRROR(0x0700) AM_READ_PORT("INPUT")
+ AM_RANGE(0x0000, 0x00ef) AM_MIRROR(0x0700) AM_WRITE(nixie_w)
+ AM_RANGE(0x00f0, 0x00ff) AM_MIRROR(0x0700) AM_WRITE(neon_w)
+ AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x083f) AM_DEVWRITE("dac", dac_bit_interface, write)
ADDRESS_MAP_END
/* Input ports */
@@ -119,33 +108,16 @@ static INPUT_PORTS_START( 4004clk )
PORT_CONFSETTING( 0x08, "60 Hz" )
INPUT_PORTS_END
-/*
- 16ms Int generator
- __ __
- _| |_|
- 0 1 0 1
-
-*/
-
-TIMER_DEVICE_CALLBACK_MEMBER(nixieclock_state::timer_callback)
-{
- m_maincpu->set_test(m_timer);
- m_timer^=1;
-}
-
void nixieclock_state::machine_start()
{
- m_timer = 0;
-
/* register for state saving */
- save_item(NAME(m_timer));
save_pointer(NAME(m_nixie), 6);
}
static MACHINE_CONFIG_START( 4004clk )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu",I4004, XTAL_5MHz / 8)
+ MCFG_CPU_ADD("maincpu", I4004, XTAL_5MHz / 8)
MCFG_CPU_PROGRAM_MAP(4004clk_rom)
MCFG_CPU_DATA_MAP(4004clk_mem)
MCFG_CPU_IO_MAP(4004clk_io)
@@ -159,7 +131,8 @@ static MACHINE_CONFIG_START( 4004clk )
MCFG_DEVICE_ADD("vref", VOLTAGE_REGULATOR, 0) MCFG_VOLTAGE_REGULATOR_OUTPUT(5.0)
MCFG_SOUND_ROUTE_EX(0, "dac", 1.0, DAC_VREF_POS_INPUT)
- MCFG_TIMER_DRIVER_ADD_PERIODIC("4004clk_timer", nixieclock_state, timer_callback, attotime::from_hz(120))
+ MCFG_CLOCK_ADD("clk", 60)
+ MCFG_CLOCK_SIGNAL_HANDLER(INPUTLINE("maincpu", I4004_TEST_LINE))
MACHINE_CONFIG_END
/* ROM definition */
@@ -185,5 +158,5 @@ ROM_END
/* Driver */
-/* YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS */
+// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS
SYST( 2008, 4004clk, 0, 0, 4004clk, 4004clk, nixieclock_state, 0, "John L. Weinrich", "4004 Nixie Clock", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/busicom.cpp b/src/mame/drivers/busicom.cpp
index 09a685d6114..2f84c930e62 100644
--- a/src/mame/drivers/busicom.cpp
+++ b/src/mame/drivers/busicom.cpp
@@ -11,7 +11,6 @@
#include "emu.h"
#include "includes/busicom.h"
-#include "cpu/i4004/i4004.h"
#include "screen.h"
@@ -23,10 +22,10 @@ uint8_t busicom_state::get_bit_selected(uint32_t val,int num)
}
return 0;
}
+
READ8_MEMBER(busicom_state::keyboard_r)
{
- static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7", "LINE8" , "LINE9"};
- return ioport(keynames[get_bit_selected(m_keyboard_shifter & 0x3ff,10)])->read();
+ return m_input_lines[get_bit_selected(m_keyboard_shifter & 0x3ff, 10)]->read();
}
READ8_MEMBER(busicom_state::printer_r)
@@ -40,6 +39,7 @@ READ8_MEMBER(busicom_state::printer_r)
WRITE8_MEMBER(busicom_state::shifter_w)
{
+ // FIXME: detect edges, maybe make 4003 shifter a device
if (BIT(data,0)) {
m_keyboard_shifter <<= 1;
m_keyboard_shifter |= BIT(data,1);
@@ -111,11 +111,11 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( busicom_io , AS_IO, 8, busicom_state )
ADDRESS_MAP_UNMAP_HIGH
- AM_RANGE(0x00, 0x00) AM_WRITE(shifter_w) // ROM0 I/O
- AM_RANGE(0x01, 0x01) AM_READWRITE(keyboard_r,printer_ctrl_w) // ROM1 I/O
- AM_RANGE(0x02, 0x02) AM_READ(printer_r) // ROM2 I/O
- AM_RANGE(0x10, 0x10) AM_WRITE(printer_w) // RAM0 output
- AM_RANGE(0x11, 0x11) AM_WRITE(status_w) // RAM1 output
+ AM_RANGE(0x0000, 0x000f) AM_MIRROR(0x0700) AM_WRITE(shifter_w) // ROM0 I/O
+ AM_RANGE(0x0010, 0x001f) AM_MIRROR(0x0700) AM_READWRITE(keyboard_r,printer_ctrl_w) // ROM1 I/O
+ AM_RANGE(0x0020, 0x002f) AM_MIRROR(0x0700) AM_READ(printer_r) // ROM2 I/O
+ AM_RANGE(0x1000, 0x103f) AM_MIRROR(0x0700) AM_WRITE(printer_w) // RAM0 output
+ AM_RANGE(0x1040, 0x105f) AM_MIRROR(0x0800) AM_WRITE(status_w) // RAM1 output
ADDRESS_MAP_END
/* Input ports */
@@ -183,11 +183,10 @@ INPUT_PORTS_END
TIMER_DEVICE_CALLBACK_MEMBER(busicom_state::timer_callback)
{
- m_timer ^=1;
- if (m_timer==1) m_drum_index++;
- if (m_drum_index==13) m_drum_index=0;
- m_maincpu->set_test(m_timer);
-
+ m_timer ^= 1;
+ if (m_timer == 1) m_drum_index++;
+ if (m_drum_index == 13) m_drum_index = 0;
+ m_maincpu->set_input_line(I4004_TEST_LINE, m_timer);
}
void busicom_state::machine_start()
@@ -214,7 +213,7 @@ void busicom_state::machine_reset()
static MACHINE_CONFIG_START( busicom )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu",I4004, 750000)
+ MCFG_CPU_ADD("maincpu", I4004, 750000)
MCFG_CPU_PROGRAM_MAP(busicom_rom)
MCFG_CPU_DATA_MAP(busicom_mem)
MCFG_CPU_IO_MAP(busicom_io)
diff --git a/src/mame/drivers/flicker.cpp b/src/mame/drivers/flicker.cpp
index 324381adfcf..7077eec8462 100644
--- a/src/mame/drivers/flicker.cpp
+++ b/src/mame/drivers/flicker.cpp
@@ -21,7 +21,7 @@
#include "emu.h"
#include "machine/genpin.h"
-#include "cpu/i4004/i4004.h"
+#include "cpu/mcs40/mcs40.h"
#include "flicker.lh"
class flicker_state : public genpin_class
@@ -57,10 +57,10 @@ static ADDRESS_MAP_START(flicker_map, AS_DATA, 8, flicker_state )
ADDRESS_MAP_END
static ADDRESS_MAP_START( flicker_io, AS_IO, 8, flicker_state )
- AM_RANGE(0x0000, 0x0000) AM_WRITE(port00_w)
- AM_RANGE(0x0001, 0x0001) AM_WRITE(port01_w)
- AM_RANGE(0x0002, 0x0002) AM_READ(port02_r)
- AM_RANGE(0x0010, 0x0010) AM_WRITE(port10_w)
+ AM_RANGE(0x0000, 0x000f) AM_MIRROR(0x0700) AM_WRITE(port00_w)
+ AM_RANGE(0x0010, 0x001f) AM_MIRROR(0x0700) AM_WRITE(port01_w)
+ AM_RANGE(0x0020, 0x002f) AM_MIRROR(0x0700) AM_READ(port02_r)
+ AM_RANGE(0x1000, 0x103f) AM_MIRROR(0x0800) AM_WRITE(port10_w)
ADDRESS_MAP_END
static INPUT_PORTS_START( flicker )
@@ -116,33 +116,27 @@ INPUT_PORTS_END
READ8_MEMBER( flicker_state::port02_r )
{
- offset = m_maincpu->state_int(I4004_RAM) & 0x0f; // we need the full address
-
if (offset < 7)
return m_switch[offset]->read();
-
- return 0;
+ else
+ return 0;
}
WRITE8_MEMBER( flicker_state::port00_w )
{
static const uint8_t patterns[16] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0, 0, 0, 0, 0, 0 };
- offset = m_maincpu->state_int(I4004_RAM); // we need the full address
output().set_digit_value(offset, patterns[data]);
}
WRITE8_MEMBER( flicker_state::port01_w )
{
-// The output lines operate the various lamps (44 of them)
- offset = m_maincpu->state_int(I4004_RAM) & 0x0f; // we need the full address
-
uint16_t test_port = m_testport->read() & 0xf81e;
uint16_t coin_port = m_coinport->read() & 0x07e0;
if (BIT(m_coinport->read(), 0) )
test_port |= coin_port;
- m_maincpu->set_test(BIT(test_port, offset));
+ m_maincpu->set_input_line(I4004_TEST_LINE, BIT(test_port, offset));
}
WRITE8_MEMBER( flicker_state::port10_w )
@@ -165,42 +159,37 @@ The coin outputs (A and B) don't activate
A large amount of data is continuously flowing through here, even when there is no
sound to produce. We need to change this to just one pulse per actual sound. */
- if (!data && offset == m_out_data)
- m_out_data = 0;
- else
+ offset &= 0x0f;
+ if (data != offset)
{
- offset = m_maincpu->state_int(I4004_RAM) & 0x0f; // we need the full address
- if (data != offset)
+ if (data != m_out_data)
{
- if (data != m_out_data)
+ m_out_data = data;
+ switch (data)
{
- m_out_data = data;
- switch (data)
- {
- case 0x01:
- m_samples->start(1, 1);
- break;
- case 0x02:
- m_samples->start(2, 2);
- break;
- case 0x03:
- m_samples->start(3, 3);
- break;
- case 0x04:
- case 0x05:
- case 0x06:
- m_samples->start(0, 0);
- break;
- case 0x07:
- case 0x08:
- m_samples->start(5, 5);
- break;
- case 0x09:
- m_samples->start(0, 6);
- break;
- default:
- break;
- }
+ case 0x01:
+ m_samples->start(1, 1);
+ break;
+ case 0x02:
+ m_samples->start(2, 2);
+ break;
+ case 0x03:
+ m_samples->start(3, 3);
+ break;
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ m_samples->start(0, 0);
+ break;
+ case 0x07:
+ case 0x08:
+ m_samples->start(5, 5);
+ break;
+ case 0x09:
+ m_samples->start(0, 6);
+ break;
+ default:
+ break;
}
}
}
diff --git a/src/mame/includes/busicom.h b/src/mame/includes/busicom.h
index 8bb6e0faa63..0809af8f6af 100644
--- a/src/mame/includes/busicom.h
+++ b/src/mame/includes/busicom.h
@@ -6,18 +6,23 @@
*
****************************************************************************/
-#ifndef BUSICOM_H_
-#define BUSICOM_H_
+#ifndef MAME_INCLUDES_BUSICOM_H
+#define MAME_INCLUDES_BUSICOM_H
-#include "cpu/i4004/i4004.h"
+#pragma once
+
+#include "cpu/mcs40/mcs40.h"
class busicom_state : public driver_device
{
public:
busicom_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_palette(*this, "palette") { }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_palette(*this, "palette")
+ , m_input_lines(*this, "LINE%u", 0)
+ {
+ }
uint8_t m_drum_index;
uint16_t m_keyboard_shifter;
@@ -37,9 +42,12 @@ public:
DECLARE_PALETTE_INIT(busicom);
uint32_t screen_update_busicom(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(timer_callback);
+ uint8_t get_bit_selected(uint32_t val,int num);
+
+private:
required_device<i4004_cpu_device> m_maincpu;
required_device<palette_device> m_palette;
- uint8_t get_bit_selected(uint32_t val,int num);
+ required_ioport_array<10> m_input_lines;
};
-#endif /* BUSICOM_H_ */
+#endif // MAME_INCLUDES_BUSICOM_H
diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp
index 6a53776ab17..aba4a66226f 100644
--- a/src/tools/unidasm.cpp
+++ b/src/tools/unidasm.cpp
@@ -110,6 +110,7 @@ CPU_DISASSEMBLE( hp_5061_3001 );
CPU_DISASSEMBLE( hp_nanoprocessor );
CPU_DISASSEMBLE( hyperstone_generic );
CPU_DISASSEMBLE( i4004 );
+CPU_DISASSEMBLE( i4040 );
CPU_DISASSEMBLE( i8008 );
CPU_DISASSEMBLE( i8051 );
CPU_DISASSEMBLE( i8052 );
@@ -284,6 +285,7 @@ static const dasm_table_entry dasm_table[] =
{ "hp_5061_3001",_16be, -1, CPU_DISASSEMBLE_NAME(hp_5061_3001) },
{ "hyperstone", _16be, 0, CPU_DISASSEMBLE_NAME(hyperstone_generic) },
{ "i4004", _8bit, 0, CPU_DISASSEMBLE_NAME(i4004) },
+ { "i4040", _8bit, 0, CPU_DISASSEMBLE_NAME(i4040) },
{ "i8008", _8bit, 0, CPU_DISASSEMBLE_NAME(i8008) },
{ "i8051", _8bit, 0, CPU_DISASSEMBLE_NAME(i8051) },
{ "i8052", _8bit, 0, CPU_DISASSEMBLE_NAME(i8052) },