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:
Vas Crabb 2017-06-28 23:57:47 +10:00
parent 1a3b2550fb
commit 6faebf562b
7 changed files with 376 additions and 173 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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