mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
MCS-40 and INTELLEC 4/MOD 40 updates:
* Make disassembler/debugger use syntax closer to what ASL accepts * Use 2D lookup to make debugger tables more compact * Allow 4-bit registers to be set independently * Save state fixes * Implement WPM/RPM instructions * Expose some signals from a 4008/4009 or 4289 * Implement RAM read/write mechanism for INTELLEC 4/MOD 40 - Can test with S and D commands in monitor * Connect INTELLEC 4/MOD 40 paper tape run output to RTS on RS232 port
This commit is contained in:
parent
1a3b2550fb
commit
6faebf562b
@ -48,15 +48,31 @@ but we're already running out.
|
||||
4289: 0 B--- AAAAAAAA
|
||||
4308: 0 B--- RRPP----
|
||||
|
||||
TODO: WPM, HLT, BBS, EIN, DIN, RPM instructions
|
||||
The "program memory" space is separate from the instruction, I/O and
|
||||
opcode spaces. It's accessed via a 4008/4009 pair, or a 4289. With a
|
||||
4004, or a 4040 with a 4008/4009 pair, this space is write-only; read
|
||||
support requires a 4040 with a 4289. Accesses are 4 bits wide. The
|
||||
address consists of the 8-bit value latched with the SRC instruction and
|
||||
a first/last bit that toggles on each program memory operation. There's
|
||||
no way for the CPU to get the sate of the first/last bit (even using
|
||||
additional I/O to read it is difficult because it's only output during
|
||||
program memory reads and writes), so the developer has to be very
|
||||
careful to always do program memory operations in pairs or track the
|
||||
current state. The only way to set it to a fixed value is to reset the
|
||||
4008 or 4289. The original intention was to use this for program memory
|
||||
write-back, using the RC value as the address and the first/last signal
|
||||
as nybble lane select.
|
||||
|
||||
TODO: HLT, BBS, EIN, DIN 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);
|
||||
ALLOW_SAVE_TYPE(mcs40_cpu_device_base::pmem);
|
||||
ALLOW_SAVE_TYPE(mcs40_cpu_device_base::phase);
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(I4004, i4004_cpu_device, "i4004", "Intel 4004")
|
||||
@ -75,27 +91,31 @@ mcs40_cpu_device_base::mcs40_cpu_device_base(
|
||||
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_program_config("program", ENDIANNESS_LITTLE, 8, 10, 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_opcodes_config("opcodes", ENDIANNESS_LITTLE, 8, rom_width, 0)
|
||||
, m_program(nullptr), m_data(nullptr), m_io(nullptr), m_opcodes(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_4289_pm_cb(*this)
|
||||
, m_4289_f_l_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_phase(phase::A1), m_cycle(cycle::OP), m_io_pending(false), m_program_op(pmem::NONE)
|
||||
, m_rom_addr(0U), m_opr(0U), m_opa(0U), m_arg(0U), m_4289_first(false)
|
||||
, 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)
|
||||
, m_cm_rom(0U), m_cm_ram(0U), m_cy(0U), m_4289_a(0U), m_4289_c(0U), m_4289_pm(0U), m_4289_f_l(0U)
|
||||
, m_index_reg_halves(), m_pc(0U), m_pcbase(0U), m_genflags(0U)
|
||||
{
|
||||
assert(!((1U + stack_ptr_mask) & stack_ptr_mask));
|
||||
assert((16U == index_reg_cnt) || (24U == index_reg_cnt));
|
||||
}
|
||||
|
||||
@ -111,7 +131,8 @@ void mcs40_cpu_device_base::device_start()
|
||||
m_program = &space(AS_PROGRAM);
|
||||
m_data = &space(AS_DATA);
|
||||
m_io = &space(AS_IO);
|
||||
m_direct = &m_program->direct();
|
||||
m_opcodes = &space(AS_DECRYPTED_OPCODES);
|
||||
m_direct = &m_opcodes->direct();
|
||||
|
||||
m_sync_cb.resolve_safe();
|
||||
m_cm_rom_cb[0].resolve_safe();
|
||||
@ -121,6 +142,8 @@ void mcs40_cpu_device_base::device_start()
|
||||
m_cm_ram_cb[2].resolve_safe();
|
||||
m_cm_ram_cb[3].resolve_safe();
|
||||
m_cy_cb.resolve_safe();
|
||||
m_4289_pm_cb.resolve_safe();
|
||||
m_4289_f_l_cb.resolve_safe();
|
||||
|
||||
m_rom_addr = 0U;
|
||||
m_opr = m_opa = m_arg = 0U;
|
||||
@ -140,7 +163,12 @@ void mcs40_cpu_device_base::device_start()
|
||||
m_cm_rom = 0x03U;
|
||||
m_cm_ram = 0x0fU;
|
||||
m_cy = 0x00U;
|
||||
m_4289_a = 0xffU;
|
||||
m_4289_c = 0x0fU;
|
||||
m_4289_pm = 0x01U;
|
||||
m_4289_f_l = 0x01U;
|
||||
|
||||
m_index_reg_halves.reset(new u8[m_index_reg_cnt]);
|
||||
m_pc = m_pcbase = 0U;
|
||||
m_genflags = 0U;
|
||||
|
||||
@ -152,9 +180,17 @@ void mcs40_cpu_device_base::device_start()
|
||||
{
|
||||
state_add(
|
||||
I4004_R01 + i,
|
||||
string_format("R%X%X%s", (i << 1) & 0x0fU, ((i << 1) + 1) & 0x0fU, BIT(i, 3) ? "*" : "").c_str(),
|
||||
string_format("R%XR%X%s", (i << 1) & 0x0fU, ((i << 1) + 1) & 0x0fU, BIT(i, 3) ? "*" : "").c_str(),
|
||||
m_index_regs[i]);
|
||||
}
|
||||
for (unsigned i = 0; m_index_reg_cnt > i; ++i)
|
||||
{
|
||||
state_add(
|
||||
I4004_R0 + i,
|
||||
string_format("R%X%s", i & 0x0fU, BIT(i, 4) ? "*" : "").c_str(),
|
||||
m_index_reg_halves[i]).mask(0x0fU).noshow().callimport().callexport();
|
||||
}
|
||||
state_add(I4004_SP, "SP", m_stack_ptr).mask(m_stack_ptr_mask);
|
||||
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);
|
||||
@ -165,10 +201,13 @@ void mcs40_cpu_device_base::device_start()
|
||||
|
||||
save_item(NAME(m_phase));
|
||||
save_item(NAME(m_cycle));
|
||||
save_item(NAME(m_io_pending));
|
||||
save_item(NAME(m_program_op));
|
||||
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_4289_first));
|
||||
save_item(NAME(m_a));
|
||||
save_item(NAME(m_c));
|
||||
save_pointer(NAME(m_addr_stack.get()), m_stack_ptr_mask + 1);
|
||||
@ -185,6 +224,10 @@ void mcs40_cpu_device_base::device_start()
|
||||
save_item(NAME(m_cm_ram));
|
||||
save_item(NAME(m_cm_rom));
|
||||
save_item(NAME(m_cy));
|
||||
save_item(NAME(m_4289_a));
|
||||
save_item(NAME(m_4289_c));
|
||||
save_item(NAME(m_4289_pm));
|
||||
save_item(NAME(m_4289_f_l));
|
||||
save_item(NAME(m_pcbase));
|
||||
}
|
||||
|
||||
@ -194,6 +237,7 @@ void mcs40_cpu_device_base::device_reset()
|
||||
m_cycle = cycle::OP;
|
||||
|
||||
m_rom_addr = 0U;
|
||||
m_4289_first = true;
|
||||
pc() = 0U;
|
||||
|
||||
m_c = 0U;
|
||||
@ -234,17 +278,22 @@ void mcs40_cpu_device_base::execute_run()
|
||||
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
|
||||
debugger_instruction_hook(this, pc());
|
||||
}
|
||||
m_4289_a = (m_4289_a & 0xf0U) | (m_rom_addr & 0x0fU);
|
||||
m_sync_cb(1);
|
||||
update_4289_pm(1U);
|
||||
update_4289_f_l(1U);
|
||||
// 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_4289_a = (m_4289_a & 0x0fU) | (m_rom_addr & 0xf0U);
|
||||
m_phase = phase::A3;
|
||||
break;
|
||||
case phase::A3:
|
||||
// high nybble of ROM address is output here
|
||||
m_4289_c = (m_rom_addr >> 8) & 0x0fU;
|
||||
update_cm_rom(BIT(m_cr, 3) ? 0x01U : 0x02U);
|
||||
m_phase = phase::M1;
|
||||
break;
|
||||
@ -288,13 +337,26 @@ void mcs40_cpu_device_base::execute_run()
|
||||
update_cm_ram(0x0fU);
|
||||
if (cycle::OP == m_cycle)
|
||||
{
|
||||
m_cycle = do_cycle1(m_opr, m_opa);
|
||||
m_program_op = pmem::NONE;
|
||||
m_cycle = do_cycle1(m_opr, m_opa, m_program_op);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_cycle2(m_opr, m_opa, m_arg);
|
||||
m_cycle = cycle::OP;
|
||||
}
|
||||
m_4289_a = m_latched_rc;
|
||||
if (pmem::NONE == m_program_op)
|
||||
{
|
||||
m_4289_c = (m_latched_rc >> 4) & 0x0fU;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_4289_c = 0x0fU;
|
||||
update_4289_pm(0x00U);
|
||||
update_4289_f_l(m_4289_first ? 0x01 : 0x00);
|
||||
m_4289_first = !m_4289_first;
|
||||
}
|
||||
m_phase = phase::X2;
|
||||
break;
|
||||
case phase::X2:
|
||||
@ -316,6 +378,20 @@ void mcs40_cpu_device_base::execute_run()
|
||||
{
|
||||
assert(m_latched_rc == m_new_rc);
|
||||
}
|
||||
if (pmem::NONE != m_program_op)
|
||||
{
|
||||
assert(cycle::OP == m_cycle);
|
||||
u16 const addr(u16(BIT(m_cr, 3) << 9) | (u16(m_4289_a) << 1) | BIT(m_4289_f_l, 0));
|
||||
if (pmem::READ == m_program_op)
|
||||
{
|
||||
m_arg = m_program->read_byte(addr) & 0x0fU;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(pmem::WRITE == m_program_op);
|
||||
m_program->write_byte(addr, get_a());
|
||||
}
|
||||
}
|
||||
m_phase = phase::X3;
|
||||
break;
|
||||
case phase::X3:
|
||||
@ -331,6 +407,8 @@ void mcs40_cpu_device_base::execute_run()
|
||||
{
|
||||
assert(m_latched_rc == m_new_rc);
|
||||
}
|
||||
if (pmem::READ == m_program_op)
|
||||
set_a(m_arg);
|
||||
m_phase = phase::A1;
|
||||
break;
|
||||
}
|
||||
@ -347,10 +425,11 @@ address_space_config const *mcs40_cpu_device_base::memory_space_config(address_s
|
||||
{
|
||||
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;
|
||||
case AS_PROGRAM: return &m_program_config;
|
||||
case AS_DATA: return &m_data_config;
|
||||
case AS_IO: return &m_io_config;
|
||||
case AS_DECRYPTED_OPCODES: return &m_opcodes_config;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,7 +440,12 @@ address_space_config const *mcs40_cpu_device_base::memory_space_config(address_s
|
||||
|
||||
void mcs40_cpu_device_base::state_import(device_state_entry const &entry)
|
||||
{
|
||||
switch (entry.index())
|
||||
if ((I4004_R0 <= entry.index()) && (I4040_R23 >= entry.index()))
|
||||
{
|
||||
u8 const reg(entry.index() - I4004_R0), pair(reg >> 1), shift(BIT(~reg, 0) << 2), mask(0x0fU << shift);
|
||||
m_index_regs[pair] = (m_index_regs[pair] & ~mask) | ((m_index_reg_halves[reg] << shift) & mask);
|
||||
}
|
||||
else switch (entry.index())
|
||||
{
|
||||
case STATE_GENPC:
|
||||
pc() = m_pc_mask & m_pc & 0x0fffU;
|
||||
@ -385,7 +469,12 @@ void mcs40_cpu_device_base::state_import(device_state_entry const &entry)
|
||||
|
||||
void mcs40_cpu_device_base::state_export(device_state_entry const &entry)
|
||||
{
|
||||
switch (entry.index())
|
||||
if ((I4004_R0 <= entry.index()) && (I4040_R23 >= entry.index()))
|
||||
{
|
||||
u8 const reg(entry.index() - I4004_R0), pair(reg >> 1), shift(BIT(~reg, 0) << 2);
|
||||
m_index_reg_halves[reg] = (m_index_regs[pair] >> shift) & 0x0fU;
|
||||
}
|
||||
else switch (entry.index())
|
||||
{
|
||||
case STATE_GENPC:
|
||||
m_pc = rom_bank() | pc();
|
||||
@ -610,10 +699,27 @@ inline void mcs40_cpu_device_base::update_cm_ram(u8 val)
|
||||
inline void mcs40_cpu_device_base::update_cy(u8 val)
|
||||
{
|
||||
u8 const diff(val ^ m_cy);
|
||||
m_cy = val;
|
||||
if (BIT(diff, 0))
|
||||
m_cy_cb(BIT(val, 0));
|
||||
}
|
||||
|
||||
inline void mcs40_cpu_device_base::update_4289_pm(u8 val)
|
||||
{
|
||||
u8 const diff(val ^ m_4289_pm);
|
||||
m_4289_pm = val;
|
||||
if (BIT(diff, 0))
|
||||
m_4289_pm_cb(BIT(val, 0));
|
||||
}
|
||||
|
||||
inline void mcs40_cpu_device_base::update_4289_f_l(u8 val)
|
||||
{
|
||||
u8 const diff(val ^ m_4289_f_l);
|
||||
m_4289_f_l = val;
|
||||
if (BIT(diff, 0))
|
||||
m_4289_f_l_cb(BIT(val, 0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
i4004_cpu_device::i4004_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
|
||||
@ -669,7 +775,7 @@ 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)
|
||||
i4004_cpu_device::cycle i4004_cpu_device::do_cycle1(u8 opr, u8 opa, pmem &program_op)
|
||||
{
|
||||
static constexpr uint8_t kbp_table[] = { 0x0, 0x1, 0x2, 0xf, 0x3, 0xf, 0xf, 0xf, 0x4, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf };
|
||||
|
||||
@ -752,6 +858,8 @@ i4004_cpu_device::cycle i4004_cpu_device::do_cycle1(u8 opr, u8 opa)
|
||||
return cycle::OP;
|
||||
|
||||
case 0xe: // WRM/WMP/WRR/WPM/WR0/WR1/WR2/WR3/SBM/RDM/RDR/ADM/RD0/RD1/RD2/RD3
|
||||
if (0x3 == opa)
|
||||
program_op = pmem::WRITE;
|
||||
return cycle::OP;
|
||||
|
||||
case 0xf:
|
||||
@ -886,6 +994,8 @@ void i4004_cpu_device::do_io(u8 opr, u8 opa)
|
||||
case 0x2: // WRR
|
||||
write_rom_port(get_a());
|
||||
break;
|
||||
case 0x3: // WPM
|
||||
break;
|
||||
case 0x4: // WR0
|
||||
case 0x5: // WR1
|
||||
case 0x6: // WR2
|
||||
@ -910,8 +1020,8 @@ void i4004_cpu_device::do_io(u8 opr, u8 opa)
|
||||
case 0xf: // RD3
|
||||
set_a(read_status());
|
||||
break;
|
||||
default:
|
||||
logerror("MCS-40: unhandled instruction OPR=%X OPA=%X\n", opr, opa);
|
||||
default: // something is badly wrong if we get here
|
||||
throw false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -943,7 +1053,7 @@ offs_t i4040_cpu_device::disasm_disassemble(
|
||||
mcs40_cpu_device_base implementation
|
||||
***********************************************************************/
|
||||
|
||||
i4040_cpu_device::cycle i4040_cpu_device::do_cycle1(u8 opr, u8 opa)
|
||||
i4040_cpu_device::cycle i4040_cpu_device::do_cycle1(u8 opr, u8 opa, pmem &program_op)
|
||||
{
|
||||
switch (opr)
|
||||
{
|
||||
@ -969,6 +1079,9 @@ i4040_cpu_device::cycle i4040_cpu_device::do_cycle1(u8 opr, u8 opa)
|
||||
case 0xb: // SB1
|
||||
set_index_reg_bank(BIT(opa, 0));
|
||||
return cycle::OP;
|
||||
case 0xe: // RPM
|
||||
program_op = pmem::READ;
|
||||
return cycle::OP;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -976,44 +1089,19 @@ i4040_cpu_device::cycle i4040_cpu_device::do_cycle1(u8 opr, u8 opa)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return i4004_cpu_device::do_cycle1(opr, opa);
|
||||
return i4004_cpu_device::do_cycle1(opr, opa, program_op);
|
||||
}
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
#ifndef MAME_CPU_I4004_I4004_H
|
||||
#define MAME_CPU_I4004_I4004_H
|
||||
#ifndef MAME_CPU_MCS40_MCS40_H
|
||||
#define MAME_CPU_MCS40_MCS40_H
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -10,17 +10,6 @@
|
||||
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,
|
||||
@ -54,6 +43,12 @@ enum
|
||||
#define MCFG_I4004_CM_RAM3_CB(obj) \
|
||||
devcb = &i4004_cpu_device::set_cm_ram_cb<3>(*device, DEVCB_##obj);
|
||||
|
||||
#define MCFG_I4004_4289_PM_CB(obj) \
|
||||
devcb = &i4004_cpu_device::set_4289_pm_cb(*device, DEVCB_##obj);
|
||||
|
||||
#define MCFG_I4004_4289_F_L_CB(obj) \
|
||||
devcb = &i4004_cpu_device::set_4289_f_l_cb(*device, DEVCB_##obj);
|
||||
|
||||
|
||||
#define MCFG_I4040_SYNC_CB(obj) \
|
||||
devcb = &i4040_cpu_device::set_sync_cb(*device, DEVCB_##obj);
|
||||
@ -79,6 +74,12 @@ enum
|
||||
#define MCFG_I4040_CY_CB(obj) \
|
||||
devcb = &i4040_cpu_device::set_cy_cb(*device, DEVCB_##obj);
|
||||
|
||||
#define MCFG_I4040_4289_PM_CB(obj) \
|
||||
devcb = &i4040_cpu_device::set_4289_pm_cb(*device, DEVCB_##obj);
|
||||
|
||||
#define MCFG_I4040_4289_F_L_CB(obj) \
|
||||
devcb = &i4040_cpu_device::set_4289_f_l_cb(*device, DEVCB_##obj);
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
@ -87,8 +88,22 @@ enum
|
||||
|
||||
class mcs40_cpu_device_base : public cpu_device
|
||||
{
|
||||
public:
|
||||
// configuration helpers
|
||||
template <typename Obj> static devcb_base &set_4289_pm_cb(device_t &device, Obj &&cb)
|
||||
{ return downcast<mcs40_cpu_device_base &>(device).set_4289_pm_cb(std::forward<Obj>(cb)); }
|
||||
template <typename Obj> static devcb_base &set_4289_f_l_cb(device_t &device, Obj &&cb)
|
||||
{ return downcast<mcs40_cpu_device_base &>(device).set_4289_f_l_cb(std::forward<Obj>(cb)); }
|
||||
|
||||
// 4008/4009 or 4289 outputs
|
||||
u8 get_4289_a() const { return m_4289_a; } // 8-bit address
|
||||
u8 get_4289_c() const { return m_4289_c; } // 4-bit chip select
|
||||
DECLARE_READ_LINE_MEMBER(get_4289_pm) const { return BIT(m_4289_pm, 0); } // 0 = active
|
||||
DECLARE_READ_LINE_MEMBER(get_4289_f_l) const { return BIT(m_4289_f_l, 0); } // 1 = odd, 0 = even
|
||||
|
||||
protected:
|
||||
enum class cycle { OP, IM, IN };
|
||||
enum class pmem { NONE, READ, WRITE };
|
||||
|
||||
mcs40_cpu_device_base(
|
||||
machine_config const &mconfig,
|
||||
@ -123,7 +138,7 @@ protected:
|
||||
|
||||
// instruction execution
|
||||
virtual bool is_io_op(u8 opr) = 0;
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa) = 0;
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) = 0;
|
||||
virtual void do_cycle2(u8 opr, u8 opa, u8 arg) = 0;
|
||||
virtual void do_io(u8 opr, u8 opa) = 0;
|
||||
|
||||
@ -170,6 +185,21 @@ protected:
|
||||
{ return m_cy_cb.set_callback(std::forward<Obj>(cb)); }
|
||||
|
||||
private:
|
||||
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_R0, I4004_R1, I4004_R2, I4004_R3, I4004_R4, I4004_R5, I4004_R6, I4004_R7,
|
||||
I4004_R8, I4004_R9, I4004_R10, I4004_R11, I4004_R12, I4004_R13, I4004_R14, I4004_R15,
|
||||
I4040_R16, I4040_R17, I4040_R18, I4040_R19, I4040_R20, I4040_R21, I4040_R22, I4040_R23,
|
||||
I4004_SP,
|
||||
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 class phase { A1, A2, A3, M1, M2, X1, X2, X3 };
|
||||
|
||||
// internal helpers
|
||||
@ -178,10 +208,12 @@ private:
|
||||
void update_cm_rom(u8 val);
|
||||
void update_cm_ram(u8 val);
|
||||
void update_cy(u8 val);
|
||||
void update_4289_pm(u8 val);
|
||||
void update_4289_f_l(u8 val);
|
||||
|
||||
// address spaces
|
||||
address_space_config m_program_config, m_data_config, m_io_config;
|
||||
address_space *m_program, *m_data, *m_io;
|
||||
address_space_config m_program_config, m_data_config, m_io_config, m_opcodes_config;
|
||||
address_space *m_program, *m_data, *m_io, *m_opcodes;
|
||||
direct_read_data *m_direct;
|
||||
|
||||
// output callbacks
|
||||
@ -189,6 +221,9 @@ private:
|
||||
devcb_write_line m_cm_rom_cb[2], m_cm_ram_cb[4];
|
||||
devcb_write_line m_cy_cb;
|
||||
|
||||
// 4008/4009 or 4289 output callbacks
|
||||
devcb_write_line m_4289_pm_cb, m_4289_f_l_cb;
|
||||
|
||||
// configuration
|
||||
bool const m_extended_cm;
|
||||
u8 const m_stack_ptr_mask;
|
||||
@ -201,10 +236,12 @@ private:
|
||||
phase m_phase;
|
||||
cycle m_cycle;
|
||||
bool m_io_pending;
|
||||
pmem m_program_op;
|
||||
|
||||
// instruction ROM fetch/decode
|
||||
u16 m_rom_bank, m_rom_addr;
|
||||
u8 m_opr, m_opa, m_arg;
|
||||
bool m_4289_first;
|
||||
|
||||
// ALU registers
|
||||
u8 m_a, m_c;
|
||||
@ -224,10 +261,12 @@ private:
|
||||
// input/output lines
|
||||
int m_test;
|
||||
u8 m_cm_rom, m_cm_ram, m_cy;
|
||||
u8 m_4289_a, m_4289_c, m_4289_pm, m_4289_f_l;
|
||||
|
||||
// state export/import
|
||||
u16 m_pc, m_pcbase;
|
||||
u8 m_genflags;
|
||||
std::unique_ptr<u8 []> m_index_reg_halves;
|
||||
u16 m_pc, m_pcbase;
|
||||
u8 m_genflags;
|
||||
};
|
||||
|
||||
|
||||
@ -261,7 +300,7 @@ protected:
|
||||
|
||||
// mcs40_cpu_device_base implementation
|
||||
virtual bool is_io_op(u8 opr) override;
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa) override;
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) override;
|
||||
virtual void do_cycle2(u8 opr, u8 opa, u8 arg) override;
|
||||
virtual void do_io(u8 opr, u8 opa) override;
|
||||
};
|
||||
@ -292,7 +331,7 @@ protected:
|
||||
uint32_t options) override;
|
||||
|
||||
// mcs40_cpu_device_base implementation
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa) override;
|
||||
virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) override;
|
||||
};
|
||||
|
||||
|
||||
@ -304,4 +343,4 @@ protected:
|
||||
DECLARE_DEVICE_TYPE(I4004, i4004_cpu_device)
|
||||
DECLARE_DEVICE_TYPE(I4040, i4040_cpu_device)
|
||||
|
||||
#endif // MAME_CPU_I4004_I4004_H
|
||||
#endif // MAME_CPU_MCS40_MCS40_H
|
||||
|
@ -23,7 +23,8 @@ enum class format
|
||||
PAIRIMM,
|
||||
ABS,
|
||||
PAGE,
|
||||
COND
|
||||
COND,
|
||||
EXT
|
||||
};
|
||||
|
||||
enum class level
|
||||
@ -37,90 +38,51 @@ struct op
|
||||
format m_format;
|
||||
level m_level;
|
||||
char const *m_name;
|
||||
op const *m_ext;
|
||||
};
|
||||
|
||||
#define OP(fmt, lvl, name) { format::fmt, level::lvl, #name }
|
||||
#define OP(fmt, lvl, name) { format::fmt, level::lvl, #name, nullptr }
|
||||
#define OPX(tbl) { format::EXT, level::I4004, nullptr, f_opx_##tbl }
|
||||
|
||||
op const f_opx_0[16] = {
|
||||
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 const f_opx_2[16] = {
|
||||
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 const f_opx_3[16] = {
|
||||
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 const f_opx_io[16] = {
|
||||
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 const f_opx_f[16] = {
|
||||
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) };
|
||||
|
||||
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),
|
||||
OPX(0), OP(COND, I4004, jcn), OPX(2), OPX(3),
|
||||
OP(ABS, I4004, jun), OP(ABS, I4004, jms), OP(REG, I4004, inc), OP(REGPAGE, I4004, isz),
|
||||
OP(REG, I4004, add), OP(REG, I4004, sub), OP(REG, I4004, ld ), OP(REG, I4004, xch),
|
||||
OP(IMM4, I4004, bbl), OP(IMM4, I4004, ldm), OPX(io), OPX(f) };
|
||||
|
||||
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) };
|
||||
char const *const f_cond[16] = {
|
||||
"$0", "nt", "c", "$3", "z", "$5", "$6", "$7",
|
||||
"$8", "t", "nc", "$b", "nz", "$d", "$e", "$f" };
|
||||
|
||||
offs_t disassemble(
|
||||
cpu_device *device,
|
||||
@ -134,8 +96,12 @@ offs_t disassemble(
|
||||
{
|
||||
offs_t npc(pc + 1);
|
||||
u8 const opcode(oprom[0]);
|
||||
op const &desc(f_ops[(f_ops[opcode].m_level > lvl) ? 0xffU : opcode]);
|
||||
op const &base_op(f_ops[(opcode >> 4) & 0x0f]);
|
||||
op const &ext_op((base_op.m_format == format::EXT) ? base_op.m_ext[opcode & 0x0f] : base_op);
|
||||
op const desc((ext_op.m_level > lvl) ? f_opx_f[0x0f] : ext_op);
|
||||
|
||||
u8 const imm4(opcode & 0x0f);
|
||||
u8 const pair(opcode & 0x0e);
|
||||
switch (desc.m_format)
|
||||
{
|
||||
case format::ILL:
|
||||
@ -145,20 +111,21 @@ offs_t disassemble(
|
||||
util::stream_format(stream, "%s", desc.m_name);
|
||||
break;
|
||||
case format::IMM4:
|
||||
util::stream_format(stream, "%-3s $%01x", desc.m_name, imm4);
|
||||
break;
|
||||
case format::REG:
|
||||
util::stream_format(stream, "%-3s $%01x", desc.m_name, opcode & 0x0fU);
|
||||
util::stream_format(stream, "%-3s r%01x", desc.m_name, imm4);
|
||||
break;
|
||||
case format::REGPAGE:
|
||||
case format::COND:
|
||||
npc++;
|
||||
util::stream_format(stream, "%-3s $%01x,$%03x", desc.m_name, opcode & 0x0fU, opram[1] | (npc & 0x0f00U));
|
||||
util::stream_format(stream, "%-3s r%01x,$%03x", desc.m_name, imm4, opram[1] | (npc & 0x0f00U));
|
||||
break;
|
||||
case format::PAIR:
|
||||
util::stream_format(stream, "%-3s $%01x", desc.m_name, opcode & 0x0eU);
|
||||
util::stream_format(stream, "%-3s r%01xr%01x", desc.m_name, pair, pair + 1U);
|
||||
break;
|
||||
case format::PAIRIMM:
|
||||
npc++;
|
||||
util::stream_format(stream, "%-3s $%01x,$%02x", desc.m_name, opcode & 0x0eU, opram[1]);
|
||||
util::stream_format(stream, "%-3s r%01xr%01x,$%02x", desc.m_name, pair, pair + 1, opram[1]);
|
||||
break;
|
||||
case format::ABS:
|
||||
npc++;
|
||||
@ -168,6 +135,12 @@ offs_t disassemble(
|
||||
npc++;
|
||||
util::stream_format(stream, "%-3s $%03x", desc.m_name, opram[1] | (npc & 0x0f00U));
|
||||
break;
|
||||
case format::COND:
|
||||
npc++;
|
||||
util::stream_format(stream, "%-3s %s,$%03x", desc.m_name, f_cond[imm4], opram[1] | (npc & 0x0f00U));
|
||||
break;
|
||||
default:
|
||||
throw false;
|
||||
}
|
||||
|
||||
offs_t flags(0U);
|
||||
|
@ -77,8 +77,8 @@ WRITE8_MEMBER(nixieclock_state::neon_w)
|
||||
output_set_neon_value(3, BIT(data,0));
|
||||
}
|
||||
|
||||
static ADDRESS_MAP_START(4004clk_rom, AS_PROGRAM, 8, nixieclock_state)
|
||||
AM_RANGE(0x0000, 0x0FFF) AM_ROM
|
||||
static ADDRESS_MAP_START(4004clk_rom, AS_DECRYPTED_OPCODES, 8, nixieclock_state)
|
||||
AM_RANGE(0x0000, 0x0FFF) AM_ROM AM_REGION("maincpu", 0)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(4004clk_mem, AS_DATA, 8, nixieclock_state)
|
||||
@ -118,7 +118,7 @@ static MACHINE_CONFIG_START( 4004clk )
|
||||
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", I4004, XTAL_5MHz / 8)
|
||||
MCFG_CPU_PROGRAM_MAP(4004clk_rom)
|
||||
MCFG_CPU_DECRYPTED_OPCODES_MAP(4004clk_rom)
|
||||
MCFG_CPU_DATA_MAP(4004clk_mem)
|
||||
MCFG_CPU_IO_MAP(4004clk_io)
|
||||
|
||||
|
@ -99,9 +99,9 @@ WRITE8_MEMBER(busicom_state::printer_ctrl_w)
|
||||
{
|
||||
}
|
||||
|
||||
static ADDRESS_MAP_START(busicom_rom, AS_PROGRAM, 8, busicom_state )
|
||||
static ADDRESS_MAP_START(busicom_rom, AS_DECRYPTED_OPCODES, 8, busicom_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x04FF) AM_ROM
|
||||
AM_RANGE(0x0000, 0x04FF) AM_ROM AM_REGION("maincpu", 0)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(busicom_mem, AS_DATA, 8, busicom_state )
|
||||
@ -214,7 +214,7 @@ void busicom_state::machine_reset()
|
||||
static MACHINE_CONFIG_START( busicom )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", I4004, 750000)
|
||||
MCFG_CPU_PROGRAM_MAP(busicom_rom)
|
||||
MCFG_CPU_DECRYPTED_OPCODES_MAP(busicom_rom)
|
||||
MCFG_CPU_DATA_MAP(busicom_mem)
|
||||
MCFG_CPU_IO_MAP(busicom_io)
|
||||
|
||||
|
@ -48,8 +48,8 @@ private:
|
||||
};
|
||||
|
||||
|
||||
static ADDRESS_MAP_START( flicker_rom, AS_PROGRAM, 8, flicker_state )
|
||||
AM_RANGE(0x0000, 0x03FF) AM_ROM
|
||||
static ADDRESS_MAP_START( flicker_rom, AS_DECRYPTED_OPCODES, 8, flicker_state )
|
||||
AM_RANGE(0x0000, 0x03FF) AM_ROM AM_REGION("maincpu", 0)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(flicker_map, AS_DATA, 8, flicker_state )
|
||||
@ -199,7 +199,7 @@ sound to produce. We need to change this to just one pulse per actual sound. */
|
||||
static MACHINE_CONFIG_START( flicker )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", I4004, XTAL_5MHz / 8)
|
||||
MCFG_CPU_PROGRAM_MAP(flicker_rom)
|
||||
MCFG_CPU_DECRYPTED_OPCODES_MAP(flicker_rom)
|
||||
MCFG_CPU_DATA_MAP(flicker_map)
|
||||
MCFG_CPU_IO_MAP(flicker_io)
|
||||
MCFG_NVRAM_ADD_0FILL("nvram")
|
||||
|
@ -20,31 +20,121 @@ public:
|
||||
intellec4_40_state(machine_config const &mconfig, device_type type, char const *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_tty(*this, "tty")
|
||||
, m_mon_rom(*this, "monitor", 0x0400)
|
||||
, m_ram(*this, "ram")
|
||||
, m_banks(*this, "bank%u", 0)
|
||||
, m_ram_page(0U), m_ram_data(0U), m_ram_write(false)
|
||||
{
|
||||
}
|
||||
|
||||
DECLARE_READ8_MEMBER(tty_r);
|
||||
DECLARE_WRITE8_MEMBER(tty_w);
|
||||
DECLARE_READ8_MEMBER(pm_read);
|
||||
DECLARE_WRITE8_MEMBER(pm_write);
|
||||
|
||||
DECLARE_READ8_MEMBER(rom0_in);
|
||||
DECLARE_READ8_MEMBER(rome_in);
|
||||
DECLARE_READ8_MEMBER(romf_in);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(rome_out);
|
||||
DECLARE_WRITE8_MEMBER(romf_out);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(ram0_out);
|
||||
DECLARE_WRITE8_MEMBER(ram1_out);
|
||||
|
||||
protected:
|
||||
virtual void driver_start() override;
|
||||
|
||||
private:
|
||||
required_device<rs232_port_device> m_tty;
|
||||
required_device<rs232_port_device> m_tty;
|
||||
required_region_ptr<u8> m_mon_rom;
|
||||
required_shared_ptr<u8> m_ram;
|
||||
required_memory_bank_array<4> m_banks;
|
||||
|
||||
u8 m_ram_page, m_ram_data;
|
||||
bool m_ram_write;
|
||||
};
|
||||
|
||||
|
||||
READ8_MEMBER(intellec4_40_state::tty_r)
|
||||
READ8_MEMBER(intellec4_40_state::pm_read)
|
||||
{
|
||||
return m_tty->rxd_r() ? 0x0 : 0x1;
|
||||
// always causes data to be latched
|
||||
u16 const addr((u16(m_ram_page) << 8) | ((offset >> 1) & 0x00ffU));
|
||||
m_ram_data = m_ram[addr];
|
||||
return space.unmap();
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(intellec4_40_state::tty_w)
|
||||
WRITE8_MEMBER(intellec4_40_state::pm_write)
|
||||
{
|
||||
// always causes data to be latched
|
||||
u16 const addr((u16(m_ram_page) << 8) | ((offset >> 1) & 0x00ffU));
|
||||
m_ram_data = m_ram[addr];
|
||||
if (m_ram_write)
|
||||
{
|
||||
bool const first(BIT(offset, 0));
|
||||
m_ram[addr] = (m_ram_data & (first ? 0x0fU : 0xf0U)) | ((data & 0x0fU) << (first ? 4 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(intellec4_40_state::rom0_in)
|
||||
{
|
||||
// bit 0 of this port is ANDed with the TTY input
|
||||
return m_tty->rxd_r() ? 0x00U : 0x01U;
|
||||
}
|
||||
|
||||
READ8_MEMBER(intellec4_40_state::rome_in)
|
||||
{
|
||||
// upper nybble of RAM data latch
|
||||
return (m_ram_data >> 4) & 0x0fU;
|
||||
}
|
||||
|
||||
READ8_MEMBER(intellec4_40_state::romf_in)
|
||||
{
|
||||
// lower nybble of RAM data latch
|
||||
return m_ram_data & 0x0fU;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(intellec4_40_state::rome_out)
|
||||
{
|
||||
// bit 0 of this port enables program memory write
|
||||
m_ram_write = BIT(data, 0);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(intellec4_40_state::romf_out)
|
||||
{
|
||||
// sets the program memory page for read/write operations
|
||||
m_ram_page = data & 0x0fU;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(intellec4_40_state::ram0_out)
|
||||
{
|
||||
// bit 0 of this port controls the TTY current loop
|
||||
m_tty->write_txd(BIT(data, 0));
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(intellec4_40_state::ram1_out)
|
||||
{
|
||||
// bit 0 of this port controls the paper tape motor (0 = stop, 1 = run)
|
||||
m_tty->write_rts(BIT(~data, 0));
|
||||
}
|
||||
|
||||
|
||||
void intellec4_40_state::driver_start()
|
||||
{
|
||||
for (unsigned i = 0; m_banks.size() > i; ++i)
|
||||
{
|
||||
m_banks[i]->configure_entry(0, &m_mon_rom[i << 8]);
|
||||
m_banks[i]->configure_entry(1, &m_ram[i << 8]);
|
||||
m_banks[i]->set_entry(0);
|
||||
}
|
||||
|
||||
save_item(NAME(m_ram_page));
|
||||
save_item(NAME(m_ram_data));
|
||||
save_item(NAME(m_ram_write));
|
||||
}
|
||||
|
||||
|
||||
ADDRESS_MAP_START(mod40_program, AS_PROGRAM, 8, intellec4_40_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION("monitor", 0x0000) // 4289 + 4 * 1702A
|
||||
AM_RANGE(0x0000, 0x01ff) AM_READWRITE(pm_read, pm_write)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
ADDRESS_MAP_START(mod40_data, AS_DATA, 8, intellec4_40_state)
|
||||
@ -54,8 +144,20 @@ ADDRESS_MAP_END
|
||||
|
||||
ADDRESS_MAP_START(mod40_io, AS_IO, 8, intellec4_40_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x000f) AM_MIRROR(0x0700) AM_READ(tty_r) // RDR when RC=00
|
||||
AM_RANGE(0x1000, 0x103f) AM_MIRROR(0x0800) AM_WRITE(tty_w) // WMP when RC=00
|
||||
AM_RANGE(0x0000, 0x000f) AM_MIRROR(0x0700) AM_READ(rom0_in)
|
||||
AM_RANGE(0x00e0, 0x00ef) AM_MIRROR(0x0700) AM_READWRITE(rome_in, rome_out)
|
||||
AM_RANGE(0x00f0, 0x00ff) AM_MIRROR(0x0700) AM_READWRITE(romf_in, romf_out)
|
||||
AM_RANGE(0x1000, 0x103f) AM_MIRROR(0x0800) AM_WRITE(ram0_out)
|
||||
AM_RANGE(0x1040, 0x107f) AM_MIRROR(0x0800) AM_WRITE(ram1_out)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
ADDRESS_MAP_START(mod40_opcodes, AS_DECRYPTED_OPCODES, 8, intellec4_40_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x00ff) AM_READ_BANK("bank0")
|
||||
AM_RANGE(0x0100, 0x01ff) AM_READ_BANK("bank1")
|
||||
AM_RANGE(0x0200, 0x02ff) AM_READ_BANK("bank2")
|
||||
AM_RANGE(0x0300, 0x03ff) AM_READ_BANK("bank3")
|
||||
AM_RANGE(0x0000, 0x0fff) AM_READONLY AM_SHARE("ram")
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
@ -64,6 +166,7 @@ MACHINE_CONFIG_START(intlc440)
|
||||
MCFG_CPU_PROGRAM_MAP(mod40_program)
|
||||
MCFG_CPU_DATA_MAP(mod40_data)
|
||||
MCFG_CPU_IO_MAP(mod40_io)
|
||||
MCFG_CPU_DECRYPTED_OPCODES_MAP(mod40_opcodes)
|
||||
|
||||
MCFG_RS232_PORT_ADD("tty", default_rs232_devices, "terminal")
|
||||
MACHINE_CONFIG_END
|
||||
@ -74,7 +177,7 @@ INPUT_PORTS_END
|
||||
|
||||
|
||||
ROM_START(intlc440)
|
||||
ROM_REGION(0x0400, "monitor", 0)
|
||||
ROM_REGION(0x0400, "monitor", 0) // 4 * 1702A
|
||||
ROM_DEFAULT_BIOS("v2.1")
|
||||
ROM_SYSTEM_BIOS(0, "v2.1", "MON 4 V2.1")
|
||||
ROMX_LOAD("mon_4-000-v_2.1.a1", 0x0000, 0x0100, CRC(8d1f56ff) SHA1(96bc19be9be4e92195fad82d7a3cadb763ab6e3f), ROM_BIOS(1))
|
||||
|
Loading…
Reference in New Issue
Block a user