From 147b5e72a401de8478df778a1f00d3a4c1be44f8 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 14 Feb 2021 23:23:14 +0100 Subject: added MM5799 MCU emulation [hap] New working machines -------------------- Basketball (Mattel) [hap, Sean Riddle] QuizKid Speller [hap, Sean Riddle] New working clones ------------------ QuizKid Racer (MM5799 version) [hap, Sean Riddle] --- scripts/src/cpu.lua | 20 ++ scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 2 + src/devices/cpu/cops1/cops1base.cpp | 235 +++++++++++++ src/devices/cpu/cops1/cops1base.h | 197 +++++++++++ src/devices/cpu/cops1/cops1d.cpp | 188 +++++++++++ src/devices/cpu/cops1/cops1d.h | 65 ++++ src/devices/cpu/cops1/cops1op.cpp | 378 +++++++++++++++++++++ src/devices/cpu/cops1/mm5799.cpp | 153 +++++++++ src/devices/cpu/cops1/mm5799.h | 61 ++++ src/devices/cpu/sm510/sm500core.cpp | 2 +- src/devices/cpu/sm510/sm510.h | 2 +- src/devices/cpu/sm510/sm510base.cpp | 2 +- src/devices/cpu/sm510/sm510core.cpp | 2 +- src/devices/cpu/sm510/sm510op.cpp | 4 +- src/devices/cpu/sm510/sm511core.cpp | 2 +- src/devices/cpu/sm510/sm590core.cpp | 2 +- src/devices/cpu/tms1000/tms1k_base.h | 1 - src/mame/drivers/hh_cop400.cpp | 39 +-- src/mame/drivers/hh_cops1.cpp | 577 ++++++++++++++++++++++++++++++++ src/mame/layout/aim65.lay | 2 +- src/mame/layout/cnbaskb.lay | 2 +- src/mame/layout/cnfball2.lay | 2 +- src/mame/layout/cqback.lay | 2 +- src/mame/layout/ebaskb2.lay | 2 +- src/mame/layout/ebball.lay | 3 +- src/mame/layout/ebball2.lay | 2 +- src/mame/layout/ebball3.lay | 2 +- src/mame/layout/efball.lay | 5 +- src/mame/layout/eleciq.lay | 2 +- src/mame/layout/esoccer.lay | 2 +- src/mame/layout/gjackpot.lay | 2 +- src/mame/layout/gpoker.lay | 2 +- src/mame/layout/h2hbaseb.lay | 2 +- src/mame/layout/h2hboxing.lay | 2 +- src/mame/layout/h2hfootb.lay | 2 +- src/mame/layout/hccbaskb.lay | 2 +- src/mame/layout/lightfgt.lay | 2 +- src/mame/layout/mbaskb.lay | 103 ++++++ src/mame/layout/mephisto_megaiv.lay | 2 +- src/mame/layout/mephisto_mondial2.lay | 2 +- src/mame/layout/mephisto_mondial68k.lay | 2 +- src/mame/layout/mephisto_smondial2.lay | 2 +- src/mame/layout/qkracerm.lay | 66 ++++ src/mame/layout/qkspeller.lay | 35 ++ src/mame/layout/rockpin.lay | 2 +- src/mame/layout/ssimon.lay | 2 +- src/mame/layout/tactix.lay | 2 +- src/mame/layout/tbaskb.lay | 2 +- src/mame/layout/tbreakup.lay | 2 +- src/mame/layout/ti95.lay | 2 +- src/mame/layout/us2pfball.lay | 2 +- src/mame/mame.lst | 5 + src/mame/mess.flt | 1 + src/tools/unidasm.cpp | 2 + 55 files changed, 2147 insertions(+), 60 deletions(-) create mode 100644 src/devices/cpu/cops1/cops1base.cpp create mode 100644 src/devices/cpu/cops1/cops1base.h create mode 100644 src/devices/cpu/cops1/cops1d.cpp create mode 100644 src/devices/cpu/cops1/cops1d.h create mode 100644 src/devices/cpu/cops1/cops1op.cpp create mode 100644 src/devices/cpu/cops1/mm5799.cpp create mode 100644 src/devices/cpu/cops1/mm5799.h create mode 100644 src/mame/drivers/hh_cops1.cpp create mode 100644 src/mame/layout/mbaskb.lay create mode 100644 src/mame/layout/qkracerm.lay create mode 100644 src/mame/layout/qkspeller.lay diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 1965cb11300..938501f7394 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -451,6 +451,26 @@ if (CPUS["COSMAC"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/cosmac/cosdasm.h") end +-------------------------------------------------- +-- National Semiconductor COPS1 family +--@src/devices/cpu/cops1/mm5799.h,CPUS["COPS1"] = true +-------------------------------------------------- + +if (CPUS["COPS1"]~=null) then + files { + MAME_DIR .. "src/devices/cpu/cops1/cops1base.cpp", + MAME_DIR .. "src/devices/cpu/cops1/cops1base.h", + MAME_DIR .. "src/devices/cpu/cops1/cops1op.cpp", + MAME_DIR .. "src/devices/cpu/cops1/mm5799.cpp", + MAME_DIR .. "src/devices/cpu/cops1/mm5799.h", + } +end + +if (CPUS["COPS1"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/cops1/cops1d.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/cops1/cops1d.h") +end + -------------------------------------------------- -- National Semiconductor COP400 family --@src/devices/cpu/cop400/cop400.h,CPUS["COP400"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 979f9fd0e49..ff6e0f45149 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -147,6 +147,7 @@ CPUS["HPC"] = true CPUS["FR"] = true CPUS["UPD78K"] = true CPUS["KS0164"] = true +--CPUS["COPS1"] = true -------------------------------------------------- -- specify available sound cores diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 58c65de5c4a..1baf05ce3e2 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -166,6 +166,7 @@ CPUS["M88000"] = true CPUS["XAVIX2"] = true CPUS["UPD78K"] = true CPUS["ROMP"] = true +CPUS["COPS1"] = true -------------------------------------------------- -- specify available sound cores; some of these are @@ -3012,6 +3013,7 @@ files { createMESSProjects(_target, _subtarget, "natsemi") files { MAME_DIR .. "src/mame/drivers/hh_cop400.cpp", + MAME_DIR .. "src/mame/drivers/hh_cops1.cpp", MAME_DIR .. "src/mame/drivers/ns5652.cpp", } diff --git a/src/devices/cpu/cops1/cops1base.cpp b/src/devices/cpu/cops1/cops1base.cpp new file mode 100644 index 00000000000..08f882df59c --- /dev/null +++ b/src/devices/cpu/cops1/cops1base.cpp @@ -0,0 +1,235 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + +National Semiconductor COPS(MM57 MCU family) cores + +This is the first "COPS" series (Controller Oriented Processor Systems), +4-bit MCUs with internal RAM and most of them internal ROM too. +It was only briefly on the market and was quickly superceded by the +2nd "COPS": the COP400 series. + +Short list of MCU types: +- MM5781+MM5782: 2KB ROM, 160 nybbles RAM +- MM5799: 1.5KB ROM, 96 nybbles RAM +- MM57140: 640 bytes ROM(10 bytes inaccessible?), 55 nybbles RAM + +Note that not every "MM57" chip is a generic MCU, there are plenty other chips, +mostly for calculators. For example MM5780 for the Quiz Kid, the decap of that +looks more like a complex state machine. + +References: +- 1977 National Semiconductor MOS/LSI databook + +TODO: +- documentation says that LB 10 is either 0 or 4, depending on RAM configuration, + but on qkracerm it's 5 (also confirmed in patent source code), so I assume + LB 10 is fully configurable as mask option + +*/ + +#include "emu.h" +#include "cops1base.h" + +#include "debugger.h" + + +cops1_base_device::cops1_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) : + cpu_device(mconfig, type, tag, owner, clock), + m_program_config("program", ENDIANNESS_LITTLE, 8, prgwidth, 0, program), + m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data), + m_prgwidth(prgwidth), + m_datawidth(datawidth), + m_opla(*this, "opla"), + m_read_k(*this), + m_read_inb(*this), + m_read_f(*this), + m_write_f(*this), + m_read_do3(*this), + m_write_do(*this), + m_write_s(*this), + m_write_blk(*this), + m_read_si(*this), + m_write_so(*this) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + COPS1_PC=1, COPS1_SA, COPS1_SB, + COPS1_A, COPS1_C, COPS1_H, COPS1_B, COPS1_F +}; + +void cops1_base_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + + // resolve callbacks + m_read_k.resolve_safe(0); + m_read_inb.resolve_safe(0); + m_read_f.resolve(); + m_write_f.resolve_safe(); + m_read_do3.resolve(); + m_write_do.resolve_safe(); + m_write_s.resolve_safe(); + m_write_blk.resolve_safe(); + m_read_si.resolve_safe(0); + m_write_so.resolve_safe(); + + // zerofill + m_pc = 0; + m_prev_pc = 0; + m_op = 0; + m_prev_op = 0; + m_arg = 0; + + m_a = 0; + m_h = 0; + m_b = 0; + m_c = 0; + m_skip = false; + m_sa = 0; + m_sb = 0; + m_serial = 0; + m_f = 0; + m_do = 0; + + // register for savestates + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_arg)); + + save_item(NAME(m_a)); + save_item(NAME(m_h)); + save_item(NAME(m_b)); + save_item(NAME(m_c)); + save_item(NAME(m_skip)); + save_item(NAME(m_sa)); + save_item(NAME(m_sb)); + save_item(NAME(m_serial)); + save_item(NAME(m_f)); + save_item(NAME(m_do)); + + // register state for debugger + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%03X").noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_prev_pc).formatstr("%03X").noshow(); + + state_add(COPS1_PC, "PC", m_pc).formatstr("%03X"); + state_add(COPS1_SA, "SA", m_sa).formatstr("%03X"); + state_add(COPS1_SB, "SB", m_sb).formatstr("%03X"); + + state_add(COPS1_A, "A", m_a).formatstr("%01X"); + state_add(COPS1_C, "C", m_c).formatstr("%01X"); + state_add(COPS1_H, "H", m_h).formatstr("%01X"); + state_add(COPS1_B, "B", m_b).formatstr("%02X"); + state_add(COPS1_F, "F", m_f).formatstr("%01X"); + + set_icountptr(m_icount); +} + +device_memory_interface::space_config_vector cops1_base_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_DATA, &m_data_config) + }; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cops1_base_device::device_reset() +{ + m_op = m_prev_op = 0; + m_pc = m_prev_pc = 0; + m_skip = false; + + // clear outputs + m_write_blk(1); + m_write_f(m_f = 0); + m_write_do(m_do = 0); + m_write_s(0); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void cops1_base_device::device_add_mconfig(machine_config &config) +{ + PLA(config, "opla", 4, 7, 15).set_format(pla_device::FMT::BERKELEY); +} + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void cops1_base_device::cycle() +{ + m_icount--; + + // shift serial data + m_write_so(m_serial & 1); + int feed = m_option_axo_si ? 1 : m_read_si(); + m_serial = (m_serial >> 1 | feed << 3) & 0xf; +} + +void cops1_base_device::increment_pc() +{ + // low part is LFSR + u8 feed = (m_pc & 0x3f) == 0 || ((m_pc >> 1 ^ m_pc) & 1) ? 0x20 : 0; + m_pc = (m_pc & ~0x3f) | (m_pc >> 1 & 0x1f) | feed; +} + +void cops1_base_device::execute_run() +{ + while (m_icount > 0) + { + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + // BLK goes low for 1 cycle with BTD + if (m_prev_op == 0x25) + m_write_blk(0); + + // fetch next opcode + debugger_instruction_hook(m_pc); + m_op = m_program->read_byte(m_pc); + increment_pc(); + cycle(); + + if (m_op != 0x25) + m_write_blk(1); + + // fetch opcode argument + if (op_argument()) + { + m_arg = m_program->read_byte(m_pc); + increment_pc(); + cycle(); + } + + // handle opcode if it's not skipped + if (m_skip) + { + m_skip = false; + m_op = 0; // fake nop + } + else + execute_one(); + } +} diff --git a/src/devices/cpu/cops1/cops1base.h b/src/devices/cpu/cops1/cops1base.h new file mode 100644 index 00000000000..cb0d85ddedb --- /dev/null +++ b/src/devices/cpu/cops1/cops1base.h @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + National Semiconductor COPS(MM57 MCU family) cores + +*/ + +#ifndef MAME_CPU_COPS1_COPS1BASE_H +#define MAME_CPU_COPS1_COPS1BASE_H + +#pragma once + +#include "machine/pla.h" + + +class cops1_base_device : public cpu_device +{ +public: + // configuration helpers + // I/O ports: + + // 4-bit K inputs + auto read_k() { return m_read_k.bind(); } + + // INB input pin + auto read_inb() { return m_read_inb.bind(); } + + // 4-bit F(flags) I/O + auto read_f() { return m_read_f.bind(); } + auto write_f() { return m_write_f.bind(); } + + // 4-bit DO(digit output) I/O + auto read_do3() { return m_read_do3.bind(); } // only DO3 can be an input + auto write_do() { return m_write_do.bind(); } + + // 8-bit Sa-Sg + Sp segment outputs + auto write_s() { return m_write_s.bind(); } + + // BLK(display blanking) output pin + auto write_blk() { return m_write_blk.bind(); } + + // 1-bit serial I/O + auto read_si() { return m_read_si.bind(); } + auto write_so() { return m_write_so.bind(); } + + // set MCU mask options: + + // RAM configuration 12 or 16 digits (default false) + auto &set_option_ram_d12(bool b) { m_option_ram_d12 = b; return *this; } + + // LB 10 real value (default 0) + auto &set_option_lb_10(u8 lb) { m_option_lb_10 = lb & 0xf; return *this; } + + // skip on Bd 13 with EXP+ (default true) + auto &set_option_excp_skip(bool b) { m_option_excp_skip = b; return *this; } + + // read SI directly with AXO (default false) + auto &set_option_axo_si(bool b) { m_option_axo_si = b; return *this; } + + // K and INB pins can be active high or active low (default high) + auto &set_option_k_active_high(bool b) { m_option_k_active_high = b; return *this; } + auto &set_option_inb_active_high(bool b) { m_option_inb_active_high = b; return *this; } + +protected: + // construction/destruction + cops1_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + // device_execute_interface overrides + virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override { return (clocks + 4 - 1) / 4; } + virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const noexcept override { return (cycles * 4); } + virtual uint32_t execute_min_cycles() const noexcept override { return 1; } + virtual uint32_t execute_max_cycles() const noexcept override { return 2; } + virtual void execute_run() override; + virtual void execute_one() = 0; + virtual bool op_argument() = 0; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + int m_icount; + + // fixed settings or mask options + int m_prgwidth; // ROM/RAM address size + int m_datawidth; // " + u16 m_prgmask; // " + u16 m_datamask; // " + + bool m_option_ram_d12 = false; + u8 m_option_lb_10 = 0; + bool m_option_excp_skip = true; + bool m_option_axo_si = false; + bool m_option_k_active_high = true; + bool m_option_inb_active_high = true; + + optional_device m_opla; // segment output PLA + + // i/o handlers + devcb_read8 m_read_k; + devcb_read_line m_read_inb; + devcb_read8 m_read_f; + devcb_write8 m_write_f; + devcb_read_line m_read_do3; + devcb_write8 m_write_do; + devcb_write8 m_write_s; + devcb_write_line m_write_blk; + devcb_read_line m_read_si; + devcb_write_line m_write_so; + + // internal state, regs + u16 m_pc; + u16 m_prev_pc; + u8 m_op; + u8 m_prev_op; + u8 m_arg; + + u8 m_a; + u8 m_h; + u8 m_b; + int m_c; + bool m_skip; + u16 m_sa; + u16 m_sb; + u8 m_serial; + u8 m_f; + u8 m_do; + + // misc handlers + void cycle(); + void increment_pc(); + + u8 ram_r(); + void ram_w(u8 data); + void pop_pc(); + void push_pc(); + + // opcode handlers + void op_ad(); + void op_add(); + void op_sub(); + void op_comp(); + void op_0ta(); + void op_adx(); + void op_hxa(); + void op_tam(); + void op_sc(); + void op_rsc(); + void op_tc(); + + void op_tin(); + void op_tf(); + void op_tkb(); + void op_tir(); + + void op_btd(); + void op_dspa(); + void op_dsps(); + void op_axo(); + void op_ldf(); + void op_read(); + + void op_go(); + void op_call(); + void op_ret(); + void op_rets(); + void op_lg(); + void op_nop(); + + void op_exc(); + void op_excm(); + void op_excp(); + void op_mta(); + void op_lm(); + + void op_sm(); + void op_rsm(); + void op_tm(); + + void op_lb(); + void op_lbl(); + void op_atb(); + void op_bta(); + void op_hxbr(); +}; + + +#endif // MAME_CPU_COPS1_COPS1BASE_H diff --git a/src/devices/cpu/cops1/cops1d.cpp b/src/devices/cpu/cops1/cops1d.cpp new file mode 100644 index 00000000000..0d20a0f0370 --- /dev/null +++ b/src/devices/cpu/cops1/cops1d.cpp @@ -0,0 +1,188 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + National Semiconductor COPS(MM57 MCU family) disassembler + +*/ + +#include "emu.h" +#include "cops1d.h" + +// constructor + +cops1_common_disassembler::cops1_common_disassembler() +{ + // init lfsr pc lut + for (u32 i = 0, pc = 0; i < 0x40; i++) + { + m_l2r[i] = pc; + m_r2l[pc] = i; + pc = increment_pc(pc); + } +} + +offs_t cops1_common_disassembler::increment_pc(offs_t pc) +{ + u8 feed = (pc & 0x3f) == 0 || ((pc >> 1 ^ pc) & 1) ? 0x20 : 0; + return (pc & ~0x3f) | (pc >> 1 & 0x1f) | feed; +} + + +// common lookup tables + +const char *const cops1_common_disassembler::s_name[] = +{ + "?", + "AD", "ADD", "SUB", "COMP", "0TA", "ADX", "HXA", "TAM", "SC", "RSC", "TC", + "TIN", "TF", "TKB", "TIR", + "BTD", "DSPA", "DSPS", "AXO", "LDF", "READ", + "GO", "CALL", "RET", "RETS", "LG/GO", "LG/CALL", "NOP", + "EXC", "EXCM", "EXCP", "MTA", "LM", + "SM", "SM", "SM", "SM", "RSM", "RSM", "RSM", "RSM", "TM", + "LB", "LBL", "ATB", "BTA", "HXBR" +}; + +// bitmask for opcode parameter +const u8 cops1_common_disassembler::s_bits[] = +{ + 0, + 0, 0, 0, 0, 0, 0x0f, 0, 0, 0, 0, 0, + 0, 0x30, 0, 0, + 0, 0, 0, 0, 0xff, 0, + 0x3f, 0x3f, 0, 0, 0xff, 0xff, 0, + 0x30, 0x30, 0x30, 0x30, 0x0f, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x3f, 0xff, 0, 0, 0 +}; + +const u32 cops1_common_disassembler::s_flags[] = +{ + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, STEP_OVER, STEP_OUT, STEP_OUT, 0, STEP_OVER, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 +}; + + +// common disasm + +offs_t cops1_common_disassembler::common_disasm(const u8 *lut_opmap, std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + // get raw opcode + u8 op = opcodes.r8(pc); + u8 instr = lut_opmap[op]; + int len = 1; + + // get parameter + u8 mask = s_bits[instr]; + u16 param = op & mask; + + if (mask == 0x30) + { + mask >>= 4; + param >>= 4; + } + + // 2-byte instructions + else if (mask == 0xff) + { + pc = increment_pc(pc); + u8 arg = params.r8(pc); + len++; + + if (instr == em_LG) + { + // bit 6 indicates GO or CALL + if (~arg & 0x40) + instr++; + + param = (~param << 7 & 0x780) | (arg >> 1 & 0x40) | (arg & 0x3f); + } + else + param = arg; + } + + // disassemble it + util::stream_format(stream, "%-8s ", s_name[instr]); + if (mask > 0) + { + if (mask < 16) + { + // SM and RSM param is scrambled + if (instr >= em_SM1 && instr <= em_SM8) + param = instr - em_SM1; + else if (instr >= em_RSM1 && instr <= em_RSM8) + param = instr - em_RSM1; + + // memory bit opcodes are 1,2,4,8 + if (instr >= em_SM1 && instr <= em_TM) + param = 1 << param; + + // TF is 1,2,3,4 + else if (instr == em_TF) + param++; + + // EXC type instructions omit param if it's 0 + if (!(param == 0 && (instr == em_EXC || instr == em_EXCM || instr == em_EXCP || instr == em_MTA))) + util::stream_format(stream, "%d", param); + } + else + { + // exception for LG + if (instr == em_LG || instr == em_LGCALL) + util::stream_format(stream, "$%02X,$%02X", param >> 6, param & 0x3f); + + // exception for LB/LBL + else if (instr == em_LB || instr == em_LBL) + { + // LB x,10 is 0 by default + if (instr == em_LB && (param & 0xf) == 10) + param &= 0x30; + + util::stream_format(stream, "%d,%d", param >> 4, param & 0xf); + } + + else + util::stream_format(stream, "$%02X", param); + } + } + + return len | s_flags[instr] | SUPPORTED; +} + + +// MM5799 disasm + +const u8 mm5799_disassembler::mm5799_opmap[0x100] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + em_NOP, em_HXBR, em_ADD, em_SC, em_TF, em_TIR, em_MTA, em_EXC, em_EXCM, em_EXCP, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, // 0 + em_DSPA, em_DSPS, em_AD, em_LBL, em_TF, em_TKB, em_MTA, em_EXC, em_EXCM, em_EXCP, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, // 1 + em_COMP, em_AXO, em_SUB, em_RSC, em_TF, em_BTD, em_MTA, em_EXC, em_EXCM, em_EXCP, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, // 2 + em_0TA, em_HXA, em_TAM, em_LDF, em_READ, em_TIN, em_MTA, em_EXC, em_EXCM, em_EXCP, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, // 3 + + em_RET, em_RETS, em_RSM8, em_BTA, em_TM, em_TM, em_TM, em_TM, em_RSM1, em_SM1, em_SM8, em_RSM4, em_RSM2, em_TC, em_SM2, em_SM4, // 4 + em_ATB, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, em_ADX, // 5 + em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, em_LG, // 6 + em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, em_LM, // 7 + + em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, // 8 + em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, // 9 + em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, // A + em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, em_CALL, // B + + em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, // C + em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, // D + em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, // E + em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO, em_GO // F +}; + +offs_t mm5799_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + return common_disasm(mm5799_opmap, stream, pc, opcodes, params); +} diff --git a/src/devices/cpu/cops1/cops1d.h b/src/devices/cpu/cops1/cops1d.h new file mode 100644 index 00000000000..1412e0c3c1b --- /dev/null +++ b/src/devices/cpu/cops1/cops1d.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + National Semiconductor COPS(MM57 MCU family) disassembler + +*/ + +#ifndef MAME_CPU_COPS1_MM57D_H +#define MAME_CPU_COPS1_MM57D_H + +#pragma once + + +class cops1_common_disassembler : public util::disasm_interface +{ +public: + cops1_common_disassembler(); + virtual ~cops1_common_disassembler() = default; + + virtual u32 opcode_alignment() const override { return 1; } + virtual u32 interface_flags() const override { return NONLINEAR_PC | PAGED; } + virtual u32 page_address_bits() const override { return 6; } + 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]; } + +protected: + // opcode mnemonics + enum e_mnemonics + { + em_ILL, + em_AD, em_ADD, em_SUB, em_COMP, em_0TA, em_ADX, em_HXA, em_TAM, em_SC, em_RSC, em_TC, + em_TIN, em_TF, em_TKB, em_TIR, + em_BTD, em_DSPA, em_DSPS, em_AXO, em_LDF, em_READ, + em_GO, em_CALL, em_RET, em_RETS, em_LG, em_LGCALL, em_NOP, + em_EXC, em_EXCM, em_EXCP, em_MTA, em_LM, + em_SM1, em_SM2, em_SM4, em_SM8, em_RSM1, em_RSM2, em_RSM4, em_RSM8, em_TM, + em_LB, em_LBL, em_ATB, em_BTA, em_HXBR + }; + + static const char *const s_name[]; + static const uint8_t s_bits[]; + static const uint32_t s_flags[]; + + u8 m_l2r[0x40]; + u8 m_r2l[0x40]; + + offs_t increment_pc(offs_t pc); + offs_t common_disasm(const u8 *lut_opmap, std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms); +}; + +class mm5799_disassembler : public cops1_common_disassembler +{ +public: + mm5799_disassembler() = default; + virtual ~mm5799_disassembler() = default; + + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + static const u8 mm5799_opmap[0x100]; + +}; + +#endif // MAME_CPU_COPS1_MM57D_H diff --git a/src/devices/cpu/cops1/cops1op.cpp b/src/devices/cpu/cops1/cops1op.cpp new file mode 100644 index 00000000000..1cc20ce61c6 --- /dev/null +++ b/src/devices/cpu/cops1/cops1op.cpp @@ -0,0 +1,378 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// COPS opcode handlers + +#include "emu.h" +#include "cops1base.h" + + +// internal helpers + +inline u8 cops1_base_device::ram_r() +{ + return m_data->read_byte(m_b) & 0xf; +} + +inline void cops1_base_device::ram_w(u8 data) +{ + m_data->write_byte(m_b, data & 0xf); +} + +void cops1_base_device::pop_pc() +{ + m_pc = m_sa; + m_sa = m_sb; +} + +void cops1_base_device::push_pc() +{ + m_sb = m_sa; + m_sa = m_pc; +} + + +// opcodes + +// arithmetic operations + +void cops1_base_device::op_ad() +{ + // add M to A + m_a = (m_a + ram_r()) & 0xf; +} + +void cops1_base_device::op_add() +{ + // ADD: add M+carry to A + m_a = m_a + ram_r() + m_c; + m_c = (m_a >= 10) ? 1 : 0; + m_a &= 0xf; + m_skip = !bool(m_c); +} + +void cops1_base_device::op_sub() +{ + // SUB: subtract A+carry from M + m_a = (m_a ^ 0xf) + ram_r() + m_c; + m_c = m_a >> 4 & 1; + m_a &= 0xf; + m_skip = bool(m_c); +} + +void cops1_base_device::op_comp() +{ + // COMP: complement A + m_a ^= 0xf; +} + +void cops1_base_device::op_0ta() +{ + // 0TA: clear A + m_a = 0; +} + +void cops1_base_device::op_adx() +{ + // ADX x: add constant to A + u8 x = m_op & 0xf; + m_a += x; + m_skip = ~m_a & 0x10 && x != 6; + m_a &= 0xf; +} + +void cops1_base_device::op_hxa() +{ + // HXA: exchange A with H + u8 h = m_h; + m_h = m_a; + m_a = h; +} + +void cops1_base_device::op_tam() +{ + // TAM: compare A with M + m_skip = m_a == ram_r(); +} + +void cops1_base_device::op_sc() +{ + // SC: set carry + m_c = 1; +} + +void cops1_base_device::op_rsc() +{ + // RSC: reset carry + m_c = 0; +} + +void cops1_base_device::op_tc() +{ + // TC: test carry + m_skip = !m_c; +} + + +// input test + +void cops1_base_device::op_tin() +{ + // TIN: test INB pin + bool t = !bool(m_read_inb() & 1); + m_skip = m_option_inb_active_high ? t : !t; +} + +void cops1_base_device::op_tf() +{ + // TF x: test F pin + u8 f = m_read_f.isnull() ? m_f : m_read_f(); + m_skip = !BIT(f, m_op >> 4 & 3); +} + +void cops1_base_device::op_tkb() +{ + // TKB: test K pins + bool t = bool(m_read_k() & 0xf); + m_skip = m_option_k_active_high ? t : !t; +} + +void cops1_base_device::op_tir() +{ + // TIR: test DO3 pin + int d = m_read_do3.isnull() ? (m_do >> 2) : m_read_do3(); + m_skip = !bool(d & 1); +} + + +// input/output + +void cops1_base_device::op_btd() +{ + // BTD: transfer B(d) to digit output latches + m_do = ~m_b & 0xf; + m_write_do(m_do); +} + +void cops1_base_device::op_dspa() +{ + // DSPA: transfer A+H+C to segment output latches, direct + u8 segs = bitswap<7>(m_h << 4 | m_a, 4,5,6,0,1,2,3); + m_write_s((m_c << 7 ^ 0x80) | segs); +} + +void cops1_base_device::op_dsps() +{ + // DSPA: transfer A+C to segment output latches, via PLA + u8 segs = ~m_opla->read((m_a + 1) & 0xf) & 0x7f; + m_write_s((m_c << 7 ^ 0x80) | segs); +} + +void cops1_base_device::op_axo() +{ + // AXO: exchange A with serial + u8 s = m_serial; + m_serial = m_a; + m_a = s; + + // mask option to read SI immediately + if (m_option_axo_si) + m_a = (m_a & 7) | (m_read_si() << 3 & 8); +} + +void cops1_base_device::op_ldf() +{ + // LDF: load F pin(s) + u8 mask = bitswap<4>(~m_arg, 7,5,3,1); + u8 f = bitswap<4>(~m_arg, 6,4,2,0); + m_f = (m_f & ~mask) | (f & mask); + m_write_f(m_f); +} + +void cops1_base_device::op_read() +{ + // READ: read K pins to A + m_a = m_read_k() & 0xf; +} + + +// control functions + +void cops1_base_device::op_go() +{ + // GO x: jump to address in page + + // jumps from page 0x1e/0x1f reset page to 0x1e + if ((m_pc & 0x780) == 0x780) + m_pc &= ~0x40; + + m_pc = (m_pc & ~0x3f) | (m_op & 0x3f); +} + +void cops1_base_device::op_call() +{ + // CALL: call subroutine + + // calls from page 0x1e/0x1f don't push PC + if ((m_pc & 0x780) != 0x780) + push_pc(); + + m_pc = (m_op & 0x3f) | 0x7c0; +} + +void cops1_base_device::op_ret() +{ + // RET: return from subroutine + pop_pc(); +} + +void cops1_base_device::op_rets() +{ + // RET: return from subroutine, skip next + op_ret(); + m_skip = true; +} + +void cops1_base_device::op_lg() +{ + // LG x: long go / long call + if (~m_arg & 0x40) + push_pc(); + + m_pc = (~m_op << 7 & 0x780) | (m_arg >> 1 & 0x40) | (m_arg & 0x3f); +} + +void cops1_base_device::op_nop() +{ + // NOP: no operation +} + + +// memory digit operations + +void cops1_base_device::op_exc() +{ + // EXC x: exchange A with M, XOR B(r) with x + u8 a = m_a; + m_a = ram_r(); + ram_w(a); + m_b ^= m_op & 0x30; +} + +void cops1_base_device::op_excm() +{ + // EXC- x: EXC + decrement B(d) + op_exc(); + m_b = (m_b & ~0xf) | ((m_b - 1) & 0xf); + m_skip = (m_b & 0xf) == 0xf; +} + +void cops1_base_device::op_excp() +{ + // EXC+ x: EXC + increment B(d) + op_exc(); + m_b = (m_b & ~0xf) | ((m_b + 1) & 0xf); + m_skip = (m_b & 0xf) == 0; + + // mask option to also skip on 13 + if (m_option_excp_skip && (m_b & 0xf) == 13) + m_skip = true; +} + +void cops1_base_device::op_mta() +{ + // MTA x: load A with M, XOR B(r) with x + m_a = ram_r(); + m_b ^= m_op & 0x30; +} + +void cops1_base_device::op_lm() +{ + // LM x: load M with constant, increment B(d) + ram_w(m_op & 0xf); + m_b = (m_b & ~0xf) | ((m_b + 1) & 0xf); +} + + +// memory bit operations + +void cops1_base_device::op_sm() +{ + // SM x: set memory bit + u8 x = 0; + + // opcode param is scrambled for some reason + switch (m_op & 0xf) + { + case 0x9: x = 1; break; + case 0xe: x = 2; break; + case 0xf: x = 4; break; + case 0xa: x = 8; break; + } + ram_w(ram_r() | x); +} + +void cops1_base_device::op_rsm() +{ + // RSM x: reset memory bit + u8 x = 0; + + // opcode param is scrambled for some reason + switch (m_op & 0xf) + { + case 0x8: x = 1; break; + case 0xc: x = 2; break; + case 0xb: x = 4; break; + case 0x2: x = 8; break; + } + ram_w(ram_r() & ~x); +} + +void cops1_base_device::op_tm() +{ + // TM x: test memory bit + m_skip = !BIT(ram_r(), m_op & 3); +} + + +// memory address operations + +void cops1_base_device::op_lb() +{ + // LB x: load B (successive LB are ignored) + if ((m_prev_op & 0xc0) == 0x00 && (m_prev_op & 0xf) >= 0xa) + return; + + // d 10 actual value is a mask option + u8 x = m_op & 0xf; + if (x == 10) + x = m_option_lb_10; + + m_b = ((m_op & 0x30) | x) & m_datamask; +} + +void cops1_base_device::op_lbl() +{ + // LBL x: load B fully + m_b = m_arg & m_datamask; +} + +void cops1_base_device::op_atb() +{ + // ATB: transfer A to B(d) + m_b = (m_b & ~0xf) | m_a; +} + +void cops1_base_device::op_bta() +{ + // BTA: transfer B(d) to A + m_a = m_b & 0xf; +} + +void cops1_base_device::op_hxbr() +{ + // HXBR: exchange H with B(r) + u8 h = m_h; + m_h = m_b >> 4; + m_b = (h << 4 | (m_b & 0xf)) & m_datamask; +} diff --git a/src/devices/cpu/cops1/mm5799.cpp b/src/devices/cpu/cops1/mm5799.cpp new file mode 100644 index 00000000000..bffb5e64a66 --- /dev/null +++ b/src/devices/cpu/cops1/mm5799.cpp @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + National Semiconductor MM5799 MCU + +*/ + +#include "emu.h" +#include "mm5799.h" + +#include "cops1d.h" + + +DEFINE_DEVICE_TYPE(MM5799, mm5799_device, "mm5799", "National Semiconductor MM5799") + + +// internal memory maps +void mm5799_device::program_map(address_map &map) +{ + map(0x0000, 0x01ff).rom(); + map(0x0400, 0x07ff).rom(); +} + +void mm5799_device::data_map(address_map &map) +{ + if (m_option_ram_d12) + { + // 8x12x4 + for (int i = 0; i < 0x80; i += 0x10) + map(i | 0x04, i | 0x0f).ram(); + } + else + { + // 6x16x4 + map(0x00, 0x5f).ram(); + } +} + + +// device definitions +mm5799_device::mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + cops1_base_device(mconfig, MM5799, tag, owner, clock, 11, address_map_constructor(FUNC(mm5799_device::program_map), this), 7, address_map_constructor(FUNC(mm5799_device::data_map), this)) +{ } + + +// disasm +std::unique_ptr mm5799_device::create_disassembler() +{ + return std::make_unique(); +} + + +// initialize +void mm5799_device::device_start() +{ + cops1_base_device::device_start(); +} + +void mm5799_device::device_reset() +{ + cops1_base_device::device_reset(); +} + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void mm5799_device::execute_one() +{ + switch (m_op & 0xc0) + { + case 0x00: + switch (m_op) + { + case 0x00: op_nop(); break; + case 0x10: op_dspa(); break; + case 0x20: op_comp(); break; + case 0x30: op_0ta(); break; + + case 0x01: op_hxbr(); break; + case 0x11: op_dsps(); break; + case 0x21: op_axo(); break; + case 0x31: op_hxa(); break; + + case 0x02: op_add(); break; + case 0x12: op_ad(); break; + case 0x22: op_sub(); break; + case 0x32: op_tam(); break; + + case 0x03: op_sc(); break; + case 0x13: op_lbl(); break; + case 0x23: op_rsc(); break; + case 0x33: op_ldf(); break; + + case 0x34: op_read(); break; + + case 0x05: op_tir(); break; + case 0x15: op_tkb(); break; + case 0x25: op_btd(); break; + case 0x35: op_tin(); break; + + case 0x04: case 0x14: case 0x24: op_tf(); break; + + case 0x06: case 0x16: case 0x26: case 0x36: op_mta(); break; + case 0x07: case 0x17: case 0x27: case 0x37: op_exc(); break; + case 0x08: case 0x18: case 0x28: case 0x38: op_excm(); break; + case 0x09: case 0x19: case 0x29: case 0x39: op_excp(); break; + + default: op_lb(); break; + } + break; // 0x00 + + case 0x40: + switch (m_op & 0x30) + { + case 0x00: + switch (m_op & 0x0f) + { + case 0x00: op_ret(); break; + case 0x01: op_rets(); break; + case 0x03: op_bta(); break; + case 0x0d: op_tc(); break; + + case 0x02: case 0x08: case 0x0b: case 0x0c: op_rsm(); break; + case 0x04: case 0x05: case 0x06: case 0x07: op_tm(); break; + case 0x09: case 0x0a: case 0x0e: case 0x0f: op_sm(); break; + } + break; + + case 0x10: + if ((m_op & 0x0f) != 0) + op_adx(); + else + op_atb(); + break; + + case 0x20: op_lg(); break; + case 0x30: op_lm(); break; + } + break; // 0x40 + + case 0x80: op_call(); break; + case 0xc0: op_go(); break; + } +} + +bool mm5799_device::op_argument() +{ + // 2-byte instructions: LBL, LDF, LG + return m_op == 0x13 || m_op == 0x33 || (m_op & 0xf0) == 0x60; +} diff --git a/src/devices/cpu/cops1/mm5799.h b/src/devices/cpu/cops1/mm5799.h new file mode 100644 index 00000000000..d8f568e3808 --- /dev/null +++ b/src/devices/cpu/cops1/mm5799.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + National Semiconductor MM5799 MCU + +*/ + +#ifndef MAME_CPU_COPS1_MM5799_H +#define MAME_CPU_COPS1_MM5799_H + +#pragma once + +#include "cops1base.h" + +// pinout reference + +/* + ____ ____ + K1 1 |* \_/ | 28 DO1 + K2 2 | | 27 DO2 + K3 3 | | 26 DO3 + K4 4 | | 25 DO4 + INB 5 | | 24 SI + SYNC 6 | | 23 SO + OSC 7 | MM5799N | 22 BLK + F3 8 | | 21 Vdd + F2 9 | | 20 Sa + F1 10 | | 19 Sb + PWR ON 11 | | 18 Sc + Sp 12 | | 17 Sd + Sg 13 | | 16 Se + Sf 14 |___________| 15 Vss + +*/ + +class mm5799_device : public cops1_base_device +{ +public: + mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_disasm_interface overrides + virtual std::unique_ptr create_disassembler() override; + + // device_execute_interface overrides + virtual void execute_one() override; + virtual bool op_argument() override; + + void data_map(address_map &map); + void program_map(address_map &map); +}; + + +DECLARE_DEVICE_TYPE(MM5799, mm5799_device) + +#endif // MAME_CPU_COPS1_MM5799_H diff --git a/src/devices/cpu/sm510/sm500core.cpp b/src/devices/cpu/sm510/sm500core.cpp index 8396d8e3107..cd4bdd7e4c8 100644 --- a/src/devices/cpu/sm510/sm500core.cpp +++ b/src/devices/cpu/sm510/sm500core.cpp @@ -136,7 +136,7 @@ void sm500_device::clock_melody() // output to R pins if (out != m_r_out) { - m_write_r(0, out, 0xff); + m_write_r(out); m_r_out = out; } } diff --git a/src/devices/cpu/sm510/sm510.h b/src/devices/cpu/sm510/sm510.h index 713d422e1e2..86240d18c99 100644 --- a/src/devices/cpu/sm510/sm510.h +++ b/src/devices/cpu/sm510/sm510.h @@ -298,7 +298,7 @@ protected: virtual void execute_one() override; virtual void get_opcode_param() override; - virtual void update_w_latch() override { m_write_s(0, m_w, 0xff); } // W is connected directly to S + virtual void update_w_latch() override { m_write_s(m_w); } // W is connected directly to S virtual void clock_melody() override; }; diff --git a/src/devices/cpu/sm510/sm510base.cpp b/src/devices/cpu/sm510/sm510base.cpp index 81b027aade8..f5f0ae6bbb2 100644 --- a/src/devices/cpu/sm510/sm510base.cpp +++ b/src/devices/cpu/sm510/sm510base.cpp @@ -161,7 +161,7 @@ void sm510_base_device::device_reset() m_y = 0; m_r = m_r_out = 0; - m_write_r(0, 0, 0xff); + m_write_r(0); } diff --git a/src/devices/cpu/sm510/sm510core.cpp b/src/devices/cpu/sm510/sm510core.cpp index 80ab6bf6ab3..b2a8c375499 100644 --- a/src/devices/cpu/sm510/sm510core.cpp +++ b/src/devices/cpu/sm510/sm510core.cpp @@ -74,7 +74,7 @@ void sm510_device::clock_melody() // output to R pins if (out != m_r_out) { - m_write_r(0, out, 0xff); + m_write_r(out); m_r_out = out; } } diff --git a/src/devices/cpu/sm510/sm510op.cpp b/src/devices/cpu/sm510/sm510op.cpp index acaf607f9df..52516c16503 100644 --- a/src/devices/cpu/sm510/sm510op.cpp +++ b/src/devices/cpu/sm510/sm510op.cpp @@ -203,7 +203,7 @@ void sm510_base_device::op_lax() void sm510_base_device::op_ptw() { // PTW: output W latch - m_write_s(0, m_w, 0xff); + m_write_s(m_w); } void sm510_base_device::op_wr() @@ -226,7 +226,7 @@ void sm510_base_device::op_ws() void sm510_base_device::op_kta() { // KTA: input K to ACC - m_acc = m_read_k(0, 0xff) & 0xf; + m_acc = m_read_k() & 0xf; } void sm510_base_device::op_atbp() diff --git a/src/devices/cpu/sm510/sm511core.cpp b/src/devices/cpu/sm510/sm511core.cpp index c7a26de07e2..70df0cd1c0e 100644 --- a/src/devices/cpu/sm510/sm511core.cpp +++ b/src/devices/cpu/sm510/sm511core.cpp @@ -138,7 +138,7 @@ void sm511_device::clock_melody() // output to R pin if (out != m_r_out) { - m_write_r(0, out, 0xff); + m_write_r(out); m_r_out = out; } } diff --git a/src/devices/cpu/sm510/sm590core.cpp b/src/devices/cpu/sm510/sm590core.cpp index 0763af6e654..fd1bca5fc9d 100644 --- a/src/devices/cpu/sm510/sm590core.cpp +++ b/src/devices/cpu/sm510/sm590core.cpp @@ -73,7 +73,7 @@ void sm590_device::device_reset() m_clk_div = 4; // 4 clock oscillations per cycle on SM59x, see datasheet page 30/pdf page 39 m_rports[0] = m_rports[1] = m_rports[2] = m_rports[3] = 0; - //m_write_r(0, 0, 0xff); // TODO: are the four ports zeroed on reset? + //m_write_r(0); // TODO: are the four ports zeroed on reset? } //------------------------------------------------- diff --git a/src/devices/cpu/tms1000/tms1k_base.h b/src/devices/cpu/tms1000/tms1k_base.h index e535e9322c9..f03d4db24d4 100644 --- a/src/devices/cpu/tms1000/tms1k_base.h +++ b/src/devices/cpu/tms1000/tms1k_base.h @@ -20,7 +20,6 @@ // pinout reference /* - ____ ____ ____ ____ R8 1 |* \_/ | 28 R7 R0 1 |* \_/ | 28 Vss R9 2 | | 27 R6 R1 2 | | 27 OSC2 diff --git a/src/mame/drivers/hh_cop400.cpp b/src/mame/drivers/hh_cop400.cpp index a5868547101..d331f933570 100644 --- a/src/mame/drivers/hh_cop400.cpp +++ b/src/mame/drivers/hh_cop400.cpp @@ -3,8 +3,8 @@ // thanks-to:Sean Riddle /*************************************************************************** - National Semiconductor COP400 MCU handhelds or other simple devices, - mostly LED electronic games/toys. + National Semiconductor COPS(COP400 MCU series) handhelds or other simple + devices, mostly LED electronic games/toys. TODO: - why does h2hbaskbc(and clones) need a workaround on writing L pins? @@ -1691,7 +1691,8 @@ ROM_END * COP420 MCU label COP420-NPG/N * 8-digit 7seg led display(1 custom digit), 1 green led, no sound - This is the COP420 version, the first release was on a MM5799 MCU. + This is the COP420 version, the first release was on a MM5799 MCU, + see hh_cops1.cpp. ***************************************************************************/ @@ -1720,8 +1721,8 @@ void qkracer_state::update_display() void qkracer_state::write_d(u8 data) { - // D: select digit, D3: input mux high bit - m_inp_mux = (m_inp_mux & 0xf) | (data << 1 & 0x10); + // D: select digit, D3: input mux low bit + m_inp_mux = (m_inp_mux & ~1) | (data >> 3 & 1); m_d = data & 0xf; update_display(); } @@ -1729,7 +1730,7 @@ void qkracer_state::write_d(u8 data) void qkracer_state::write_g(u8 data) { // G: select digit, input mux - m_inp_mux = (m_inp_mux & 0x10) | (data & 0xf); + m_inp_mux = (m_inp_mux & 1) | (data << 1 & 0x1e); m_g = data & 0xf; update_display(); } @@ -1757,42 +1758,42 @@ WRITE_LINE_MEMBER(qkracer_state::write_sk) // config static INPUT_PORTS_START( qkracer ) - PORT_START("IN.0") // G0 port IN + PORT_START("IN.0") // D3 port IN + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_Q) PORT_NAME("Amateur") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_W) PORT_NAME("Pro") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_E) PORT_NAME("Complex") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_R) PORT_NAME("Tables") + + PORT_START("IN.1") // G0 port IN PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("7") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("8") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("9") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_SLASH_PAD) PORT_NAME(UTF8_DIVIDE) - PORT_START("IN.1") // G1 port IN + PORT_START("IN.2") // G1 port IN PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_ASTERISK) PORT_NAME(UTF8_MULTIPLY) - PORT_START("IN.2") // G2 port IN + PORT_START("IN.3") // G2 port IN PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("-") - PORT_START("IN.3") // G3 port IN + PORT_START("IN.4") // G3 port IN PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Slow") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Fast") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("0") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("+") - - PORT_START("IN.4") // D3 port IN - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_Q) PORT_NAME("Amateur") - PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_W) PORT_NAME("Pro") - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_E) PORT_NAME("Complex") - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_CODE(KEYCODE_R) PORT_NAME("Tables") INPUT_PORTS_END void qkracer_state::qkracer(machine_config &config) { /* basic machine hardware */ - COP420(config, m_maincpu, 1000000); // approximation - RC osc. R=47K, C=100pF - m_maincpu->set_config(COP400_CKI_DIVISOR_32, COP400_CKO_OSCILLATOR_OUTPUT, false); // guessed + COP420(config, m_maincpu, 950000); // approximation - RC osc. R=47K, C=100pF + m_maincpu->set_config(COP400_CKI_DIVISOR_16, COP400_CKO_OSCILLATOR_OUTPUT, false); // guessed m_maincpu->write_d().set(FUNC(qkracer_state::write_d)); m_maincpu->write_g().set(FUNC(qkracer_state::write_g)); m_maincpu->write_l().set(FUNC(qkracer_state::write_l)); @@ -1948,7 +1949,7 @@ CONS( 1980, plus1, 0, 0, plus1, plus1, plus1_state, e CONS( 1981, lightfgt, 0, 0, lightfgt, lightfgt, lightfgt_state, empty_init, "Milton Bradley", "Electronic Lightfight - The Games of Dueling Lights", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) CONS( 1982, bship82, bship, 0, bship82, bship82, bship82_state, empty_init, "Milton Bradley", "Electronic Battleship (1982 version)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) // *** -CONS( 1978, qkracer, 0, 0, qkracer, qkracer, qkracer_state, empty_init, "National Semiconductor", "QuizKid Racer (COP420 version)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) +CONS( 1979, qkracer, 0, 0, qkracer, qkracer, qkracer_state, empty_init, "National Semiconductor", "QuizKid Racer (COP420 version)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) CONS( 1987, vidchal, 0, 0, vidchal, vidchal, vidchal_state, empty_init, "Select Merchandise", "Video Challenger", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/hh_cops1.cpp b/src/mame/drivers/hh_cops1.cpp new file mode 100644 index 00000000000..1f8cbe5a3bf --- /dev/null +++ b/src/mame/drivers/hh_cops1.cpp @@ -0,0 +1,577 @@ +// license:BSD-3-Clause +// copyright-holders:hap +// thanks-to:Sean Riddle +/*************************************************************************** + + National Semiconductor COPS(MM57 MCU series) handhelds + + TODO: + - qkracerm RAM configuration is unknown (it also works fine with 8x12) + - qkracerm link cable + +***************************************************************************/ + +#include "emu.h" + +#include "cpu/cops1/mm5799.h" +#include "machine/ds8874.h" +#include "video/pwm.h" +#include "sound/spkrdev.h" +#include "speaker.h" + +// internal artwork +#include "mbaskb.lh" +#include "qkracerm.lh" +#include "qkspeller.lh" + +//#include "hh_cops1_test.lh" // common test-layout - use external artwork + + +class hh_cops1_state : public driver_device +{ +public: + hh_cops1_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_speaker(*this, "speaker"), + m_inputs(*this, "IN.%u", 0) + { } + + // devices + required_device m_maincpu; + optional_device m_display; + optional_device m_speaker; + optional_ioport_array<9> m_inputs; // max 9 + + u16 m_inp_mux = 0; + u16 m_grid = 0; + + // MCU output pin state + u8 m_s = 0; + u8 m_do = 0; + u8 m_f = 0; + int m_blk = false; + + u8 read_inputs(int columns); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; +}; + + +// machine start/reset + +void hh_cops1_state::machine_start() +{ + // register for savestates + save_item(NAME(m_inp_mux)); + save_item(NAME(m_grid)); + save_item(NAME(m_s)); + save_item(NAME(m_do)); + save_item(NAME(m_f)); + save_item(NAME(m_blk)); +} + +void hh_cops1_state::machine_reset() +{ +} + + + +/*************************************************************************** + + Helper Functions + +***************************************************************************/ + +// generic input handlers + +u8 hh_cops1_state::read_inputs(int columns) +{ + u8 ret = 0; + + // read selected input rows + for (int i = 0; i < columns; i++) + if (m_inp_mux >> i & 1) + ret |= m_inputs[i]->read(); + + return ret; +} + + + +/*************************************************************************** + + Minidrivers (subclass, I/O, Inputs, Machine Config, ROM Defs) + +***************************************************************************/ + +namespace { + +/*************************************************************************** + + Mattel Basketball (model 2437) + * PCB label: MA 6017/18/19 + * MM5799 MCU bonded directly to PCB (die label MM4799 C NCX) + * 4001 and 74145, also bonded to PCB + * 2-digit 7seg led display, 21 leds, 2-bit sound + + Judging from videos online, there are two versions of Basketball. One where + the display shows "12" at power-on(as on MAME), and one that shows "15". + + Mattel Hockey and Soccer are on nearly identical hardware. + +***************************************************************************/ + +class mbaskb_state : public hh_cops1_state +{ +public: + mbaskb_state(const machine_config &mconfig, device_type type, const char *tag) : + hh_cops1_state(mconfig, type, tag) + { } + + void update_display(); + void write_do(u8 data); + void write_blk(int state); + void write_s(u8 data); + void write_f(u8 data); + u8 read_f(); + void mbaskb(machine_config &config); +}; + +// handlers + +void mbaskb_state::update_display() +{ + // DO4321: 74154 CBAD + u8 d = (m_do >> 1 & 7) | (m_do << 3 & 8); + u16 sel = m_blk ? (1 << d) : 0; + + // 74154 output 2,6: speaker out + u8 spk = bitswap<2>(sel, 6,2); + m_speaker->level_w(spk); + + // 74154 output 3-5,10-13: digit/led select + u8 dsp = bitswap<7>(sel, 11,4,12,5,13,3,10); + m_display->matrix((m_f << 5 & 0x80) | dsp, m_s); +} + +void mbaskb_state::write_do(u8 data) +{ + // DO: 74154 inputs + m_do = data; + update_display(); +} + +void mbaskb_state::write_blk(int state) +{ + // BLK: 74154 enable + m_blk = state; + update_display(); +} + +void mbaskb_state::write_s(u8 data) +{ + // Sa-Sg: digit segment/led data + m_s = data; + update_display(); +} + +void mbaskb_state::write_f(u8 data) +{ + // F3: led data + m_f = data; + update_display(); +} + +u8 mbaskb_state::read_f() +{ + // F1: difficulty switch + return m_inputs[2]->read() | (m_f & 2); +} + +// config + +static INPUT_PORTS_START( mbaskb ) + PORT_START("IN.0") // port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_16WAY + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_16WAY + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_16WAY + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_16WAY + + PORT_START("IN.1") // INB + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) + + PORT_START("IN.2") // F1 + PORT_CONFNAME( 0x01, 0x00, DEF_STR( Difficulty ) ) + PORT_CONFSETTING( 0x00, "1" ) + PORT_CONFSETTING( 0x01, "2" ) +INPUT_PORTS_END + +void mbaskb_state::mbaskb(machine_config &config) +{ + /* basic machine hardware */ + MM5799(config, m_maincpu, 370000); // approximation + m_maincpu->write_do().set(FUNC(mbaskb_state::write_do)); + m_maincpu->write_blk().set(FUNC(mbaskb_state::write_blk)); + m_maincpu->write_s().set(FUNC(mbaskb_state::write_s)); + m_maincpu->write_f().set(FUNC(mbaskb_state::write_f)); + m_maincpu->read_f().set(FUNC(mbaskb_state::read_f)); + m_maincpu->read_k().set_ioport("IN.0"); + m_maincpu->read_inb().set_ioport("IN.1"); + + /* video hardware */ + PWM_DISPLAY(config, m_display).set_size(8, 7); + m_display->set_segmask(3, 0x7f); + m_display->set_bri_levels(0.01, 0.2); // player led is brighter + config.set_default_layout(layout_mbaskb); + + /* sound hardware */ + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_speaker); + static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 }; + m_speaker->set_levels(4, speaker_levels); + m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25); +} + +// roms + +ROM_START( mbaskb ) + ROM_REGION( 0x0800, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD( "mm4799_c_ncx", 0x0000, 0x0200, CRC(d0e5fce1) SHA1(04708c043a763bf92d765095e9551388a1d967e8) ) + ROM_CONTINUE( 0x0400, 0x0400 ) + + ROM_REGION( 254, "maincpu:opla", 0 ) + ROM_LOAD( "mm5799_mbaskb_output.pla", 0, 254, CRC(c8d225f1) SHA1(4f1e1977e96e53d1d716b7785c4c3971ed9ff65b) ) +ROM_END + + + + + +/*************************************************************************** + + National Semiconductor QuizKid Racer (MM5799 version) + * MM5799 MCU bonded directly to PCB (die label MM4799 C DUZ) + * DS8874 LED driver, die bonded to PCB as well + * 8-digit 7seg led display(1 custom digit), 1 green led, no sound + * optional link cable to compete with another player (see patent US4051605) + + This is the first version of QuizKid Racer, the 2nd release is on a + COP420 MCU, see hh_cop400.cpp. + +***************************************************************************/ + +class qkracerm_state : public hh_cops1_state +{ +public: + qkracerm_state(const machine_config &mconfig, device_type type, const char *tag) : + hh_cops1_state(mconfig, type, tag), + m_ds8874(*this, "ds8874") + { } + + required_device m_ds8874; + void ds8874_output_w(u16 data); + + void update_display(); + void write_do(u8 data); + void write_s(u8 data); + u8 read_k(); + void qkracerm(machine_config &config); +}; + +// handlers + +void qkracerm_state::update_display() +{ + m_display->matrix(m_grid, m_s); +} + +void qkracerm_state::ds8874_output_w(u16 data) +{ + // DS8874N outputs: digit select, input mux + m_grid = ~data; + m_inp_mux = m_grid >> 3; + update_display(); +} + +void qkracerm_state::write_do(u8 data) +{ + // DO1: DS8874N CP + // DO4: DS8874N _DATA + m_ds8874->cp_w(BIT(data, 0)); + m_ds8874->data_w(BIT(data, 3)); +} + +void qkracerm_state::write_s(u8 data) +{ + // S: digit segment data + m_s = data; + update_display(); +} + +u8 qkracerm_state::read_k() +{ + // K: multiplexed inputs + return read_inputs(5); +} + +// config + +static INPUT_PORTS_START( qkracerm ) + PORT_START("IN.0") // DS8874 OUT 4 port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_Q) PORT_NAME("Amateur") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_W) PORT_NAME("Pro") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_E) PORT_NAME("Complex") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_R) PORT_NAME("Tables") + + PORT_START("IN.1") // DS8874 OUT 5 port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("7") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("8") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("9") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SLASH_PAD) PORT_NAME(UTF8_DIVIDE) + + PORT_START("IN.2") // DS8874 OUT 6 port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_ASTERISK) PORT_NAME(UTF8_MULTIPLY) + + PORT_START("IN.3") // DS8874 OUT 7 port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("-") + + PORT_START("IN.4") // DS8874 OUT 8 port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Slow") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Fast") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("0") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("+") +INPUT_PORTS_END + +void qkracerm_state::qkracerm(machine_config &config) +{ + /* basic machine hardware */ + MM5799(config, m_maincpu, 220000); // approximation + m_maincpu->set_option_lb_10(5); + m_maincpu->write_do().set(FUNC(qkracerm_state::write_do)); + m_maincpu->write_s().set(FUNC(qkracerm_state::write_s)); + m_maincpu->read_k().set(FUNC(qkracerm_state::read_k)); + + /* video hardware */ + DS8874(config, m_ds8874).write_output().set(FUNC(qkracerm_state::ds8874_output_w)); + PWM_DISPLAY(config, m_display).set_size(9, 7); + m_display->set_segmask(0xdf, 0x7f); + m_display->set_segmask(0x20, 0x41); // equals sign + config.set_default_layout(layout_qkracerm); + + /* no sound! */ +} + +// roms + +ROM_START( qkracerm ) + ROM_REGION( 0x0800, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD( "mm4799_c_duz", 0x0000, 0x0200, CRC(8b484d2a) SHA1(809e902a11e23bed010ac795ab8dc50e5c1869dc) ) + ROM_CONTINUE( 0x0400, 0x0400 ) + + ROM_REGION( 254, "maincpu:opla", 0 ) + ROM_LOAD( "mm5799_qkracerm_output.pla", 0, 254, CRC(f095fc51) SHA1(e3321d5cc4ecef363df7ef94f47e860c7a6d8c7e) ) +ROM_END + + + + + +/*************************************************************************** + + National Semiconductor QuizKid Speller + * MM5799 MCU bonded directly to PCB (die label MM4799 C NDF) + * 2-digit 7seg led display, green led, red led, no sound + + The manual included 99 pictures for matching the words, with increased + difficulty. For example 10 = owl, 90 = kangaroo. + + Modes: + - Spell: match numbered picture with word + - Learn: same as Spell, but only the 1st letter + - Game: player 1 enters word, player 2 needs to guess it + +***************************************************************************/ + +class qkspeller_state : public hh_cops1_state +{ +public: + qkspeller_state(const machine_config &mconfig, device_type type, const char *tag) : + hh_cops1_state(mconfig, type, tag) + { } + + void update_display(); + void write_do(u8 data); + void write_s(u8 data); + void write_f(u8 data); + u8 read_f(); + u8 read_k(); + void qkspeller(machine_config &config); +}; + +// handlers + +void qkspeller_state::update_display() +{ + m_display->matrix((m_f << 1 & 0xc) | (m_do & 3), m_inp_mux); +} + +void qkspeller_state::write_do(u8 data) +{ + // DO1,DO2: digit select + m_do = data; + update_display(); +} + +void qkspeller_state::write_s(u8 data) +{ + // S: digit segment data, input mux + m_inp_mux = data; + update_display(); +} + +void qkspeller_state::write_f(u8 data) +{ + // F2,F3: led data + m_f = data; + update_display(); +} + +u8 qkspeller_state::read_f() +{ + // F1: 3-pos switch (GND, floating, Vcc) + if (m_inputs[8]->read() == 2) + return m_f; + else + return (m_inputs[8]->read() & 1) | (m_f & ~1); +} + +u8 qkspeller_state::read_k() +{ + // K: multiplexed inputs + return read_inputs(8); +} + +// config + +static INPUT_PORTS_START( qkspeller ) + PORT_START("IN.0") // Sa port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') + + PORT_START("IN.1") // Sb port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') + + PORT_START("IN.2") // Sc port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') + + PORT_START("IN.3") // Sd port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') + + PORT_START("IN.4") // Se port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CODE(KEYCODE_DEL) PORT_CHAR(8) PORT_NAME("Erase") + + PORT_START("IN.5") // Sf port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') + + PORT_START("IN.6") // Sg port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') + + PORT_START("IN.7") // Sp port K + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_NAME("Start") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(13) PORT_NAME("Next") + + PORT_START("IN.8") // F1 + PORT_CONFNAME( 0x03, 0x00, "Mode" ) + PORT_CONFSETTING( 0x00, "Spell" ) + PORT_CONFSETTING( 0x02, "Learn" ) + PORT_CONFSETTING( 0x01, "Game" ) + + PORT_START("TEST.0") // INB test pad + PORT_CONFNAME( 0x01, 0x00, "Factory Test 1" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) + + PORT_START("TEST.1") // DO3 test pad + PORT_CONFNAME( 0x01, 0x00, "Factory Test 2" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) +INPUT_PORTS_END + +void qkspeller_state::qkspeller(machine_config &config) +{ + /* basic machine hardware */ + MM5799(config, m_maincpu, 220000); // approximation + m_maincpu->write_do().set(FUNC(qkspeller_state::write_do)); + m_maincpu->write_s().set(FUNC(qkspeller_state::write_s)); + m_maincpu->write_f().set(FUNC(qkspeller_state::write_f)); + m_maincpu->read_f().set(FUNC(qkspeller_state::read_f)); + m_maincpu->read_k().set(FUNC(qkspeller_state::read_k)); + m_maincpu->read_inb().set_ioport("TEST.0"); + m_maincpu->read_do3().set_ioport("TEST.1"); + + /* video hardware */ + PWM_DISPLAY(config, m_display).set_size(4, 7); + m_display->set_segmask(3, 0x7f); + config.set_default_layout(layout_qkspeller); + + /* no sound! */ +} + +// roms + +ROM_START( qkspeller ) + ROM_REGION( 0x0800, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD( "mm4799_c_ndf", 0x0000, 0x0200, CRC(0f497a12) SHA1(78eb79dcc414ed2a955450ffb3be431ecc2edb0c) ) + ROM_CONTINUE( 0x0400, 0x0400 ) + + ROM_REGION( 254, "maincpu:opla", 0 ) + ROM_LOAD( "mm5799_qkspeller_output.pla", 0, 254, CRC(c8d225f1) SHA1(4f1e1977e96e53d1d716b7785c4c3971ed9ff65b) ) +ROM_END + + + +} // anonymous namespace + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +CONS( 1978, mbaskb, 0, 0, mbaskb, mbaskb, mbaskb_state, empty_init, "Mattel", "Basketball (Mattel)", MACHINE_SUPPORTS_SAVE ) + +CONS( 1977, qkracerm, qkracer, 0, qkracerm, qkracerm, qkracerm_state, empty_init, "National Semiconductor", "QuizKid Racer (MM5799 version)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW | MACHINE_NODEVICE_LAN ) +CONS( 1978, qkspeller, 0, 0, qkspeller, qkspeller, qkspeller_state, empty_init, "National Semiconductor", "QuizKid Speller", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) diff --git a/src/mame/layout/aim65.lay b/src/mame/layout/aim65.lay index da6ed02aa7b..98adf2f4bc8 100644 --- a/src/mame/layout/aim65.lay +++ b/src/mame/layout/aim65.lay @@ -26,7 +26,7 @@ copyright-holders:Dirk Best, Eric Roberts - + diff --git a/src/mame/layout/cnbaskb.lay b/src/mame/layout/cnbaskb.lay index 040c6845d63..e158ab2d898 100644 --- a/src/mame/layout/cnbaskb.lay +++ b/src/mame/layout/cnbaskb.lay @@ -36,7 +36,7 @@ license:CC0 - + diff --git a/src/mame/layout/cnfball2.lay b/src/mame/layout/cnfball2.lay index 86a271744da..7d7c8a88d7d 100644 --- a/src/mame/layout/cnfball2.lay +++ b/src/mame/layout/cnfball2.lay @@ -69,7 +69,7 @@ license:CC0 - + diff --git a/src/mame/layout/cqback.lay b/src/mame/layout/cqback.lay index f49d451c2a2..6c222e081d7 100644 --- a/src/mame/layout/cqback.lay +++ b/src/mame/layout/cqback.lay @@ -77,7 +77,7 @@ license:CC0 - + diff --git a/src/mame/layout/ebaskb2.lay b/src/mame/layout/ebaskb2.lay index b05e58b14f0..33d50a09dbd 100644 --- a/src/mame/layout/ebaskb2.lay +++ b/src/mame/layout/ebaskb2.lay @@ -73,7 +73,7 @@ license:CC0 - + diff --git a/src/mame/layout/ebball.lay b/src/mame/layout/ebball.lay index 8b5962ff955..e5316131664 100644 --- a/src/mame/layout/ebball.lay +++ b/src/mame/layout/ebball.lay @@ -71,7 +71,7 @@ license:CC0 - + @@ -91,7 +91,6 @@ license:CC0 - diff --git a/src/mame/layout/ebball2.lay b/src/mame/layout/ebball2.lay index 5deafee899c..d4e0dd67c99 100644 --- a/src/mame/layout/ebball2.lay +++ b/src/mame/layout/ebball2.lay @@ -74,7 +74,7 @@ license:CC0 - + diff --git a/src/mame/layout/ebball3.lay b/src/mame/layout/ebball3.lay index a8d94a10a0f..e599ff20e7d 100644 --- a/src/mame/layout/ebball3.lay +++ b/src/mame/layout/ebball3.lay @@ -121,7 +121,7 @@ license:CC0 - + diff --git a/src/mame/layout/efball.lay b/src/mame/layout/efball.lay index 1a6165e27c9..42677d480c8 100644 --- a/src/mame/layout/efball.lay +++ b/src/mame/layout/efball.lay @@ -65,7 +65,7 @@ license:CC0 - + @@ -265,8 +265,7 @@ license:CC0 - - + diff --git a/src/mame/layout/eleciq.lay b/src/mame/layout/eleciq.lay index c769de62b16..263b6d0237e 100644 --- a/src/mame/layout/eleciq.lay +++ b/src/mame/layout/eleciq.lay @@ -49,7 +49,7 @@ license:CC0 - + diff --git a/src/mame/layout/esoccer.lay b/src/mame/layout/esoccer.lay index 4fc02bc466d..9f43a873633 100644 --- a/src/mame/layout/esoccer.lay +++ b/src/mame/layout/esoccer.lay @@ -31,7 +31,7 @@ license:CC0 - + diff --git a/src/mame/layout/gjackpot.lay b/src/mame/layout/gjackpot.lay index e1b3b626e8f..051df2b1c11 100644 --- a/src/mame/layout/gjackpot.lay +++ b/src/mame/layout/gjackpot.lay @@ -126,7 +126,7 @@ license:CC0 - + diff --git a/src/mame/layout/gpoker.lay b/src/mame/layout/gpoker.lay index c821b6f2f47..6423c185ae7 100644 --- a/src/mame/layout/gpoker.lay +++ b/src/mame/layout/gpoker.lay @@ -118,7 +118,7 @@ license:CC0 - + diff --git a/src/mame/layout/h2hbaseb.lay b/src/mame/layout/h2hbaseb.lay index 7785dc0d2a1..bbf6493cc2e 100644 --- a/src/mame/layout/h2hbaseb.lay +++ b/src/mame/layout/h2hbaseb.lay @@ -138,7 +138,7 @@ license:CC0 - + diff --git a/src/mame/layout/h2hboxing.lay b/src/mame/layout/h2hboxing.lay index c52ac86f81e..9a87924a786 100644 --- a/src/mame/layout/h2hboxing.lay +++ b/src/mame/layout/h2hboxing.lay @@ -28,7 +28,7 @@ license:CC0 - + diff --git a/src/mame/layout/h2hfootb.lay b/src/mame/layout/h2hfootb.lay index c0bd3a45e33..da7075f75ac 100644 --- a/src/mame/layout/h2hfootb.lay +++ b/src/mame/layout/h2hfootb.lay @@ -74,7 +74,7 @@ license:CC0 - + diff --git a/src/mame/layout/hccbaskb.lay b/src/mame/layout/hccbaskb.lay index 962812a84d6..a0aa83d57a9 100644 --- a/src/mame/layout/hccbaskb.lay +++ b/src/mame/layout/hccbaskb.lay @@ -31,7 +31,7 @@ license:CC0 - + diff --git a/src/mame/layout/lightfgt.lay b/src/mame/layout/lightfgt.lay index fcfc8d290a1..b489a705d74 100644 --- a/src/mame/layout/lightfgt.lay +++ b/src/mame/layout/lightfgt.lay @@ -193,7 +193,7 @@ license:CC0 - + diff --git a/src/mame/layout/mbaskb.lay b/src/mame/layout/mbaskb.lay new file mode 100644 index 00000000000..fe201d1486a --- /dev/null +++ b/src/mame/layout/mbaskb.lay @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/mephisto_megaiv.lay b/src/mame/layout/mephisto_megaiv.lay index 0b4817a3075..522f974ace3 100644 --- a/src/mame/layout/mephisto_megaiv.lay +++ b/src/mame/layout/mephisto_megaiv.lay @@ -464,7 +464,7 @@ license:CC0 - + diff --git a/src/mame/layout/mephisto_mondial2.lay b/src/mame/layout/mephisto_mondial2.lay index 286b049522a..e914904aee7 100644 --- a/src/mame/layout/mephisto_mondial2.lay +++ b/src/mame/layout/mephisto_mondial2.lay @@ -432,7 +432,7 @@ license:CC0 - + diff --git a/src/mame/layout/mephisto_mondial68k.lay b/src/mame/layout/mephisto_mondial68k.lay index b58e148b89a..28f98098114 100644 --- a/src/mame/layout/mephisto_mondial68k.lay +++ b/src/mame/layout/mephisto_mondial68k.lay @@ -439,7 +439,7 @@ license:CC0 - + diff --git a/src/mame/layout/mephisto_smondial2.lay b/src/mame/layout/mephisto_smondial2.lay index 5ab5905c900..b36a693a5a5 100644 --- a/src/mame/layout/mephisto_smondial2.lay +++ b/src/mame/layout/mephisto_smondial2.lay @@ -467,7 +467,7 @@ license:CC0 - + diff --git a/src/mame/layout/qkracerm.lay b/src/mame/layout/qkracerm.lay new file mode 100644 index 00000000000..732393aa9a6 --- /dev/null +++ b/src/mame/layout/qkracerm.lay @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/qkspeller.lay b/src/mame/layout/qkspeller.lay new file mode 100644 index 00000000000..700301df324 --- /dev/null +++ b/src/mame/layout/qkspeller.lay @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/rockpin.lay b/src/mame/layout/rockpin.lay index 2cdb61cdf2c..9cf299a1a78 100644 --- a/src/mame/layout/rockpin.lay +++ b/src/mame/layout/rockpin.lay @@ -54,7 +54,7 @@ license:CC0 - + diff --git a/src/mame/layout/ssimon.lay b/src/mame/layout/ssimon.lay index bc819d755a3..7e0c4d8ffee 100644 --- a/src/mame/layout/ssimon.lay +++ b/src/mame/layout/ssimon.lay @@ -162,7 +162,7 @@ license:CC0 - + diff --git a/src/mame/layout/tactix.lay b/src/mame/layout/tactix.lay index 5693f5f1553..91d2078f94d 100644 --- a/src/mame/layout/tactix.lay +++ b/src/mame/layout/tactix.lay @@ -66,7 +66,7 @@ license:CC0 - + diff --git a/src/mame/layout/tbaskb.lay b/src/mame/layout/tbaskb.lay index 4caa3270a47..55a225c1882 100644 --- a/src/mame/layout/tbaskb.lay +++ b/src/mame/layout/tbaskb.lay @@ -30,7 +30,7 @@ license:CC0 - + diff --git a/src/mame/layout/tbreakup.lay b/src/mame/layout/tbreakup.lay index f4ac35df267..aba4066e07b 100644 --- a/src/mame/layout/tbreakup.lay +++ b/src/mame/layout/tbreakup.lay @@ -52,7 +52,7 @@ license:CC0 - + diff --git a/src/mame/layout/ti95.lay b/src/mame/layout/ti95.lay index 268093d2bbb..a0e5f7596f5 100644 --- a/src/mame/layout/ti95.lay +++ b/src/mame/layout/ti95.lay @@ -215,7 +215,7 @@ license:CC0 - + diff --git a/src/mame/layout/us2pfball.lay b/src/mame/layout/us2pfball.lay index c057f03666c..4761e603057 100644 --- a/src/mame/layout/us2pfball.lay +++ b/src/mame/layout/us2pfball.lay @@ -100,7 +100,7 @@ license:CC0 - + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index d252a3befef..2d10d048738 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -16090,6 +16090,11 @@ qkracer // National Semiconductor unkeinv // Gordon Barlow Design vidchal // Select Merchandise +@source:hh_cops1.cpp +mbaskb // Mattel +qkracerm // National Semiconductor +qkspeller // National Semiconductor + @source:hh_hmcs40.cpp alnattck // Coleco bambball // Bambino diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 16c68616db1..168887afa47 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -386,6 +386,7 @@ hektor.cpp hhtiger.cpp hh_amis2k.cpp hh_cop400.cpp +hh_cops1.cpp hh_hmcs40.cpp hh_melps4.cpp hh_pic16.cpp diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index f361eff0b6b..81a250c0ebf 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -112,6 +112,7 @@ using util::BIT; #include "cpu/minx/minxd.h" #include "cpu/mips/mips3dsm.h" #include "cpu/mips/mips1dsm.h" +#include "cpu/cops1/cops1d.h" #include "cpu/mn1880/mn1880d.h" #include "cpu/mn10200/mn102dis.h" #include "cpu/msm65x2/msm65x2d.h" @@ -496,6 +497,7 @@ static const dasm_table_entry dasm_table[] = { "mips1le", le, 0, []() -> util::disasm_interface * { return new mips1_disassembler; } }, { "mips3be", be, 0, []() -> util::disasm_interface * { return new mips3_disassembler; } }, { "mips3le", le, 0, []() -> util::disasm_interface * { return new mips3_disassembler; } }, + { "mm5799", le, 0, []() -> util::disasm_interface * { return new mm5799_disassembler; } }, { "mn10200", le, 0, []() -> util::disasm_interface * { return new mn10200_disassembler; } }, { "mn1870", be, 0, []() -> util::disasm_interface * { return new mn1870_disassembler; } }, { "mn1880", be, 0, []() -> util::disasm_interface * { return new mn1880_disassembler; } }, -- cgit v1.2.3