Rewrote 4004 core and disassembler:

* Renamed to MCS-40.
* Emulated 8-clock instruction cycle, interruptible at any point.
* Converted TEST input to an input line.
* Added SYNC and CM output lines.
* Added support for 4040 CY output, logical operations, extended registers, ROM banking and disassembly.
* Made I/O space mapping more flexible to support the variety of peripherals available.
* Notable missing features are 4040 interrupt and halt, and "program memory" space.
This commit is contained in:
Vas Crabb 2017-06-27 04:01:05 +10:00
parent 5ced18cf72
commit 5ada035d17
14 changed files with 1647 additions and 927 deletions

View File

@ -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
--------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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); }

View File

@ -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")
{ }
nixieclock_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) { }
required_device<i4004_cpu_device> m_maincpu;
required_ioport m_input;
DECLARE_READ8_MEMBER( data_r );
DECLARE_WRITE8_MEMBER( nixie_w );
DECLARE_WRITE8_MEMBER( neon_w );
uint16_t m_nixie[16];
uint8_t m_timer;
protected:
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);
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);
}
uint16_t m_nixie[16];
};
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;
}
inline void nixieclock_state::output_set_nixie_value(int index, int value)
{
output().set_indexed_value("nixie", index, value);
}
inline void nixieclock_state::output_set_neon_value(int index, int value)
{
output().set_indexed_value("neon", index, value);
}
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 )

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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) },