From 9ca21b386bf7e0801b32e096dcde1cc8609f7b0c Mon Sep 17 00:00:00 2001 From: hap Date: Wed, 25 Sep 2024 16:11:06 +0200 Subject: [PATCH] hmcs40: add hmcs46/hmcs47 --- src/devices/cpu/hmcs40/hmcs40.cpp | 143 +++++++++++++++++++++++----- src/devices/cpu/hmcs40/hmcs40.h | 69 +++++++++++++- src/devices/cpu/hmcs40/hmcs40d.h | 3 +- src/devices/cpu/hmcs40/hmcs40op.cpp | 6 +- 4 files changed, 191 insertions(+), 30 deletions(-) diff --git a/src/devices/cpu/hmcs40/hmcs40.cpp b/src/devices/cpu/hmcs40/hmcs40.cpp index 38e150b9575..a28c40904ca 100644 --- a/src/devices/cpu/hmcs40/hmcs40.cpp +++ b/src/devices/cpu/hmcs40/hmcs40.cpp @@ -53,13 +53,20 @@ DEFINE_DEVICE_TYPE(HD44820, hd44820_device, "hd44820", "Hitachi HD44820") // CMO DEFINE_DEVICE_TYPE(HD44828, hd44828_device, "hd44828", "Hitachi HD44828") // CMOS, low-power // HMCS46C/CL, 42 pins, 32 I/O lines, 4096x10 ROM, 256x4 RAM (no PMOS version exists) -//DEFINE_DEVICE_TYPE(HD44840, hd44840_device, "hd44840", "Hitachi HD44840") // CMOS -//DEFINE_DEVICE_TYPE(HD44848, hd44848_device, "hd44848", "Hitachi HD44848") // CMOS, low-power +DEFINE_DEVICE_TYPE(HD44840, hd44840_device, "hd44840", "Hitachi HD44840") // CMOS +DEFINE_DEVICE_TYPE(HD44848, hd44848_device, "hd44848", "Hitachi HD44848") // CMOS, low-power // HMCS47A/C/CL, 54 pins(QFP) or 64 pins(DIP), 44 I/O lines, 4096x10 ROM, 256x4 RAM -//DEFINE_DEVICE_TYPE(HD38870, hd38870_device, "hd38870", "Hitachi HD38870") // PMOS -//DEFINE_DEVICE_TYPE(HD44860, hd44860_device, "hd44860", "Hitachi HD44860") // CMOS -//DEFINE_DEVICE_TYPE(HD44868, hd44868_device, "hd44868", "Hitachi HD44868") // CMOS, low-power +DEFINE_DEVICE_TYPE(HD38870, hd38870_device, "hd38870", "Hitachi HD38870") // PMOS +DEFINE_DEVICE_TYPE(HD44860, hd44860_device, "hd44860", "Hitachi HD44860") // CMOS +DEFINE_DEVICE_TYPE(HD44868, hd44868_device, "hd44868", "Hitachi HD44868") // CMOS, low-power + +// LCD-III, 64 pins, HMCS44C core, LCDC with 4 commons and 32 segments +//DEFINE_DEVICE_TYPE(HD44790, hd44790_device, "hd44790", "Hitachi HD44790") // CMOS +//DEFINE_DEVICE_TYPE(HD44795, hd44795_device, "hd44795", "Hitachi HD44795") // CMOS, low-power + +// LCD-IV, 64 pins, HMCS46C core, LCDC with 4 commons and 32 segments +//DEFINE_DEVICE_TYPE(HD613901, hd613901_device, "hd613901", "Hitachi HD613901") // CMOS //------------------------------------------------- @@ -139,6 +146,33 @@ hd44828_device::hd44828_device(const machine_config &mconfig, const char *tag, d { } +hmcs46_cpu_device::hmcs46_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity) : + hmcs40_cpu_device(mconfig, type, tag, owner, clock, HMCS46_FAMILY, polarity, 4, 12, 12, address_map_constructor(FUNC(hmcs46_cpu_device::program_2k), this), 8, address_map_constructor(FUNC(hmcs46_cpu_device::data_256x4), this)) +{ } + +hd44840_device::hd44840_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + hmcs46_cpu_device(mconfig, HD44840, tag, owner, clock, IS_CMOS) +{ } +hd44848_device::hd44848_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + hmcs46_cpu_device(mconfig, HD44848, tag, owner, clock, IS_CMOS) +{ } + + +hmcs47_cpu_device::hmcs47_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity) : + hmcs40_cpu_device(mconfig, type, tag, owner, clock, HMCS47_FAMILY, polarity, 4, 12, 12, address_map_constructor(FUNC(hmcs47_cpu_device::program_2k), this), 8, address_map_constructor(FUNC(hmcs47_cpu_device::data_256x4), this)) +{ } + +hd38870_device::hd38870_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + hmcs47_cpu_device(mconfig, HD38870, tag, owner, clock, IS_PMOS) +{ } +hd44860_device::hd44860_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + hmcs47_cpu_device(mconfig, HD44860, tag, owner, clock, IS_CMOS) +{ } +hd44868_device::hd44868_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + hmcs47_cpu_device(mconfig, HD44868, tag, owner, clock, IS_CMOS) +{ } + + //------------------------------------------------- // initialization //------------------------------------------------- @@ -163,7 +197,7 @@ void hmcs40_cpu_device::device_start() m_pc = 0; m_prev_pc = 0; - m_page = 0; + m_pc_upper = 0; m_a = 0; m_b = 0; m_x = 0; @@ -195,7 +229,7 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_pc)); save_item(NAME(m_prev_pc)); - save_item(NAME(m_page)); + save_item(NAME(m_pc_upper)); save_item(NAME(m_a)); save_item(NAME(m_b)); save_item(NAME(m_x)); @@ -249,6 +283,10 @@ void hmcs40_cpu_device::device_reset() // all I/O ports set to input reset_io(); + + // HMCS46/47 R70 set to 1 (already the default on CMOS devices) + if (m_family == HMCS46_FAMILY || m_family == HMCS47_FAMILY) + m_r[7] |= 1; } @@ -281,10 +319,19 @@ std::unique_ptr hmcs40_cpu_device::create_disassembler() // internal memory maps //------------------------------------------------- -// On HMCS42/3/4/5, only half of the ROM address range contains user-executable code, -// there is up to 128 bytes of pattern data in the 2nd half. The 2nd half also includes -// a couple of pages with factory test code by Hitachi, only executable when MCU test -// mode is enabled externally. This data can still be accessed with the P opcode. +/* + +On HMCS42/43/44/45, only half of the ROM address range contains user-executable +code, there is up to 128 bytes of pattern data in the 2nd half. The 2nd half +also includes a couple of pages with factory test code by Hitachi, only executable +when MCU test mode is enabled externally (TEST pin). This data can still be accessed +with the P opcode. + +On HMCS46/47, the 2nd half can be jumped to with a bank bit from R70. These MCUs +have 2 more banks with factory test code, but that part of the ROM is only accessible +under MCU test mode. + +*/ void hmcs40_cpu_device::program_1k(address_map &map) { @@ -310,6 +357,11 @@ void hmcs40_cpu_device::data_160x4(address_map &map) map(0xc0, 0xcf).ram().mirror(0x30); } +void hmcs40_cpu_device::data_256x4(address_map &map) +{ + map(0x00, 0xff).ram(); +} + device_memory_interface::space_config_vector hmcs40_cpu_device::memory_space_config() const { return space_config_vector { @@ -453,6 +505,44 @@ void hmcs45_cpu_device::write_r(u8 index, u8 data) logerror("ineffective write to port R%d = $%X @ $%04X\n", index, data & 0xf, m_prev_pc); } +// HMCS46: +// R0-R3 are i/o, R4,R5,R7 are extra registers, no R6 +// D0-D15 are i/o + +u8 hmcs46_cpu_device::read_r(u8 index) +{ + index &= 7; + + if (index == 6) + logerror("read from unknown port R%d @ $%04X\n", index, m_prev_pc); + + return hmcs40_cpu_device::read_r(index); +} + +void hmcs46_cpu_device::write_r(u8 index, u8 data) +{ + index &= 7; + + if (index != 6) + hmcs40_cpu_device::write_r(index, data); + else + logerror("ineffective write to port R%d = $%X @ $%04X\n", index, data & 0xf, m_prev_pc); +} + +// HMCS47: +// R0-R5 are i/o, R6 is output-only, R7 is an extra register +// D0-D15 are i/o + +u8 hmcs47_cpu_device::read_r(u8 index) +{ + index &= 7; + + if (index == 6) + logerror("read from output port R%d @ $%04X\n", index, m_prev_pc); + + return hmcs40_cpu_device::read_r(index); +} + //------------------------------------------------- // interrupt/timer @@ -506,23 +596,13 @@ void hmcs40_cpu_device::execute_set_input(int line, int state) // clock tc if it is in counter mode if (m_cf && line == 1) - increment_tc(); + clock_timer(); } m_int[line] = state; } -void hmcs40_cpu_device::cycle() -{ - m_icount--; - m_prescaler = (m_prescaler + 1) & 0x3f; - - // timer prescaler overflow - if (m_prescaler == 0 && !m_cf) - increment_tc(); -} - -void hmcs40_cpu_device::increment_tc() +void hmcs40_cpu_device::clock_timer() { // increment timer/counter m_tc = (m_tc + 1) & 0xf; @@ -535,6 +615,15 @@ void hmcs40_cpu_device::increment_tc() } } +void hmcs40_cpu_device::clock_prescaler() +{ + m_prescaler = (m_prescaler + 1) & 0x3f; + + // timer prescaler overflow + if (m_prescaler == 0 && !m_cf) + clock_timer(); +} + //------------------------------------------------- // execute @@ -555,6 +644,12 @@ inline void hmcs40_cpu_device::increment_pc() m_pc = (m_pc & ~mask) | ((m_pc << 1 | fb) & mask); } +void hmcs40_cpu_device::cycle() +{ + m_icount--; + clock_prescaler(); +} + void hmcs40_cpu_device::execute_run() { // in HLT state, the internal clock is not running @@ -568,7 +663,7 @@ void hmcs40_cpu_device::execute_run() { // LPU is handled 1 cycle later if ((m_prev_op & 0x7e0) == 0x340) - m_pc = ((m_page << 6) | (m_pc & 0x3f)) & m_pcmask; + m_pc = ((m_pc_upper << 6) | (m_pc & 0x3f)) & m_pcmask; // remember previous state m_prev_op = m_op; diff --git a/src/devices/cpu/hmcs40/hmcs40.h b/src/devices/cpu/hmcs40/hmcs40.h index c1c24d81b0d..e17bd020aa7 100644 --- a/src/devices/cpu/hmcs40/hmcs40.h +++ b/src/devices/cpu/hmcs40/hmcs40.h @@ -127,8 +127,9 @@ protected: // memory maps void program_1k(address_map &map); void program_2k(address_map &map); - void data_160x4(address_map &map); void data_80x4(address_map &map); + void data_160x4(address_map &map); + void data_256x4(address_map &map); address_space_config m_program_config; address_space_config m_data_config; @@ -159,7 +160,7 @@ protected: u16 m_pc; // program counter u16 m_prev_pc; - u8 m_page; // LPU prepared page + u8 m_pc_upper; // LPU prepared upper bits of PC u8 m_a; // 4-bit accumulator u8 m_b; // 4-bit B register u8 m_x; // 1/3/4-bit X register @@ -188,6 +189,7 @@ protected: // misc internal helpers void increment_pc(); + void cycle(); u8 ram_r(); void ram_w(u8 data); @@ -200,9 +202,9 @@ protected: virtual int read_d(u8 index); virtual void write_d(u8 index, int state); - void cycle(); - void increment_tc(); void take_interrupt(); + void clock_timer(); + void clock_prescaler(); // opcode handlers void op_illegal(); @@ -409,6 +411,57 @@ public: }; +class hmcs46_cpu_device : public hmcs40_cpu_device +{ +protected: + hmcs46_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity); + + // overrides + virtual u8 read_r(u8 index) override; + virtual void write_r(u8 index, u8 data) override; +}; + +class hd44840_device : public hmcs46_cpu_device +{ +public: + hd44840_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class hd44848_device : public hmcs46_cpu_device +{ +public: + hd44848_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + +class hmcs47_cpu_device : public hmcs40_cpu_device +{ +protected: + hmcs47_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity); + + // overrides + virtual u8 read_r(u8 index) override; +}; + +class hd38870_device : public hmcs47_cpu_device +{ +public: + hd38870_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class hd44860_device : public hmcs47_cpu_device +{ +public: + hd44860_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class hd44868_device : public hmcs47_cpu_device +{ +public: + hd44868_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + DECLARE_DEVICE_TYPE(HD38750, hd38750_device) DECLARE_DEVICE_TYPE(HD38755, hd38755_device) DECLARE_DEVICE_TYPE(HD44750, hd44750_device) @@ -424,4 +477,12 @@ DECLARE_DEVICE_TYPE(HD38825, hd38825_device) DECLARE_DEVICE_TYPE(HD44820, hd44820_device) DECLARE_DEVICE_TYPE(HD44828, hd44828_device) +DECLARE_DEVICE_TYPE(HD44840, hd44840_device) +DECLARE_DEVICE_TYPE(HD44848, hd44848_device) + +DECLARE_DEVICE_TYPE(HD38870, hd38870_device) +DECLARE_DEVICE_TYPE(HD44860, hd44860_device) +DECLARE_DEVICE_TYPE(HD44868, hd44868_device) + + #endif // MAME_CPU_HMCS40_HMCS40_H diff --git a/src/devices/cpu/hmcs40/hmcs40d.h b/src/devices/cpu/hmcs40/hmcs40d.h index a02d7e87a1b..f67ba8f3b9f 100644 --- a/src/devices/cpu/hmcs40/hmcs40d.h +++ b/src/devices/cpu/hmcs40/hmcs40d.h @@ -18,8 +18,9 @@ public: virtual ~hmcs40_disassembler(); virtual u32 opcode_alignment() const override { return 1; } - virtual u32 interface_flags() const override { return NONLINEAR_PC | PAGED; } + virtual u32 interface_flags() const override { return NONLINEAR_PC | PAGED2LEVEL; } virtual u32 page_address_bits() const override { return 6; } + virtual u32 page2_address_bits() const override { return 5; } virtual offs_t pc_linear_to_real(offs_t pc) const override { return (pc & ~0x3f) | m_l2r[pc & 0x3f]; } virtual offs_t pc_real_to_linear(offs_t pc) const override { return (pc & ~0x3f) | m_r2l[pc & 0x3f]; } virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; diff --git a/src/devices/cpu/hmcs40/hmcs40op.cpp b/src/devices/cpu/hmcs40/hmcs40op.cpp index 17e307ca6fa..713dd111777 100644 --- a/src/devices/cpu/hmcs40/hmcs40op.cpp +++ b/src/devices/cpu/hmcs40/hmcs40op.cpp @@ -465,7 +465,11 @@ void hmcs40_cpu_device::op_lpu() if (m_s) { m_block_int = true; - m_page = m_op & 0x1f; + m_pc_upper = m_op & 0x1f; + + // on HMCS46/47, also latches bank from R70 + if (m_family == HMCS46_FAMILY || m_family == HMCS47_FAMILY) + m_pc_upper |= ~m_r[7] << 5 & 0x20; } else m_op |= 0x400; // indicate unhandled LPU