diff options
-rw-r--r-- | scripts/src/cpu.lua | 14 | ||||
-rw-r--r-- | scripts/target/mame/arcade.lua | 2 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 2 | ||||
-rw-r--r-- | src/devices/cpu/i4004/4004dasm.cpp | 133 | ||||
-rw-r--r-- | src/devices/cpu/i4004/i4004.cpp | 529 | ||||
-rw-r--r-- | src/devices/cpu/i4004/i4004.h | 107 | ||||
-rw-r--r-- | src/devices/cpu/mcs40/mcs40.cpp | 1022 | ||||
-rw-r--r-- | src/devices/cpu/mcs40/mcs40.h | 307 | ||||
-rw-r--r-- | src/devices/cpu/mcs40/mcs40dasm.cpp | 189 | ||||
-rw-r--r-- | src/mame/drivers/4004clk.cpp | 133 | ||||
-rw-r--r-- | src/mame/drivers/busicom.cpp | 27 | ||||
-rw-r--r-- | src/mame/drivers/flicker.cpp | 83 | ||||
-rw-r--r-- | src/mame/includes/busicom.h | 24 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
14 files changed, 1647 insertions, 927 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 2684a186546..468c2da140b 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -770,19 +770,19 @@ if (CPUS["IE15"]~=null or _OPTIONS["with-tools"]) then end -------------------------------------------------- --- Intel 4004 ---@src/devices/cpu/i4004/i4004.h,CPUS["I4004"] = true +-- Intel MCS-40 +--@src/devices/cpu/mcs40/mcs40.h,CPUS["MCS40"] = true -------------------------------------------------- -if (CPUS["I4004"]~=null) then +if (CPUS["MCS40"]~=null) then files { - MAME_DIR .. "src/devices/cpu/i4004/i4004.cpp", - MAME_DIR .. "src/devices/cpu/i4004/i4004.h", + MAME_DIR .. "src/devices/cpu/mcs40/mcs40.cpp", + MAME_DIR .. "src/devices/cpu/mcs40/mcs40.h", } end -if (CPUS["I4004"]~=null or _OPTIONS["with-tools"]) then - table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/i4004/4004dasm.cpp") +if (CPUS["MCS40"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/mcs40/mcs40dasm.cpp") end -------------------------------------------------- diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 7568f7281a6..d60498ba70d 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -103,7 +103,7 @@ CPUS["MINX"] = true CPUS["SSEM"] = true CPUS["AVR8"] = true --CPUS["TMS1000"] = true -CPUS["I4004"] = true +CPUS["MCS40"] = true CPUS["SUPERFX"] = true CPUS["Z8"] = true CPUS["I8008"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index ee6edf37da8..cdbd0eea109 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -103,7 +103,7 @@ CPUS["MINX"] = true CPUS["SSEM"] = true CPUS["AVR8"] = true CPUS["TMS1000"] = true -CPUS["I4004"] = true +CPUS["MCS40"] = true CPUS["SUPERFX"] = true CPUS["Z8"] = true CPUS["I8008"] = true 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 ®_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) }, |