summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2021-02-26 18:24:44 +0100
committer hap <happppp@users.noreply.github.com>2021-02-26 18:24:59 +0100
commit2f02c96baffbe8a628ab2d4bbc325efe945100d7 (patch)
tree62775b657ed7e7490e0351ceb8bbd9bdb166efb8
parent1a0b9509851e61a6a86004ae00f3065870d1c40a (diff)
added MM76 disassembler and preliminary PPS-4/1 MCU core [hap]
New machines marked as NOT_WORKING ---------------------------------- Electronic Master Mind (Invicta) [hap, Sean Riddle]
-rw-r--r--scripts/src/cpu.lua28
-rw-r--r--scripts/target/mame/arcade.lua1
-rw-r--r--scripts/target/mame/mess.lua2
-rw-r--r--src/devices/cpu/amis2000/amis2000.cpp4
-rw-r--r--src/devices/cpu/amis2000/amis2000op.cpp6
-rw-r--r--src/devices/cpu/cops1/cops1base.cpp12
-rw-r--r--src/devices/cpu/cops1/cops1base.h63
-rw-r--r--src/devices/cpu/cops1/cops1d.cpp5
-rw-r--r--src/devices/cpu/cops1/cops1d.h4
-rw-r--r--src/devices/cpu/cops1/mm5799.cpp2
-rw-r--r--src/devices/cpu/cops1/mm5799.h56
-rw-r--r--src/devices/cpu/cops1/mm5799op.cpp (renamed from src/devices/cpu/cops1/cops1op.cpp)92
-rw-r--r--src/devices/cpu/e0c6200/e0c6200.cpp2
-rw-r--r--src/devices/cpu/e0c6200/e0c6s46.cpp10
-rw-r--r--src/devices/cpu/hmcs40/hmcs40.cpp14
-rw-r--r--src/devices/cpu/hmcs40/hmcs40op.cpp2
-rw-r--r--src/devices/cpu/melps4/melps4.cpp3
-rw-r--r--src/devices/cpu/melps4/melps4op.cpp2
-rw-r--r--src/devices/cpu/pps41/mm76.cpp71
-rw-r--r--src/devices/cpu/pps41/mm76.h59
-rw-r--r--src/devices/cpu/pps41/mm76op.cpp46
-rw-r--r--src/devices/cpu/pps41/pps41base.cpp230
-rw-r--r--src/devices/cpu/pps41/pps41base.h94
-rw-r--r--src/devices/cpu/pps41/pps41d.cpp141
-rw-r--r--src/devices/cpu/pps41/pps41d.h66
-rw-r--r--src/devices/cpu/sm510/sm510base.cpp3
-rw-r--r--src/devices/cpu/sm510/sm510op.cpp2
-rw-r--r--src/devices/cpu/sm510/sm511core.cpp2
-rw-r--r--src/devices/cpu/ucom4/ucom4.cpp11
-rw-r--r--src/devices/cpu/ucom4/ucom4op.cpp10
-rw-r--r--src/mame/drivers/hh_pps41.cpp162
-rw-r--r--src/mame/drivers/hh_ucom4.cpp4
-rw-r--r--src/mame/layout/hh_melps4_test.lay2
-rw-r--r--src/mame/layout/hh_pps41_test.lay37
-rw-r--r--src/mame/layout/hh_ucom4_test.lay2
-rw-r--r--src/mame/mame.lst3
-rw-r--r--src/mame/mess.flt1
-rw-r--r--src/tools/unidasm.cpp2
38 files changed, 1100 insertions, 156 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 938501f7394..0ca72a6b3d7 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -452,7 +452,7 @@ if (CPUS["COSMAC"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
--- National Semiconductor COPS1 family
+-- National Semiconductor COPS(MM57) family
--@src/devices/cpu/cops1/mm5799.h,CPUS["COPS1"] = true
--------------------------------------------------
@@ -460,9 +460,9 @@ 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",
+ MAME_DIR .. "src/devices/cpu/cops1/mm5799op.cpp",
}
end
@@ -472,7 +472,7 @@ if (CPUS["COPS1"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
--- National Semiconductor COP400 family
+-- National Semiconductor COPS(COP400) family
--@src/devices/cpu/cop400/cop400.h,CPUS["COP400"] = true
--------------------------------------------------
@@ -2178,7 +2178,7 @@ end
--------------------------------------------------
-- Panasonic MN1880
---@src/devices/cpu/mn1800/mn1880.h,CPUS["MN1880"] = true
+--@src/devices/cpu/mn1880/mn1880.h,CPUS["MN1880"] = true
--------------------------------------------------
if (CPUS["MN1880"]~=null) then
@@ -2871,6 +2871,26 @@ if (CPUS["PPS4"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
+-- Rockwell PPS-4/1
+--@src/devices/cpu/pps41/mm76.h,CPUS["PPS41"] = true
+--------------------------------------------------
+
+if (CPUS["PPS41"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/cpu/pps41/pps41base.cpp",
+ MAME_DIR .. "src/devices/cpu/pps41/pps41base.h",
+ MAME_DIR .. "src/devices/cpu/pps41/mm76.cpp",
+ MAME_DIR .. "src/devices/cpu/pps41/mm76.h",
+ MAME_DIR .. "src/devices/cpu/pps41/mm76op.cpp",
+ }
+end
+
+if (CPUS["PPS41"]~=null or _OPTIONS["with-tools"]) then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pps41/pps41d.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pps41/pps41d.h")
+end
+
+--------------------------------------------------
-- Hitachi HD61700
--@src/devices/cpu/hd61700/hd61700.h,CPUS["HD61700"] = true
--------------------------------------------------
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 7d66cd65977..f63bb1b1226 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -119,6 +119,7 @@ CPUS["COSMAC"] = true
CPUS["UNSP"] = true
CPUS["HCD62121"] = true
CPUS["PPS4"] = true
+--CPUS["PPS41"] = true
CPUS["UPD7725"] = true
CPUS["HD61700"] = true
CPUS["LC8670"] = true
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index f81851af8ee..841ee009def 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -121,6 +121,7 @@ CPUS["COSMAC"] = true
CPUS["UNSP"] = true
CPUS["HCD62121"] = true
CPUS["PPS4"] = true
+CPUS["PPS41"] = true
CPUS["UPD7725"] = true
CPUS["HD61700"] = true
CPUS["LC8670"] = true
@@ -3456,6 +3457,7 @@ files {
MAME_DIR .. "src/mame/includes/aim65.h",
MAME_DIR .. "src/mame/machine/aim65.cpp",
MAME_DIR .. "src/mame/drivers/aim65_40.cpp",
+ MAME_DIR .. "src/mame/drivers/hh_pps41.cpp",
}
createMESSProjects(_target, _subtarget, "rtpc")
diff --git a/src/devices/cpu/amis2000/amis2000.cpp b/src/devices/cpu/amis2000/amis2000.cpp
index 70df8370ae4..0558f5117db 100644
--- a/src/devices/cpu/amis2000/amis2000.cpp
+++ b/src/devices/cpu/amis2000/amis2000.cpp
@@ -250,7 +250,9 @@ void amis2000_base_device::execute_run()
// remember previous opcode
m_prev_op = m_op;
- debugger_instruction_hook(m_pc);
+ // fetch next opcode
+ if (!m_skip)
+ debugger_instruction_hook(m_pc);
m_op = m_program->read_byte(m_pc);
m_pc = (m_pc + 1) & 0x1fff;
diff --git a/src/devices/cpu/amis2000/amis2000op.cpp b/src/devices/cpu/amis2000/amis2000op.cpp
index 92c2eaae3dc..53c17f4bb4c 100644
--- a/src/devices/cpu/amis2000/amis2000op.cpp
+++ b/src/devices/cpu/amis2000/amis2000op.cpp
@@ -205,7 +205,7 @@ void amis2000_base_device::op_inp()
void amis2000_base_device::op_out()
{
// OUT: pulse output ACC and RAM to D-pins
- logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc);
+ logerror("unknown opcode $%02X at $%04X\n", m_op, m_pc);
}
void amis2000_base_device::op_disb()
@@ -359,7 +359,7 @@ void amis2000_base_device::op_nop()
void amis2000_base_device::op_halt()
{
// HALT: debugger breakpoint for devkit-use
- logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc);
+ logerror("unknown opcode $%02X at $%04X\n", m_op, m_pc);
}
@@ -405,7 +405,7 @@ void amis2000_base_device::op_sam()
void amis2000_base_device::op_sos()
{
// SOS: skip next on SF(timer output), clear SF
- logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc);
+ logerror("unknown opcode $%02X at $%04X\n", m_op, m_pc);
}
void amis2000_base_device::op_tf1()
diff --git a/src/devices/cpu/cops1/cops1base.cpp b/src/devices/cpu/cops1/cops1base.cpp
index 540724e61c2..713cde93a9c 100644
--- a/src/devices/cpu/cops1/cops1base.cpp
+++ b/src/devices/cpu/cops1/cops1base.cpp
@@ -2,7 +2,7 @@
// copyright-holders:hap
/*
-National Semiconductor COPS(MM57 MCU family) cores
+ 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.
@@ -36,7 +36,7 @@ TODO:
#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) :
+cops1_base_device::cops1_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 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),
@@ -192,8 +192,9 @@ void cops1_base_device::cycle()
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;
+ int feed = ((m_pc & 0x3e) == 0) ? 1 : 0;
+ feed ^= (m_pc >> 1 ^ m_pc) & 1;
+ m_pc = (m_pc & ~0x3f) | (m_pc >> 1 & 0x1f) | (feed << 5);
}
void cops1_base_device::execute_run()
@@ -209,7 +210,8 @@ void cops1_base_device::execute_run()
m_write_blk(0);
// fetch next opcode
- debugger_instruction_hook(m_pc);
+ if (!m_skip)
+ debugger_instruction_hook(m_pc);
m_op = m_program->read_byte(m_pc);
increment_pc();
cycle();
diff --git a/src/devices/cpu/cops1/cops1base.h b/src/devices/cpu/cops1/cops1base.h
index 485e120c6e8..b4ff862ebcc 100644
--- a/src/devices/cpu/cops1/cops1base.h
+++ b/src/devices/cpu/cops1/cops1base.h
@@ -64,7 +64,7 @@ public:
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);
+ cops1_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data);
// device-level overrides
virtual void device_start() override;
@@ -72,10 +72,10 @@ protected:
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 u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; }
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); }
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return 2; }
virtual void execute_run() override;
virtual void execute_one() = 0;
virtual bool op_argument() = 0;
@@ -138,59 +138,6 @@ protected:
// 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();
};
diff --git a/src/devices/cpu/cops1/cops1d.cpp b/src/devices/cpu/cops1/cops1d.cpp
index 0d20a0f0370..60bab31a9f5 100644
--- a/src/devices/cpu/cops1/cops1d.cpp
+++ b/src/devices/cpu/cops1/cops1d.cpp
@@ -24,8 +24,9 @@ cops1_common_disassembler::cops1_common_disassembler()
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;
+ int feed = ((pc & 0x3e) == 0) ? 1 : 0;
+ feed ^= (pc >> 1 ^ pc) & 1;
+ return (pc & ~0x3f) | (pc >> 1 & 0x1f) | (feed << 5);
}
diff --git a/src/devices/cpu/cops1/cops1d.h b/src/devices/cpu/cops1/cops1d.h
index 4ebe6636412..d0491d8f04d 100644
--- a/src/devices/cpu/cops1/cops1d.h
+++ b/src/devices/cpu/cops1/cops1d.h
@@ -39,8 +39,8 @@ protected:
};
static const char *const s_name[];
- static const uint8_t s_bits[];
- static const uint32_t s_flags[];
+ static const u8 s_bits[];
+ static const u32 s_flags[];
u8 m_l2r[0x40];
u8 m_r2l[0x40];
diff --git a/src/devices/cpu/cops1/mm5799.cpp b/src/devices/cpu/cops1/mm5799.cpp
index 7ea0ce4a1ff..85f6674806d 100644
--- a/src/devices/cpu/cops1/mm5799.cpp
+++ b/src/devices/cpu/cops1/mm5799.cpp
@@ -42,7 +42,7 @@ void mm5799_device::data_map(address_map &map)
// device definitions
-mm5799_device::mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+mm5799_device::mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 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))
{ }
diff --git a/src/devices/cpu/cops1/mm5799.h b/src/devices/cpu/cops1/mm5799.h
index d8f568e3808..a07aecd97fa 100644
--- a/src/devices/cpu/cops1/mm5799.h
+++ b/src/devices/cpu/cops1/mm5799.h
@@ -37,7 +37,7 @@
class mm5799_device : public cops1_base_device
{
public:
- mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ mm5799_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
@@ -53,6 +53,60 @@ protected:
void data_map(address_map &map);
void program_map(address_map &map);
+
+ // opcode helpers
+ 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();
};
diff --git a/src/devices/cpu/cops1/cops1op.cpp b/src/devices/cpu/cops1/mm5799op.cpp
index c87821e7c11..180ae257011 100644
--- a/src/devices/cpu/cops1/cops1op.cpp
+++ b/src/devices/cpu/cops1/mm5799op.cpp
@@ -1,31 +1,31 @@
// license:BSD-3-Clause
// copyright-holders:hap
-// COPS opcode handlers
+// MM5799 opcode handlers
#include "emu.h"
-#include "cops1base.h"
+#include "mm5799.h"
// internal helpers
-inline u8 cops1_base_device::ram_r()
+inline u8 mm5799_device::ram_r()
{
return m_data->read_byte(m_b) & 0xf;
}
-inline void cops1_base_device::ram_w(u8 data)
+inline void mm5799_device::ram_w(u8 data)
{
m_data->write_byte(m_b, data & 0xf);
}
-void cops1_base_device::pop_pc()
+void mm5799_device::pop_pc()
{
m_pc = m_sa;
m_sa = m_sb;
}
-void cops1_base_device::push_pc()
+void mm5799_device::push_pc()
{
m_sb = m_sa;
m_sa = m_pc;
@@ -36,13 +36,13 @@ void cops1_base_device::push_pc()
// arithmetic operations
-void cops1_base_device::op_ad()
+void mm5799_device::op_ad()
{
// add M to A
m_a = (m_a + ram_r()) & 0xf;
}
-void cops1_base_device::op_add()
+void mm5799_device::op_add()
{
// ADD: add M+carry to A
m_a = m_a + ram_r() + m_c;
@@ -51,7 +51,7 @@ void cops1_base_device::op_add()
m_skip = !bool(m_c);
}
-void cops1_base_device::op_sub()
+void mm5799_device::op_sub()
{
// SUB: subtract A+carry from M
m_a = (m_a ^ 0xf) + ram_r() + m_c;
@@ -60,19 +60,19 @@ void cops1_base_device::op_sub()
m_skip = bool(m_c);
}
-void cops1_base_device::op_comp()
+void mm5799_device::op_comp()
{
// COMP: complement A
m_a ^= 0xf;
}
-void cops1_base_device::op_0ta()
+void mm5799_device::op_0ta()
{
// 0TA: clear A
m_a = 0;
}
-void cops1_base_device::op_adx()
+void mm5799_device::op_adx()
{
// ADX x: add constant to A
u8 x = m_op & 0xf;
@@ -81,7 +81,7 @@ void cops1_base_device::op_adx()
m_a &= 0xf;
}
-void cops1_base_device::op_hxa()
+void mm5799_device::op_hxa()
{
// HXA: exchange A with H
u8 h = m_h;
@@ -89,25 +89,25 @@ void cops1_base_device::op_hxa()
m_a = h;
}
-void cops1_base_device::op_tam()
+void mm5799_device::op_tam()
{
// TAM: compare A with M
m_skip = m_a == ram_r();
}
-void cops1_base_device::op_sc()
+void mm5799_device::op_sc()
{
// SC: set carry
m_c = 1;
}
-void cops1_base_device::op_rsc()
+void mm5799_device::op_rsc()
{
// RSC: reset carry
m_c = 0;
}
-void cops1_base_device::op_tc()
+void mm5799_device::op_tc()
{
// TC: test carry
m_skip = !m_c;
@@ -116,28 +116,28 @@ void cops1_base_device::op_tc()
// input test
-void cops1_base_device::op_tin()
+void mm5799_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()
+void mm5799_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()
+void mm5799_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()
+void mm5799_device::op_tir()
{
// TIR: test DO3 pin
int d = m_read_do3.isnull() ? (m_do >> 2) : m_read_do3();
@@ -147,28 +147,28 @@ void cops1_base_device::op_tir()
// input/output
-void cops1_base_device::op_btd()
+void mm5799_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()
+void mm5799_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()
+void mm5799_device::op_dsps()
{
// DSPS: 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()
+void mm5799_device::op_axo()
{
// AXO: exchange A with serial
u8 s = m_serial;
@@ -180,7 +180,7 @@ void cops1_base_device::op_axo()
m_a = (m_a & 7) | (m_read_si() << 3 & 8);
}
-void cops1_base_device::op_ldf()
+void mm5799_device::op_ldf()
{
// LDF x: load F pin(s)
u8 mask = bitswap<4>(~m_arg, 7,5,3,1);
@@ -189,7 +189,7 @@ void cops1_base_device::op_ldf()
m_write_f(m_f);
}
-void cops1_base_device::op_read()
+void mm5799_device::op_read()
{
// READ: read K pins to A
m_a = m_read_k() & 0xf;
@@ -198,7 +198,7 @@ void cops1_base_device::op_read()
// control functions
-void cops1_base_device::op_go()
+void mm5799_device::op_go()
{
// GO x: jump to address in page
@@ -209,7 +209,7 @@ void cops1_base_device::op_go()
m_pc = (m_pc & ~0x3f) | (m_op & 0x3f);
}
-void cops1_base_device::op_call()
+void mm5799_device::op_call()
{
// CALL x: call subroutine
@@ -220,20 +220,20 @@ void cops1_base_device::op_call()
m_pc = (m_op & 0x3f) | 0x7c0;
}
-void cops1_base_device::op_ret()
+void mm5799_device::op_ret()
{
// RET: return from subroutine
pop_pc();
}
-void cops1_base_device::op_rets()
+void mm5799_device::op_rets()
{
// RET: return from subroutine, skip next
op_ret();
m_skip = true;
}
-void cops1_base_device::op_lg()
+void mm5799_device::op_lg()
{
// LG x: long go / long call
if (~m_arg & 0x40)
@@ -242,7 +242,7 @@ void cops1_base_device::op_lg()
m_pc = (~m_op << 7 & 0x780) | (m_arg >> 1 & 0x40) | (m_arg & 0x3f);
}
-void cops1_base_device::op_nop()
+void mm5799_device::op_nop()
{
// NOP: no operation
}
@@ -250,7 +250,7 @@ void cops1_base_device::op_nop()
// memory digit operations
-void cops1_base_device::op_exc()
+void mm5799_device::op_exc()
{
// EXC x: exchange A with M, XOR B(r) with x
u8 a = m_a;
@@ -259,7 +259,7 @@ void cops1_base_device::op_exc()
m_b ^= m_op & 0x30;
}
-void cops1_base_device::op_excm()
+void mm5799_device::op_excm()
{
// EXC- x: EXC + decrement B(d)
op_exc();
@@ -267,7 +267,7 @@ void cops1_base_device::op_excm()
m_skip = (m_b & 0xf) == 0xf;
}
-void cops1_base_device::op_excp()
+void mm5799_device::op_excp()
{
// EXC+ x: EXC + increment B(d)
op_exc();
@@ -279,14 +279,14 @@ void cops1_base_device::op_excp()
m_skip = true;
}
-void cops1_base_device::op_mta()
+void mm5799_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()
+void mm5799_device::op_lm()
{
// LM x: load M with constant, increment B(d)
ram_w(m_op & 0xf);
@@ -296,7 +296,7 @@ void cops1_base_device::op_lm()
// memory bit operations
-void cops1_base_device::op_sm()
+void mm5799_device::op_sm()
{
// SM x: set memory bit
u8 x = 0;
@@ -312,7 +312,7 @@ void cops1_base_device::op_sm()
ram_w(ram_r() | x);
}
-void cops1_base_device::op_rsm()
+void mm5799_device::op_rsm()
{
// RSM x: reset memory bit
u8 x = 0;
@@ -328,7 +328,7 @@ void cops1_base_device::op_rsm()
ram_w(ram_r() & ~x);
}
-void cops1_base_device::op_tm()
+void mm5799_device::op_tm()
{
// TM x: test memory bit
m_skip = !BIT(ram_r(), m_op & 3);
@@ -337,7 +337,7 @@ void cops1_base_device::op_tm()
// memory address operations
-void cops1_base_device::op_lb()
+void mm5799_device::op_lb()
{
// LB x: load B (successive LB are ignored)
if ((m_prev_op & 0xc0) == 0x00 && (m_prev_op & 0xf) >= 0xa)
@@ -351,25 +351,25 @@ void cops1_base_device::op_lb()
m_b = ((m_op & 0x30) | x) & m_datamask;
}
-void cops1_base_device::op_lbl()
+void mm5799_device::op_lbl()
{
// LBL x: load B fully
m_b = m_arg & m_datamask;
}
-void cops1_base_device::op_atb()
+void mm5799_device::op_atb()
{
// ATB: transfer A to B(d)
m_b = (m_b & ~0xf) | m_a;
}
-void cops1_base_device::op_bta()
+void mm5799_device::op_bta()
{
// BTA: transfer B(d) to A
m_a = m_b & 0xf;
}
-void cops1_base_device::op_hxbr()
+void mm5799_device::op_hxbr()
{
// HXBR: exchange H with B(r)
u8 h = m_h;
diff --git a/src/devices/cpu/e0c6200/e0c6200.cpp b/src/devices/cpu/e0c6200/e0c6200.cpp
index 0cd9f4ef2cb..322401ed121 100644
--- a/src/devices/cpu/e0c6200/e0c6200.cpp
+++ b/src/devices/cpu/e0c6200/e0c6200.cpp
@@ -839,7 +839,7 @@ void e0c6200_cpu_device::execute_one()
// illegal opcode
default:
- logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc);
+ logerror("unknown opcode $%03X at $%04X\n", m_op, m_prev_pc);
break;
} // 0xff0
diff --git a/src/devices/cpu/e0c6200/e0c6s46.cpp b/src/devices/cpu/e0c6200/e0c6s46.cpp
index 5094c36a5f7..7c5b1196fb0 100644
--- a/src/devices/cpu/e0c6200/e0c6s46.cpp
+++ b/src/devices/cpu/e0c6200/e0c6s46.cpp
@@ -390,7 +390,7 @@ void e0c6s46_device::clock_watchdog()
// initial reset after 3 to 4 seconds
if (++m_watchdog_count == 4)
{
- logerror("%s watchdog reset\n", tag());
+ logerror("watchdog reset\n");
m_watchdog_count = 0;
device_reset();
}
@@ -690,7 +690,7 @@ u8 e0c6s46_device::io_r(offs_t offset)
default:
if (!machine().side_effects_disabled())
- logerror("%s unknown io_r from $0F%02X at $%04X\n", tag(), offset, m_prev_pc);
+ logerror("unknown io_r from $0F%02X at $%04X\n", offset, m_prev_pc);
break;
}
@@ -758,7 +758,7 @@ void e0c6s46_device::io_w(offs_t offset, u8 data)
// d2: OSC3 on (high freq)
// d3: clock source OSC1 or OSC3
if (data & 8)
- logerror("%s io_w selected OSC3! PC=$%04X\n", tag(), m_prev_pc);
+ logerror("io_w selected OSC3! PC=$%04X\n", m_prev_pc);
m_osc = data;
break;
@@ -861,7 +861,7 @@ void e0c6s46_device::io_w(offs_t offset, u8 data)
// d2: reset envelope
// d3: trigger one-shot buzzer
if (data & 1)
- logerror("%s io_w enabled envelope, PC=$%04X\n", tag(), m_prev_pc);
+ logerror("io_w enabled envelope, PC=$%04X\n", m_prev_pc);
m_bz_envelope = data & 3;
m_bz_1shot_on |= data & 8;
break;
@@ -874,7 +874,7 @@ void e0c6s46_device::io_w(offs_t offset, u8 data)
default:
if (machine().phase() > machine_phase::RESET)
- logerror("%s unknown io_w $%X to $0F%02X at $%04X\n", tag(), data, offset, m_prev_pc);
+ logerror("unknown io_w $%X to $0F%02X at $%04X\n", data, offset, m_prev_pc);
break;
}
}
diff --git a/src/devices/cpu/hmcs40/hmcs40.cpp b/src/devices/cpu/hmcs40/hmcs40.cpp
index 505856ef79c..ce4846e105b 100644
--- a/src/devices/cpu/hmcs40/hmcs40.cpp
+++ b/src/devices/cpu/hmcs40/hmcs40.cpp
@@ -376,7 +376,7 @@ u8 hmcs43_cpu_device::read_r(int index)
index &= 7;
if (index >= 2)
- logerror("%s read from %s port R%d at $%04X\n", tag(), (index >= 4) ? "unknown" : "output", index, m_prev_pc);
+ logerror("read from %s port R%d at $%04X\n", (index >= 4) ? "unknown" : "output", index, m_prev_pc);
return hmcs40_cpu_device::read_r(index);
}
@@ -388,7 +388,7 @@ void hmcs43_cpu_device::write_r(int index, u8 data)
if (index != 0 && index < 4)
hmcs40_cpu_device::write_r(index, data);
else
- logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc);
+ logerror("ineffective write to port R%d = $%X at $%04X\n", index, data & 0xf, m_prev_pc);
}
int hmcs43_cpu_device::read_d(int index)
@@ -396,7 +396,7 @@ int hmcs43_cpu_device::read_d(int index)
index &= 15;
if (index >= 4)
- logerror("%s read from output pin D%d at $%04X\n", tag(), index, m_prev_pc);
+ logerror("read from output pin D%d at $%04X\n", index, m_prev_pc);
return hmcs40_cpu_device::read_d(index);
}
@@ -410,7 +410,7 @@ u8 hmcs44_cpu_device::read_r(int index)
index &= 7;
if (index >= 6)
- logerror("%s read from unknown port R%d at $%04X\n", tag(), index, m_prev_pc);
+ logerror("read from unknown port R%d at $%04X\n", index, m_prev_pc);
return hmcs40_cpu_device::read_r(index);
}
@@ -422,7 +422,7 @@ void hmcs44_cpu_device::write_r(int index, u8 data)
if (index < 6)
hmcs40_cpu_device::write_r(index, data);
else
- logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc);
+ logerror("ineffective write to port R%d = $%X at $%04X\n", index, data & 0xf, m_prev_pc);
}
// HMCS45:
@@ -434,7 +434,7 @@ u8 hmcs45_cpu_device::read_r(int index)
index &= 7;
if (index >= 6)
- logerror("%s read from %s port R%d at $%04X\n", tag(), (index == 7) ? "unknown" : "output", index, m_prev_pc);
+ logerror("read from %s port R%d at $%04X\n", (index == 7) ? "unknown" : "output", index, m_prev_pc);
return hmcs40_cpu_device::read_r(index);
}
@@ -446,7 +446,7 @@ void hmcs45_cpu_device::write_r(int index, u8 data)
if (index != 7)
hmcs40_cpu_device::write_r(index, data);
else
- logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc);
+ logerror("ineffective write to port R%d = $%X at $%04X\n", index, data & 0xf, m_prev_pc);
}
diff --git a/src/devices/cpu/hmcs40/hmcs40op.cpp b/src/devices/cpu/hmcs40/hmcs40op.cpp
index a0c6c6efb5c..d5251094ad7 100644
--- a/src/devices/cpu/hmcs40/hmcs40op.cpp
+++ b/src/devices/cpu/hmcs40/hmcs40op.cpp
@@ -49,7 +49,7 @@ void hmcs40_cpu_device::push_stack()
void hmcs40_cpu_device::op_illegal()
{
- logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc);
+ logerror("unknown opcode $%03X at $%04X\n", m_op, m_prev_pc);
}
diff --git a/src/devices/cpu/melps4/melps4.cpp b/src/devices/cpu/melps4/melps4.cpp
index e179c331de2..e5903387823 100644
--- a/src/devices/cpu/melps4/melps4.cpp
+++ b/src/devices/cpu/melps4/melps4.cpp
@@ -452,7 +452,8 @@ void melps4_cpu_device::execute_run()
m_prohibit_irq = false;
// fetch next opcode
- debugger_instruction_hook(m_pc);
+ if (!m_skip)
+ debugger_instruction_hook(m_pc);
m_icount--;
m_op = m_program->read_word(m_pc) & 0x1ff;
m_bitmask = 1 << (m_op & 3);
diff --git a/src/devices/cpu/melps4/melps4op.cpp b/src/devices/cpu/melps4/melps4op.cpp
index 755d5a10ef1..349f38047c2 100644
--- a/src/devices/cpu/melps4/melps4op.cpp
+++ b/src/devices/cpu/melps4/melps4op.cpp
@@ -696,5 +696,5 @@ void melps4_cpu_device::op_nop()
void melps4_cpu_device::op_illegal()
{
- logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc);
+ logerror("unknown opcode $%03X at $%04X\n", m_op, m_prev_pc);
}
diff --git a/src/devices/cpu/pps41/mm76.cpp b/src/devices/cpu/pps41/mm76.cpp
new file mode 100644
index 00000000000..073d8406bbd
--- /dev/null
+++ b/src/devices/cpu/pps41/mm76.cpp
@@ -0,0 +1,71 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell MM76 MCU
+
+*/
+
+#include "emu.h"
+#include "mm76.h"
+
+#include "pps41d.h"
+
+
+DEFINE_DEVICE_TYPE(MM76, mm76_device, "mm76", "Rockwell MM76")
+
+
+// internal memory maps
+void mm76_device::program_map(address_map &map)
+{
+ map(0x0000, 0x01ff).rom();
+ map(0x0380, 0x03ff).rom();
+}
+
+void mm76_device::data_map(address_map &map)
+{
+ map(0x00, 0x02f).ram();
+}
+
+
+// device definitions
+mm76_device::mm76_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ pps41_base_device(mconfig, MM76, tag, owner, clock, 10, address_map_constructor(FUNC(mm76_device::program_map), this), 6, address_map_constructor(FUNC(mm76_device::data_map), this))
+{ }
+
+
+// machine config
+void mm76_device::device_add_mconfig(machine_config &config)
+{
+ PLA(config, "opla", 5, 8, 17).set_format(pla_device::FMT::BERKELEY);
+}
+
+
+// disasm
+std::unique_ptr<util::disasm_interface> mm76_device::create_disassembler()
+{
+ return std::make_unique<mm76_disassembler>();
+}
+
+
+// initialize
+void mm76_device::device_start()
+{
+ pps41_base_device::device_start();
+ m_stack_levels = 1;
+}
+
+void mm76_device::device_reset()
+{
+ pps41_base_device::device_reset();
+}
+
+
+//-------------------------------------------------
+// execute
+//-------------------------------------------------
+
+void mm76_device::execute_one()
+{
+ op_nop();
+}
diff --git a/src/devices/cpu/pps41/mm76.h b/src/devices/cpu/pps41/mm76.h
new file mode 100644
index 00000000000..8df0866f80a
--- /dev/null
+++ b/src/devices/cpu/pps41/mm76.h
@@ -0,0 +1,59 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell MM76 MCU
+
+*/
+
+#ifndef MAME_CPU_PPS41_MM76_H
+#define MAME_CPU_PPS41_MM76_H
+
+#pragma once
+
+#include "pps41base.h"
+
+// pinout reference
+
+/*
+...
+
+*/
+
+class mm76_device : public pps41_base_device
+{
+public:
+ mm76_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ // device_disasm_interface overrides
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ // device_execute_interface overrides
+ virtual void execute_one() override;
+
+ void data_map(address_map &map);
+ void program_map(address_map &map);
+
+ // opcode helpers
+ u8 ram_r();
+ void ram_w(u8 data);
+ void pop_pc();
+ void push_pc();
+ void op_illegal();
+
+ virtual bool op_is_prefix(u8 op) override { return (op & 0xf0) == 0x30; };
+
+ // opcode handlers
+ void op_nop();
+};
+
+
+DECLARE_DEVICE_TYPE(MM76, mm76_device)
+
+#endif // MAME_CPU_PPS41_MM76_H
diff --git a/src/devices/cpu/pps41/mm76op.cpp b/src/devices/cpu/pps41/mm76op.cpp
new file mode 100644
index 00000000000..55b1980f859
--- /dev/null
+++ b/src/devices/cpu/pps41/mm76op.cpp
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+
+// MM76 opcode handlers
+
+#include "emu.h"
+#include "mm76.h"
+
+
+// internal helpers
+
+inline u8 mm76_device::ram_r()
+{
+ return m_data->read_byte(m_b & m_datamask) & 0xf;
+}
+
+inline void mm76_device::ram_w(u8 data)
+{
+ m_data->write_byte(m_b & m_datamask, data & 0xf);
+}
+
+void mm76_device::pop_pc()
+{
+ m_pc = m_stack[0] & m_prgmask;
+ for (int i = 0; i < m_stack_levels-1; i++)
+ m_stack[i] = m_stack[i+1];
+}
+
+void mm76_device::push_pc()
+{
+ for (int i = m_stack_levels-1; i >= 1; i--)
+ m_stack[i] = m_stack[i-1];
+ m_stack[0] = m_pc;
+}
+
+void mm76_device::op_illegal()
+{
+ logerror("unknown opcode $%02X at $%03X\n", m_op, m_prev_pc);
+}
+
+
+// opcodes
+
+void mm76_device::op_nop()
+{
+}
diff --git a/src/devices/cpu/pps41/pps41base.cpp b/src/devices/cpu/pps41/pps41base.cpp
new file mode 100644
index 00000000000..55cf0506171
--- /dev/null
+++ b/src/devices/cpu/pps41/pps41base.cpp
@@ -0,0 +1,230 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell PPS-4/1 MCU cores
+
+This is the single-chip evolution of Rockwell's older PPS-4 CPU. It is similar,
+but a lot of things were simplified, the ALU instructions are less diverse.
+
+Part numbers:
+- A75xx = MM75 - 28 pin dip
+- A76xx = MM76 - 42 pin spider
+- A77xx = MM77 - 42 pin spider
+- A78xx = MM78 - 42 pin spider
+- A79xx = MM76C - 52 pin spider
+- A86xx = MM76E - 42 pin spider
+- B76xx = MM76L - 40 pin dip
+- B77xx = MM77L - 40 pin dip
+- B78xx = MM78L - 40 pin dip
+- B86xx = MM76EL - 40 pin dip
+- B90xx = MM78LA - 42 pin spider
+
+"spider" = 2 rows of pins on each side, just like standard PPS-4 CPUs.
+"L" only difference is low-power
+
+References:
+- Series MM76 Product Description
+- Series MM77 Product Description
+- MM76 Microcomputer Programming Manual
+- MM77 Microcomputer Programming Manual
+
+TODO:
+- add extended opcodes to disasm? it's easy to add there, but the emulation goes
+ through prefixes 1 cycle at the time which means the live disasm gets messy
+- WIP
+
+*/
+
+#include "emu.h"
+#include "pps41base.h"
+
+#include "debugger.h"
+
+
+pps41_base_device::pps41_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 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")
+{ }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+enum
+{
+ PPS41_PC=1, PPS41_A, PPS41_C, PPS41_B
+};
+
+void pps41_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
+ //..
+
+ // zerofill
+ m_pc = 0;
+ m_prev_pc = 0;
+ m_op = 0;
+ m_prev_op = 0;
+ m_prev2_op = 0;
+ memset(m_stack, 0, sizeof(m_stack));
+
+ m_a = 0;
+ m_b = 0;
+ m_prev_b = 0;
+ m_prev2_b = 0;
+ m_ram_addr = 0;
+ m_ram_delay = false;
+ m_sag = false;
+ m_c = 0;
+ m_prev_c = 0;
+ m_c_in = 0;
+ m_c_delay = false;
+ m_skip = false;
+ m_skip_count = 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_prev2_op));
+ save_item(NAME(m_stack));
+
+ save_item(NAME(m_a));
+ save_item(NAME(m_b));
+ save_item(NAME(m_prev_b));
+ save_item(NAME(m_prev2_b));
+ save_item(NAME(m_ram_addr));
+ save_item(NAME(m_ram_delay));
+ save_item(NAME(m_sag));
+ save_item(NAME(m_c));
+ save_item(NAME(m_prev_c));
+ save_item(NAME(m_c_in));
+ save_item(NAME(m_c_delay));
+ save_item(NAME(m_skip));
+ save_item(NAME(m_skip_count));
+
+ // 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(PPS41_PC, "PC", m_pc).formatstr("%03X");
+
+ state_add(PPS41_A, "A", m_a).formatstr("%01X");
+ state_add(PPS41_C, "C", m_c_in).formatstr("%01X");
+ state_add(PPS41_B, "B", m_b).formatstr("%02X");
+
+ set_icountptr(m_icount);
+}
+
+device_memory_interface::space_config_vector pps41_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 pps41_base_device::device_reset()
+{
+ m_op = m_prev_op = 0;
+ m_pc = m_prgmask >> 1 & ~0x3f;
+ m_skip = false;
+ m_skip_count = 0;
+
+ // clear outputs
+ //..
+}
+
+
+//-------------------------------------------------
+// execute
+//-------------------------------------------------
+
+void pps41_base_device::cycle()
+{
+ m_icount--;
+}
+
+void pps41_base_device::increment_pc()
+{
+ // low part is LFSR
+ int feed = ((m_pc & 0x3e) == 0) ? 1 : 0;
+ feed ^= (m_pc >> 1 ^ m_pc) & 1;
+ m_pc = (m_pc & ~0x3f) | (m_pc >> 1 & 0x1f) | (feed << 5);
+}
+
+void pps41_base_device::execute_run()
+{
+ while (m_icount > 0)
+ {
+ // remember previous state
+ m_prev2_op = m_prev_op;
+ m_prev_op = m_op;
+ m_prev_pc = m_pc;
+
+ m_prev2_b = m_prev_b;
+ m_prev_b = m_b;
+ m_prev_c = m_c;
+
+ // fetch next opcode
+ if (!m_skip && !m_skip_count)
+ debugger_instruction_hook(m_pc);
+ m_op = m_program->read_byte(m_pc);
+ increment_pc();
+ cycle();
+
+ // handle opcode if it's not skipped
+ if (m_skip)
+ {
+ // still skip through prefix(es)
+ m_skip = op_is_prefix(m_op);
+ m_op = 0; // fake nop
+ }
+ else if (m_skip_count)
+ {
+ m_skip_count--;
+
+ // restore opcode state
+ m_op = m_prev_op;
+ m_prev_op = m_prev2_op;
+ }
+ else
+ execute_one();
+
+ // some opcodes delay RAM address(Bl part) adjustment for 1 cycle
+ m_ram_addr = m_b;
+
+ if (m_ram_delay)
+ {
+ m_ram_addr = (m_ram_addr & ~0xf) | (m_prev_b & 0xf);
+ m_ram_delay = false;
+ }
+
+ // SAG sets RAM address(Bu part) to 3 for the next cycle
+ if (m_sag)
+ {
+ m_ram_addr = (m_ram_addr & 0xf) | 0x30;
+ m_sag = false;
+ }
+
+ // and some opcodes delay carry adjustment for 1 cycle
+ m_c_in = m_c_delay ? m_prev_c : m_c;
+ m_c_delay = false;
+ }
+}
diff --git a/src/devices/cpu/pps41/pps41base.h b/src/devices/cpu/pps41/pps41base.h
new file mode 100644
index 00000000000..b8b42a44a78
--- /dev/null
+++ b/src/devices/cpu/pps41/pps41base.h
@@ -0,0 +1,94 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell PPS-4/1 MCU cores
+
+*/
+
+#ifndef MAME_CPU_PPS41_PPS41BASE_H
+#define MAME_CPU_PPS41_PPS41BASE_H
+
+#pragma once
+
+#include "machine/pla.h"
+
+
+class pps41_base_device : public cpu_device
+{
+public:
+ // configuration helpers
+ // I/O ports:
+
+ //..
+
+ // set MCU mask options:
+
+ //..
+
+protected:
+ // construction/destruction
+ pps41_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 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;
+
+ // device_execute_interface overrides
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return 2; }
+ virtual void execute_run() override;
+ virtual void execute_one() = 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; // "
+
+ optional_device<pla_device> m_opla; // segment output PLA
+
+ // i/o handlers
+ //..
+
+ // internal state, regs
+ u16 m_pc;
+ u16 m_prev_pc;
+ u8 m_op;
+ u8 m_prev_op;
+ u8 m_prev2_op;
+ int m_stack_levels;
+ u16 m_stack[2]; // max 2
+
+ u8 m_a;
+ u8 m_b;
+ u8 m_prev_b;
+ u8 m_prev2_b;
+ u8 m_ram_addr;
+ bool m_ram_delay;
+ bool m_sag;
+ int m_c;
+ int m_prev_c;
+ int m_c_in;
+ bool m_c_delay;
+ bool m_skip;
+ int m_skip_count;
+
+ // misc handlers
+ virtual bool op_is_prefix(u8 op) = 0;
+ void cycle();
+ void increment_pc();
+};
+
+
+#endif // MAME_CPU_PPS41_PPS41BASE_H
diff --git a/src/devices/cpu/pps41/pps41d.cpp b/src/devices/cpu/pps41/pps41d.cpp
new file mode 100644
index 00000000000..8925bb82c71
--- /dev/null
+++ b/src/devices/cpu/pps41/pps41d.cpp
@@ -0,0 +1,141 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell PPS-4/1 disassembler
+
+*/
+
+#include "emu.h"
+#include "pps41d.h"
+
+// constructor
+
+pps41_common_disassembler::pps41_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 pps41_common_disassembler::increment_pc(offs_t pc)
+{
+ int feed = ((pc & 0x3e) == 0) ? 1 : 0;
+ feed ^= (pc >> 1 ^ pc) & 1;
+ return (pc & ~0x3f) | (pc >> 1 & 0x1f) | (feed << 5);
+}
+
+
+// common lookup tables
+
+const char *const pps41_common_disassembler::s_name[] =
+{
+ "?",
+ "XAB", "LBA", "LB", "EOB",
+ "SB", "RB", "SKBF",
+ "XAS", "LSA",
+ "L", "X", "XDSK", "XNSK",
+ "A", "AC", "ACSK", "ASK", "COM", "RC", "SC", "SKNC", "LAI", "AISK",
+ "RT", "RTSK", "T", "NOP", "TL", "TM", "TML", "TR",
+ "SKMEA", "SKBEI", "SKAEI",
+ "SOS", "ROS", "SKISL", "IBM", "OB", "IAM", "OA", "IOS", "I1", "I2C", "INT1H", "DIN1", "INT0L", "DIN0", "SEG1", "SEG2"
+};
+
+// number of bits per opcode parameter
+// note: d4 means hex, d5 means inverted, d6 means extended
+const u8 pps41_common_disassembler::s_bits[] =
+{
+ 0,
+ 0, 0, 4, 2,
+ 2, 2, 2,
+ 0, 0,
+ 2, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 4, 4,
+ 0, 0, 0x36, 0, 0x76, 0x36, 0x76, 0x34,
+ 0, 0x40, 0x60,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+const u32 pps41_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, 0,
+ STEP_OUT, STEP_OUT, 0, 0, 0, STEP_OVER, 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 pps41_common_disassembler::common_disasm(const u8 *lut_opmap, std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ // get raw opcode
+ u8 op = opcodes.r8(pc);
+ u8 instr = lut_opmap[op];
+
+ // get parameter
+ u8 bits = s_bits[instr];
+ u16 mask = (1 << (bits & 0xf)) - 1;
+ bits &= 0xf0;
+
+ u16 param = op & mask;
+ if (bits & 0x20)
+ param ^= mask;
+
+ // memory bit opcodes are 1,2,3,4
+ if (instr == em_SB || instr == em_RB || instr == em_SKBF)
+ param++;
+
+ // disassemble it
+ util::stream_format(stream, "%-6s ", s_name[instr]);
+ if (mask > 0)
+ {
+ if (bits & 0x10)
+ util::stream_format(stream, (mask & ~0xf) ? "$%02X" : "$%X", param);
+ else
+ util::stream_format(stream, "%d", param);
+ }
+
+ return 1 | s_flags[instr] | SUPPORTED;
+}
+
+
+// MM76 disasm
+
+const u8 mm76_disassembler::mm76_opmap[0x100] =
+{
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ em_NOP, em_SKNC, em_RT, em_RTSK, em_INT0L,em_INT1H,em_DIN1, em_DIN0, em_SKBF, em_SKBF, em_SKBF, em_SKBF, em_SC, em_RC, em_SEG1, em_SEG2, // 0
+ em_SB, em_SB, em_SB, em_SB, em_RB, em_RB, em_RB, em_RB, em_OA, em_OB, em_IAM, em_IBM, em_EOB, em_EOB, em_EOB, em_EOB, // 1
+ em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, em_LB, // 2
+ em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, em_TR, // 3
+
+ em_AC, em_ACSK, em_A, em_ASK, em_LBA, em_COM, em_XAB, em_SKMEA,em_ILL, em_ILL, em_I1, em_I2C, em_LSA, em_IOS, em_XAS, em_ILL, // 4
+ em_L, em_L, em_L, em_L, em_XNSK, em_XNSK, em_XNSK, em_XNSK, em_X, em_X, em_X, em_X, em_XDSK, em_XDSK, em_XDSK, em_XDSK, // 5
+ em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, em_AISK, // 6
+ em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, em_LAI, // 7
+
+ em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, // 8
+ em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, // 9
+ em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, // A
+ em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, em_TM, // B
+
+ em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, // C
+ em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, // D
+ em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, // E
+ em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T, em_T // F
+};
+
+offs_t mm76_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ return common_disasm(mm76_opmap, stream, pc, opcodes, params);
+}
diff --git a/src/devices/cpu/pps41/pps41d.h b/src/devices/cpu/pps41/pps41d.h
new file mode 100644
index 00000000000..5e35adbd53b
--- /dev/null
+++ b/src/devices/cpu/pps41/pps41d.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Rockwell PPS-4/1 disassembler
+
+*/
+
+#ifndef MAME_CPU_PPS41_PPS41D_H
+#define MAME_CPU_PPS41_PPS41D_H
+
+#pragma once
+
+
+class pps41_common_disassembler : public util::disasm_interface
+{
+public:
+ pps41_common_disassembler();
+ virtual ~pps41_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_XAB, em_LBA, em_LB, em_EOB,
+ em_SB, em_RB, em_SKBF,
+ em_XAS, em_LSA,
+ em_L, em_X, em_XDSK, em_XNSK,
+ em_A, em_AC, em_ACSK, em_ASK, em_COM, em_RC, em_SC, em_SKNC, em_LAI, em_AISK,
+ em_RT, em_RTSK, em_T, em_NOP, em_TL, em_TM, em_TML, em_TR,
+ em_SKMEA, em_SKBEI, em_SKAEI,
+ em_SOS, em_ROS, em_SKISL, em_IBM, em_OB, em_IAM, em_OA, em_IOS, em_I1, em_I2C, em_INT1H, em_DIN1, em_INT0L, em_DIN0, em_SEG1, em_SEG2,
+ };
+
+ static const char *const s_name[];
+ static const u8 s_bits[];
+ static const u32 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 &params);
+};
+
+class mm76_disassembler : public pps41_common_disassembler
+{
+public:
+ mm76_disassembler() = default;
+ virtual ~mm76_disassembler() = default;
+
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+private:
+ static const u8 mm76_opmap[0x100];
+
+};
+
+#endif // MAME_CPU_PPS41_PPS41D_H
diff --git a/src/devices/cpu/sm510/sm510base.cpp b/src/devices/cpu/sm510/sm510base.cpp
index f5f0ae6bbb2..cca35da7730 100644
--- a/src/devices/cpu/sm510/sm510base.cpp
+++ b/src/devices/cpu/sm510/sm510base.cpp
@@ -302,7 +302,8 @@ void sm510_base_device::execute_run()
m_prev_pc = m_pc;
// fetch next opcode
- debugger_instruction_hook(m_pc);
+ if (!m_skip)
+ debugger_instruction_hook(m_pc);
m_op = m_program->read_byte(m_pc);
increment_pc();
get_opcode_param();
diff --git a/src/devices/cpu/sm510/sm510op.cpp b/src/devices/cpu/sm510/sm510op.cpp
index 52516c16503..8570f6139b5 100644
--- a/src/devices/cpu/sm510/sm510op.cpp
+++ b/src/devices/cpu/sm510/sm510op.cpp
@@ -468,5 +468,5 @@ void sm510_base_device::op_clkhi()
void sm510_base_device::op_illegal()
{
- logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_prev_pc);
+ logerror("unknown opcode $%02X at $%04X\n", m_op, m_prev_pc);
}
diff --git a/src/devices/cpu/sm510/sm511core.cpp b/src/devices/cpu/sm510/sm511core.cpp
index 70df0cd1c0e..90de18142f7 100644
--- a/src/devices/cpu/sm510/sm511core.cpp
+++ b/src/devices/cpu/sm510/sm511core.cpp
@@ -153,7 +153,7 @@ void sm511_device::init_melody()
{
u8 data = m_melody_rom[i];
if (data & 0xc0 || (data & 0x0f) > 13)
- logerror("%s unknown melody ROM data $%02X at $%02X\n", tag(), data, i);
+ logerror("unknown melody ROM data $%02X at $%02X\n", data, i);
}
}
diff --git a/src/devices/cpu/ucom4/ucom4.cpp b/src/devices/cpu/ucom4/ucom4.cpp
index 3eab39eca70..8d98f1d2f94 100644
--- a/src/devices/cpu/ucom4/ucom4.cpp
+++ b/src/devices/cpu/ucom4/ucom4.cpp
@@ -277,7 +277,7 @@ u8 ucom4_cpu_device::input_r(int index)
case PORTD: inp = m_read_d(index, 0xff) | m_port_out[index]; break;
default:
- logerror("%s read from unknown port %c at $%03X\n", tag(), 'A' + index, m_prev_pc);
+ logerror("read from unknown port %c at $%03X\n", 'A' + index, m_prev_pc);
break;
}
@@ -300,7 +300,7 @@ void ucom4_cpu_device::output_w(int index, u8 data)
case PORTI: m_write_i(index, data & 7, 0xff); break;
default:
- logerror("%s write to unknown port %c = $%X at $%03X\n", tag(), 'A' + index, data, m_prev_pc);
+ logerror("write to unknown port %c = $%X at $%03X\n", 'A' + index, data, m_prev_pc);
break;
}
@@ -315,7 +315,7 @@ u8 upd557l_cpu_device::input_r(int index)
index &= 0xf;
if (index == PORTB)
- logerror("%s read from unknown port %c at $%03X\n", tag(), 'A' + index, m_prev_pc);
+ logerror("read from unknown port %c at $%03X\n", 'A' + index, m_prev_pc);
else
return ucom4_cpu_device::input_r(index);
@@ -328,7 +328,7 @@ void upd557l_cpu_device::output_w(int index, u8 data)
data &= 0xf;
if (index == PORTH || index == PORTI)
- logerror("%s write to unknown port %c = $%X at $%03X\n", tag(), 'A' + index, data, m_prev_pc);
+ logerror("write to unknown port %c = $%X at $%03X\n", 'A' + index, data, m_prev_pc);
else
{
// only G0 for port G
@@ -409,7 +409,8 @@ void ucom4_cpu_device::execute_run()
m_prev_pc = m_pc;
// fetch next opcode
- debugger_instruction_hook(m_pc);
+ if (!m_skip)
+ debugger_instruction_hook(m_pc);
m_icount--;
m_op = m_program->read_byte(m_pc);
m_bitmask = 1 << (m_op & 0x03);
diff --git a/src/devices/cpu/ucom4/ucom4op.cpp b/src/devices/cpu/ucom4/ucom4op.cpp
index 4facf3efb3b..cecd08d800e 100644
--- a/src/devices/cpu/ucom4/ucom4op.cpp
+++ b/src/devices/cpu/ucom4/ucom4op.cpp
@@ -41,7 +41,7 @@ void ucom4_cpu_device::push_stack()
void ucom4_cpu_device::op_illegal()
{
- logerror("%s unknown opcode $%02X at $%03X\n", tag(), m_op, m_prev_pc);
+ logerror("unknown opcode $%02X at $%03X\n", m_op, m_prev_pc);
}
@@ -337,7 +337,7 @@ void ucom4_cpu_device::op_ci()
m_skip = (m_acc == (m_arg & 0x0f));
if ((m_arg & 0xf0) != 0xc0)
- logerror("%s CI opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xf0, m_prev_pc);
+ logerror("CI opcode unexpected upper arg $%02X at $%03X\n", m_arg & 0xf0, m_prev_pc);
}
void ucom4_cpu_device::op_cm()
@@ -364,7 +364,7 @@ void ucom4_cpu_device::op_cli()
m_skip = (m_dpl == (m_arg & 0x0f));
if ((m_arg & 0xf0) != 0xe0)
- logerror("%s CLI opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xf0, m_prev_pc);
+ logerror("CLI opcode unexpected upper arg $%02X at $%03X\n", m_arg & 0xf0, m_prev_pc);
}
void ucom4_cpu_device::op_tmb()
@@ -447,7 +447,7 @@ inline bool ucom4_cpu_device::check_op_43()
{
// these opcodes are officially only supported on uCOM-43
if (m_family != NEC_UCOM43)
- logerror("%s using uCOM-43 opcode $%02X at $%03X\n", tag(), m_op, m_prev_pc);
+ logerror("using uCOM-43 opcode $%02X at $%03X\n", m_op, m_prev_pc);
return (m_family == NEC_UCOM43);
}
@@ -689,7 +689,7 @@ void ucom4_cpu_device::op_stm()
m_timer->adjust(base * ((m_arg & 0x3f) + 1));
if ((m_arg & 0xc0) != 0x80)
- logerror("%s STM opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xc0, m_prev_pc);
+ logerror("STM opcode unexpected upper arg $%02X at $%03X\n", m_arg & 0xc0, m_prev_pc);
}
void ucom4_cpu_device::op_ttm()
diff --git a/src/mame/drivers/hh_pps41.cpp b/src/mame/drivers/hh_pps41.cpp
new file mode 100644
index 00000000000..f3ef9ea653a
--- /dev/null
+++ b/src/mame/drivers/hh_pps41.cpp
@@ -0,0 +1,162 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+// thanks-to:Sean Riddle, Kevin Horton
+/***************************************************************************
+
+ Rockwell PPS-4/1 MCU series handhelds
+
+ TODO:
+ - WIP
+
+***************************************************************************/
+
+#include "emu.h"
+
+#include "cpu/pps41/mm76.h"
+#include "video/pwm.h"
+#include "sound/spkrdev.h"
+#include "speaker.h"
+
+// internal artwork
+//#include "mastmind.lh"
+
+//#include "hh_pps41_test.lh" // common test-layout - use external artwork
+
+
+class hh_pps41_state : public driver_device
+{
+public:
+ hh_pps41_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<pps41_base_device> m_maincpu;
+ optional_device<pwm_display_device> m_display;
+ optional_device<speaker_sound_device> m_speaker;
+ optional_ioport_array<8> m_inputs; // max 8
+
+ u16 m_inp_mux = 0;
+
+ // MCU output pin state
+ //..
+
+ u8 read_inputs(int columns);
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+};
+
+
+// machine start/reset
+
+void hh_pps41_state::machine_start()
+{
+ // register for savestates
+ save_item(NAME(m_inp_mux));
+}
+
+void hh_pps41_state::machine_reset()
+{
+}
+
+
+
+/***************************************************************************
+
+ Helper Functions
+
+***************************************************************************/
+
+// generic input handlers
+
+u8 hh_pps41_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 {
+
+/***************************************************************************
+
+ Invicta Electronic Master Mind
+ * x
+
+ Invicta is the owner of the Mastermind game rights. The back of the unit
+ says (C) 1977, but this electronic handheld version came out in 1979.
+
+***************************************************************************/
+
+class mastmind_state : public hh_pps41_state
+{
+public:
+ mastmind_state(const machine_config &mconfig, device_type type, const char *tag) :
+ hh_pps41_state(mconfig, type, tag)
+ { }
+
+ void mastmind(machine_config &config);
+};
+
+// handlers
+
+// config
+
+static INPUT_PORTS_START( mastmind )
+INPUT_PORTS_END
+
+void mastmind_state::mastmind(machine_config &config)
+{
+ /* basic machine hardware */
+ MM76(config, m_maincpu, 100000); // approximation
+
+ /* video hardware */
+ PWM_DISPLAY(config, m_display).set_size(4, 8);
+ m_display->set_segmask(3, 0xff);
+ //config.set_default_layout(layout_mastmind);
+
+ /* no sound! */
+}
+
+// roms
+
+ROM_START( mastmind )
+ ROM_REGION( 0x0400, "maincpu", ROMREGION_ERASE00 )
+ ROM_LOAD( "mm75_a7525-11", 0x0000, 0x0200, BAD_DUMP CRC(d144ee6b) SHA1(1e0b521b1e79f94377780470a52e22ee2deaf1d4) ) // wrong byte/bit ordering
+ ROM_CONTINUE( 0x0380, 0x0080 )
+
+ ROM_REGION( 100, "maincpu:opla", 0 )
+ ROM_LOAD( "mm76_mastmind_output.pla", 0, 100, NO_DUMP ) // that's a lie
+ROM_END
+
+
+
+} // anonymous namespace
+
+/***************************************************************************
+
+ Game driver(s)
+
+***************************************************************************/
+
+// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS
+CONS( 1979, mastmind, 0, 0, mastmind, mastmind, mastmind_state, empty_init, "Invicta Plastics", "Electronic Master Mind (Invicta)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/hh_ucom4.cpp b/src/mame/drivers/hh_ucom4.cpp
index c6c778bb9b3..074bf619f55 100644
--- a/src/mame/drivers/hh_ucom4.cpp
+++ b/src/mame/drivers/hh_ucom4.cpp
@@ -227,8 +227,8 @@ namespace {
This is Bambino's first game, it is not known if ET-01 exists. Emix Corp.
wasn't initially a toy company, the first release was through Tomy. Emix
created the Bambino brand afterwards. It is claimed to be the first
- computerized VFD game (true, unless TI Speak & Spell(1978), or even Invicta
- Electronic Mastermind(1977) are considered games)
+ computerized VFD game (true, unless TI Speak & Spell or M.E.M. Memoquiz
+ from 1978 are considered VFD games)
known releases:
- Japan: "Missile Guerilla Warfare Maneuvers", published by Tomy
diff --git a/src/mame/layout/hh_melps4_test.lay b/src/mame/layout/hh_melps4_test.lay
index 4f1315c3b29..d737d012688 100644
--- a/src/mame/layout/hh_melps4_test.lay
+++ b/src/mame/layout/hh_melps4_test.lay
@@ -10,7 +10,7 @@ license:CC0
<element name="led" defstate="0">
<disk state="0"><color red="0.0" green="0.0" blue="0.0" /></disk>
- <disk state="1"><color red="1.0" green="0.5" blue="0.3" /></disk>
+ <disk state="1"><color red="0.5" green="1.0" blue="1.0" /></disk>
</element>
diff --git a/src/mame/layout/hh_pps41_test.lay b/src/mame/layout/hh_pps41_test.lay
new file mode 100644
index 00000000000..d737d012688
--- /dev/null
+++ b/src/mame/layout/hh_pps41_test.lay
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+license:CC0
+-->
+<mamelayout version="2">
+
+ <!-- define elements -->
+
+ <element name="static_black"><rect><color red="0.0" green="0.0" blue="0.0" /></rect></element>
+
+ <element name="led" defstate="0">
+ <disk state="0"><color red="0.0" green="0.0" blue="0.0" /></disk>
+ <disk state="1"><color red="0.5" green="1.0" blue="1.0" /></disk>
+ </element>
+
+
+ <!-- build screen -->
+
+ <view name="Test Layout">
+ <bounds left="0" right="32" top="0" bottom="16" />
+ <element ref="static_black">
+ <bounds left="0" right="32" top="0" bottom="16" />
+ </element>
+
+ <!-- max 16*32 matrix -->
+
+ <repeat count="16">
+ <param name="y" start="0" increment="1" />
+
+ <repeat count="32">
+ <param name="x" start="0" increment="1" />
+ <element name="~y~.~x~" ref="led"><bounds x="~x~" y="~y~" width="0.5" height="0.5" /></element>
+ </repeat>
+ </repeat>
+
+ </view>
+</mamelayout>
diff --git a/src/mame/layout/hh_ucom4_test.lay b/src/mame/layout/hh_ucom4_test.lay
index af24003941d..d737d012688 100644
--- a/src/mame/layout/hh_ucom4_test.lay
+++ b/src/mame/layout/hh_ucom4_test.lay
@@ -10,7 +10,7 @@ license:CC0
<element name="led" defstate="0">
<disk state="0"><color red="0.0" green="0.0" blue="0.0" /></disk>
- <disk state="1"><color red="0.3" green="1.0" blue="0.3" /></disk>
+ <disk state="1"><color red="0.5" green="1.0" blue="1.0" /></disk>
</element>
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 5f9bf1edf5e..ffdee2746d8 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -16162,6 +16162,9 @@ ttfballa // Toytronic
us2pfball // US Games
uspbball // US Games
+@source:hh_pps41.cpp
+mastmind // Invicta
+
@source:hh_sm510.cpp
auslalom // Elektronika
bassmate // Telko
diff --git a/src/mame/mess.flt b/src/mame/mess.flt
index 168887afa47..801939fa2fe 100644
--- a/src/mame/mess.flt
+++ b/src/mame/mess.flt
@@ -390,6 +390,7 @@ hh_cops1.cpp
hh_hmcs40.cpp
hh_melps4.cpp
hh_pic16.cpp
+hh_pps41.cpp
hh_sm510.cpp
hh_tms1k.cpp
hh_ucom4.cpp
diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp
index 81a250c0ebf..7bf28fec35c 100644
--- a/src/tools/unidasm.cpp
+++ b/src/tools/unidasm.cpp
@@ -131,6 +131,7 @@ using util::BIT;
#include "cpu/pic17/pic17d.h"
#include "cpu/powerpc/ppc_dasm.h"
#include "cpu/pps4/pps4dasm.h"
+#include "cpu/pps41/pps41d.h"
#include "cpu/psx/psxdasm.h"
#include "cpu/rii/riidasm.h"
#include "cpu/romp/rompdasm.h"
@@ -498,6 +499,7 @@ static const dasm_table_entry dasm_table[] =
{ "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; } },
+ { "mm76", le, 0, []() -> util::disasm_interface * { return new mm76_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; } },