diff --git a/hash/lnux4004.xml b/hash/lnux4004.xml
new file mode 100644
index 00000000000..96ac8fe94d7
--- /dev/null
+++ b/hash/lnux4004.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ Debian GNU/Linux 7 (Linux uMIPS 4.4.292+)
+ 2024
+ Dmitry Grinberg
+
+
+
+
+
+
+
+
diff --git a/hash/pc98.xml b/hash/pc98.xml
index f59320148af..917a7d67b15 100644
--- a/hash/pc98.xml
+++ b/hash/pc98.xml
@@ -21057,11 +21057,11 @@ Missing [7220] text selector for choices
1992
M.N.M.ソフトウェア (M.N.M. Software)
+
@@ -23586,11 +23586,14 @@ TODO: to install to HDD should be "INST1.BAT B: A:" but it fails recogni
-
Headquarters - America no Akumu
1994
アルゴラボ 算法研究所 (Algolab)
+
@@ -41281,6 +41284,9 @@ Cannot install, gets stuck at "please insert disk and press mouse" prompt
Space Invaders
1992
ウィズ (Wiz)
+
@@ -41383,7 +41389,6 @@ Cannot install, gets stuck at "please insert disk and press mouse" prompt
Special Stage - Paris-Dakar Sabaku no Shissou
1992
-
アレックス (Allex)
@@ -53763,12 +53768,13 @@ Hangs after name entry with illegal opcode 0f 0e at PC=FF2C3
-
+
Mole Mole
1985
クロスメディアソフト (Cross Media Soft)
+
diff --git a/hash/to_flop.xml b/hash/to_flop.xml
index 0d4c845911c..5dd2a87e9e0 100644
--- a/hash/to_flop.xml
+++ b/hash/to_flop.xml
@@ -4,6 +4,10 @@
license:CC0-1.0
Thanks to DCMOTO (http://dcmoto.free.fr) for info!
+
+FIXME: Many of these images should be 5.25" rather than 3.5". (The old custom Thomson floppy emulation didn't care about form factor.)
+TODO: SAP format is not currently supported.
+TBD: Which images are compatible with which systems?
-->
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 634a6eab870..6988e9202db 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -4844,6 +4844,8 @@ if (BUSES["SPECTRUM"]~=null) then
MAME_DIR .. "src/devices/bus/spectrum/mikroplus.h",
MAME_DIR .. "src/devices/bus/spectrum/mpoker.cpp",
MAME_DIR .. "src/devices/bus/spectrum/mpoker.h",
+ MAME_DIR .. "src/devices/bus/spectrum/musicmachine.cpp",
+ MAME_DIR .. "src/devices/bus/spectrum/musicmachine.h",
MAME_DIR .. "src/devices/bus/spectrum/opus.cpp",
MAME_DIR .. "src/devices/bus/spectrum/opus.h",
MAME_DIR .. "src/devices/bus/spectrum/plus2test.cpp",
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index d462d65ee8f..053caa56129 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -3320,6 +3320,17 @@ if (MACHINES["SAA5070"]~=null) then
}
end
+---------------------------------------------------
+--
+--@src/devices/machine/sc16is741.h,MACHINES["SC16IS741"] = true
+---------------------------------------------------
+if (MACHINES["SC16IS741"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/sc16is741.cpp",
+ MAME_DIR .. "src/devices/machine/sc16is741.h",
+ }
+end
+
---------------------------------------------------
--
--@src/devices/machine/scc66470.h,MACHINES["SCC66470"] = true
@@ -4474,6 +4485,18 @@ if (MACHINES["PC87306"]~=null) then
}
end
+---------------------------------------------------
+--
+--@src/devices/machine/pc97338.h,MACHINES["PC97338"] = true
+---------------------------------------------------
+
+if (MACHINES["PC97338"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/pc97338.cpp",
+ MAME_DIR .. "src/devices/machine/pc97338.h",
+ }
+end
+
---------------------------------------------------
--
--@src/devices/machine/w83787f.h,MACHINES["W83787F"] = true
diff --git a/src/devices/bus/cpc/musicmachine.cpp b/src/devices/bus/cpc/musicmachine.cpp
index a513e9d5fd3..83c5bef8dfc 100644
--- a/src/devices/bus/cpc/musicmachine.cpp
+++ b/src/devices/bus/cpc/musicmachine.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Barry Rodewald
/*
* The Music Machine - MIDI and sampling expansion
- * by Ram Electronics
+ * by Ram Electronics Ltd
*/
#include "emu.h"
@@ -16,7 +16,7 @@
// DEVICE DEFINITIONS
//**************************************************************************
-DEFINE_DEVICE_TYPE(CPC_MUSICMACHINE, cpc_musicmachine_device, "cpcmusic", "The Music Machine")
+DEFINE_DEVICE_TYPE(CPC_MUSICMACHINE, cpc_musicmachine_device, "cpcmusic", "The Music Machine (CPC)")
void cpc_musicmachine_device::device_add_mconfig(machine_config &config)
diff --git a/src/devices/bus/spectrum/exp.cpp b/src/devices/bus/spectrum/exp.cpp
index 90015c8c72a..22d0a5665e5 100644
--- a/src/devices/bus/spectrum/exp.cpp
+++ b/src/devices/bus/spectrum/exp.cpp
@@ -167,6 +167,7 @@ void spectrum_expansion_slot_device::mreq_w(offs_t offset, uint8_t data)
#include "mgt.h"
#include "mikroplus.h"
#include "mpoker.h"
+#include "musicmachine.h"
#include "opus.h"
#include "plus2test.h"
#include "protek.h"
@@ -215,6 +216,7 @@ void spectrum_expansion_devices(device_slot_interface &device)
device.option_add("mikroplus", SPECTRUM_MIKROPLUS);
device.option_add("mpoker", SPECTRUM_MPOKER);
device.option_add("mprint", SPECTRUM_MPRINT);
+ device.option_add("musicmachine", SPECTRUM_MUSICMACHINE);
device.option_add("opus", SPECTRUM_OPUS);
device.option_add("plusd", SPECTRUM_PLUSD);
device.option_add("proceed", SPECTRUM_PROCEED);
@@ -244,6 +246,7 @@ void spec128_expansion_devices(device_slot_interface &device)
device.option_add("mface128", SPECTRUM_MFACE128);
device.option_add("mikroplus", SPECTRUM_MIKROPLUS);
device.option_add("mprint", SPECTRUM_MPRINT);
+ device.option_add("musicmachine", SPECTRUM_MUSICMACHINE);
device.option_add("opus", SPECTRUM_OPUS);
device.option_add("plusd", SPECTRUM_PLUSD);
device.option_add("plus2test", SPECTRUM_PLUS2TEST);
@@ -259,5 +262,6 @@ void specpls3_expansion_devices(device_slot_interface &device)
{
device.option_add("kempjoy", SPECTRUM_KEMPJOY);
device.option_add("mface3", SPECTRUM_MFACE3);
+ device.option_add("musicmachine", SPECTRUM_MUSICMACHINE);
}
diff --git a/src/devices/bus/spectrum/musicmachine.cpp b/src/devices/bus/spectrum/musicmachine.cpp
new file mode 100644
index 00000000000..f8eb8679bcb
--- /dev/null
+++ b/src/devices/bus/spectrum/musicmachine.cpp
@@ -0,0 +1,149 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+/*
+ * The Music Machine - MIDI and sampling expansion
+ * by Ram Electronics Ltd
+ */
+
+#include "emu.h"
+#include "musicmachine.h"
+
+#include "bus/midi/midi.h"
+#include "machine/6850acia.h"
+#include "machine/clock.h"
+#include "sound/dac.h"
+
+#include "speaker.h"
+
+
+namespace {
+
+class spectrum_musicmachine_device : public device_t, public device_spectrum_expansion_interface
+{
+public:
+ // construction/destruction
+ spectrum_musicmachine_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ void write_acia_clock(u8 data);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+ // device_spectrum_expansion_interface implementation
+ virtual u8 iorq_r(offs_t offset) override;
+ virtual void iorq_w(offs_t offset, u8 data) override;
+
+private:
+ required_device m_acia;
+ required_device m_dac;
+
+ bool m_irq_select;
+};
+
+
+void spectrum_musicmachine_device::device_add_mconfig(machine_config &config)
+{
+ ACIA6850(config, m_acia).txd_handler().set("mdout", FUNC(midi_port_device::write_txd));
+ m_acia->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w));
+ MIDI_PORT(config, "mdin", midiin_slot, "midiin").rxd_handler().set(m_acia, FUNC(acia6850_device::write_rxd));
+ MIDI_PORT(config, "mdout", midiout_slot, "midiout");
+ clock_device &acia_clock(CLOCK(config, "acia_clock", 31250*16));
+ acia_clock.signal_handler().set(FUNC(spectrum_musicmachine_device::write_acia_clock));
+
+ SPEAKER(config, "speaker").front_center();
+ ZN429E(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.2);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+spectrum_musicmachine_device::spectrum_musicmachine_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SPECTRUM_MUSICMACHINE, tag, owner, clock)
+ , device_spectrum_expansion_interface(mconfig, *this)
+ , m_acia(*this,"acia")
+ , m_dac(*this,"dac")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void spectrum_musicmachine_device::device_start()
+{
+ save_item(NAME(m_irq_select));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void spectrum_musicmachine_device::device_reset()
+{
+ m_irq_select = false;
+}
+
+void spectrum_musicmachine_device::write_acia_clock(u8 data)
+{
+ m_acia->write_txc(data);
+ m_acia->write_rxc(data);
+}
+
+u8 spectrum_musicmachine_device::iorq_r(offs_t offset)
+{
+ u8 data = (offset & 1) ? m_slot->fb_r() : 0xff;
+
+ switch (offset & 0xff)
+ {
+ case 0x7f:
+ if ((offset & 0x3ff) == 0x27f)
+ data = m_acia->status_r();
+ else if ((offset & 0x3ff) == 0x37f)
+ data = m_acia->data_r();
+ break;
+ case 0xbf:
+ // TODO ADC_READ
+ break;
+ case 0xdf:
+ // TODO Strobe: ADC_START
+ break;
+ }
+
+ return data;
+}
+
+void spectrum_musicmachine_device::iorq_w(offs_t offset, u8 data)
+{
+ switch (offset & 0xff)
+ {
+ case 0x5f:
+ m_irq_select = data & 1;
+ break;
+ case 0x7f:
+ if ((offset & 0x3ff) == 0x07f)
+ m_acia->control_w(data);
+ else if ((offset & 0x3ff) == 0x17f)
+ m_acia->data_w(data);
+ break;
+ case 0x9f:
+ m_dac->write(data);
+ break;
+ case 0xdf:
+ // TODO Strobe: ADC_START
+ break;
+ }
+}
+
+} // anonymous namespace
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE_PRIVATE(SPECTRUM_MUSICMACHINE, device_spectrum_expansion_interface, spectrum_musicmachine_device, "spectrummusic", "The Music Machine (ZX)")
diff --git a/src/devices/bus/spectrum/musicmachine.h b/src/devices/bus/spectrum/musicmachine.h
new file mode 100644
index 00000000000..59efe6e04e8
--- /dev/null
+++ b/src/devices/bus/spectrum/musicmachine.h
@@ -0,0 +1,20 @@
+// license:BSD-3-Clause
+// copyright-holders:Barry Rodewald
+/*
+ * The Music Machine - MIDI and sampling expansion
+ * by Ram Electronics
+ *
+ * Contains a 6850 AICA, Ferranti ZN429E8 DAC and ZN449 ADC
+ */
+
+#ifndef MAME_BUS_SPECTRUM_MUSICMACHINE_H
+#define MAME_BUS_SPECTRUM_MUSICMACHINE_H
+
+#pragma once
+
+#include "exp.h"
+
+
+DECLARE_DEVICE_TYPE(SPECTRUM_MUSICMACHINE, device_spectrum_expansion_interface)
+
+#endif // MAME_BUS_SPECTRUM_MUSICMACHINE_H
diff --git a/src/devices/machine/mc6843.cpp b/src/devices/machine/mc6843.cpp
index d1df8e4d4ee..4731ee78dbe 100644
--- a/src/devices/machine/mc6843.cpp
+++ b/src/devices/machine/mc6843.cpp
@@ -6,6 +6,18 @@
#include "emu.h"
#include "mc6843.h"
+#include "imagedev/floppy.h"
+
+#define LOG_SETUP (1U << 1)
+#define LOG_IRQ (1U << 2)
+#define LOG_COMMAND (1U << 3)
+#define LOG_STATUS (1U << 4)
+#define LOG_LIVE (1U << 5)
+#define LOG_RW (1U << 6)
+
+//#define VERBOSE (LOG_GENERAL | LOG_SETUP | LOG_IRQ | LOG_COMMAND | LOG_STATUS | LOG_LIVE | LOG_RW)
+#include "logmacro.h"
+
DEFINE_DEVICE_TYPE(MC6843, mc6843_device, "mc6843", "Motorola MC6843 FDC")
mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
@@ -70,6 +82,8 @@ void mc6843_device::device_reset()
m_stra = 0x00;
m_sar = 0x00;
m_strb = 0x00;
+
+ m_irq(CLEAR_LINE);
}
void mc6843_device::map(address_map &map)
@@ -98,7 +112,7 @@ void mc6843_device::set_floppy(floppy_image_device *floppy)
m_floppy = floppy;
- logerror("floppy %s\n", m_floppy ? m_floppy->tag() : "-");
+ LOGMASKED(LOG_SETUP, "floppy %s\n", m_floppy ? m_floppy->tag() : "-");
int next_ready = m_floppy ? m_floppy->ready_r() : 1;
@@ -115,7 +129,7 @@ u8 mc6843_device::dir_r()
{
if(!machine().side_effects_disabled()) {
m_dir_loaded = false;
- logerror("dir_r %02x\n", m_dir);
+ LOG("dir_r %02x\n", m_dir);
}
return m_dir;
}
@@ -124,37 +138,65 @@ void mc6843_device::dor_w(u8 data)
{
m_dor = data;
m_dor_loaded = true;
- logerror("dor_w %02x\n", m_dor);
+ LOG("dor_w %02x\n", m_dor);
m_strb &= ~SB_DTERR;
- if(m_strb == 0)
- m_isr &= 0x7;
}
u8 mc6843_device::ctar_r()
{
if(!machine().side_effects_disabled())
- logerror("ctar_r %02x\n", m_ctar);
+ LOG("ctar_r %02x\n", m_ctar);
return m_ctar;
}
void mc6843_device::ctar_w(u8 data)
{
m_ctar = data;
- logerror("ctar_w %02x\n", m_ctar);
+ LOG("ctar_w %02x\n", m_ctar);
}
void mc6843_device::isr_raise(u8 flag)
{
- m_isr |= flag;
+ if((m_isr & flag) != flag) {
+ LOGMASKED(LOG_IRQ, "isr_raise%s%s%s%s\n",
+ (flag & I_RWCE) ? " RWCE" : "",
+ (flag & I_SCE) ? " SCE" : "",
+ (flag & I_SSR) ? " SSR" : "",
+ (flag & I_STRB) ? " STRB" : "");
+ m_isr |= flag;
+ if(!(m_cmr & 0x80) && !((m_cmr & 0x40) && flag == I_STRB)) {
+ LOGMASKED(LOG_IRQ, "IRQ asserted\n");
+ m_irq(ASSERT_LINE);
+ }
+ }
+}
+
+void mc6843_device::isr_lower(u8 flag)
+{
+ flag &= m_isr;
+ if(flag != 0) {
+ LOGMASKED(LOG_IRQ, "isr_lower%s%s%s%s\n",
+ (flag & I_RWCE) ? " RWCE" : "",
+ (flag & I_SCE) ? " SCE" : "",
+ (flag & I_SSR) ? " SSR" : "",
+ (flag & I_STRB) ? " STRB" : "");
+ m_isr &= ~flag;
+ if(!(m_cmr & 0x80) && !((m_cmr & 0x40) ? (m_isr & 0x7) : m_isr)) {
+ LOGMASKED(LOG_IRQ, "IRQ cleared\n");
+ m_irq(CLEAR_LINE);
+ }
+ }
}
u8 mc6843_device::isr_r()
{
u8 res = m_isr;
+ if(m_strb & SB_DTERR)
+ m_isr |= I_STRB;
if(!machine().side_effects_disabled()) {
- logerror("isr_r %02x\n", m_isr);
- m_isr &= 0x8;
+ LOG("isr_r %02x\n", m_isr);
+ isr_lower(I_RWCE | I_SCE | I_SSR);
}
return res;
}
@@ -175,18 +217,22 @@ void mc6843_device::cmr_w(u8 data)
live_abort();
m_state = S_IDLE;
} else {
- logerror("cmr_w %02x - dropped busy\n", data);
+ LOGMASKED(LOG_COMMAND, "cmr_w %02x - dropped busy\n", data);
return;
}
}
m_cmr = data;
- logerror("cmr_w %02x - isr=%s isr3=%s %s fwf=%d %s\n", m_cmr,
+ LOGMASKED(LOG_COMMAND, "cmr_w %02x - isr=%s isr3=%s %s fwf=%d %s\n", m_cmr,
m_cmr & 0x80 ? "off" : "on",
m_cmr & 0x40 ? "off" : "on",
m_cmr & 0x20 ? "dma" : "pio",
m_cmr & 0x10 ? 1 : 0,
cmds[m_cmr & 0xf]);
+ if(((m_cmr & 0x80) && m_isr) || ((m_cmr & 0x40) && (m_isr == I_STRB))) {
+ LOGMASKED(LOG_IRQ, "IRQ inhibited (cmr=%02x)\n", m_cmr);
+ m_irq(CLEAR_LINE);
+ }
command_start();
}
@@ -218,7 +264,7 @@ u8 mc6843_device::stra_r()
if(!machine().side_effects_disabled()) {
static int prev = -1;
if(prev != res) {
- logerror("stra_r %02x -%s%s%s%s%s%s%s%s\n", res,
+ LOGMASKED(LOG_STATUS, "stra_r %02x -%s%s%s%s%s%s%s%s\n", res,
res & SA_BUSY ? " busy" : "",
res & SA_IDX ? " idx" : "",
res & SA_TNEQ ? " tneq" : "",
@@ -236,14 +282,16 @@ u8 mc6843_device::stra_r()
void mc6843_device::sur_w(u8 data)
{
m_sur = data;
- logerror("sur_w %02x\n", m_sur);
+ LOGMASKED(LOG_SETUP, "sur_w %02x (%.03f ms head settling, %.03f ms track to track seek)\n", m_sur,
+ clocks_to_attotime(4096 * (data & 0xf)).as_attoseconds() / double(ATTOSECONDS_PER_MILLISECOND),
+ clocks_to_attotime(1024 * (data >> 4)).as_attoseconds() / double(ATTOSECONDS_PER_MILLISECOND));
}
u8 mc6843_device::strb_r()
{
u8 strb = m_strb;
if(!machine().side_effects_disabled()) {
- logerror("strb_r %02x -%s%s%s%s%s%s%s%s\n", strb,
+ LOGMASKED(LOG_STATUS, "strb_r %02x -%s%s%s%s%s%s%s%s\n", strb,
strb & SB_HERR ? " herr" : "",
strb & SB_WERR ? " werr" : "",
strb & SB_FI ? " fi" : "",
@@ -252,9 +300,11 @@ u8 mc6843_device::strb_r()
strb & SB_DMERR ? " dmerr" : "",
strb & SB_CRC ? " crc" : "",
strb & SB_DTERR ? " dterr" : "");
- m_strb &= ~(SB_HERR|SB_WERR|SB_SERR|SB_SAERR|SB_DMERR|SB_CRC|SB_DTERR);
+ m_strb &= ~(SB_HERR|SB_WERR|SB_SERR|SB_DMERR|SB_CRC|SB_DTERR);
+ if(!(m_stra & SA_BUSY))
+ m_strb &= ~SB_SAERR;
if(m_strb == 0)
- m_isr &= 0x7;
+ isr_lower(I_STRB);
}
return strb;
}
@@ -262,34 +312,34 @@ u8 mc6843_device::strb_r()
void mc6843_device::sar_w(u8 data)
{
m_sar = data & 0x1f;
- logerror("sar_w %02x\n", m_sar);
+ LOGMASKED(LOG_SETUP, "sar_w %02x\n", m_sar);
}
void mc6843_device::gcr_w(u8 data)
{
m_gcr = data & 0x7f;
- logerror("gcr_w %02x\n", m_gcr);
+ LOGMASKED(LOG_SETUP, "gcr_w %02x\n", m_gcr);
}
void mc6843_device::ccr_w(u8 data)
{
m_ccr = data & 3;
- logerror("ccr_w %02x\n", m_ccr);
+ LOGMASKED(LOG_SETUP, "ccr_w %02x\n", m_ccr);
}
void mc6843_device::ltar_w(u8 data)
{
m_ltar = data & 0x7f;
- logerror("ltar_w %02x\n", m_ltar);
+ LOGMASKED(LOG_SETUP, "ltar_w %02x\n", m_ltar);
}
void mc6843_device::index_callback(floppy_image_device *floppy, int state)
{
if(state) {
live_sync();
- logerror("idam %d\n", m_idam_turns);
if(m_idam_turns) {
m_idam_turns --;
+ LOGMASKED(LOG_LIVE, "idam %d\n", m_idam_turns);
if(!m_idam_turns) {
live_abort();
m_state = S_IDAM_NOT_FOUND;
@@ -319,7 +369,7 @@ void mc6843_device::command_start()
switch(m_cmr & 0xf) {
case C_STZ:
- logerror("Seek to track 0\n");
+ LOGMASKED(LOG_COMMAND, "Seek to track 0\n");
if(m_floppy)
m_floppy->dir_w(1);
m_stra |= SA_BUSY;
@@ -328,7 +378,7 @@ void mc6843_device::command_start()
break;
case C_SEK:
- logerror("Seek from track %d to %d\n", m_ctar, m_gcr);
+ LOGMASKED(LOG_COMMAND, "Seek from track %u to %u\n", m_ctar, m_gcr);
if(m_gcr > m_ctar) {
if(m_floppy)
m_floppy->dir_w(0);
@@ -351,7 +401,7 @@ void mc6843_device::command_start()
m_stra &= ~(SA_DDM|SA_TNEQ);
m_strb &= ~SB_DMERR;
if(m_strb == 0)
- m_isr &= 0x7;
+ isr_lower(I_STRB);
m_state = S_SRW_WAIT_READY;
break;
@@ -401,14 +451,20 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
switch(m_state) {
case S_IDLE:
+ if(timeout) {
+ LOGMASKED(LOG_LIVE, "%s: Head unloaded (idle timeout)\n", machine().time().to_string());
+ m_head_loaded = false;
+ }
return;
case S_STZ_STEP:
- if(m_floppy && !m_floppy->trk00_r()) {
+ if(m_floppy && m_floppy->trk00_r()) {
m_floppy->stp_w(0);
m_floppy->stp_w(1);
}
m_step_count --;
+ if(m_floppy)
+ LOGMASKED(LOG_LIVE, "%s: %s track 0; %d steps left\n", machine().time().to_string(), m_floppy->trk00_r() ? "Seek" : "Found", m_step_count);
m_state = S_STZ_STEP_WAIT;
delay(1024 * (m_sur >> 4));
return;
@@ -418,7 +474,13 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
return;
if(m_step_count)
m_state = S_STZ_STEP;
- else {
+ else if(!m_floppy || m_floppy->trk00_r()) {
+ m_strb |= SB_SERR;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_SCE | I_STRB);
+ return;
+ } else {
m_ctar = m_gcr = 0;
m_state = S_STZ_HEAD_SETTLING;
delay(4096 * (m_sur & 15));
@@ -441,6 +503,7 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_floppy->stp_w(1);
}
m_step_count --;
+ LOGMASKED(LOG_LIVE, "%s: Seek: %d steps left\n", machine().time().to_string(), m_step_count);
m_state = S_SEEK_STEP_WAIT;
delay(1024 * (m_sur >> 4));
return;
@@ -518,6 +581,7 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_stra &= ~SA_BUSY;
m_state = S_IDLE;
isr_raise(I_RWCE);
+ delay(4096 * (m_sur & 15));
return;
case S_IDAM_BAD_CRC:
@@ -525,10 +589,11 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_stra &= ~SA_BUSY;
m_state = S_IDLE;
isr_raise(I_RWCE | I_STRB);
+ delay(4096 * (m_sur & 15));
return;
case S_IDAM_FOUND:
- if(m_cmr & 0x20)
+ if(!(m_cmr & 0x20))
isr_raise(I_SSR);
if((m_cmr & 0xf) == C_SSR || (m_cmr & 0xf) == C_MSR || (m_cmr & 0xf) == C_RCR)
live_start(L_DAM_SEARCH);
@@ -544,7 +609,8 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_strb |= SB_SAERR;
m_state = S_IDLE;
isr_raise(I_RWCE | I_STRB);
- logerror("not found\n");
+ LOGMASKED(LOG_LIVE, "not found\n");
+ delay(4096 * (m_sur & 15));
return;
case S_DAM_NOT_FOUND:
@@ -552,6 +618,7 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_stra &= ~SA_BUSY;
m_state = S_IDLE;
isr_raise(I_RWCE | I_STRB);
+ delay(4096 * (m_sur & 15));
return;
case S_DAM_BAD_CRC:
@@ -559,6 +626,7 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_stra &= ~SA_BUSY;
m_state = S_IDLE;
isr_raise(I_RWCE | I_STRB);
+ delay(4096 * (m_sur & 15));
return;
case S_DAM_DONE:
@@ -574,6 +642,7 @@ void mc6843_device::run(bool timeout, bool ready, bool index)
m_stra &= ~SA_BUSY;
m_state = S_IDLE;
isr_raise(I_RWCE);
+ delay(4096 * (m_sur & 15));
return;
}
}
@@ -621,14 +690,12 @@ void mc6843_device::live_sync()
{
if(m_cur_live.state != L_IDLE && !m_cur_live.tm.is_never()) {
if(m_cur_live.tm > machine().time()) {
- if(0)
- logerror("%s: Rolling back and replaying (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ LOGMASKED(LOG_LIVE, "%s: Rolling back and replaying (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
rollback();
live_run(machine().time());
m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
} else {
- if(0)
- logerror("%s: Committing (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ LOGMASKED(LOG_LIVE, "%s: Committing (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
if(m_cur_live.next_state != -1) {
m_cur_live.state = m_cur_live.next_state;
@@ -717,8 +784,7 @@ void mc6843_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- if(0)
- logerror("%s: shift = %04x data=%02x c=%d\n", m_cur_live.tm.to_string(), m_cur_live.shift_reg,
+ LOGMASKED(LOG_LIVE, "%s: shift = %04x data=%02x c=%d\n", m_cur_live.tm.to_string(), m_cur_live.shift_reg,
(m_cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(m_cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(m_cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -742,10 +808,11 @@ void mc6843_device::live_run(attotime limit)
return;
if(m_cur_live.bit_counter == 16) {
- logerror("%s IDAM track %d\n", m_cur_live.tm.to_string(), m_cur_live.data_reg);
+ LOGMASKED(LOG_RW, "%s IDAM track %u (ctar=%u)\n", m_cur_live.tm.to_string(), m_cur_live.data_reg, m_ctar);
if(m_cur_live.data_reg != m_ltar) {
m_state = S_IDAM_BAD_TRACK;
live_delay(L_IDLE);
+ m_idam_turns = 0;
return;
} else
@@ -758,7 +825,7 @@ void mc6843_device::live_run(attotime limit)
return;
if(m_cur_live.bit_counter == 48) {
- logerror("%s IDAM sector %d\n", m_cur_live.tm.to_string(), m_cur_live.data_reg);
+ LOGMASKED(LOG_RW, "%s IDAM sector %u (sar=%u)\n", m_cur_live.tm.to_string(), m_cur_live.data_reg, m_sar);
if(m_cur_live.data_reg != m_sar)
m_cur_live.state = L_IDAM_SEARCH;
else
@@ -771,11 +838,12 @@ void mc6843_device::live_run(attotime limit)
return;
if(m_cur_live.bit_counter == 96) {
- logerror("IDAM crc remainder %04x\n", m_cur_live.crc);
+ LOGMASKED(LOG_RW, "IDAM crc remainder %04x\n", m_cur_live.crc);
if(m_cur_live.crc)
m_state = S_IDAM_BAD_CRC;
else
m_state = S_IDAM_FOUND;
+ m_idam_turns = 0;
live_delay(L_IDLE);
return;
}
@@ -788,13 +856,13 @@ void mc6843_device::live_run(attotime limit)
if(m_cur_live.shift_reg == 0xf56a || m_cur_live.shift_reg == 0xf56f) {
m_cur_live.data_separator_phase = false;
m_cur_live.bit_counter = 0;
- logerror("DAM mark %02x\n", m_cur_live.data_reg);
+ LOGMASKED(LOG_RW, "DAM mark %02x\n", m_cur_live.data_reg);
if(m_cur_live.shift_reg == 0xf56f) {
- logerror("DAM found\n");
+ LOGMASKED(LOG_RW, "DAM found\n");
m_cur_live.crc = 0xbf84;
m_cur_live.state = L_DAM_READ;
} else {
- logerror("DDAM found\n");
+ LOGMASKED(LOG_RW, "DDAM found\n");
m_cur_live.crc = 0x8fe7;
live_delay(L_DAM_DELETED);
return;
@@ -819,7 +887,7 @@ void mc6843_device::live_run(attotime limit)
case L_DAM_READ_BYTE: {
int byte = m_cur_live.bit_counter >> 4;
- logerror("byte %02x = %02x crc %04x\n", byte, m_cur_live.data_reg, m_cur_live.crc);
+ LOGMASKED(LOG_RW, "byte %02x = %02x crc %04x\n", byte, m_cur_live.data_reg, m_cur_live.crc);
if(byte <= 128) {
if((m_cmr & 0xf) != C_RCR) {
if(m_dir_loaded)
@@ -919,7 +987,7 @@ void mc6843_device::live_run(attotime limit)
if(!m_dor_loaded)
m_strb |= SB_DTERR;
m_dor_loaded = false;
- logerror("write %02x\n", m_dor);
+ LOGMASKED(LOG_RW, "write %02x\n", m_dor);
if(m_cmr & 0x10) {
m_cur_live.shift_reg = m_dor << 8;
m_cur_live.bit_counter = 8;
diff --git a/src/devices/machine/mc6843.h b/src/devices/machine/mc6843.h
index b433e02dfe6..bc9728b4221 100644
--- a/src/devices/machine/mc6843.h
+++ b/src/devices/machine/mc6843.h
@@ -10,9 +10,10 @@
#pragma once
-#include "imagedev/floppy.h"
#include "fdc_pll.h"
+class floppy_image_device;
+
class mc6843_device : public device_t
{
public:
@@ -180,6 +181,7 @@ class mc6843_device : public device_t
void command_start();
void run(bool timeout, bool ready, bool index);
void isr_raise(u8 flag);
+ void isr_lower(u8 flag);
void delay(int);
void live_start(int state, bool start_writing = false);
void checkpoint();
diff --git a/src/devices/machine/pc97338.cpp b/src/devices/machine/pc97338.cpp
new file mode 100644
index 00000000000..a7ad2c0bb40
--- /dev/null
+++ b/src/devices/machine/pc97338.cpp
@@ -0,0 +1,387 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+National Semiconductor PC97338 Super I/O
+
+TODO:
+- PC87338 (no MTEST register, bunch of other small differences)
+- Eventually inherit from PC87306, emulate what's in between;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "pc97338.h"
+
+#define LOG_WARN (1U << 1) // Show warnings
+
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(PC97338, pc97338_device, "pc97338", "National Semiconductor PC97338 Super I/O")
+
+pc97338_device::pc97338_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PC97338, tag, owner, clock)
+ , device_isa16_card_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(pc97338_device::config_map), this))
+// , m_kbdc(*this, "pc_kbdc")
+// , m_rtc(*this, "rtc")
+ , m_pc_com(*this, "uart%d", 0U)
+ , m_pc_lpt(*this, "lpta")
+// , m_gp20_reset_callback(*this)
+// , m_gp25_gatea20_callback(*this)
+ , m_irq1_callback(*this)
+ , m_irq8_callback(*this)
+ , m_irq9_callback(*this)
+ , m_txd1_callback(*this)
+ , m_ndtr1_callback(*this)
+ , m_nrts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_ndtr2_callback(*this)
+ , m_nrts2_callback(*this)
+{ }
+
+void pc97338_device::device_start()
+{
+ set_isa_device();
+ //m_isa->set_dma_channel(0, this, true);
+ //m_isa->set_dma_channel(1, this, true);
+ //m_isa->set_dma_channel(2, this, true);
+ //m_isa->set_dma_channel(3, this, true);
+ remap(AS_IO, 0, 0x400);
+}
+
+void pc97338_device::device_reset()
+{
+ m_locked_state = 2;
+}
+
+device_memory_interface::space_config_vector pc97338_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+void pc97338_device::device_add_mconfig(machine_config &config)
+{
+ PC_LPT(config, m_pc_lpt);
+ m_pc_lpt->irq_handler().set(FUNC(pc97338_device::irq_parallel_w));
+
+ NS16550(config, m_pc_com[0], XTAL(1'843'200));
+ m_pc_com[0]->out_int_callback().set(FUNC(pc97338_device::irq_serial1_w));
+ m_pc_com[0]->out_tx_callback().set(FUNC(pc97338_device::txd_serial1_w));
+ m_pc_com[0]->out_dtr_callback().set(FUNC(pc97338_device::dtr_serial1_w));
+ m_pc_com[0]->out_rts_callback().set(FUNC(pc97338_device::rts_serial1_w));
+
+ NS16550(config, m_pc_com[1], XTAL(1'843'200));
+ m_pc_com[1]->out_int_callback().set(FUNC(pc97338_device::irq_serial2_w));
+ m_pc_com[1]->out_tx_callback().set(FUNC(pc97338_device::txd_serial2_w));
+ m_pc_com[1]->out_dtr_callback().set(FUNC(pc97338_device::dtr_serial2_w));
+ m_pc_com[1]->out_rts_callback().set(FUNC(pc97338_device::rts_serial2_w));
+}
+
+void pc97338_device::remap(int space_id, offs_t start, offs_t end)
+{
+ if (space_id == AS_IO)
+ {
+ // TODO: BADDR1/0 config pin controlled
+ u16 superio_base = 0x002e;
+ m_isa->install_device(superio_base, superio_base + 1, read8sm_delegate(*this, FUNC(pc97338_device::read)), write8sm_delegate(*this, FUNC(pc97338_device::write)));
+
+ if (BIT(m_fer, 0))
+ m_isa->install_device(0x378, 0x37f, read8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::write)));
+
+ if (BIT(m_fer, 1))
+ m_isa->install_device(0x3f8, 0x3ff, read8sm_delegate(*m_pc_com[0], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[0], FUNC(ns16450_device::ins8250_w)));
+
+ if (BIT(m_fer, 2))
+ m_isa->install_device(0x2f8, 0x2ff, read8sm_delegate(*m_pc_com[1], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[1], FUNC(ns16450_device::ins8250_w)));
+ }
+}
+
+u8 pc97338_device::read(offs_t offset)
+{
+ if (m_locked_state)
+ {
+ if (!machine().side_effects_disabled())
+ m_locked_state --;
+ return (m_locked_state) ? 0x88 : 0x00;
+ }
+
+ if (offset == 0)
+ return m_index;
+
+ return space().read_byte(m_index);
+}
+
+void pc97338_device::write(offs_t offset, u8 data)
+{
+ if (offset == 0)
+ {
+ m_index = data;
+ }
+ else
+ {
+ // TODO: two writes, first one just unlocks?
+ space().write_byte(m_index, data);
+ }
+}
+
+void pc97338_device::config_map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(pc97338_device::fer_r), FUNC(pc97338_device::fer_w));
+ map(0x01, 0x01).rw(FUNC(pc97338_device::far_r), FUNC(pc97338_device::far_w));
+// map(0x02, 0x02) PTR Power and Test Register
+// map(0x03, 0x03) FCR Function Control Register
+// map(0x04, 0x04) PCR Parallel port Control Register
+// map(0x05, 0x05).rw(FUNC(pc97338_device::krr_r), FUNC(pc97338_device::krr_w));
+// map(0x06, 0x06) PMC Power Management Control Register
+// map(0x07, 0x07) TUP Tape, UART and Parallel Port Configuration Register
+ // SID Super I/O Identification Register
+ // bits 7-3 -> 01110 TL/C/12379-27
+ // bits 2-0 ->
+ map(0x08, 0x08).lr8(
+ NAME([] (offs_t offset) { return 0xb0; })
+ );
+// map(0x09, 0x09) ASC Advanced Super I/O Configuration Register
+// map(0x0a, 0x0a) CS0LA Chip Select 0 Low Address
+// map(0x0b, 0x0b) CS0CF Chip Select 0 Configuration Address
+// map(0x0c, 0x0c) CS1LA Chip Select 1 Low Address
+// map(0x0d, 0x0d) CS1CF Chip Select 1 Configuration Address
+// map(0x0e, 0x0e) IRC InfraRed Configuration Register
+// map(0x0f, 0x0f) GPBA General Purpose I/O Port Base Address
+// map(0x10, 0x10) CS0HA Chip Select 0 High Address
+// map(0x11, 0x11) CS1HA Chip Select 1 High Address
+// map(0x12, 0x12) SCF0 Super I/O Configuration Register 0
+// map(0x18, 0x18) SCF1 Super I/O Configuration Register 1
+// map(0x19, 0x19)
+
+// map(0x1b, 0x1b) PNP0 Plug and Play Configuration 0 Register
+// map(0x1c, 0x1c) PNP1 Plug and Play Configuration 1 Register
+
+// map(0x40, 0x40) SCF2 Super I/O Configuration Register 2
+// map(0x41, 0x41) PNP2 PnP Configuration Register 2
+// map(0x42, 0x43) PBAL/PBAH Parallel Port Base Address Low/High Registers
+// map(0x44, 0x45) S1BAL/S1BAH SCC1 Base Address Low/High Registers
+// map(0x46, 0x47) S2BAL/S2BAH SCC2 Base Address Low/High Registers
+// map(0x48, 0x49) FBAL/FBAH FDC Base Address Low/High Registers
+// map(0x4a, 0x4b) SBAL/SBAH Super I/O Chip Base Address Low/High Registers
+// map(0x4c, 0x4e) SIRQ1/2/3 System IRQ Input Configuration Register
+// map(0x4f, 0x4f) PNP3 PnP Configuration Register 3
+
+// map(0x50, 0x50) SCF3 Super I/O Configuration Register 3
+// map(0x51, 0x51) CLK Clock Control Register
+// map(0x52, 0x52) MTEST Manufacturing Test Register (not present on '87338)
+}
+
+/*
+ * [0x00] FER Function Enable Register
+ * xx-- ----
+ * --x- ---- FDC address select
+ * ---x ---- (0) x2 floppy drives (1) x4 floppy drives
+ * ---- x--- FDC enable
+ * ---- -x-- UART2 enable
+ * ---- --x- UART1 enable
+ * ---- ---x Parallel Port enable
+ */
+u8 pc97338_device::fer_r(offs_t offset)
+{
+ return m_fer;
+}
+
+void pc97338_device::fer_w(offs_t offset, u8 data)
+{
+ m_fer = data;
+ remap(AS_IO, 0, 0x400);
+}
+
+/*
+ * [0x01] FAR Function Address Register
+ * xxxx ---- UART2 address select
+ * xx-- xx-- UART1 address select
+ * ---- --xx parallel address select
+ */
+u8 pc97338_device::far_r(offs_t offset)
+{
+ return m_far;
+}
+
+void pc97338_device::far_w(offs_t offset, u8 data)
+{
+ m_far = data;
+ remap(AS_IO, 0, 0x400);
+}
+
+/*
+ * Serial
+ */
+
+void pc97338_device::irq_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ request_irq(3, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void pc97338_device::irq_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ request_irq(4, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void pc97338_device::txd_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_txd1_callback(state);
+}
+
+void pc97338_device::txd_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_txd2_callback(state);
+}
+
+void pc97338_device::dtr_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_ndtr1_callback(state);
+}
+
+void pc97338_device::dtr_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_ndtr2_callback(state);
+}
+
+void pc97338_device::rts_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_nrts1_callback(state);
+}
+
+void pc97338_device::rts_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_nrts2_callback(state);
+}
+
+void pc97338_device::rxd1_w(int state)
+{
+ m_pc_com[0]->rx_w(state);
+}
+
+void pc97338_device::ndcd1_w(int state)
+{
+ m_pc_com[0]->dcd_w(state);
+}
+
+void pc97338_device::ndsr1_w(int state)
+{
+ m_pc_com[0]->dsr_w(state);
+}
+
+void pc97338_device::nri1_w(int state)
+{
+ m_pc_com[0]->ri_w(state);
+}
+
+void pc97338_device::ncts1_w(int state)
+{
+ m_pc_com[0]->cts_w(state);
+}
+
+void pc97338_device::rxd2_w(int state)
+{
+ m_pc_com[1]->rx_w(state);
+}
+
+void pc97338_device::ndcd2_w(int state)
+{
+ m_pc_com[1]->dcd_w(state);
+}
+
+void pc97338_device::ndsr2_w(int state)
+{
+ m_pc_com[1]->dsr_w(state);
+}
+
+void pc97338_device::nri2_w(int state)
+{
+ m_pc_com[1]->ri_w(state);
+}
+
+void pc97338_device::ncts2_w(int state)
+{
+ m_pc_com[1]->cts_w(state);
+}
+
+/*
+ * Parallel
+ */
+
+void pc97338_device::irq_parallel_w(int state)
+{
+ if (!(BIT(m_fer, 0)))
+ return;
+ request_irq(5, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+void pc97338_device::request_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 1:
+ m_irq1_callback(state);
+ break;
+ case 3:
+ m_isa->irq3_w(state);
+ break;
+ case 4:
+ m_isa->irq4_w(state);
+ break;
+ case 5:
+ m_isa->irq5_w(state);
+ break;
+ case 6:
+ m_isa->irq6_w(state);
+ break;
+ case 7:
+ m_isa->irq7_w(state);
+ break;
+ case 8:
+ m_irq8_callback(state);
+ break;
+ case 9:
+ m_irq9_callback(state);
+ break;
+ case 10:
+ m_isa->irq10_w(state);
+ break;
+ case 11:
+ m_isa->irq11_w(state);
+ break;
+ case 12:
+ m_isa->irq12_w(state);
+ break;
+ case 14:
+ m_isa->irq14_w(state);
+ break;
+ case 15:
+ m_isa->irq15_w(state);
+ break;
+ }
+}
+
diff --git a/src/devices/machine/pc97338.h b/src/devices/machine/pc97338.h
new file mode 100644
index 00000000000..e7d5a45387d
--- /dev/null
+++ b/src/devices/machine/pc97338.h
@@ -0,0 +1,124 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_PC97336_H
+#define MAME_MACHINE_PC97336_H
+
+#pragma once
+
+#include "bus/isa/isa.h"
+//#include "machine/8042kbdc.h"
+//#include "machine/ds128x.h"
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+
+class pc97338_device : public device_t,
+ public device_isa16_card_interface,
+ public device_memory_interface
+{
+public:
+ pc97338_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~pc97338_device() {}
+
+ void remap(int space_id, offs_t start, offs_t end) override;
+
+// auto gp20_reset() { return m_gp20_reset_callback.bind(); }
+// auto gp25_gatea20() { return m_gp25_gatea20_callback.bind(); }
+ auto irq1() { return m_irq1_callback.bind(); }
+ auto irq8() { return m_irq8_callback.bind(); }
+ auto irq9() { return m_irq9_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto ndtr1() { return m_ndtr1_callback.bind(); }
+ auto nrts1() { return m_nrts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto ndtr2() { return m_ndtr2_callback.bind(); }
+ auto nrts2() { return m_nrts2_callback.bind(); }
+
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+private:
+ const address_space_config m_space_config;
+
+// required_device m_kbdc;
+// required_device m_rtc;
+ required_device_array m_pc_com;
+ required_device m_pc_lpt;
+
+// devcb_write_line m_gp20_reset_callback;
+// devcb_write_line m_gp25_gatea20_callback;
+ devcb_write_line m_irq1_callback;
+ devcb_write_line m_irq8_callback;
+ devcb_write_line m_irq9_callback;
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_ndtr1_callback;
+ devcb_write_line m_nrts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_ndtr2_callback;
+ devcb_write_line m_nrts2_callback;
+
+ void request_irq(int irq, int state);
+
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ void config_map(address_map &map) ATTR_COLD;
+
+ u8 far_r(offs_t offset);
+ void far_w(offs_t offset, u8 data);
+
+ u8 fer_r(offs_t offset);
+ void fer_w(offs_t offset, u8 data);
+
+// u8 keybc_status_r(offs_t offset);
+// void keybc_command_w(offs_t offset, u8 data);
+// u8 rtc_r(offs_t offset);
+// void rtc_w(offs_t offset, u8 data);
+//
+// void kbdp21_gp25_gatea20_w(int state);
+// void kbdp20_gp20_reset_w(int state);
+//
+// void irq_keyboard_w(int state);
+// void irq_mouse_w(int state);
+//
+// u8 krr_r(offs_t offset);
+// void krr_w(offs_t offset, u8 data);
+
+ void irq_parallel_w(int state);
+
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
+
+ u8 m_index = 0;
+
+ u8 m_locked_state = 2;
+// u8 m_krr = 0;
+ u8 m_fer = 0;
+ u8 m_far = 0;
+};
+
+
+DECLARE_DEVICE_TYPE(PC97338, pc97338_device);
+
+#endif // MAME_MACHINE_PC97336_H
diff --git a/src/devices/machine/sc16is741.cpp b/src/devices/machine/sc16is741.cpp
new file mode 100644
index 00000000000..5e82d2f37f2
--- /dev/null
+++ b/src/devices/machine/sc16is741.cpp
@@ -0,0 +1,1264 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*
+ I²C/SPI UART with 64-byte transmit and receive FIFOs
+
+ _______
+ VDD 1 |* | 16 XTAL1
+ A0 _CS 2 | | 15 XTAL2
+ A1 SI 3 | | 14 _RESET
+ n.c. SO 4 | | 13 RX
+ SCL SCLK 5 | | 12 TX
+ SDA VSS 6 | | 11 _CTS
+ _IRQ 7 | | 10 _RTS
+ I2C _SPI 8 |_______| 9 VSS
+
+ Partially software-compatible with the ubiquitous 16C450.
+
+ TODO:
+ * When are registers considered "read" for side effects?
+ * The rest of the registers
+ * The rest of the interrupts
+ * 9-bit mode
+ * Xon/Xoff handshaking
+ * Special character detect
+ * Loopback
+ * Break detection
+ * IrDA mode
+ * I²C interface
+ * Sleep mode
+ * SC16IS741 differences
+ */
+#include "emu.h"
+#include "sc16is741.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+
+namespace {
+
+#define IER_CTS_INT() (BIT(m_ier, 7))
+#define IER_RTS_INT() (BIT(m_ier, 6))
+#define IER_XOFF_INT() (BIT(m_ier, 5))
+#define IER_SLEEP_MODE() (BIT(m_ier, 4))
+#define IER_MODEM_STATUS_INT() (BIT(m_ier, 3))
+#define IER_LINE_STATUS_INT() (BIT(m_ier, 2))
+#define IER_THR_INT() (BIT(m_ier, 1))
+#define IER_RHR_INT() (BIT(m_ier, 0))
+
+#define FCR_RX_TRIGGER() (BIT(m_fcr, 6, 2))
+#define FCR_TX_TRIGGER() (BIT(m_fcr, 4, 2))
+#define FCR_FIFO_ENABLE() (BIT(m_fcr, 0))
+
+#define LCR_DL_ENABLE() (BIT(m_lcr, 7))
+#define LCR_BREAK() (BIT(m_lcr, 6))
+#define LCR_SET_PARITY() (BIT(m_lcr, 5))
+#define LCR_EVEN_PARITY() (BIT(m_lcr, 4))
+#define LCR_PARITY_ENABLE() (BIT(m_lcr, 3))
+#define LCR_STOP_BIT() (BIT(m_lcr, 2))
+
+#define MCR_CLOCK_DIV4() (BIT(m_mcr, 7))
+#define MCR_TCR_TLR_ENABLE() (BIT(m_mcr, 2))
+
+#define TCR_LEVEL_RESUME() (BIT(m_tcr, 4, 4))
+#define TCR_LEVEL_HALT() (BIT(m_tcr, 0, 4))
+
+#define EFR_AUTO_CTS() (BIT(m_efr, 7))
+#define EFR_AUTO_RTS() (BIT(m_efr, 6))
+#define EFR_ENHANCED() (BIT(m_efr, 4))
+
+
+constexpr u8 RX_TRIGGER_LEVELS[4] = { 8, 16, 56, 60 };
+constexpr u8 TX_TRIGGER_LEVELS[4] = { 8, 16, 32, 56 };
+
+char const *const SOFT_FLOW_CONTROL_DESC[16] = {
+ "no soft transmit flow control, no soft receive flow control",
+ "no soft transmit flow control, receiver compares Xon2, Xoff2",
+ "no soft transmit flow control, receiver compares Xon1, Xoff1",
+ "no soft transmit flow control, receiver compares Xon1 and Xon2, Xoff1 and Xoff2",
+ "transmit Xon2, Xoff2, no soft receive flow control",
+ "transmit Xon2, Xoff2, receiver compares Xon2, Xoff2",
+ "transmit Xon2, Xoff2, receiver compares Xon1, Xoff1",
+ "transmit Xon2, Xoff2, receiver compares Xon1 or Xon2, Xoff1 or Xoff2",
+ "transmit Xon1, Xoff1, no soft receive flow control",
+ "transmit Xon1, Xoff1, receiver compares Xon2, Xoff2",
+ "transmit Xon1, Xoff1, receiver compares Xon1, Xoff1",
+ "transmit Xon1, Xoff1, receiver compares Xon1 or Xon2, Xoff1 or Xoff2",
+ "transmit Xon1 and Xon2, Xoff1 and Xoff2, no soft receive flow control",
+ "transmit Xon1 and Xon2, Xoff1 and Xoff2, receiver compares Xon2, Xoff2",
+ "transmit Xon1 and Xon2, Xoff1 and Xoff2, receiver compares Xon1, Xoff1",
+ "transmit Xon1 and Xon2, Xoff1 and Xoff2, receiver compares Xon1 and Xon2, Xoff1 and Xoff2" };
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE(SC16IS741A, sc16is741a_device, "sc16is741a", "NXP SC16IS741A UART")
+
+
+ALLOW_SAVE_TYPE(sc16is741a_device::phase);
+
+enum class sc16is741a_device::phase : u8
+{
+ IDLE,
+ COMMAND,
+ WRITE,
+ READ
+};
+
+
+enum class sc16is741a_device::parity : u8
+{
+ NONE,
+ ODD,
+ EVEN,
+ MARK,
+ SPACE
+};
+
+
+enum sc16is741a_device::interrupt : u8
+{
+ INTERRUPT_LINE_STATUS = 0x80,
+ INTERRUPT_RX_TIMEOUT = 0x40,
+ INTERRUPT_RHR = 0x20,
+ INTERRUPT_THR = 0x10,
+ INTERRUPT_MODEM_STATUS = 0x08,
+ INTERRUPT_XOFF = 0x04,
+ INTERRUPT_SPECIAL_CHAR = 0x02,
+ INTERRUPT_CTS_RTS = 0x01
+};
+
+
+sc16is741a_device::sc16is741a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SC16IS741A, tag, owner, clock),
+ m_so_cb(*this),
+ m_irq_cb(*this),
+ m_tx_cb(*this),
+ m_rts_cb(*this),
+ m_shift_timer{ nullptr, nullptr },
+ m_rx_timeout_timer(nullptr)
+{
+}
+
+sc16is741a_device::~sc16is741a_device()
+{
+}
+
+
+void sc16is741a_device::sclk_w(int state)
+{
+ if ((phase::COMMAND == m_phase) || (phase::WRITE == m_phase))
+ {
+ if (state && !m_sclk)
+ {
+ m_buffer = (m_buffer << 1) | m_si;
+ if (!--m_bits)
+ {
+ if (phase::COMMAND == m_phase)
+ {
+ m_command = m_buffer;
+ if (BIT(m_buffer, 7))
+ {
+ m_phase = phase::READ;
+ reg_r(true);
+ }
+ else
+ {
+ m_phase = phase::WRITE;
+ }
+ }
+ else
+ {
+ reg_w();
+ }
+ m_bits = 8;
+ }
+ }
+ }
+ else if (phase::READ == m_phase)
+ {
+ if (!state && m_sclk)
+ {
+ m_so_cb(BIT(m_buffer, 7));
+ }
+ else if (state && !m_sclk)
+ {
+ m_buffer = (m_buffer << 1) | (m_buffer >> 7);
+ --m_bits;
+ if (!m_bits)
+ {
+ reg_r(false);
+ m_bits = 8;
+ }
+ else if (7 == m_bits)
+ {
+ if ((BIT(m_command, 3, 4) == 0x00) && ((0xbf == m_lcr) || !LCR_DL_ENABLE()))
+ pop_rx_fifo();
+ }
+ }
+ }
+ m_sclk = state ? 1 : 0;
+}
+
+void sc16is741a_device::cs_w(int state)
+{
+ if (state)
+ {
+ m_phase = phase::IDLE;
+ m_so_cb(1);
+ }
+ else if (m_cs)
+ {
+ m_phase = phase::COMMAND;
+ m_bits = 8;
+ }
+ m_cs = state ? 1 : 0;
+}
+
+void sc16is741a_device::si_w(int state)
+{
+ m_si = state ? 1 : 0;
+}
+
+void sc16is741a_device::rx_w(int state)
+{
+ if (m_divisor) // FIXME: check EFCR[1]
+ {
+ if (!m_rx_remain)
+ {
+ if (m_rx && !state)
+ {
+ // start bit
+ m_rx_remain = m_rx_intervals;
+ m_rx_count = 0;
+ m_shift_timer[0]->adjust(attotime::from_ticks(m_divisor * 16 / 2, clock()));
+ }
+ }
+ else if (!m_rx_count)
+ {
+ if (state)
+ {
+ // false start
+ m_rx_remain = 0;
+ m_shift_timer[0]->reset();
+ }
+ }
+ }
+ m_rx = state ? 1 : 0;
+}
+
+void sc16is741a_device::cts_w(int state)
+{
+ bool const asserted(EFR_AUTO_CTS() && !state && m_cts);
+ if (bool(state) != bool(m_cts))
+ {
+ m_interrupts |= INTERRUPT_MODEM_STATUS;
+ if (state && IER_CTS_INT() && !(m_interrupts & INTERRUPT_CTS_RTS))
+ {
+ LOG("CTS deasserted, setting CTS interrupt\n");
+ m_interrupts |= INTERRUPT_CTS_RTS;
+ }
+ update_irq();
+ }
+ m_cts = state ? 1 : 0;
+ if (asserted)
+ check_tx();
+}
+
+
+void sc16is741a_device::device_resolve_objects()
+{
+ m_tx = 1;
+ m_rx = 1;
+ m_cts = 0;
+ m_sclk = 0;
+ m_cs = 1;
+ m_si = 1;
+ m_bits = 0;
+ m_buffer = 0;
+}
+
+void sc16is741a_device::device_start()
+{
+ m_shift_timer[0] = timer_alloc(FUNC(sc16is741a_device::rx_shift), this);
+ m_shift_timer[1] = timer_alloc(FUNC(sc16is741a_device::tx_shift), this);
+ m_rx_timeout_timer = timer_alloc(FUNC(sc16is741a_device::rx_timeout), this);
+
+ m_spr = 0x00;
+ m_dl = 0x0000;
+ std::fill(std::begin(m_xon_xoff), std::end(m_xon_xoff), 0);
+ m_tx_count = 0;
+ m_rx_count = 0;
+ for (auto &data : m_fifo_data)
+ std::fill(std::begin(data), std::end(data), 0);
+ m_divisor = 0;
+
+ save_item(NAME(m_irq));
+ save_item(NAME(m_tx));
+ save_item(NAME(m_rts));
+ save_item(NAME(m_rx));
+ save_item(NAME(m_cts));
+ save_item(NAME(m_sclk));
+ save_item(NAME(m_cs));
+ save_item(NAME(m_si));
+ save_item(NAME(m_phase));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_buffer));
+ save_item(NAME(m_command));
+ save_item(NAME(m_ier));
+ save_item(NAME(m_fcr));
+ save_item(NAME(m_lcr));
+ save_item(NAME(m_mcr));
+ save_item(NAME(m_spr));
+ save_item(NAME(m_tcr));
+ save_item(NAME(m_tlr));
+ save_item(NAME(m_dl));
+ save_item(NAME(m_efr));
+ save_item(NAME(m_xon_xoff));
+ save_item(NAME(m_shift_reg));
+ save_item(NAME(m_rx_remain));
+ save_item(NAME(m_rx_count));
+ save_item(NAME(m_tx_remain));
+ save_item(NAME(m_tx_count));
+ save_item(NAME(m_fifo_head));
+ save_item(NAME(m_fifo_tail));
+ save_item(NAME(m_fifo_empty));
+ save_item(NAME(m_fifo_data));
+ save_item(NAME(m_fifo_errors));
+ save_item(NAME(m_interrupts));
+}
+
+void sc16is741a_device::device_reset()
+{
+ m_shift_timer[0]->reset();
+ m_shift_timer[1]->reset();
+ m_rx_timeout_timer->reset();
+
+ m_phase = phase::IDLE;
+
+ m_ier = 0x00;
+ m_fcr = 0x00;
+ m_lcr = 0x1d;
+ m_mcr = 0x00;
+ m_tcr = 0x00;
+ m_tlr = 0x00;
+ m_efr = 0x00;
+
+ std::fill(std::begin(m_shift_reg), std::end(m_shift_reg), 0xffff);
+ m_rx_remain = 0;
+ m_tx_remain = 0;
+
+ std::fill(std::begin(m_fifo_tail), std::end(m_fifo_tail), 0);
+ fifo_reset(0);
+ fifo_reset(1);
+ m_fifo_errors = 0;
+
+ m_interrupts = 0x00;
+
+ update_trigger_levels();
+ update_data_frame();
+ update_divisor();
+
+ m_irq_cb(m_irq = CLEAR_LINE);
+ m_tx_cb(m_tx = 1);
+ m_rts_cb(m_rts = 1);
+}
+
+void sc16is741a_device::device_post_load()
+{
+ update_trigger_levels();
+ update_data_frame();
+ update_divisor();
+}
+
+
+inline void sc16is741a_device::update_irq()
+{
+ bool const pending(
+ (IER_LINE_STATUS_INT() && (m_interrupts & INTERRUPT_LINE_STATUS)) ||
+ (IER_MODEM_STATUS_INT() && (m_interrupts & INTERRUPT_MODEM_STATUS)) ||
+ (IER_RHR_INT() && (m_interrupts & (INTERRUPT_RX_TIMEOUT | INTERRUPT_RHR))) ||
+ ((IER_CTS_INT() || IER_RTS_INT()) && (m_interrupts & INTERRUPT_CTS_RTS)));
+ if (pending != (ASSERT_LINE == m_irq))
+ {
+ LOG(pending ? "asserting IRQ\n" : "deasserting IRQ\n");
+ m_irq_cb(m_irq = (pending ? ASSERT_LINE : CLEAR_LINE));
+ }
+}
+
+inline void sc16is741a_device::update_tx()
+{
+ u8 const state(LCR_BREAK() ? 0 : BIT(m_shift_reg[1], 0));
+ if (state != m_tx)
+ m_tx_cb(m_tx = state);
+}
+
+inline void sc16is741a_device::set_rts(u8 state)
+{
+ if (state != m_rts)
+ m_rts_cb(m_rts = state);
+}
+
+
+inline void sc16is741a_device::reg_r(bool first)
+{
+ u8 const ch(BIT(m_command, 1, 2));
+ u8 const addr(BIT(m_command, 3, 4));
+
+ // must be zero
+ if (0 != ch)
+ {
+ if (first)
+ logerror("read from unsupported ch %1$u register address 0x%2$02x\n", ch, addr);
+ m_buffer = 0xff;
+ return;
+ }
+
+ switch (addr)
+ {
+ case 0x00:
+ if ((0xbf != m_lcr) && LCR_DL_ENABLE())
+ m_buffer = BIT(m_dl, 0, 8);
+ else
+ m_buffer = m_fifo_data[0][m_fifo_tail[0]];
+ return;
+ case 0x01:
+ if ((0xbf != m_lcr) && LCR_DL_ENABLE())
+ m_buffer = BIT(m_dl, 8, 8);
+ else
+ m_buffer = m_ier;
+ return;
+ case 0x02:
+ if (0xbf == m_lcr)
+ m_buffer = m_efr;
+ else
+ iir_r(first);
+ return;
+ case 0x03:
+ m_buffer = m_lcr;
+ return;
+ case 0x04:
+ if (0xbf == m_lcr)
+ xon_xoff_r(first);
+ else
+ m_buffer = m_mcr;
+ return;
+ case 0x05:
+ if (0xbf == m_lcr)
+ xon_xoff_r(first);
+ else
+ lsr_r(first);
+ return;
+ case 0x06:
+ if (0xbf == m_lcr)
+ xon_xoff_r(first);
+ else if (MCR_TCR_TLR_ENABLE() && EFR_ENHANCED())
+ m_buffer = m_tcr;
+ else
+ msr_r(first);
+ return;
+ case 0x07:
+ if (0xbf == m_lcr)
+ xon_xoff_r(first);
+ else if (MCR_TCR_TLR_ENABLE() && EFR_ENHANCED())
+ m_buffer = m_tcr;
+ else
+ m_buffer = m_spr;
+ return;
+ case 0x08:
+ txlvl_r(first);
+ return;
+ case 0x09:
+ rxlvl_r(first);
+ return;
+ }
+
+ if (first)
+ logerror("read from unimplemented register address 0x%1$02x\n", addr);
+ m_buffer = 0xff;
+}
+
+inline void sc16is741a_device::reg_w()
+{
+ u8 const ch(BIT(m_command, 1, 2));
+ u8 const addr(BIT(m_command, 3, 4));
+
+ // must be zero
+ if (0 != ch)
+ {
+ logerror("write to unsupported ch %1$u register address 0x%2$02x = 0x%3$02x\n", ch, addr, m_buffer);
+ return;
+ }
+
+ switch (addr)
+ {
+ case 0x00:
+ if ((0xbf != m_lcr) && LCR_DL_ENABLE())
+ dl_w();
+ else
+ thr_w();
+ return;
+ case 0x01:
+ if ((0xbf != m_lcr) && LCR_DL_ENABLE())
+ dl_w();
+ else
+ ier_w();
+ return;
+ case 0x02:
+ if (0xbf == m_lcr)
+ efr_w();
+ else
+ fcr_w();
+ return;
+ case 0x03:
+ lcr_w();
+ return;
+ case 0x04:
+ if (0xbf == m_lcr)
+ xon_xoff_w();
+ else
+ mcr_w();
+ return;
+ case 0x05:
+ if (0xbf == m_lcr)
+ xon_xoff_w();
+ else
+ break; // LSR is read-only
+ return;
+ case 0x06:
+ if (0xbf == m_lcr)
+ xon_xoff_w();
+ else if (MCR_TCR_TLR_ENABLE() && EFR_ENHANCED())
+ tcr_w();
+ else
+ break; // MSR is read-only
+ return;
+ case 0x07:
+ if (0xbf == m_lcr)
+ xon_xoff_w();
+ else if (MCR_TCR_TLR_ENABLE() && EFR_ENHANCED())
+ tlr_w();
+ else
+ m_spr = m_buffer;
+ return;
+ case 0x0d:
+ reserved_w();
+ return;
+ case 0x0e:
+ uart_reset_w();
+ return;
+ }
+
+ logerror("write to unimplemented register address 0x%1$02x = 0x%2$02x\n", addr, m_buffer);
+}
+
+
+inline void sc16is741a_device::iir_r(bool first)
+{
+ if (first)
+ {
+ m_buffer = BIT(m_fcr, 0) ? 0xc0 : 0x00;
+ if (!m_irq)
+ {
+ m_buffer |= 0x01;
+ }
+ else if (IER_LINE_STATUS_INT() && (m_interrupts & INTERRUPT_LINE_STATUS))
+ {
+ m_buffer |= 0x06;
+ }
+ else if (IER_RHR_INT() && (m_interrupts & INTERRUPT_RX_TIMEOUT))
+ {
+ m_buffer |= 0x0c;
+ }
+ else if (IER_RHR_INT() && (m_interrupts & INTERRUPT_RHR))
+ {
+ m_buffer |= 0x04;
+ }
+ else if (IER_THR_INT() && (m_interrupts & INTERRUPT_THR))
+ {
+ m_buffer |= 0x02;
+
+ LOG("clearing THR interrupt\n");
+ m_interrupts &= ~INTERRUPT_THR;
+ }
+ else if (IER_MODEM_STATUS_INT() && (m_interrupts & INTERRUPT_MODEM_STATUS))
+ {
+ m_buffer |= 0x00;
+ }
+ else if ((IER_CTS_INT() || IER_RTS_INT()) && (m_interrupts & INTERRUPT_CTS_RTS))
+ {
+ m_buffer |= 0x20;
+
+ LOG("clearing CTS/RTS interrupt\n");
+ m_interrupts &= ~INTERRUPT_CTS_RTS;
+ }
+
+ LOG("read IIR (0x%1$02x)\n", m_buffer);
+ }
+}
+
+inline void sc16is741a_device::lsr_r(bool first)
+{
+ m_buffer =
+ (m_fifo_errors ? 0x80 : 0x00) |
+ ((m_fifo_empty[1] && !m_tx_remain) ? 0x40 : 0x00) |
+ (m_fifo_empty[1] ? 0x20 : 0x00) |
+ (!m_fifo_empty[0] ? 0x01 : 0x00);
+ if (!m_fifo_empty[0])
+ m_buffer |= m_fifo_data[1][m_fifo_tail[0]];
+
+ if (first)
+ LOG("read LSR (0x%1$02x)\n", m_buffer);
+}
+
+inline void sc16is741a_device::msr_r(bool first)
+{
+ if (first)
+ {
+ m_buffer =
+ (!m_cts ? 0x10 : 0x00) |
+ ((m_interrupts & INTERRUPT_MODEM_STATUS) ? 0x01 : 0x00);
+ m_interrupts &= ~INTERRUPT_MODEM_STATUS;
+
+ LOG("read MSR (0x%1$02x)\n", m_buffer);
+ }
+}
+
+inline void sc16is741a_device::txlvl_r(bool first)
+{
+ m_buffer = fifo_spaces(1);
+
+ if (first)
+ LOG("read TXLVL (0x%1$02x)\n", m_buffer);
+}
+
+inline void sc16is741a_device::rxlvl_r(bool first)
+{
+ m_buffer = fifo_fill_level(0);
+
+ if (first)
+ LOG("read RXLVL (0x%1$02x)\n", m_buffer);
+}
+
+inline void sc16is741a_device::xon_xoff_r(bool first)
+{
+ m_buffer = m_xon_xoff[BIT(m_command, 3, 2)];
+
+ if (first)
+ LOG("read %1$s%2$u (0x%3$02x)\n", BIT(m_command, 4) ? "XOFF" : "XON", BIT(m_command, 3) + 1, m_buffer);
+}
+
+
+inline void sc16is741a_device::thr_w()
+{
+ m_fifo_data[2][fifo_push(1)] = m_buffer;
+
+ if (m_interrupts & INTERRUPT_THR)
+ {
+ LOG("THR written, clearing THR interrupt\n");
+ m_interrupts &= ~INTERRUPT_THR;
+ }
+
+ check_tx();
+ update_irq(); // doing this here avoids a glitch if the FIFO is immediately popped
+}
+
+inline void sc16is741a_device::ier_w()
+{
+ LOG(EFR_ENHANCED()
+ ? "IER = 0x%1$02x (CTS interrupt %2$s, RTS interrupt %3$s, Xoff interrupt %4$s, sleep mode %5$s, modem status interrupt %6$s, RX status interrupt %7$s, THR interrupt %8$s, RHR interrupt %9$s)\n"
+ : "IER = 0x%1$02x (modem status interrupt %6$s, RX status interrupt %7$s, THR interrupt %8$s, RHR interrupt %9$s)\n",
+ m_buffer & (EFR_ENHANCED() ? 0xff : 0x0f),
+ BIT(m_buffer, 7) ? "enabled" : "disabled",
+ BIT(m_buffer, 6) ? "enabled" : "disabled",
+ BIT(m_buffer, 5) ? "enabled" : "disabled",
+ BIT(m_buffer, 4) ? "enabled" : "disabled",
+ BIT(m_buffer, 3) ? "enabled" : "disabled",
+ BIT(m_buffer, 2) ? "enabled" : "disabled",
+ BIT(m_buffer, 1) ? "enabled" : "disabled",
+ BIT(m_buffer, 0) ? "enabled" : "disabled");
+
+ if (EFR_ENHANCED())
+ m_ier = m_buffer;
+ else
+ m_ier = (m_ier & 0xf0) | (m_buffer & 0x0f);
+ update_irq();
+}
+
+inline void sc16is741a_device::fcr_w()
+{
+ LOG(EFR_ENHANCED()
+ ? "FCR = 0x%1$02x (RX trigger %2$u, TX trigger %3$u, reserved %4$u, %5$sTX FIFO reset, %6$sRX FIFO reset, FIFO %7$s)\n"
+ : "FCR = 0x%1$02x (RX trigger %2$u, reserved %4$u, %5$sTX FIFO reset, %6$sRX FIFO reset, FIFO %7$s)\n",
+ m_buffer & (EFR_ENHANCED() ? 0xff : 0xcf),
+ RX_TRIGGER_LEVELS[BIT(m_buffer, 6, 2)],
+ TX_TRIGGER_LEVELS[BIT(m_buffer, 4, 2)],
+ BIT(m_buffer, 3),
+ BIT(m_buffer, 2) ? "" : "no ",
+ BIT(m_buffer, 1) ? "" : "no ",
+ BIT(m_buffer, 0) ? "enabled" : "disabled");
+
+ if (BIT(m_buffer, 3))
+ logerror("reserved bit FCR[3] is set\n");
+
+ if (BIT(m_buffer, 2))
+ fifo_reset(1);
+
+ if (BIT(m_buffer, 1))
+ {
+ fifo_reset(0);
+ m_fifo_errors = 0;
+ m_interrupts &= ~(INTERRUPT_LINE_STATUS | INTERRUPT_RX_TIMEOUT | INTERRUPT_RHR);
+ if (EFR_AUTO_RTS() && m_rts) // FIXME: check EFCR[4]
+ {
+ LOG("RX FIFO reset, asserting RTS\n");
+ set_rts(0);
+ }
+ update_irq();
+ }
+
+ if (EFR_ENHANCED())
+ m_fcr = m_buffer & 0xf9;
+ else
+ m_fcr = (m_fcr & 0x30) | (m_buffer & 0xc9);
+ update_trigger_levels();
+}
+
+inline void sc16is741a_device::lcr_w()
+{
+ LOG("LCR = 0x%1$02x (divisor latch %2$s, %3$sbreak, %4$s parity %5$s, %6$s stop bits, word length %7$u)\n",
+ m_buffer,
+ BIT(m_buffer, 7) ? "enabled" : "disabled",
+ BIT(m_buffer, 6) ? "" : "no ",
+ BIT(m_buffer, 5) ? (BIT(m_buffer, 4) ? "0" : "1") : (BIT(m_buffer, 4) ? "even" : "odd"),
+ BIT(m_buffer, 3) ? "on" : "off",
+ !BIT(m_buffer, 2) ? "1" : !BIT(m_buffer, 0, 2) ? "1.5" : "2",
+ BIT(m_buffer, 0, 2) + 5);
+
+ m_lcr = m_buffer;
+ update_tx();
+ update_data_frame();
+}
+
+inline void sc16is741a_device::mcr_w()
+{
+ LOG(EFR_ENHANCED()
+ ? "MCR = 0x%1$02x (divide-by-%2$u, %3$s mode, Xon Any %4$s, loopback %5$s, reserved %6$u, TCR and TLR %7$s, RTS %8$s, reserved %9$u)\n"
+ : "MCR = 0x%1$02x (loopback %5$s, reserved %6$u, TCR and TLR %7$s, RTS %8$s, reserved %9$u)\n",
+ m_buffer & (EFR_ENHANCED() ? 0xff : 0x1f),
+ BIT(m_buffer, 7) ? 4 : 1,
+ BIT(m_buffer, 6) ? "IrDA" : "normal UART",
+ BIT(m_buffer, 5) ? "enabled" : "disabled",
+ BIT(m_buffer, 4) ? "enabled" : "disabled",
+ BIT(m_buffer, 3),
+ BIT(m_buffer, 2) ? "enabled" : "disabled",
+ BIT(m_buffer, 1) ? "active" : "inactive",
+ BIT(m_buffer, 0));
+
+ if (BIT(m_buffer, 3))
+ logerror("reserved bit MCR[3] is set\n");
+ if (BIT(m_buffer, 0))
+ logerror("reserved bit MCR[0] is set\n");
+
+ if (!EFR_AUTO_RTS()) // FIXME: check EFCR[4]
+ set_rts(BIT(~m_buffer, 1));
+
+ if (EFR_ENHANCED())
+ {
+ m_mcr = m_buffer;
+ update_divisor();
+ }
+ else
+ {
+ m_mcr = (m_mcr & 0xe0) | (m_buffer & 0x1f);
+ }
+}
+
+inline void sc16is741a_device::tcr_w()
+{
+ LOG("TCR = 0x%1$02x (resume transmission at %2$u*4 characters, halt transmission at %3$u*4 characters)\n",
+ m_buffer,
+ BIT(m_buffer, 4, 4),
+ BIT(m_buffer, 0, 4));
+
+ m_tcr = m_buffer;
+}
+
+inline void sc16is741a_device::tlr_w()
+{
+ LOG("TLR = 0x%1$02x (RX FIFO trigger level %2$u*4 characters%3$s, TX FIFO trigger level %4$u*4 spaces%5$s)\n",
+ m_buffer,
+ BIT(m_buffer, 4, 4),
+ BIT(m_buffer, 4, 4) ? "" : " - use FCR[7:6]",
+ BIT(m_buffer, 0, 4),
+ BIT(m_buffer, 0, 4) ? "" : " - use FCR[5:4]");
+
+ m_tlr = m_buffer;
+ update_trigger_levels();
+}
+
+inline void sc16is741a_device::reserved_w()
+{
+ logerror("reserved register address 0x%1$02x = 0x%2$02x\n", BIT(m_command, 3, 4), m_buffer);
+}
+
+inline void sc16is741a_device::uart_reset_w()
+{
+ LOG("UART reset = 0x%1$02x (reserved %2$u, reserved %3$u, reserved %4$u, reserved %5$u, %6$ssoftware reset, reserved %7$u, reserved %8$u, reserved %9$u)\n",
+ m_buffer,
+ BIT(m_buffer, 7),
+ BIT(m_buffer, 6),
+ BIT(m_buffer, 5),
+ BIT(m_buffer, 4),
+ BIT(m_buffer, 3) ? "" : "no ",
+ BIT(m_buffer, 2),
+ BIT(m_buffer, 1),
+ BIT(m_buffer, 0));
+
+ if (BIT(m_buffer, 7))
+ logerror("reserved bit UART reset[7] is set\n");
+ if (BIT(m_buffer, 6))
+ logerror("reserved bit UART reset[6] is set\n");
+ if (BIT(m_buffer, 5))
+ logerror("reserved bit UART reset[5] is set\n");
+ if (BIT(m_buffer, 4))
+ logerror("reserved bit UART reset[4] is set\n");
+ if (BIT(m_buffer, 2))
+ logerror("reserved bit UART reset[2] is set\n");
+ if (BIT(m_buffer, 1))
+ logerror("reserved bit UART reset[1] is set\n");
+ if (BIT(m_buffer, 0))
+ logerror("reserved bit UART reset[0] is set\n");
+
+ // TODO: is this instantaneous reset, or is the reset condition held until the bit is cleared?
+ if (BIT(m_buffer, 3))
+ device_reset();
+}
+
+inline void sc16is741a_device::dl_w()
+{
+ LOG("DL%1$c = 0x%2$02x\n", BIT(m_command, 3) ? 'H' : 'L', m_buffer);
+
+ m_dl = (m_dl & (BIT(m_command, 3) ? 0x00ff : 0xff00)) | (u16(m_buffer) << (BIT(m_command, 3) ? 8 : 0));
+ update_divisor();
+}
+
+inline void sc16is741a_device::efr_w()
+{
+ LOG("EFR = 0x%1$02x (CTS flow control %2$s, RTS flow control %3$s, special character detect %4$s, enhanced functions %5$s, %6$s)\n",
+ m_buffer,
+ BIT(m_buffer, 7) ? "enabled" : "disabled",
+ BIT(m_buffer, 6) ? "enabled" : "disabled",
+ BIT(m_buffer, 5) ? "enabled" : "disabled",
+ BIT(m_buffer, 4) ? "enabled" : "disabled",
+ SOFT_FLOW_CONTROL_DESC[BIT(m_buffer, 0, 4)]);
+
+ if (!BIT(m_buffer, 6)) // FIXME: check EFCR[4]
+ {
+ // auto RTS off, ensure RTS output is up-to-date
+ set_rts(BIT(~m_mcr, 1));
+ }
+ else if (!EFR_AUTO_RTS())
+ {
+ // enabling auto RTS
+ if (FCR_FIFO_ENABLE())
+ {
+ u8 const level(fifo_fill_level(0));
+ set_rts(((level <= (TCR_LEVEL_RESUME() * 4)) || (level < (TCR_LEVEL_HALT() * 4))) ? 0 : 1);
+ }
+ else
+ {
+ set_rts(m_fifo_empty[0] ? 0 : 1);
+ }
+ }
+
+ m_efr = m_buffer;
+ check_tx();
+}
+
+inline void sc16is741a_device::xon_xoff_w()
+{
+ LOG("%1$s%2$u = 0x%3$02x\n", BIT(m_command, 4) ? "XOFF" : "XON", BIT(m_command, 3) + 1, m_buffer);
+
+ m_xon_xoff[BIT(m_command, 3, 2)] = m_buffer;
+}
+
+
+inline void sc16is741a_device::pop_rx_fifo()
+{
+ assert(!m_fifo_empty[0] || !m_fifo_errors);
+
+ if (!m_fifo_empty[0] && m_fifo_data[1][m_fifo_tail[0]])
+ {
+ assert(m_fifo_errors);
+ assert(m_interrupts & INTERRUPT_LINE_STATUS);
+ if (!--m_fifo_errors)
+ {
+ LOG("read last data error, clearing line status interrupt\n");
+ m_interrupts &= ~INTERRUPT_LINE_STATUS;
+ update_irq();
+ }
+ }
+
+ fifo_pop(0);
+ u8 const level(fifo_fill_level(0));
+ if (m_fifo_empty[0])
+ m_rx_timeout_timer->reset();
+ else
+ m_rx_timeout_timer->adjust(attotime::from_ticks(m_divisor * 16 / 2 * 4 * m_rx_intervals, clock()));
+
+ if (m_interrupts & INTERRUPT_RX_TIMEOUT)
+ {
+ LOG("clearing RX timeout interrupt\n");
+ m_interrupts &= ~INTERRUPT_RX_TIMEOUT;
+ update_irq();
+ }
+
+ if (m_interrupts & INTERRUPT_RHR)
+ {
+ if (FCR_FIFO_ENABLE())
+ {
+ if (level < m_rx_trigger)
+ {
+ LOG("RX FIFO level %1$u within %2$u, clearing RHR interrupt\n", level, m_rx_trigger);
+ m_interrupts &= ~INTERRUPT_RHR;
+ update_irq();
+ }
+ }
+ else if (m_fifo_empty[0])
+ {
+ LOG("RHR empty, clearing RHR interrupt\n");
+ m_interrupts &= ~INTERRUPT_RHR;
+ update_irq();
+ }
+ }
+
+ if (EFR_AUTO_RTS() && m_rts) // FIXME: check EFCR[4]
+ {
+ if (FCR_FIFO_ENABLE())
+ {
+ u8 const trigger(TCR_LEVEL_RESUME());
+ if (level <= (trigger * 4))
+ {
+ LOG("RX FIFO level %1$u within %2$u*4, asserting RTS\n", level, trigger);
+ set_rts(0);
+ }
+ }
+ else
+ {
+ LOG("RHR empty, asserting RTS\n");
+ set_rts(0);
+ }
+ }
+}
+
+inline bool sc16is741a_device::check_tx()
+{
+ if (m_tx_remain || m_fifo_empty[1] || (EFR_AUTO_CTS() && m_cts) || !m_divisor) // FIXME: check EFCR[2]
+ return false;
+
+ u16 const data(u16(m_fifo_data[2][fifo_pop(1)] & util::make_bitmask(m_word_length)) << 1);
+ if (parity::NONE == m_parity)
+ {
+ m_shift_reg[1] = ~util::make_bitmask(m_word_length + 1) | data;
+ }
+ else
+ {
+ m_shift_reg[1] = ~util::make_bitmask(m_word_length + 2) | data;
+ switch (m_parity)
+ {
+ case parity::ODD:
+ m_shift_reg[1] |= BIT(~population_count_32(data), 0) << (m_word_length + 1);
+ break;
+ case parity::EVEN:
+ m_shift_reg[1] |= BIT(population_count_32(data), 0) << (m_word_length + 1);
+ break;
+ case parity::MARK:
+ m_shift_reg[1] |= u16(1) << (m_word_length + 1);
+ break;
+ default:
+ break;
+ }
+ }
+ m_tx_remain = m_tx_intervals;
+ m_tx_count = 0;
+ update_tx();
+ m_shift_timer[1]->adjust(attotime::from_ticks(m_divisor * 16 / 2, clock()));
+
+ if (IER_THR_INT() && !(m_interrupts & INTERRUPT_THR))
+ {
+ if (FCR_FIFO_ENABLE())
+ {
+ // TODO: does this only happen at the trigger level, or any time the FIFO is popped above the trigger level?
+ u8 const spaces(fifo_spaces(1));
+ if (spaces >= m_tx_trigger)
+ {
+ LOG("TX FIFO spaces %1$u exceed %2$u, setting THR interrupt\n", spaces, m_tx_trigger);
+ m_interrupts |= INTERRUPT_THR;
+ update_irq();
+ }
+ else
+ {
+ LOG("THR empty, setting THR interrupt\n");
+ m_interrupts |= INTERRUPT_THR;
+ update_irq();
+ }
+ }
+ }
+
+ return true;
+}
+
+
+inline u8 sc16is741a_device::fifo_spaces(unsigned n) const
+{
+ if (m_fifo_empty[n])
+ return FIFO_LENGTH;
+ else
+ return (FIFO_LENGTH - m_fifo_head[n] + m_fifo_tail[n]) % FIFO_LENGTH;
+}
+
+inline u8 sc16is741a_device::fifo_fill_level(unsigned n) const
+{
+ if (!m_fifo_empty[n] && (m_fifo_head[n] == m_fifo_tail[n]))
+ return FIFO_LENGTH;
+ else
+ return (FIFO_LENGTH + m_fifo_head[n] - m_fifo_tail[n]) % FIFO_LENGTH;
+}
+
+inline void sc16is741a_device::fifo_reset(unsigned n)
+{
+ m_fifo_head[n] = m_fifo_tail[n];
+ m_fifo_empty[n] = true;
+}
+
+inline u8 sc16is741a_device::fifo_push(unsigned n)
+{
+ if (!FCR_FIFO_ENABLE())
+ {
+ if (!m_fifo_empty[n])
+ LOG("%1$s FIFO overrun\n", n ? "TX" : "RX");
+ m_fifo_empty[n] = false;
+ return m_fifo_head[n];
+ }
+ else if ((m_fifo_head[n] != m_fifo_tail[n]) || m_fifo_empty[n])
+ {
+ m_fifo_empty[n] = false;
+ return std::exchange(m_fifo_head[n], (m_fifo_head[n] + 1) & 0x3f);
+ }
+ else
+ {
+ LOG("%1$s FIFO overrun\n", n ? "TX" : "RX");
+ return (m_fifo_head[n] - 1) & 0x3f;
+ }
+}
+
+inline u8 sc16is741a_device::fifo_pop(unsigned n)
+{
+ if (m_fifo_empty[n])
+ {
+ assert(m_fifo_head[n] == m_fifo_tail[n]);
+ LOG("%1$s FIFO underrun\n", n ? "TX" : "RX");
+ return m_fifo_tail[n];
+ }
+ else if ((m_fifo_head[n] != m_fifo_tail[n]) || FCR_FIFO_ENABLE())
+ {
+ u8 const result(std::exchange(m_fifo_tail[n], (m_fifo_tail[n] + 1) & 0x3f));
+ if (m_fifo_head[n] == m_fifo_tail[n])
+ m_fifo_empty[n] = true;
+ return result;
+ }
+ else
+ {
+ m_fifo_empty[n] = true;
+ return m_fifo_tail[n];
+ }
+}
+
+
+TIMER_CALLBACK_MEMBER(sc16is741a_device::rx_shift)
+{
+ assert(m_divisor);
+
+ m_shift_reg[0] = (m_shift_reg[0] >> 1) | (u16(m_rx) << 15);
+ --m_rx_remain;
+ ++m_rx_count;
+ if (m_rx_remain)
+ {
+ m_shift_timer[0]->adjust(attotime::from_ticks(m_divisor * 16, clock()));
+ }
+ else
+ {
+ u8 const data(BIT(m_shift_reg[0], 16 + 1 - m_rx_count, m_rx_count - ((parity::NONE == m_parity) ? 2 : 3)));
+ u8 lsr(
+ (BIT(~m_shift_reg[0], 15) ? 0x08 : 0x00) |
+ ((!m_fifo_empty[0] && (!FCR_FIFO_ENABLE() || (m_fifo_head[0] == m_fifo_tail[0]))) ? 0x02 : 0x00));
+ switch (m_parity)
+ {
+ case parity::NONE:
+ break;
+ case parity::ODD:
+ lsr |= BIT(population_count_32(data) ^ BIT(~m_shift_reg[0], 14), 0) << 2;
+ break;
+ case parity::EVEN:
+ lsr |= BIT(population_count_32(data) ^ BIT(m_shift_reg[0], 14), 0) << 2;
+ break;
+ case parity::MARK:
+ lsr |= BIT(~m_shift_reg[0], 14) << 2;
+ break;
+ case parity::SPACE:
+ lsr |= BIT(m_shift_reg[0], 14) << 2;
+ break;
+ }
+ m_shift_reg[0] = 0xffff;
+ u8 const pos(fifo_push(0));
+ if (lsr && (!BIT(lsr, 1) || !m_fifo_data[1][pos]))
+ ++m_fifo_errors;
+ m_fifo_data[0][pos] = data;
+ m_fifo_data[1][pos] = lsr;
+ u8 const level(fifo_fill_level(0));
+ m_rx_timeout_timer->adjust(attotime::from_ticks(m_divisor * 16 / 2 * 4 * m_rx_intervals, clock()));
+
+ if (!(m_interrupts & INTERRUPT_LINE_STATUS))
+ {
+ if (lsr)
+ {
+ assert(1 == m_fifo_errors);
+ LOG("data error, setting line status interrupt\n");
+ m_interrupts |= INTERRUPT_LINE_STATUS;
+ update_irq();
+ }
+ }
+
+ if (!(m_interrupts & INTERRUPT_RHR))
+ {
+ if (FCR_FIFO_ENABLE())
+ {
+ if (level >= m_rx_trigger)
+ {
+ LOG("RX FIFO level %1$u exceeds %2$u, setting RHR interrupt\n", level, m_rx_trigger);
+ m_interrupts |= INTERRUPT_RHR;
+ update_irq();
+ }
+ }
+ else
+ {
+ LOG("RHR full, setting RHR interrupt\n");
+ m_interrupts |= INTERRUPT_RHR;
+ update_irq();
+ }
+ }
+
+ if (EFR_AUTO_RTS() && !m_rts) // FIXME: check EFCR[4]
+ {
+ if (FCR_FIFO_ENABLE())
+ {
+ u8 const trigger(TCR_LEVEL_HALT());
+ if (level >= (trigger * 4))
+ {
+ LOG("RX FIFO level %1$u exceeds %2$u*4, deasserting RTS\n", level, trigger);
+ if (IER_RTS_INT() && !(m_interrupts & INTERRUPT_CTS_RTS))
+ {
+ LOG("setting RTS interrupt\n");
+ m_interrupts |= INTERRUPT_CTS_RTS;
+ update_irq();
+ }
+ set_rts(1);
+ }
+ }
+ else
+ {
+ LOG("RHR full, deasserting RTS\n");
+ if (IER_RTS_INT() && !(m_interrupts & INTERRUPT_CTS_RTS))
+ {
+ LOG("setting RTS interrupt\n");
+ m_interrupts |= INTERRUPT_CTS_RTS;
+ update_irq();
+ }
+ set_rts(1);
+ }
+ }
+ }
+}
+
+TIMER_CALLBACK_MEMBER(sc16is741a_device::tx_shift)
+{
+ assert(m_divisor);
+
+ if (!BIT(++m_tx_count, 0))
+ {
+ m_shift_reg[1] = (m_shift_reg[1] >> 1) | u16(0x8000);
+ update_tx();
+ }
+
+ if (--m_tx_remain)
+ m_shift_timer[1]->adjust(attotime::from_ticks(m_divisor * 16 / 2, clock()));
+ else if (!check_tx())
+ m_shift_timer[1]->reset();
+}
+
+TIMER_CALLBACK_MEMBER(sc16is741a_device::rx_timeout)
+{
+ if (IER_RHR_INT() && !(m_interrupts & INTERRUPT_RX_TIMEOUT))
+ {
+ LOG("setting RX timeout interrupt\n");
+ m_interrupts |= INTERRUPT_RX_TIMEOUT;
+ update_irq();
+ }
+}
+
+
+inline void sc16is741a_device::update_trigger_levels()
+{
+ u8 const rx_level(BIT(m_tlr, 4, 4));
+ u8 const tx_level(BIT(m_tlr, 0, 4));
+ m_rx_trigger = rx_level ? (rx_level * 4) : RX_TRIGGER_LEVELS[FCR_RX_TRIGGER()];
+ m_tx_trigger = tx_level ? (tx_level * 4) : TX_TRIGGER_LEVELS[FCR_TX_TRIGGER()];
+}
+
+inline void sc16is741a_device::update_data_frame()
+{
+ m_word_length = BIT(m_lcr, 0, 2) + 5;
+ if (!LCR_PARITY_ENABLE())
+ m_parity = parity::NONE;
+ else if (!LCR_SET_PARITY())
+ m_parity = LCR_EVEN_PARITY() ? parity::EVEN : parity::ODD;
+ else
+ m_parity = LCR_EVEN_PARITY() ? parity::SPACE : parity::MARK;
+ u8 const stop(!LCR_STOP_BIT() ? 2 : (5 == m_word_length) ? 3 : 4);
+ m_rx_intervals = m_word_length + ((parity::NONE == m_parity) ? 2 : 3);
+ m_tx_intervals = ((m_word_length + ((parity::NONE == m_parity) ? 1 : 2)) * 2) + stop;
+}
+
+inline void sc16is741a_device::update_divisor()
+{
+ bool const zero(!m_divisor);
+ m_divisor = u32(m_dl) * (MCR_CLOCK_DIV4() ? 4 : 1);
+ if (!zero && !m_divisor)
+ {
+ if (m_rx_remain)
+ {
+ // FIXME: receive shift register immediately transferred to RHR
+ LOG("suspending reception due to zero divisor\n");
+ m_rx_remain = 0;
+ m_shift_timer[0]->reset();
+ }
+
+ if (!m_shift_timer[1]->expire().is_never())
+ {
+ LOG("suspending transmission due to zero divisor\n");
+ m_shift_timer[1]->reset();
+ }
+
+ m_rx_timeout_timer->reset();
+ }
+ else if (zero && m_divisor)
+ {
+ if (m_tx_remain && m_shift_timer[1]->expire().is_never())
+ {
+ LOG("non-zero divisor caused transmission to resume\n");
+ m_shift_timer[1]->adjust(attotime::from_ticks(m_divisor * 16 / 2, clock()));
+ }
+ }
+}
diff --git a/src/devices/machine/sc16is741.h b/src/devices/machine/sc16is741.h
new file mode 100644
index 00000000000..ff445e68ec7
--- /dev/null
+++ b/src/devices/machine/sc16is741.h
@@ -0,0 +1,132 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+// I²C/SPI UART with 64-byte transmit and receive FIFOs
+#ifndef MAME_MACHINE_SC16IS741_H
+#define MAME_MACHINE_SC16IS741_H
+
+#pragma once
+
+
+class sc16is741a_device : public device_t
+{
+public:
+ sc16is741a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+ virtual ~sc16is741a_device();
+
+ auto so_cb() { return m_so_cb.bind(); }
+ auto irq_cb() { return m_irq_cb.bind(); }
+ auto tx_cb() { return m_tx_cb.bind(); }
+ auto rts_cb() { return m_rts_cb.bind(); }
+
+ void sclk_w(int state);
+ void cs_w(int state);
+ void si_w(int state);
+ void rx_w(int state);
+ void cts_w(int state);
+
+protected:
+ virtual void device_resolve_objects() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_post_load() override ATTR_COLD;
+
+private:
+ static inline constexpr u8 FIFO_LENGTH = 64;
+
+ enum class phase : u8;
+ enum class parity : u8;
+ enum interrupt : u8;
+
+ void update_irq();
+ void update_tx();
+ void set_rts(u8 state);
+
+ void reg_r(bool first);
+ void reg_w();
+
+ void iir_r(bool first);
+ void lsr_r(bool first);
+ void msr_r(bool first);
+ void txlvl_r(bool first);
+ void rxlvl_r(bool first);
+ void xon_xoff_r(bool first);
+
+ void thr_w();
+ void ier_w();
+ void fcr_w();
+ void lcr_w();
+ void mcr_w();
+ void tcr_w();
+ void tlr_w();
+ void reserved_w();
+ void uart_reset_w();
+ void dl_w();
+ void efr_w();
+ void xon_xoff_w();
+
+ void pop_rx_fifo();
+ bool check_tx();
+
+ u8 fifo_spaces(unsigned n) const;
+ u8 fifo_fill_level(unsigned n) const;
+ void fifo_reset(unsigned n);
+ u8 fifo_push(unsigned n);
+ u8 fifo_pop(unsigned n);
+
+ TIMER_CALLBACK_MEMBER(rx_shift);
+ TIMER_CALLBACK_MEMBER(tx_shift);
+ TIMER_CALLBACK_MEMBER(rx_timeout);
+
+ void update_trigger_levels();
+ void update_data_frame();
+ void update_divisor();
+
+ devcb_write_line m_so_cb;
+ devcb_write_line m_irq_cb;
+ devcb_write_line m_tx_cb;
+ devcb_write_line m_rts_cb;
+
+ emu_timer *m_shift_timer[2];
+ emu_timer *m_rx_timeout_timer;
+
+ u8 m_irq, m_tx, m_rts;
+ u8 m_rx, m_cts;
+
+ u8 m_sclk, m_cs, m_si;
+ phase m_phase;
+ u8 m_bits, m_buffer;
+ u8 m_command;
+
+ u8 m_ier;
+ u8 m_fcr;
+ u8 m_lcr;
+ u8 m_mcr;
+ u8 m_spr;
+ u8 m_tcr;
+ u8 m_tlr;
+ u16 m_dl;
+ u8 m_efr;
+ u8 m_xon_xoff[4];
+
+ u16 m_shift_reg[2];
+ u8 m_rx_remain, m_rx_count;
+ u8 m_tx_remain, m_tx_count;
+
+ u8 m_fifo_head[2], m_fifo_tail[2];
+ bool m_fifo_empty[2];
+ u8 m_fifo_data[3][FIFO_LENGTH];
+ u8 m_fifo_errors;
+
+ u8 m_interrupts;
+
+ u32 m_divisor;
+ u8 m_word_length;
+ parity m_parity;
+ u8 m_rx_intervals, m_tx_intervals;
+ u8 m_rx_trigger, m_tx_trigger;
+};
+
+
+DECLARE_DEVICE_TYPE(SC16IS741A, sc16is741a_device)
+
+#endif // MAME_MACHINE_SC16IS741_H
diff --git a/src/devices/machine/spi_psram.cpp b/src/devices/machine/spi_psram.cpp
index 659ae3ad32c..b463c8adcfa 100644
--- a/src/devices/machine/spi_psram.cpp
+++ b/src/devices/machine/spi_psram.cpp
@@ -30,9 +30,13 @@
Example PSRAM:
* AP Memory APS1604L-SQ (2 MiB)
+ * AP Memory APS1604M-SQ (2 MiB)
* AP Memory APS3204L-SQ (4 MiB)
+ * AP Memory APS3204M-SQ (4 MiB)
* AP Memory APS6404L-SQ (8 MiB)
+ * AP Memory APS6404M-SQ (8 MiB)
* AP Memory APS12804L-SQ (16 MiB)
+ * AP Memory APS12804M-SQ (16 MiB)
* ISS IS66WVS1M8 (1 MiB)
* ISS IS66WVS2M8 (2 MiB)
* ISS IS66WVS8M8 (8 MiB)
@@ -54,30 +58,20 @@
#include "spi_psram.h"
-DEFINE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device, "spi_psram", "Generic SPI RAM")
+DEFINE_DEVICE_TYPE(SPI_RAM, spi_ram_device, "spi_ram", "Generic SPI RAM")
+DEFINE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device, "spi_psram", "Generic SPI/QPI Pseudo-SRAM")
-ALLOW_SAVE_TYPE(spi_psram_device::phase)
-
-enum class spi_psram_device::phase : u8
-{
- IDLE,
- COMMAND,
- ADDRESS,
- WAIT,
- READ,
- WRITE
-};
-
-
-enum spi_psram_device::command : u8
+enum spi_ram_device::command : u8
{
COMMAND_READ = 0x03,
COMMAND_FAST_READ = 0x0b, // 8 wait cycles in SPI mode, 4 wait cycles in QPI mode
COMMAND_FAST_READ_QUAD = 0xeb, // 6 wait cycles, always 4-bit address and data
+ COMMAND_WRAPPED_READ = 0x8b, // 8 wait cycles in SPI mode, 5 wait cycles in QPI mode
COMMAND_WRITE = 0x02,
COMMAND_WRITE_QUAD = 0x38, // always 4-bit address and data
+ COMMAND_WRAPPED_WRITE = 0x82,
COMMAND_QPI_ENTER = 0x35,
COMMAND_QPI_EXIT = 0xf5,
@@ -100,20 +94,38 @@ enum spi_psram_device::command : u8
};
-spi_psram_device::spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
- device_t(mconfig, SPI_PSRAM, tag, owner, clock),
+ALLOW_SAVE_TYPE(spi_ram_device::phase)
+
+enum class spi_ram_device::phase : u8
+{
+ IDLE,
+ COMMAND,
+ ADDRESS,
+ WAIT,
+ READ,
+ WRITE
+};
+
+
+spi_ram_device::spi_ram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ spi_ram_device(mconfig, SPI_RAM, tag, owner, clock)
+{
+}
+
+spi_ram_device::spi_ram_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, type, tag, owner, clock),
m_sio_cb(*this),
m_ram(),
m_size(0)
{
}
-spi_psram_device::~spi_psram_device()
+spi_ram_device::~spi_ram_device()
{
}
-void spi_psram_device::ce_w(int state)
+void spi_ram_device::ce_w(int state)
{
if (state)
{
@@ -130,7 +142,7 @@ void spi_psram_device::ce_w(int state)
m_ce = state ? 1 : 0;
}
-void spi_psram_device::sclk_w(int state)
+void spi_ram_device::sclk_w(int state)
{
switch (m_phase)
{
@@ -139,12 +151,13 @@ void spi_psram_device::sclk_w(int state)
case phase::WRITE:
if (state && !m_sclk)
{
- m_buffer = (m_buffer << m_cmd_width) | (m_sio & util::make_bitmask(m_cmd_width));
+ m_buffer = (m_buffer << m_data_width) | (m_sio & util::make_bitmask(m_data_width));
m_bits -= m_data_width;
if (!m_bits)
{
if (phase::COMMAND == m_phase)
{
+ m_phase = phase::IDLE;
m_cmd = u8(m_buffer);
start_command();
}
@@ -187,25 +200,37 @@ void spi_psram_device::sclk_w(int state)
}
break;
+ case phase::WAIT:
+ if (state && !m_sclk)
+ {
+ m_bits -= m_data_width;
+ if (!m_bits)
+ {
+ m_bits = 8;
+ m_phase = m_next_phase;
+ }
+ }
+ break;
+
default:
break;
}
m_sclk = state ? 1 : 0;
}
-void spi_psram_device::sio_w(offs_t offset, u8 data, u8 mem_mask)
+void spi_ram_device::sio_w(offs_t offset, u8 data, u8 mem_mask)
{
m_sio = data & 0xf;
}
-void spi_psram_device::device_validity_check(validity_checker &valid) const
+void spi_ram_device::device_validity_check(validity_checker &valid) const
{
if (!m_size || (m_size & (m_size - 1)) || (m_size > 0x0100'0000))
osd_printf_error("Unsupported size %u (must be a power of 2 not larger than 16M)\n", m_size);
}
-void spi_psram_device::device_resolve_objects()
+void spi_ram_device::device_resolve_objects()
{
m_wrap_mask = util::make_bitmask(10);
m_addr = 0;
@@ -213,15 +238,17 @@ void spi_psram_device::device_resolve_objects()
m_cmd_width = 1;
m_data_width = 1;
m_bits = 0;
+ m_wait = 0;
m_ce = 1;
m_sclk = 0;
m_sio = 0xf;
m_phase = phase::IDLE;
+ m_next_phase = phase::IDLE;
m_cmd = 0;
}
-void spi_psram_device::device_start()
+void spi_ram_device::device_start()
{
if (!m_size || (m_size & (m_size - 1)) || (m_size > 0x0100'0000))
osd_printf_error("%s: Unsupported size %u (must be a power of 2 not larger than 16M)\n", tag(), m_size);
@@ -235,64 +262,77 @@ void spi_psram_device::device_start()
save_item(NAME(m_cmd_width));
save_item(NAME(m_data_width));
save_item(NAME(m_bits));
+ save_item(NAME(m_wait));
save_item(NAME(m_ce));
save_item(NAME(m_sclk));
save_item(NAME(m_sio));
save_item(NAME(m_phase));
+ save_item(NAME(m_next_phase));
save_item(NAME(m_cmd));
}
-void spi_psram_device::start_command()
+void spi_ram_device::start_command()
{
- switch (m_cmd)
+ switch (cmd())
{
case COMMAND_READ:
- // FIXME: AP Memory devices don't support this command in QPI mode
- m_buffer = 0;
- m_data_width = m_cmd_width;
- m_bits = 24;
- m_phase = phase::ADDRESS;
- break;
+ // FIXME: wait cycles depend on mode and device family
+ start_read(m_cmd_width, 0);
+ return;
case COMMAND_WRITE:
- m_buffer = 0;
- m_data_width = m_cmd_width;
- m_bits = 24;
- m_phase = phase::ADDRESS;
- break;
+ start_write(m_cmd_width);
+ return;
default:
- logerror("unimplemented command 0x%02x\n", m_cmd);
- m_phase = phase::IDLE;
+ logerror("unimplemented command 0x%02x in %u-bit mode\n", cmd(), m_cmd_width);
}
}
-void spi_psram_device::address_complete()
+void spi_ram_device::address_complete()
{
- switch (m_cmd)
+ if (m_wait)
{
- case COMMAND_READ:
- // FIXME: wait cycles depend on mode and device family
- m_buffer = m_ram[m_addr];
- m_data_width = m_cmd_width;
+ m_phase = phase::WAIT;
+ m_bits = m_wait;
+ }
+ else
+ {
+ m_buffer = (phase::READ == m_next_phase) ? m_ram[m_addr] : 0;
m_bits = 8;
- m_phase = phase::READ;
- break;
+ m_phase = m_next_phase;
+ }
+}
- case COMMAND_WRITE:
- m_buffer = 0;
- m_data_width = m_cmd_width;
- m_bits = 8;
- m_phase = phase::WRITE;
- break;
- default:
- throw false; // if we get here, there's a bug in the code
- }
+inline void spi_ram_device::set_cmd_width(u8 width)
+{
+ m_cmd_width = width;
}
-inline void spi_psram_device::next_address()
+inline void spi_ram_device::start_read(u8 width, u8 wait)
+{
+ m_buffer = 0;
+ m_data_width = width;
+ m_bits = 24;
+ m_wait = wait * width;
+ m_phase = phase::ADDRESS;
+ m_next_phase = phase::READ;
+}
+
+inline void spi_ram_device::start_write(u8 width)
+{
+ m_buffer = 0;
+ m_data_width = width;
+ m_bits = 24;
+ m_wait = 0;
+ m_phase = phase::ADDRESS;
+ m_next_phase = phase::WRITE;
+}
+
+
+inline void spi_ram_device::next_address()
{
if (m_wrap_mask)
{
@@ -304,3 +344,84 @@ inline void spi_psram_device::next_address()
m_phase = phase::IDLE;
}
}
+
+
+
+spi_psram_device::spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ spi_ram_device(mconfig, SPI_PSRAM, tag, owner, clock)
+{
+}
+
+spi_psram_device::~spi_psram_device()
+{
+}
+
+
+void spi_psram_device::device_resolve_objects()
+{
+ spi_ram_device::device_resolve_objects();
+
+ m_reset_enable = false;
+}
+
+void spi_psram_device::device_start()
+{
+ spi_ram_device::device_start();
+
+ save_item(NAME(m_reset_enable));
+}
+
+
+void spi_psram_device::start_command()
+{
+ bool const reset_enable(std::exchange(m_reset_enable, false));
+ switch (cmd())
+ {
+ case COMMAND_READ:
+ if (cmd_width() == 4)
+ {
+ // FIXME: AP Memory and Vilsion Technology devices don't support command 0x03 in QPI mode
+ start_read(4, 4);
+ return;
+ }
+ break;
+
+ case COMMAND_FAST_READ:
+ start_read(cmd_width(), (cmd_width() == 4) ? 4 : 8);
+ return;
+
+ case COMMAND_FAST_READ_QUAD:
+ start_read(4, 6);
+ return;
+
+ case COMMAND_WRITE_QUAD:
+ start_write(4);
+ return;
+
+ case COMMAND_QPI_ENTER:
+ if (cmd_width() == 1)
+ {
+ set_cmd_width(4);
+ return;
+ }
+ break;
+
+ case COMMAND_QPI_EXIT:
+ if (cmd_width() == 4)
+ {
+ set_cmd_width(1);
+ return;
+ }
+ break;
+
+ case COMMAND_RESET_ENABLE:
+ m_reset_enable = true;
+ return;
+
+ case COMMAND_RESET:
+ if (reset_enable)
+ set_cmd_width(1);
+ return;
+ }
+ spi_ram_device::start_command();
+}
diff --git a/src/devices/machine/spi_psram.h b/src/devices/machine/spi_psram.h
index d2bc5923763..2bbc858b30f 100644
--- a/src/devices/machine/spi_psram.h
+++ b/src/devices/machine/spi_psram.h
@@ -9,11 +9,11 @@
#include
-class spi_psram_device : public device_t
+class spi_ram_device : public device_t
{
public:
- spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
- virtual ~spi_psram_device();
+ spi_ram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
+ virtual ~spi_ram_device();
void set_size(u32 size) { m_size = size; }
auto sio_cb() { return m_sio_cb.bind(); }
@@ -24,17 +24,28 @@ class spi_psram_device : public device_t
void si_w(int state) { sio_w(0, state ? 0xf : 0xe, 0x1); }
protected:
+ enum command : u8;
+
+ spi_ram_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
+
virtual void device_validity_check(validity_checker &valid) const override ATTR_COLD;
virtual void device_resolve_objects() override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
- void start_command();
- void address_complete();
- void next_address();
+ virtual void start_command();
+
+ u8 cmd_width() const { return m_cmd_width; }
+ u8 cmd() const { return m_cmd; }
+
+ void set_cmd_width(u8 width);
+ void start_read(u8 width, u8 wait);
+ void start_write(u8 width);
private:
enum class phase : u8;
- enum command : u8;
+
+ void address_complete();
+ void next_address();
devcb_write8 m_sio_cb;
@@ -45,13 +56,32 @@ class spi_psram_device : public device_t
u32 m_buffer;
u8 m_cmd_width, m_data_width;
u8 m_bits;
+ u8 m_wait;
u8 m_ce, m_sclk, m_sio;
- phase m_phase;
+ phase m_phase, m_next_phase;
u8 m_cmd;
};
+class spi_psram_device : public spi_ram_device
+{
+public:
+ spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
+ virtual ~spi_psram_device();
+
+protected:
+ virtual void device_resolve_objects() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+
+ virtual void start_command() override;
+
+private:
+ bool m_reset_enable;
+};
+
+
+DECLARE_DEVICE_TYPE(SPI_RAM, spi_ram_device)
DECLARE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device)
#endif // MAME_MACHINE_SPI_PSRAM_H
diff --git a/src/devices/machine/spi_sdcard.cpp b/src/devices/machine/spi_sdcard.cpp
index ec4267b9ec3..5fd7526ef25 100644
--- a/src/devices/machine/spi_sdcard.cpp
+++ b/src/devices/machine/spi_sdcard.cpp
@@ -41,6 +41,7 @@
#include "logmacro.h"
+
namespace {
constexpr u8 DATA_RESPONSE_OK = 0x05;
@@ -152,16 +153,17 @@ spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, device_type
write_miso(*this),
m_image(*this, "image"),
m_preferred_type(SD_TYPE_V2),
- m_ignore_stop_bit(false),
m_blksize(512),
m_type(SD_TYPE_V2),
m_state(SD_STATE_IDLE),
m_ss(0), m_in_bit(0), m_clk_state(0),
m_in_latch(0), m_out_latch(0xff), m_cur_bit(0),
m_out_delay(0), m_out_count(0), m_out_ptr(0), m_write_ptr(0), m_xferblk(512), m_blknext(0),
+ m_crc_off(true),
m_bACMD(false)
{
std::fill(std::begin(m_csd), std::end(m_csd), 0);
+ std::fill(std::begin(m_cmd), std::end(m_cmd), 0xff);
}
spi_sdcard_device::~spi_sdcard_device()
@@ -187,6 +189,7 @@ void spi_sdcard_device::device_start()
save_item(NAME(m_write_ptr));
save_item(NAME(m_xferblk));
save_item(NAME(m_blknext));
+ save_item(NAME(m_crc_off));
save_item(NAME(m_bACMD));
}
@@ -238,6 +241,7 @@ std::error_condition spi_sdcard_device::image_loaded(device_image_interface &ima
}
m_blksize = m_xferblk = info.sectorbytes;
+ m_crc_off = true;
// set up common CSD fields
m_csd[0] = 0x00; // 127: CSD_STRUCTURE:2 (00b) 0:6
@@ -354,6 +358,26 @@ void spi_sdcard_device::spi_clock_w(int state)
m_clk_state = state;
}
+void spi_sdcard_device::spi_ss_w(int state)
+{
+ if (!m_ss && state)
+ {
+ LOGMASKED(LOG_SPI, "SDCARD: selected\n");
+ std::fill(std::begin(m_cmd), std::end(m_cmd), 0xff);
+ m_state = SD_STATE_IDLE;
+ m_in_latch = 0;
+ m_cur_bit = 0;
+ m_out_latch = 0xff;
+ m_out_delay = 0;
+ m_out_count = 0;
+ }
+ else if (m_ss && !state)
+ {
+ LOGMASKED(LOG_SPI, "SDCARD: deselected\n");
+ }
+ m_ss = state;
+}
+
void spi_sdcard_device::latch_in()
{
m_in_latch &= ~0x01;
@@ -446,7 +470,7 @@ void spi_sdcard_device::shift_out()
void spi_sdcard_device::do_command()
{
- if (((m_cmd[0] & 0xc0) == 0x40) && ((m_cmd[5] & 1) || m_ignore_stop_bit))
+ if (((m_cmd[0] & 0xc0) == 0x40) && ((m_cmd[5] & 1) || m_crc_off))
{
LOGMASKED(LOG_COMMAND, "SDCARD: cmd %02d %02x %02x %02x %02x %02x\n", m_cmd[0] & 0x3f, m_cmd[1], m_cmd[2], m_cmd[3], m_cmd[4], m_cmd[5]);
bool clean_cmd = true;
@@ -682,8 +706,8 @@ void spi_sdcard_device::do_command()
break;
case 59: // CMD59 - CRC_ON_OFF
+ m_crc_off = !BIT(m_cmd[4], 0);
m_data[0] = 0;
- // TODO CRC 1-on, 0-off
send_data(1, SD_STATE_STBY);
break;
diff --git a/src/devices/machine/spi_sdcard.h b/src/devices/machine/spi_sdcard.h
index fc907370972..8eb9ec90d34 100644
--- a/src/devices/machine/spi_sdcard.h
+++ b/src/devices/machine/spi_sdcard.h
@@ -18,12 +18,11 @@ class spi_sdcard_device : public device_t
void set_prefer_sd() { m_preferred_type = SD_TYPE_V2; }
void set_prefer_sdhc() { m_preferred_type = SD_TYPE_HC; }
- void set_ignore_stop_bit(bool ignore) { m_ignore_stop_bit = ignore; }
// SPI 4-wire interface
auto spi_miso_callback() { return write_miso.bind(); }
void spi_clock_w(int state);
- void spi_ss_w(int state) { m_ss = state; }
+ void spi_ss_w(int state);
void spi_mosi_w(int state) { m_in_bit = state; }
bool get_card_present() { return m_image->exists(); }
@@ -62,7 +61,6 @@ class spi_sdcard_device : public device_t
// configuration
sd_type m_preferred_type;
- bool m_ignore_stop_bit;
// mounted image info
std::vector m_sectorbuf;
@@ -80,6 +78,7 @@ class spi_sdcard_device : public device_t
u16 m_out_count, m_out_ptr, m_write_ptr;
u16 m_xferblk;
u32 m_blknext;
+ bool m_crc_off;
bool m_bACMD;
};
diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h
index c0183879e80..aafc74a11b8 100644
--- a/src/devices/video/s3virge.h
+++ b/src/devices/video/s3virge.h
@@ -7,8 +7,8 @@
*
*/
-#ifndef MAME_BUS_ISA_S3VIRGE_H
-#define MAME_BUS_ISA_S3VIRGE_H
+#ifndef MAME_VIDEO_S3VIRGE_H
+#define MAME_VIDEO_S3VIRGE_H
#pragma once
@@ -230,4 +230,4 @@ DECLARE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device)
DECLARE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device)
DECLARE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device)
-#endif // MAME_BUS_ISA_S3VIRGE_H
+#endif // MAME_VIDEO_S3VIRGE_H
diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp
index 4f31c91ca02..2d900f27459 100644
--- a/src/emu/diserial.cpp
+++ b/src/emu/diserial.cpp
@@ -45,21 +45,6 @@ device_serial_interface::device_serial_interface(const machine_config &mconfig,
m_tra_clock_state(false),
m_rcv_clock_state(false)
{
- /* if sum of all bits in the byte is even, then the data
- has even parity, otherwise it has odd parity */
- for (int i=0; i<256; i++)
- {
- int sum = 0;
- int data = i;
-
- for (int b=0; b<8; b++)
- {
- sum+=data & 0x01;
- data = data>>1;
- }
-
- m_serial_parity_table[i] = sum & 0x01;
- }
}
device_serial_interface::~device_serial_interface()
@@ -317,13 +302,13 @@ void device_serial_interface::receive_register_extract()
receive_register_reset();
/* strip off stop bits and parity */
- assert(m_rcv_bit_count >0 && m_rcv_bit_count <= 16);
- data = m_rcv_register_data>>(16-m_rcv_bit_count);
+ assert(m_rcv_bit_count > 0 && m_rcv_bit_count <= 16);
+ data = m_rcv_register_data >> (16 - m_rcv_bit_count);
/* mask off other bits so data byte has 0's in unused bits */
- data &= ~(0xff<adjust(m_tra_rate, 0, m_tra_rate);
m_tra_bit_count_transmitted = 0;
@@ -390,40 +373,35 @@ void device_serial_interface::transmit_register_setup(u8 data_byte)
m_tra_flags &=~TRANSMIT_REGISTER_EMPTY;
/* start bit */
- for (i=0; i>1;
+ transmit_register_add_bit(BIT(transmit_data, 0));
+ transmit_data >>= 1;
}
/* parity */
- if (m_df_parity!=PARITY_NONE)
+ if (m_df_parity != PARITY_NONE)
{
/* odd or even parity */
u8 parity = 0;
switch (m_df_parity)
{
case PARITY_ODD:
-
- /* get parity */
- /* if parity = 0, data has even parity - i.e. there is an even number of one bits in the data */
- /* if parity = 1, data has odd parity - i.e. there is an odd number of one bits in the data */
- parity = serial_helper_get_parity(data_byte) ^ 1;
+ // get parity
+ // if parity[0] = 0, data has even parity - i.e. there is an even number of one bits in the data
+ // if parity[0] = 1, data has odd parity - i.e. there is an odd number of one bits in the data
+ parity = BIT(population_count_32(data_byte), 0) ^ 1;
break;
case PARITY_EVEN:
- parity = serial_helper_get_parity(data_byte);
+ parity = BIT(population_count_32(data_byte), 0);
break;
case PARITY_MARK:
parity = 1;
@@ -436,7 +414,7 @@ void device_serial_interface::transmit_register_setup(u8 data_byte)
}
/* TX stop bit(s) */
- for (i=0; i
+
+#include "lnux4004.lh"
+
+
+namespace {
+
+class linux4004_state : public driver_device
+{
+public:
+ static constexpr feature_type unemulated_features() { return feature::GRAPHICS; }
+
+ linux4004_state(machine_config const &mconfig, device_type type, char const *tag)
+ : driver_device(mconfig, type, tag)
+ , m_cpu(*this, "u1")
+ , m_psram(*this, "u%u", 5U)
+ , m_sdcard(*this, "sd")
+ , m_uart(*this, "u9")
+ , m_memory(*this, "memory")
+ , m_status(*this, "status")
+ , m_rom_bank(*this, "rom")
+ , m_led_pc(*this, "pc%u", 0U)
+ , m_led_sdcard(*this, "storage")
+ {
+ }
+
+ void linux4004(machine_config &config) ATTR_COLD;
+
+protected:
+ virtual void machine_start() override ATTR_COLD;
+ virtual void machine_reset() override ATTR_COLD;
+
+private:
+ template void psram_sio_w(offs_t offset, u8 data, u8 mem_mask);
+ template void miso_w(int state);
+
+ u8 u3_r();
+ void u4002_1_3_w(u8 data);
+ void u4002_1_4_w(u8 data);
+ void u4002_2_3_w(u8 data);
+ template void led_pc_w(offs_t offset, u8 data);
+
+ void umips_rom(address_map &map) ATTR_COLD;
+ void umips_ram(address_map &map) ATTR_COLD;
+ void umips_status(address_map &map) ATTR_COLD;
+ void umips_rom_ports(address_map &map) ATTR_COLD;
+ void umips_ram_ports(address_map &map) ATTR_COLD;
+
+ required_device m_cpu;
+ required_device_array m_psram;
+ required_device m_sdcard;
+ required_device m_uart;
+ required_shared_ptr m_memory;
+ required_shared_ptr m_status;
+ required_memory_bank m_rom_bank;
+
+ output_finder<32> m_led_pc;
+ output_finder<> m_led_sdcard;
+
+ u8 m_psram_so[2];
+ u8 m_u3_in;
+};
+
+
+INPUT_PORTS_START(linux4004)
+ PORT_START("CONF")
+ PORT_CONFNAME(0x03, 0x00, "TLB Entries")
+ PORT_CONFSETTING( 0x03, "4")
+ PORT_CONFSETTING( 0x02, "8")
+ PORT_CONFSETTING( 0x01, "12")
+ PORT_CONFSETTING( 0x00, "16")
+ PORT_CONFNAME(0x04, 0x00, "U4002-2-4 Installed")
+ PORT_CONFSETTING( 0x00, DEF_STR(No))
+ PORT_CONFSETTING( 0x04, DEF_STR(Yes))
+INPUT_PORTS_END
+
+
+void linux4004_state::linux4004(machine_config &config)
+{
+ config.set_default_layout(layout_lnux4004);
+
+ I4004(config, m_cpu, 5.5296_MHz_XTAL / 7);
+ m_cpu->set_rom_map(&linux4004_state::umips_rom);
+ m_cpu->set_ram_memory_map(&linux4004_state::umips_ram);
+ m_cpu->set_ram_status_map(&linux4004_state::umips_status);
+ m_cpu->set_rom_ports_map(&linux4004_state::umips_rom_ports);
+ m_cpu->set_ram_ports_map(&linux4004_state::umips_ram_ports);
+
+ SPI_PSRAM(config, m_psram[0]);
+ m_psram[0]->set_size(8 << 20); // supports 4 MiB to 16 MiB
+ m_psram[0]->sio_cb().set(FUNC(linux4004_state::psram_sio_w<0>));
+
+ SPI_PSRAM(config, m_psram[1]);
+ m_psram[1]->set_size(4 << 20); // supports 128 KiB to 16 MiB
+ m_psram[1]->sio_cb().set(FUNC(linux4004_state::psram_sio_w<1>));
+
+ SPI_SDCARD(config, m_sdcard, 0U);
+ m_sdcard->spi_miso_callback().set(FUNC(linux4004_state::miso_w<3>));
+
+ SC16IS741A(config, m_uart, 3.072_MHz_XTAL);
+ m_uart->so_cb().set(FUNC(linux4004_state::miso_w<2>));
+ m_uart->irq_cb().set_inputline(m_cpu, I4004_TEST_LINE).invert();
+ m_uart->tx_cb().set("rs232", FUNC(rs232_port_device::write_txd));
+ m_uart->rts_cb().set("rs232", FUNC(rs232_port_device::write_rts));
+
+ auto &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
+ rs232.rxd_handler().set(m_uart, FUNC(sc16is741a_device::rx_w));
+ rs232.cts_handler().set(m_uart, FUNC(sc16is741a_device::cts_w));
+
+ SOFTWARE_LIST(config, "sdcard_list").set_original("lnux4004");
+}
+
+
+void linux4004_state::machine_start()
+{
+ m_rom_bank->configure_entries(0, 2, memregion("4004firmware")->base(), 0x1000);
+ m_led_pc.resolve();
+ m_led_sdcard.resolve();
+
+ std::fill(std::begin(m_psram_so), std::end(m_psram_so), 1);
+ m_u3_in = 0;
+
+ save_item(NAME(m_psram_so));
+ save_item(NAME(m_u3_in));
+}
+
+void linux4004_state::machine_reset()
+{
+ ioport_value const conf(ioport("CONF")->read());
+ auto const tlb_empty(BIT(conf, 0, 2));
+ auto const u4002_2_4(BIT(conf, 2));
+
+ m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).unmap_readwrite(0x0000, 0x02ff);
+ m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).unmap_readwrite(0x00, 0xbf);
+ m_cpu->space(i4004_cpu_device::AS_RAM_PORTS).unmap_readwrite(0x08, 0x0b);
+ m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).install_ram(0x0000, 0x02ff - (tlb_empty * 0x40), m_memory.target());
+ m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).install_ram(0x00, 0xbf - (tlb_empty * 0x10), m_status.target());
+ m_cpu->space(i4004_cpu_device::AS_RAM_PORTS).install_write_handler(0x08, 0x0b - tlb_empty, emu::rw_delegate(*this, FUNC(linux4004_state::led_pc_w<4>)));
+ if (!u4002_2_4)
+ {
+ m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).unmap_readwrite(0x01c0, 0x01ff);
+ m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).unmap_readwrite(0x70, 0x7f);
+ }
+
+ std::fill(m_memory.begin(), m_memory.end(), 0);
+ std::fill(m_status.begin(), m_status.end(), 0);
+
+ u4002_1_3_w(0);
+ u4002_1_4_w(0);
+ u4002_2_3_w(0);
+ for (auto &led : m_led_pc)
+ led = 0;
+}
+
+
+template
+void linux4004_state::psram_sio_w(offs_t offset, u8 data, u8 mem_mask)
+{
+ m_psram_so[N] = BIT(data | ~mem_mask, 1);
+ miso_w<0>(m_psram_so[0] & m_psram_so[1]);
+}
+
+template
+void linux4004_state::miso_w(int state)
+{
+ m_u3_in = (m_u3_in & ~(u8(1) << N)) | (u8(state ? 1 : 0) << N);
+}
+
+
+u8 linux4004_state::u3_r()
+{
+ return m_u3_in;
+}
+
+void linux4004_state::u4002_1_3_w(u8 data)
+{
+ m_sdcard->spi_mosi_w(BIT(~data, 0));
+ m_sdcard->spi_clock_w(BIT(~data, 1));
+ m_sdcard->spi_ss_w(BIT(data, 2) ? ASSERT_LINE : CLEAR_LINE);
+ m_led_sdcard = BIT(~data, 2);
+ m_rom_bank->set_entry(BIT(data, 3) ^ 0x01);
+}
+
+void linux4004_state::u4002_1_4_w(u8 data)
+{
+ m_uart->si_w(BIT(~data, 0)); // TODO: also connected to VFD
+ m_uart->sclk_w(BIT(~data, 1)); // TODO: also connected to VFD
+ // VFD_NCS_HV
+ m_uart->cs_w(BIT(~data, 3));
+}
+
+void linux4004_state::u4002_2_3_w(u8 data)
+{
+ m_psram[0]->si_w(BIT(~data, 0));
+ m_psram[1]->si_w(BIT(~data, 0));
+ m_psram[0]->sclk_w(BIT(~data, 1));
+ m_psram[1]->sclk_w(BIT(~data, 1));
+ m_psram[0]->ce_w(BIT(~data, 2));
+ m_psram[1]->ce_w(BIT(~data, 3));
+}
+
+template
+void linux4004_state::led_pc_w(offs_t offset, u8 data)
+{
+ for (unsigned i = 0; 4 > i; ++i)
+ m_led_pc[i | ((N + offset) << 2)] = BIT(data, i);
+}
+
+
+void linux4004_state::umips_rom(address_map &map)
+{
+ map.unmap_value_low();
+ map.global_mask(0x0fff);
+ map(0x0000, 0x0fff).bankr(m_rom_bank);
+}
+
+void linux4004_state::umips_ram(address_map &map)
+{
+ map.unmap_value_low();
+ map(0x0000, 0x02ff).ram().share(m_memory); // up to twelve 4002 chips
+}
+
+void linux4004_state::umips_status(address_map &map)
+{
+ map.unmap_value_low();
+ map(0x00, 0xbf).ram().share(m_status); // up to twelve 4002 chips
+}
+
+void linux4004_state::umips_rom_ports(address_map &map)
+{
+ map.unmap_value_high();
+ map.global_mask(0x0ff);
+ map(0x000, 0x0ff).r(FUNC(linux4004_state::u3_r));
+}
+
+void linux4004_state::umips_ram_ports(address_map &map)
+{
+ map(0x00, 0x03).w(FUNC(linux4004_state::led_pc_w<0>));
+ map(0x04, 0x04).w(FUNC(linux4004_state::u4002_1_3_w));
+ map(0x05, 0x05).w(FUNC(linux4004_state::u4002_1_4_w));
+ map(0x06, 0x06).w(FUNC(linux4004_state::u4002_2_3_w));
+ map(0x08, 0x0b).w(FUNC(linux4004_state::led_pc_w<4>));
+}
+
+
+ROM_START(lnux4004)
+ ROM_REGION(0x2000, "4004firmware", 0)
+ ROM_LOAD("umips.u4", 0x0000, 0x2000, CRC(27dd98c1) SHA1(a9d2b1990e7ae8ce4a53950430c5186d4cf55a01)) // AT28C64B
+ROM_END
+
+} // anonymous namespace
+
+
+SYST( 2024, lnux4004, 0, 0, linux4004, linux4004, linux4004_state, empty_init, "Dmitry Grinberg", "Linux/4004", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/homelab/homelab.cpp b/src/mame/homelab/homelab.cpp
index cd64e24af77..53e8cd40c49 100644
--- a/src/mame/homelab/homelab.cpp
+++ b/src/mame/homelab/homelab.cpp
@@ -251,10 +251,10 @@ u8 homelab2_state::memE000_r(offs_t offset)
u8 gfx;
if (m_screenshadow_is_text_mode)
{
- const int vramRelIndex0 = offset % 0x400; // Character address in video ram First character in 0x001
- const int row8_index0 = (offset - 1) / 0x400; // Row index in char [0-7]
- u8 const chr = m_vram[vramRelIndex0]; // get char in videoram
- gfx = m_p_chargen[chr | (row8_index0 << 8)]; // get dot pattern in chargen
+ const int vramRelIndex0 = offset & 0x3ff; // Character address in video ram First character in 0x001
+ const int row8_index0 = ((offset - 1) & 0x1c00) >> 10; // Row index in char [0-7]
+ u8 const chr = m_vram[vramRelIndex0]; // get char in videoram
+ gfx = m_p_chargen[chr | (row8_index0 << 8)]; // get dot pattern in chargen
}
else
{
diff --git a/src/mame/ibm/thinkpad600.cpp b/src/mame/ibm/thinkpad600.cpp
index 9876cc85c0c..271a6ae1e49 100644
--- a/src/mame/ibm/thinkpad600.cpp
+++ b/src/mame/ibm/thinkpad600.cpp
@@ -1,7 +1,16 @@
// license:BSD-3-Clause
-// copyright-holders:
-/*************************************************************************************************************
-Skeleton driver for IBM ThinkPad 600 series.
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+IBM ThinkPad 600 series
+
+TODO:
+- Intel e28f004b5t80 flash ROM;
+- RTC (what's the CMOS here?);
+- keyboard (thru H8/3437);
+
+===================================================================================================
+
The IBM ThinkPad 600 series was a series of notebook computers introduced in 1998 by IBM as an lighter and
slimmer alternative to the 770 series. Three models were produced, the 600, 600E, and 600X.
@@ -46,9 +55,16 @@ Hardware for the 600 model.
-TI TCM320AC36C (Voice-Band Audio Processor [VBAPE]).
-Large BGA chip silkscreened "IPI I8L7360 F27904A".
-*************************************************************************************************************/
+**************************************************************************************************/
#include "emu.h"
+
+#include "bus/isa/isa_cards.h"
+#include "bus/rs232/hlemouse.h"
+#include "bus/rs232/null_modem.h"
+#include "bus/rs232/rs232.h"
+#include "bus/rs232/sun_kbd.h"
+#include "bus/rs232/terminal.h"
#include "cpu/h8/h83337.h"
#include "cpu/i386/i386.h"
#include "machine/pci.h"
@@ -58,7 +74,7 @@ Hardware for the 600 model.
#include "machine/i82371eb_ide.h"
#include "machine/i82371eb_acpi.h"
#include "machine/i82371eb_usb.h"
-#include "bus/isa/isa_cards.h"
+#include "machine/pc97338.h"
#include "speaker.h"
@@ -85,7 +101,7 @@ class thinkpad600_state : public driver_device
void main_map(address_map &map);
void mcu_map(address_map &map);
- //static void superio_config(device_t *device);
+ static void superio_config(device_t *device);
};
void thinkpad600_state::main_map(address_map &map)
@@ -101,22 +117,47 @@ void thinkpad600_state::mcu_map(address_map &map)
static INPUT_PORTS_START(thinkpad600)
INPUT_PORTS_END
+void thinkpad600_state::superio_config(device_t *device)
+{
+ pc97338_device &fdc = *downcast(device);
+// fdc.set_sysopt_pin(1);
+// fdc.gp20_reset().set_inputline(":maincpu", INPUT_LINE_RESET);
+// fdc.gp25_gatea20().set_inputline(":maincpu", INPUT_LINE_A20);
+ fdc.irq1().set(":pci:07.0", FUNC(i82371eb_isa_device::pc_irq1_w));
+ fdc.irq8().set(":pci:07.0", FUNC(i82371eb_isa_device::pc_irq8n_w));
+ fdc.txd1().set(":serport0", FUNC(rs232_port_device::write_txd));
+ fdc.ndtr1().set(":serport0", FUNC(rs232_port_device::write_dtr));
+ fdc.nrts1().set(":serport0", FUNC(rs232_port_device::write_rts));
+ fdc.txd2().set(":serport1", FUNC(rs232_port_device::write_txd));
+ fdc.ndtr2().set(":serport1", FUNC(rs232_port_device::write_dtr));
+ fdc.nrts2().set(":serport1", FUNC(rs232_port_device::write_rts));
+}
+
+static void isa_com(device_slot_interface &device)
+{
+ device.option_add("microsoft_mouse", MSFT_HLE_SERIAL_MOUSE);
+ device.option_add("logitech_mouse", LOGITECH_HLE_SERIAL_MOUSE);
+ device.option_add("wheel_mouse", WHEEL_HLE_SERIAL_MOUSE);
+ device.option_add("msystems_mouse", MSYSTEMS_HLE_SERIAL_MOUSE);
+ device.option_add("rotatable_mouse", ROTATABLE_HLE_SERIAL_MOUSE);
+ device.option_add("terminal", SERIAL_TERMINAL);
+ device.option_add("null_modem", NULL_MODEM);
+ device.option_add("sun_kbd", SUN_KBD_ADAPTOR);
+}
+
+static void isa_internal_devices(device_slot_interface &device)
+{
+ device.option_add("pc97338", PC97338);
+}
+
void thinkpad600_state::thinkpad600_base(machine_config &config)
{
// TODO: move away, maps on MB resource, bump to H83437
h83337_device &mcu(H83337(config, "mcu", XTAL(16'000'000))); // Actually an Hitachi HD64F3437TF, unknown clock
mcu.set_addrmap(AS_PROGRAM, &thinkpad600_state::mcu_map);
+// mcu.set_disable();
}
-//void thinkpad600_state::superio_config(device_t *device)
-//{
-//}
-
-//static void isa_internal_devices(device_slot_interface &device)
-//{
-// device.option_add("w83787f", W83787F);
-//}
-
void thinkpad600_state::thinkpad600e(machine_config &config)
{
PENTIUM2(config, m_maincpu, 366'000'000); // Intel Pentium II 366 Mobile MMC-2 (PMG36602002AA)
@@ -124,7 +165,7 @@ void thinkpad600_state::thinkpad600e(machine_config &config)
m_maincpu->set_irq_acknowledge_callback("pci:07.0:pic8259_master", FUNC(pic8259_device::inta_cb));
m_maincpu->smiact().set("pci:00.0", FUNC(i82443bx_host_device::smi_act_w));
- // TODO: PCI config space guessed from a Fujitsu Lifebook
+ // TODO: PCI config space guessed from a Fujitsu Lifebook, confirm me for ThinkPad
PCI_ROOT(config, "pci", 0);
I82443BX_HOST(config, "pci:00.0", 0, "maincpu", 64*1024*1024);
i82371eb_isa_device &isa(I82371EB_ISA(config, "pci:07.0", 0, m_maincpu));
@@ -145,7 +186,21 @@ void thinkpad600_state::thinkpad600e(machine_config &config)
// TODO: NeoMagic at "pci:14.0" / "pci:14.1" (video & AC'97 integrated sound, likely requires BIOS)
// TODO: motherboard Super I/O resource here
-// ISA16_SLOT(config, "board4", 0, "pci:07.0:isabus", isa_internal_devices, "pc97338", true).set_option_machine_config("pc97338", superio_config);
+ ISA16_SLOT(config, "board4", 0, "pci:07.0:isabus", isa_internal_devices, "pc97338", true).set_option_machine_config("pc97338", superio_config);
+
+ rs232_port_device &serport0(RS232_PORT(config, "serport0", isa_com, nullptr));
+ serport0.rxd_handler().set("board4:pc97338", FUNC(pc97338_device::rxd1_w));
+ serport0.dcd_handler().set("board4:pc97338", FUNC(pc97338_device::ndcd1_w));
+ serport0.dsr_handler().set("board4:pc97338", FUNC(pc97338_device::ndsr1_w));
+ serport0.ri_handler().set("board4:pc97338", FUNC(pc97338_device::nri1_w));
+ serport0.cts_handler().set("board4:pc97338", FUNC(pc97338_device::ncts1_w));
+
+ rs232_port_device &serport1(RS232_PORT(config, "serport1", isa_com, nullptr));
+ serport1.rxd_handler().set("board4:pc97338", FUNC(pc97338_device::rxd2_w));
+ serport1.dcd_handler().set("board4:pc97338", FUNC(pc97338_device::ndcd2_w));
+ serport1.dsr_handler().set("board4:pc97338", FUNC(pc97338_device::ndsr2_w));
+ serport1.ri_handler().set("board4:pc97338", FUNC(pc97338_device::nri2_w));
+ serport1.cts_handler().set("board4:pc97338", FUNC(pc97338_device::ncts2_w));
thinkpad600_base(config);
}
@@ -155,7 +210,7 @@ void thinkpad600_state::thinkpad600(machine_config &config)
PENTIUM2(config, m_maincpu, 300'000'000); // Intel Pentium II 300 Mobile MMC-1 (PMD30005002AA)
m_maincpu->set_disable();
- // TODO: fill me, uses earlier AB
+ // TODO: fill me, uses earlier PIIX4 AB
PCI_ROOT(config, "pci", 0);
thinkpad600_base(config);
@@ -163,8 +218,16 @@ void thinkpad600_state::thinkpad600(machine_config &config)
ROM_START(thinkpad600e)
- ROM_REGION( 0x80000, "pci:07.0", 0 )
- ROM_LOAD( "e28f004b5t80-10l1056_rev15_h0399m.u60", 0x00000, 0x80000, CRC(fba7567b) SHA1(a84e7d4e5740150e78e5002714c9125705f3356a) ) // BIOS
+ ROM_REGION( 0x80000, "bios", 0 )
+ ROM_LOAD( "e28f004b5t80-10l1056_rev15_h0399m.u60", 0x00000, 0x80000, CRC(fba7567b) SHA1(a84e7d4e5740150e78e5002714c9125705f3356a) )
+
+ ROM_REGION( 0x80000, "pci:07.0", ROMREGION_ERASEFF )
+ // TODO: in linear mapping it will boot to a terminal only Flash ROM BIOS programmer
+ // 0x40000-0x5ffff contains standard x86 startup, this hookup needs confirmation later on.
+ ROM_COPY( "bios", 0x40000, 0x60000, 0x20000 )
+ ROM_COPY( "bios", 0x60000, 0x40000, 0x20000 )
+ ROM_COPY( "bios", 0x00000, 0x20000, 0x20000 )
+ ROM_COPY( "bios", 0x20000, 0x00000, 0x20000 )
ROM_REGION(0x0f780, "mcu", 0)
ROM_LOAD( "hd64f3437tf-10l1057_rev04_h0499m.u39", 0x00000, 0x0f780, CRC(c21c928b) SHA1(33e3e6966f003655ffc2f3ac07772d2d3245740d) )
@@ -181,7 +244,7 @@ ROM_END
ROM_START(thinkpad600)
ROM_REGION( 0x80000, "pci:07.0", 0 )
- ROM_LOAD( "tms28f004b_18l9949_rev16-i2298m.u76", 0x00000, 0x80000, CRC(00a52b32) SHA1(08db425b8edb3a036f22beb588caa6f050fc8eb2) ) // BIOS
+ ROM_LOAD( "tms28f004b_18l9949_rev16-i2298m.u76", 0x00000, 0x80000, CRC(00a52b32) SHA1(08db425b8edb3a036f22beb588caa6f050fc8eb2) )
ROM_REGION(0x0f780, "mcu", 0)
ROM_LOAD( "hd64f3437tf_10l9950_rev08_i2798m.u32", 0x00000, 0x0f780, CRC(546ec51c) SHA1(5d9b4be590307c4059ff11c434d0901819427649) )
diff --git a/src/mame/igs/igs017.cpp b/src/mame/igs/igs017.cpp
index b37dbe620ef..f2039643fcb 100644
--- a/src/mame/igs/igs017.cpp
+++ b/src/mame/igs/igs017.cpp
@@ -26,6 +26,7 @@ Year + Game PCB CPU Sound
99 Tarzan (V107) NO-0228? Z180 U6295 IGS031 IGS025 IGS029 Battery
99 Tarzan (V109C) NO-0248-1 Z180 U6295 IGS031 IGS025 Battery
00 Chaoji Damanguan 2 - Jiaqiang Ban (V100C) NO-0271 68000 K668 IGS031 IGS025 Battery
+00? Jungle King (V103A) NO-0230-1 Z180 U6295 IGS031 IGS025 (N9) Battery
00? Super Tarzan (V100I) NO-0230-1 Z180 K668 IGS031 IGS025 Battery
00? Happy Skill (V611IT) NO-0281 Z180 K668 IGS031 IGS025 Battery
00? Champion Poker 2 (V100A) unreadable Z180 M6295 IGS031 IGS025 Battery
@@ -658,6 +659,7 @@ class igs017_state : public driver_device
void init_cpoker2();
void init_happyskl();
void init_iqblocka();
+ void init_jking103a();
void init_lhzb2();
void init_lhzb2a();
void init_mgcs();
@@ -1326,6 +1328,15 @@ void igs017_state::init_starzan()
// m_igs_string->dump("starzan_string.key", 0xa86f, 0xa966, false);
}
+void igs017_state::init_jking103a()
+{
+ starzan_decrypt_program_rom();
+ m_igs017_igs031->tarzan_decrypt_tiles(1);
+ m_igs017_igs031->tarzan_decrypt_sprites(0, 0);
+
+// m_igs_string->dump("jking103a_string.key", 0xb14d, 0xb244, false);
+}
+
void igs017_state::init_happyskl()
{
@@ -5680,6 +5691,28 @@ ROM_START( tarzanc )
ROM_LOAD( "tarzan_string.key", 0x00, 0xec, CRC(595fe40c) SHA1(0b46983400d237d8bde97a72eaa99b718a03387e) )
ROM_END
+// IGS PCB NO-0248
+ROM_START( tarzanb ) // V110 TARZAN C
+ ROM_REGION( 0x40000, "maincpu", 0 )
+ ROM_LOAD( "t.z._v110.u19", 0x00000, 0x40000, CRC(16026d12) SHA1(df08641b4bc1437648f0a8cd5f7a8a4786c07041) )
+
+ ROM_REGION( 0x400000, "igs017_igs031:sprites", ROMREGION_ERASE00 )
+ ROM_LOAD( "igs_a2103_cg_v100f.u15", 0x000000, 0x200000, CRC(afe56ed5) SHA1(656cee6a59f2930eec9acd11b84b416cc7354e01) )
+
+ ROM_REGION( 0x80000, "igs017_igs031:tilemaps", 0 )
+ ROM_LOAD( "t.z._text_u5.u5", 0x00000, 0x80000, CRC(1724e039) SHA1(d628499b61f98f7c9034d70b82ee25e002190ece) )
+
+ ROM_REGION( 0x80000, "oki", 0 )
+ ROM_LOAD( "igs_s2102_sp_v102.u14", 0x00000, 0x80000, CRC(90dda82d) SHA1(67fbc1e8d76b85e124136e2f1df09c8b6c5a8f97) )
+
+ ROM_REGION( 0x2dd * 2, "plds", ROMREGION_ERASE )
+ ROM_LOAD( "eg.u20", 0x000, 0x2dd, NO_DUMP )
+ ROM_LOAD( "eg.u21", 0x2dd, 0x2dd, NO_DUMP )
+
+ ROM_REGION( 0xec, "igs_string", 0 )
+ ROM_LOAD( "tarzanb_string.key", 0x00, 0xec, CRC(595fe40c) SHA1(0b46983400d237d8bde97a72eaa99b718a03387e) )
+ROM_END
+
// sets below are guesswork, assembled from partial dumps...
// IGS NO-0248-1? Mislabeled?
@@ -5727,27 +5760,6 @@ ROM_START( tarzana )
ROM_LOAD( "tarzan_string.key", 0x00, 0xec, CRC(595fe40c) SHA1(0b46983400d237d8bde97a72eaa99b718a03387e) )
ROM_END
-// IGS PCB NO-0248
-ROM_START( tarzanb ) // V110 TARZAN C
- ROM_REGION( 0x40000, "maincpu", 0 )
- ROM_LOAD( "t.z._v110.u19", 0x00000, 0x40000, CRC(16026d12) SHA1(df08641b4bc1437648f0a8cd5f7a8a4786c07041) )
-
- ROM_REGION( 0x400000, "igs017_igs031:sprites", ROMREGION_ERASE00 )
- ROM_LOAD( "igs_a2103_cg_v100f.u15", 0x000000, 0x200000, CRC(afe56ed5) SHA1(656cee6a59f2930eec9acd11b84b416cc7354e01) )
-
- ROM_REGION( 0x80000, "igs017_igs031:tilemaps", 0 )
- ROM_LOAD( "t.z._text_u5.u5", 0x00000, 0x80000, CRC(1724e039) SHA1(d628499b61f98f7c9034d70b82ee25e002190ece) )
-
- ROM_REGION( 0x80000, "oki", 0 )
- ROM_LOAD( "igs_s2102_sp_v102.u14", 0x00000, 0x80000, CRC(90dda82d) SHA1(67fbc1e8d76b85e124136e2f1df09c8b6c5a8f97) )
-
- ROM_REGION( 0x2dd * 2, "plds", ROMREGION_ERASE )
- ROM_LOAD( "eg.u20", 0x000, 0x2dd, NO_DUMP )
- ROM_LOAD( "eg.u21", 0x2dd, 0x2dd, NO_DUMP )
-
- ROM_REGION( 0xec, "igs_string", 0 )
- ROM_LOAD( "tarzanb_string.key", 0x00, 0xec, CRC(595fe40c) SHA1(0b46983400d237d8bde97a72eaa99b718a03387e) )
-ROM_END
/***************************************************************************
@@ -5820,6 +5832,29 @@ ROM_START( starzan )
ROM_LOAD( "starzan_string.key", 0x00, 0xec, CRC(b33f5050) SHA1(900d3c48944dbdd95d9e48d74c355e82e00ac012) )
ROM_END
+// default settings password is all start button
+ROM_START( jking103a )
+ ROM_REGION( 0x40000, "maincpu", 0 )
+ ROM_LOAD( "jungleking_v103a.u9", 0x00000, 0x40000, CRC(acd23f7e) SHA1(84d487c240d6773c81c04ee12a4aafa7e34affc7) )
+
+ ROM_REGION( 0x400000, "igs017_igs031:sprites", 0 )
+ ROM_LOAD( "igs_a2104_cg_v110.u3", 0x00000, 0x400000, CRC(dcbff16f) SHA1(2bf77ef4448c26124c8d8d18bb7ffe4105cfa940) ) // FIXED BITS (xxxxxxx0xxxxxxxx)
+ // empty u2
+
+ ROM_REGION( 0x80000, "igs017_igs031:tilemaps", 0 )
+ ROM_LOAD( "igs_t2105_cg_v110.u11", 0x00000, 0x80000, CRC(1d4be260) SHA1(6374c61735144b3ff54d5e490f26adac4a10b14d) )
+
+ ROM_REGION( 0x80000, "oki", 0 )
+ ROM_LOAD( "igs_s2102_sp_v102.u8", 0x00000, 0x80000, CRC(90dda82d) SHA1(67fbc1e8d76b85e124136e2f1df09c8b6c5a8f97) )
+
+ ROM_REGION( 0x2dd * 2, "plds", ROMREGION_ERASE )
+ ROM_LOAD( "eg.u20", 0x000, 0x2dd, NO_DUMP )
+ ROM_LOAD( "eg.u21", 0x2dd, 0x2dd, NO_DUMP )
+
+ ROM_REGION( 0xec, "igs_string", 0 )
+ ROM_LOAD( "jking103a_string.key", 0x00, 0xec, BAD_DUMP CRC(8d288f5e) SHA1(19c184600d80838ef04be8ab29c93d91cf3161c9) ) // TODO: check this
+ROM_END
+
/***************************************************************************
@@ -5855,18 +5890,17 @@ ROM_START( happyskl )
ROM_END
-// PCB was heavily corroded and not working
+// dump confirmed from two PCBs
ROM_START( cpoker2 )
ROM_REGION( 0x40000, "maincpu", 0 )
- ROM_LOAD( "u9.bin", 0x00000, 0x40000, CRC(8d79eb4d) SHA1(9cad09013f83335ec78c3ff78715bc5d9a989eb7) )
+ ROM_LOAD( "champion_2_v100a.u9", 0x00000, 0x40000, CRC(8d79eb4d) SHA1(9cad09013f83335ec78c3ff78715bc5d9a989eb7) )
ROM_REGION( 0x400000, "igs017_igs031:sprites", 0 )
- // the following ROM wasn't readable on this PCB, but it's the same as the one in happyskl. Assuming same contents for now
- ROM_LOAD( "igs_a2701_cg_v100.u3", 0x00000, 0x400000, BAD_DUMP CRC(f3756a51) SHA1(8dd4677584f309cec4b068be9f9370a7a172a031) ) // FIXED BITS (xxxxxxx0xxxxxxxx) - 1xxxxxxxxxxxxxxxxxxxxx = 0x00
+ ROM_LOAD( "igs_a2701_cg_v100.u3", 0x00000, 0x400000, CRC(f3756a51) SHA1(8dd4677584f309cec4b068be9f9370a7a172a031) )
// U2 (overlay) not populated
ROM_REGION( 0x80000, "igs017_igs031:tilemaps", 0 )
- ROM_LOAD( "u11.bin", 0x00000, 0x80000, CRC(34475c83) SHA1(376ff68d89c25471483b074dcf7542f42f954e67) ) // 1xxxxxxxxxxxxxxxxxx = 0x00
+ ROM_LOAD( "champion_2_text.u11", 0x00000, 0x80000, CRC(34475c83) SHA1(376ff68d89c25471483b074dcf7542f42f954e67) ) // 1xxxxxxxxxxxxxxxxxx = 0x00
ROM_REGION( 0x80000, "oki", 0 )
ROM_LOAD( "igs_s2702_sp_v100.u8", 0x00000, 0x80000, CRC(0ec9b1b5) SHA1(b8c7e068ddf6777a184339e6796be33e442a3df4) ) // same as happyskl
@@ -5940,6 +5974,7 @@ GAME ( 1999, tarzana, tarzanc, tarzan, tarzan, igs017_state, init_tarzana
GAME ( 1999, tarzanb, tarzanc, tarzan, tarzan, igs017_state, init_tarzanc, ROT0, "IGS", "Tarzan Chuang Tian Guan (China, V110)", 0 )
GAME ( 2000, sdmg2p, 0, sdmg2p, sdmg2p, igs017_state, init_sdmg2p, ROT0, "IGS", "Maque Wangchao / Chaoji Damanguan 2 - Jiaqiang Ban (China, V100C)", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING ) // 麻雀王朝 / 超級大滿貫 2 -加強版 protection kicks in after starting game, hopper isn't hooked up correctly
GAMEL( 2000?, starzan, 0, starzan, starzan, igs017_state, init_starzan, ROT0, "IGS (G.F. Gioca license)", "Super Tarzan (Italy, V100I)", 0, layout_igsslot )
+GAMEL( 2000?, jking103a,starzan, starzan, starzan, igs017_state, init_jking103a,ROT0, "IGS", "Jungle King (V103A)", 0, layout_igsslot )
GAMEL( 2000?, happyskl, 0, happyskl, happyskl, igs017_state, init_happyskl, ROT0, "IGS", "Happy Skill (Italy, V611IT)", 0, layout_igspoker )
GAMEL( 2000?, cpoker2, 0, cpoker2, cpoker2, igs017_state, init_cpoker2, ROT0, "IGS", "Champion Poker 2 (V100A)", 0, layout_igspoker )
GAME ( 2000?, spkrform, spk306us, spkrform, spkrform, igs017_state, init_spkrform, ROT0, "IGS", "Super Poker (V100xD03) / Formosa", MACHINE_UNEMULATED_PROTECTION ) // poker game enabling forced with a patch. Parent spk306us in driver spoker.cpp
diff --git a/src/mame/igs/igs_m027xa.cpp b/src/mame/igs/igs_m027xa.cpp
index 9caa81548c4..97da91afe44 100644
--- a/src/mame/igs/igs_m027xa.cpp
+++ b/src/mame/igs/igs_m027xa.cpp
@@ -9,6 +9,9 @@ These games use the IGS027A processor.
Triple Fever (V105US) (tripfevb) hangs after paying out tickets, with the MCU
apparently attempting serial communication with something.
+TODO:
+* Does crzybugsj actually support a hopper? It shows in the input test, but
+ both the Payout and Ticket buttons seem to use the ticket dispenser.
*/
#include "emu.h"
@@ -31,9 +34,6 @@ apparently attempting serial communication with something.
#include "crzybugs.lh"
#include "tripfev.lh"
-#define LOG_DEBUG (1U << 1)
-//#define VERBOSE (LOG_DEBUG)
-#include "logmacro.h"
namespace {
@@ -49,14 +49,16 @@ class igs_m027xa_state : public driver_device
m_oki(*this, "oki"),
m_screen(*this, "screen"),
m_ticket(*this, "ticket"),
+ m_hopper(*this, "hopper"),
m_external_rom(*this, "user1"),
m_io_test(*this, "TEST%u", 0U),
m_io_dsw(*this, "DSW%u", 1U),
m_out_lamps(*this, "lamp%u", 1U)
{ }
- void igs_mahjong_xa(machine_config &config);
- void igs_mahjong_xa_xor(machine_config &config);
+ void base(machine_config &config);
+ void base_xor(machine_config &config);
+ void hopper_xor(machine_config &config);
void init_crzybugs();
void init_crzybugsj();
@@ -77,6 +79,7 @@ class igs_m027xa_state : public driver_device
required_device m_oki;
required_device m_screen;
optional_device m_ticket;
+ optional_device m_hopper;
required_region_ptr m_external_rom;
optional_ioport_array<3> m_io_test;
@@ -226,13 +229,19 @@ INPUT_PORTS_START( crzybugs )
PORT_MODIFY("TEST1")
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 ) PORT_NAME("Start / Stop All Reels")
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT ) PORT_NAME("Ticket")
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("ticket", ticket_dispenser_device, line_r)
PORT_MODIFY("TEST2")
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SLOT_STOP2 ) PORT_NAME("Stop Reel 2 / Small")
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SLOT_STOP3 ) PORT_NAME("Stop Reel 3 / Take Score")
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SLOT_STOP1 ) PORT_NAME("Stop Reel 1 / Double Up")
+INPUT_PORTS_END
+
+INPUT_PORTS_START( crzybugs_us )
+ PORT_INCLUDE(crzybugs)
+
+ PORT_MODIFY("TEST1")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT ) PORT_NAME("Ticket")
PORT_MODIFY("DSW1")
PORT_DIPNAME( 0x01, 0x01, DEF_STR(Demo_Sounds) ) PORT_DIPLOCATION("SW1:1")
@@ -278,6 +287,30 @@ INPUT_PORTS_START( crzybugs )
PORT_DIPSETTING( 0x00, DEF_STR(Yes) )
INPUT_PORTS_END
+INPUT_PORTS_START( crzybugs_jp )
+ PORT_INCLUDE(crzybugs)
+
+ PORT_MODIFY("TEST0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("hopper", hopper_device, line_r)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT )
+
+ PORT_MODIFY("TEST1")
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Ticket")
+
+ PORT_MODIFY("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR(Demo_Sounds) ) PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x00, DEF_STR(Off) )
+ PORT_DIPSETTING( 0x01, DEF_STR(On) )
+ PORT_DIPNAME( 0x06, 0x06, "Symbol" ) PORT_DIPLOCATION("SW1:2,3")
+ PORT_DIPSETTING( 0x00, "Both" )
+ PORT_DIPSETTING( 0x02, "Both (duplicate)" )
+ PORT_DIPSETTING( 0x04, "Fruit" )
+ PORT_DIPSETTING( 0x06, "Bug" )
+ PORT_DIPNAME( 0x08, 0x08, "Hold Pair" ) PORT_DIPLOCATION("SW1:4")
+ PORT_DIPSETTING( 0x08, DEF_STR(Off) )
+ PORT_DIPSETTING( 0x00, "Regular" )
+INPUT_PORTS_END
+
INPUT_PORTS_START( tripfev )
PORT_INCLUDE(base)
@@ -436,7 +469,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(igs_m027xa_state::interrupt)
}
-void igs_m027xa_state::igs_mahjong_xa(machine_config &config)
+void igs_m027xa_state::base(machine_config &config)
{
IGS027A(config, m_maincpu, 22'000'000); // Crazy Bugs has a 22MHz crystal, what about the others?
m_maincpu->set_addrmap(AS_PROGRAM, &igs_m027xa_state::main_map);
@@ -479,13 +512,20 @@ void igs_m027xa_state::igs_mahjong_xa(machine_config &config)
OKIM6295(config, m_oki, 1000000, okim6295_device::PIN7_HIGH).add_route(ALL_OUTPUTS, "mono", 0.5);
}
-void igs_m027xa_state::igs_mahjong_xa_xor(machine_config &config)
+void igs_m027xa_state::base_xor(machine_config &config)
{
- igs_mahjong_xa(config);
+ base(config);
m_maincpu->set_addrmap(AS_PROGRAM, &igs_m027xa_state::main_xor_map);
}
+void igs_m027xa_state::hopper_xor(machine_config &config)
+{
+ base_xor(config);
+
+ HOPPER(config, m_hopper, attotime::from_msec(50));
+}
+
// prg at u34
// text at u15
// cg at u32 / u12
@@ -612,7 +652,7 @@ ROM_END
ROM_START( crzybugsj ) // IGS PCB-0575-04-HU - Has IGS027A, MX10EXAQC, IGS031, Oki M6295, 2x 8-dip banks
ROM_REGION( 0x04000, "maincpu", 0 )
// Internal ROM of IGS027A ARM based MCU
- ROM_LOAD( "m6.u42", 0x00000, 0x4000, NO_DUMP ) // sticker marked 'M6'
+ ROM_LOAD( "m6.u42", 0x00000, 0x4000, CRC(ae3a0b2a) SHA1(60265c98278625791cdf6af6b242888e45b6b3bb) ) // sticker marked 'M6'
ROM_REGION32_LE( 0x200000, "user1", 0 ) // external ARM data / prg
ROM_LOAD( "crazy_bugs_v-103jp.u34", 0x000000, 0x200000, CRC(1e35ed79) SHA1(0e4f8b706cdfcaf2aacdc40eec422df9d865b311) )
@@ -733,7 +773,7 @@ void igs_m027xa_state::pgm_create_dummy_internal_arm_region()
for (int i = 0; i < 0x4000 / 2; i += 2)
{
temp16[i] = 0xff1e;
- temp16[i +1] = 0xe12f;
+ temp16[i + 1] = 0xe12f;
}
@@ -766,8 +806,8 @@ void igs_m027xa_state::init_crzybugs()
void igs_m027xa_state::init_crzybugsj()
{
crzybugsj_decrypt(machine());
- //qlgs_gfx_decrypt(machine());
- pgm_create_dummy_internal_arm_region();
+ m_igs017_igs031->sdwx_gfx_decrypt();
+ m_igs017_igs031->tarzan_decrypt_sprites(0, 0);
}
void igs_m027xa_state::init_tripfev()
@@ -788,17 +828,17 @@ void igs_m027xa_state::init_wldfruit()
// These use the MX10EXAQC (80c51XA from Philips)
// the PCBs are closer to igs_fear.cpp in terms of layout
-GAME( 2008, haunthig, 0, igs_mahjong_xa, base, igs_m027xa_state, init_hauntedh, ROT0, "IGS", "Haunted House (IGS, V109US)", MACHINE_NOT_WORKING ) // IGS FOR V109US 2008 10 14
-GAME( 2006, haunthiga, haunthig, igs_mahjong_xa, base, igs_m027xa_state, init_hauntedh, ROT0, "IGS", "Haunted House (IGS, V101US)", MACHINE_NOT_WORKING ) // IGS FOR V101US 2006 08 23
+GAME( 2008, haunthig, 0, base, base, igs_m027xa_state, init_hauntedh, ROT0, "IGS", "Haunted House (IGS, V109US)", MACHINE_NOT_WORKING ) // IGS FOR V109US 2008 10 14
+GAME( 2006, haunthiga, haunthig, base, base, igs_m027xa_state, init_hauntedh, ROT0, "IGS", "Haunted House (IGS, V101US)", MACHINE_NOT_WORKING ) // IGS FOR V101US 2006 08 23
-GAMEL( 2009, crzybugs, 0, igs_mahjong_xa_xor, crzybugs, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V204US)", 0, layout_crzybugs ) // IGS FOR V204US 2009 5 19
-GAMEL( 2006, crzybugsa, crzybugs, igs_mahjong_xa_xor, crzybugs, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V202US)", 0, layout_crzybugs ) // IGS FOR V100US 2006 3 29 but also V202US string
-GAMEL( 2005, crzybugsb, crzybugs, igs_mahjong_xa_xor, crzybugs, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V200US)", 0, layout_crzybugs ) // FOR V100US 2005 7 20 but also V200US string
+GAMEL( 2009, crzybugs, 0, base_xor, crzybugs_us, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V204US)", 0, layout_crzybugs ) // IGS FOR V204US 2009 5 19
+GAMEL( 2006, crzybugsa, crzybugs, base_xor, crzybugs_us, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V202US)", 0, layout_crzybugs ) // IGS FOR V100US 2006 3 29 but also V202US string
+GAMEL( 2005, crzybugsb, crzybugs, base_xor, crzybugs_us, igs_m027xa_state, init_crzybugs, ROT0, "IGS", "Crazy Bugs (V200US)", 0, layout_crzybugs ) // FOR V100US 2005 7 20 but also V200US string
-GAME( 2007, crzybugsj, crzybugs, igs_mahjong_xa, crzybugs, igs_m027xa_state, init_crzybugsj, ROT0, "IGS", "Crazy Bugs (V103JP)", MACHINE_NOT_WORKING ) // IGS FOR V101JP 2007 06 08
+GAMEL( 2007, crzybugsj, crzybugs, hopper_xor, crzybugs_jp, igs_m027xa_state, init_crzybugsj, ROT0, "IGS", "Crazy Bugs (V103JP)", 0, layout_crzybugs ) // IGS FOR V101JP 2007 06 08 (test mode calls this V102JP, ROM label was V103JP)
-GAMEL( 2006, tripfev, 0, igs_mahjong_xa_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V108US)", 0, layout_tripfev )
-GAMEL( 2006, tripfeva, tripfev, igs_mahjong_xa_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V107US)", 0, layout_tripfev ) // IGS FOR V107US 2006 09 07
-GAMEL( 2006, tripfevb, tripfev, igs_mahjong_xa_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V105US)", MACHINE_NOT_WORKING, layout_tripfev )
+GAMEL( 2006, tripfev, 0, base_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V108US)", 0, layout_tripfev )
+GAMEL( 2006, tripfeva, tripfev, base_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V107US)", 0, layout_tripfev ) // IGS FOR V107US 2006 09 07
+GAMEL( 2006, tripfevb, tripfev, base_xor, tripfev, igs_m027xa_state, init_tripfev, ROT0, "IGS", "Triple Fever (V105US)", MACHINE_NOT_WORKING, layout_tripfev )
-GAME( 200?, wldfruit, 0, igs_mahjong_xa, base, igs_m027xa_state, init_wldfruit, ROT0, "IGS", "Wild Fruit (V208US)", MACHINE_NOT_WORKING ) // IGS-----97----V208US
+GAME( 200?, wldfruit, 0, base, base, igs_m027xa_state, init_wldfruit, ROT0, "IGS", "Wild Fruit (V208US)", MACHINE_NOT_WORKING ) // IGS-----97----V208US
diff --git a/src/mame/igs/igs_m036.cpp b/src/mame/igs/igs_m036.cpp
index 4ed74d8b9b1..2d5aacf1e70 100644
--- a/src/mame/igs/igs_m036.cpp
+++ b/src/mame/igs/igs_m036.cpp
@@ -418,6 +418,31 @@ ROM_START( lhzbgqb )
ROM_END
+// this PCB has IGS036 MCU, R5F21256SN MCU, TT5665, ALTERA EPM3032ALC44-10N (stickered IS U15)
+// ROM labels actually are written "super 70's..."
+ROM_START( super70s )
+ ROM_REGION( 0x04000, "maincpu", 0 )
+ // Internal ROM of IGS036 ARM based MCU
+ ROM_LOAD( "f9_igs036.u28", 0x00000, 0x4000, NO_DUMP )
+
+ ROM_REGION( 0x8000, "mcu", 0 )
+ ROM_LOAD( "r5f21256sn.u32", 0x0000, 0x8000, NO_DUMP )
+
+ // this seems to be dumped half sized if compared to other dumps in the driver of this same kind of ROM
+ ROM_REGION32_LE( 0x200000, "user1", 0 ) // external ARM data / prg
+ ROM_LOAD( "super_70s_v-100us.u31", 0x000000, 0x100000, BAD_DUMP CRC(60020aa3) SHA1(f6be4f9588192ef1e57182e5a61228440e5cfa64) ) // EV29LV160, BADADDR xxxxxxxxxxxxxxxxxx-x
+
+ // this seems to be dumped half sized if compared to other dumps in the driver of this same kind of ROM
+ ROM_REGION( 0x400000, "tt5665", 0 ) // samples
+ ROM_LOAD( "super_70s_v100us_u27.u27", 0x000000, 0x400000, BAD_DUMP CRC(a57fbc1c) SHA1(c7b0c72e678cd4120f576283eca8d718c058994c) ) // EV29LV640, 11xxxxxxxxxxxxxxxxxxxx = 0x00
+
+ // these seem to be dumped half sized if compared to other dumps in the driver of this same kind of ROM
+ ROM_REGION( 0x800000, "gfx", 0 )
+ ROM_LOAD( "super_70s_v100us_u25.u25", 0x000000, 0x400000, BAD_DUMP CRC(41baefa5) SHA1(1817bf43b3f72df35d50ef1ceb151d77ecfb988b) ) // EV29LV640
+ ROM_LOAD( "super_70s_v100us_u26.u26", 0x400000, 0x400000, BAD_DUMP CRC(39bb6c75) SHA1(bc52e51f1ad3588253cb42eb61baa11d0720c5a5) ) // EV29LV640
+ROM_END
+
+
void igs_m036_state::pgm_create_dummy_internal_arm_region(void)
{
uint16_t *temp16 = (uint16_t *)memregion("maincpu")->base();
@@ -547,6 +572,8 @@ GAME( 200?, lhzb3in1, 0, igs_m036_tt, igs_m036, igs_m036_state, init_cjddzsp
GAME( 200?, igsm312, 0, igs_m036_tt, igs_m036, igs_m036_state, init_igsm312, ROT0, "IGS", "unknown 'IGS 6POKER2' game (V312CN)", MACHINE_IS_SKELETON ) // there's very little code and no gfx ROMs, might be a 'set/clear' chip for a gambling game.
+GAME( 200?, super70s, 0, igs_m036_tt, igs_m036, igs_m036_state, init_igsm312, ROT0, "IGS", "Super 70's (V100US)", MACHINE_IS_SKELETON )
+
GAME( 2010, lhfy, 0, igs_m036_tt, igs_m036, igs_m036_state, init_igsm312, ROT0, "IGS", "Long Hu Feng Yun Gao Qing Ban (V206CN)", MACHINE_IS_SKELETON )
GAME( 2010, lhzbgqb, 0, igs_m036_tt, igs_m036, igs_m036_state, init_igsm312, ROT0, "IGS", "Long Hu Zheng Ba Gao Qing Ban (V105CN)", MACHINE_IS_SKELETON )
diff --git a/src/mame/igs/pgmcrypt.cpp b/src/mame/igs/pgmcrypt.cpp
index d243259bd32..28f3084773b 100644
--- a/src/mame/igs/pgmcrypt.cpp
+++ b/src/mame/igs/pgmcrypt.cpp
@@ -1476,49 +1476,26 @@ void mgzz_decrypt(running_machine &machine)
}
// IGS FOR V101JP 2007 06 08
-
-static const uint8_t crzybugsj_tab[0x100] = {
- 0x67, 0x9b, 0x05, 0x4a, 0x32, 0xcf, 0x41, 0xf8, 0xf8, 0xd5, 0xac, 0x5e, 0xd2, 0x6d, 0xbc, 0xd9,
- 0x3a, 0x15, 0x63, 0x71, 0xd6, 0x65, 0x5f, 0xce, 0xba, 0x9d, 0x1c, 0x75, 0x75, 0x25, 0x3c, 0x64,
- 0xd6, 0x83, 0xc6, 0x7c, 0x7a, 0xe1, 0x13, 0x3c, 0xb9, 0xbe, 0xd4, 0x12, 0x1e, 0xcf, 0x0e, 0xa4,
- 0x43, 0x07, 0xdd, 0x7f, 0x7d, 0x93, 0x8d, 0x79, 0xaf, 0xc5, 0x5e, 0x16, 0x26, 0xc6, 0x7b, 0x77,
- 0xd1, 0xdf, 0x0e, 0xe3, 0x7a, 0x64, 0xfe, 0xd3, 0x60, 0xd0, 0xa3, 0x3e, 0x4e, 0x10, 0x66, 0x98,
- 0x57, 0x03, 0x3d, 0xea, 0x4b, 0x0e, 0x5e, 0x83, 0xf6, 0xcf, 0xc8, 0x19, 0x4f, 0xd6, 0x0b, 0xcc,
- 0xc8, 0x69, 0x21, 0x82, 0x0c, 0xdd, 0x6f, 0x6a, 0x34, 0xe1, 0x4f, 0x15, 0xe6, 0xfd, 0xa7, 0xce,
- 0xbe, 0xd1, 0x38, 0x58, 0x17, 0xf2, 0xa1, 0xf7, 0xbe, 0x2e, 0x4c, 0x0e, 0xc8, 0x5d, 0xf7, 0xa1,
- 0x2a, 0x71, 0xd2, 0xe6, 0x07, 0x6f, 0x56, 0xcb, 0xdd, 0xe3, 0x00, 0x0b, 0x3e, 0x3d, 0xd4, 0xbf,
- 0x24, 0x41, 0x7a, 0x4e, 0xb8, 0xb4, 0x67, 0xc3, 0x2e, 0xa0, 0x57, 0xb5, 0xf1, 0xe4, 0x67, 0x29,
- 0x9e, 0xf8, 0x4e, 0x81, 0x45, 0x62, 0x90, 0xff, 0x7c, 0x90, 0xad, 0xea, 0xee, 0x18, 0x02, 0x1c,
- 0x6e, 0x14, 0x6a, 0x44, 0x08, 0x9f, 0x6b, 0xe9, 0xe8, 0x5a, 0x7c, 0x2e, 0xa2, 0x32, 0x60, 0x5d,
- 0x6a, 0x8d, 0x9c, 0xf7, 0x9d, 0x23, 0x24, 0x39, 0x47, 0x65, 0xb7, 0x3f, 0x8e, 0xb7, 0x68, 0xe4,
- 0xa6, 0x19, 0x60, 0xc2, 0xde, 0xc7, 0xb5, 0x4e, 0x23, 0x94, 0x39, 0x76, 0x6b, 0x9f, 0x16, 0xf7,
- 0x39, 0xb0, 0x65, 0xb6, 0xe7, 0xe5, 0xdb, 0xbf, 0xd7, 0x95, 0xbd, 0x3b, 0x36, 0x71, 0xfe, 0x8f,
- 0x15, 0x10, 0xe5, 0x63, 0x12, 0xa5, 0x1a, 0xee, 0x77, 0x49, 0x2e, 0xb4, 0x25, 0xd4, 0x83, 0x2d
-};
-
void crzybugsj_decrypt(running_machine &machine)
{
- auto const src = reinterpret_cast(machine.root_device().memregion("user1")->base());
-
- int const rom_size = 0x80000;
+ memory_region *const region = machine.root_device().memregion("user1");
+ auto const src = util::little_endian_cast(reinterpret_cast(region->base()));
+ auto const rom_size = region->bytes();
for (int i = 0; i < rom_size / 2; i++)
{
- int x = src[i];
+ uint16_t x = 0;
- // may need corrected
IGS27_CRYPT1
- IGS27_CRYPT2_ALT // correct
- IGS27_CRYPT3_ALT // correct
- IGS27_CRYPT4 // correct
- IGS27_CRYPT5 // correct
+ IGS27_CRYPT2_ALT
+ IGS27_CRYPT3_ALT
+ IGS27_CRYPT4
+ IGS27_CRYPT5
IGS27_CRYPT6
IGS27_CRYPT7
IGS27_CRYPT8
- x ^= crzybugsj_tab[(i >> 1) & 0xff] << 8;
-
- src[i] = x;
+ src[i] ^= x;
}
}
diff --git a/src/mame/jaleco/bestleag.cpp b/src/mame/jaleco/bestleag.cpp
index f1abea4e8cd..c5dfa30f802 100644
--- a/src/mame/jaleco/bestleag.cpp
+++ b/src/mame/jaleco/bestleag.cpp
@@ -1,28 +1,17 @@
// license:BSD-3-Clause
-// copyright-holders:Angelo Salese, David Haywood
-/*******************************************************************************************
+// copyright-holders:Angelo Salese, David Haywood, Pierpaolo Prazzoli
+/**************************************************************************************************
Best League (c) 1993
A Big Striker Italian bootleg (made by Playmark?) running on a different hardware.
-driver by David Haywood & Angelo Salese
-
-Changes 29/03/2005 - Pierpaolo Prazzoli
-- Fixed tilemaps and sprites offset
-- Fixed visible area
-- Fixed dip-switches
-- Added oki banking
-- Added sprites wraparound
-- Added sprites color masking
-
-Dip Locations added according to Service Mode
-
-*******************************************************************************************/
+**************************************************************************************************/
#include "emu.h"
#include "cpu/m68000/m68000.h"
#include "sound/okim6295.h"
+
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
@@ -34,19 +23,31 @@ namespace {
class bestleag_state : public driver_device
{
public:
- bestleag_state(const machine_config &mconfig, device_type type, const char *tag) :
- driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_oki(*this, "oki"),
- m_gfxdecode(*this, "gfxdecode"),
- m_palette(*this, "palette"),
- m_bgram(*this, "bgram"),
- m_fgram(*this, "fgram"),
- m_txram(*this, "txram"),
- m_vregs(*this, "vregs"),
- m_spriteram(*this, "spriteram")
+ bestleag_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_vregs(*this, "vregs")
+ , m_maincpu(*this, "maincpu")
+ , m_oki(*this, "oki")
+ , m_gfxdecode(*this, "gfxdecode")
+ , m_palette(*this, "palette")
+ , m_bgram(*this, "bgram")
+ , m_fgram(*this, "fgram")
+ , m_txram(*this, "txram")
+ , m_spriteram(*this, "spriteram")
{ }
+ void bestleag(machine_config &config) ATTR_COLD;
+
+protected:
+ tilemap_t *m_tx_tilemap = nullptr;
+ tilemap_t *m_bg_tilemap = nullptr;
+ tilemap_t *m_fg_tilemap = nullptr;
+ void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ required_shared_ptr m_vregs;
+
+private:
required_device m_maincpu;
required_device m_oki;
required_device m_gfxdecode;
@@ -55,12 +56,8 @@ class bestleag_state : public driver_device
required_shared_ptr m_bgram;
required_shared_ptr m_fgram;
required_shared_ptr m_txram;
- required_shared_ptr m_vregs;
required_shared_ptr m_spriteram;
- tilemap_t *m_tx_tilemap = nullptr;
- tilemap_t *m_bg_tilemap = nullptr;
- tilemap_t *m_fg_tilemap = nullptr;
void txram_w(offs_t offset, uint16_t data);
void bgram_w(offs_t offset, uint16_t data);
@@ -70,20 +67,23 @@ class bestleag_state : public driver_device
TILE_GET_INFO_MEMBER(get_tx_tile_info);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
- TILEMAP_MAPPER_MEMBER(bsb_bg_scan);
+ TILEMAP_MAPPER_MEMBER(bg_scan);
virtual void video_start() override ATTR_COLD;
- uint32_t screen_update_bestleag(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- uint32_t screen_update_bestleaw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
- void bestleag(machine_config &config);
- void bestleaw(machine_config &config);
- void bestleag_map(address_map &map) ATTR_COLD;
+ void main_map(address_map &map) ATTR_COLD;
};
+class bestleaw_state : public bestleag_state
+{
+public:
+ bestleaw_state(const machine_config &mconfig, device_type type, const char *tag)
+ : bestleag_state(mconfig, type, tag)
+ { }
-/* Video Handling */
+protected:
+ virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
+};
TILE_GET_INFO_MEMBER(bestleag_state::get_tx_tile_info)
@@ -116,7 +116,7 @@ TILE_GET_INFO_MEMBER(bestleag_state::get_fg_tile_info)
0);
}
-TILEMAP_MAPPER_MEMBER(bestleag_state::bsb_bg_scan)
+TILEMAP_MAPPER_MEMBER(bestleag_state::bg_scan)
{
int offset;
@@ -130,22 +130,19 @@ TILEMAP_MAPPER_MEMBER(bestleag_state::bsb_bg_scan)
void bestleag_state::video_start()
{
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(bestleag_state::get_tx_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 256, 32);
- m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(bestleag_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(bestleag_state::bsb_bg_scan)), 16, 16, 128, 64);
- m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(bestleag_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(bestleag_state::bsb_bg_scan)), 16, 16, 128, 64);
+ m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(bestleag_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(bestleag_state::bg_scan)), 16, 16, 128, 64);
+ m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(bestleag_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(bestleag_state::bg_scan)), 16, 16, 128, 64);
m_tx_tilemap->set_transparent_pen(15);
m_fg_tilemap->set_transparent_pen(15);
}
+/*
+ * Sprites are the same to sslam, but using 16x16 sprites instead of 8x8,
+ * moved start address to 0x16/2?
+ */
void bestleag_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- /*
- Sprites are the same to sslam, but using 16x16 sprites instead of 8x8
-
- Note: sprite chip is different than the other Big Striker sets and they
- include several similiarities with other Playmark games (including
- the sprite end code and the data being offset (i.e. spriteram starting from 0x16/2))
- */
for (int offs = 0x16/2; offs < m_spriteram.length() - 3; offs += 4)
{
int code = m_spriteram[offs+3] & 0xfff;
@@ -189,7 +186,7 @@ void bestleag_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec
}
}
-uint32_t bestleag_state::screen_update_bestleag(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+uint32_t bestleag_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0,(m_vregs[0x00/2] & 0xfff) + (m_vregs[0x08/2] & 0x7) - 3);
m_bg_tilemap->set_scrolly(0,m_vregs[0x02/2]);
@@ -205,7 +202,7 @@ uint32_t bestleag_state::screen_update_bestleag(screen_device &screen, bitmap_in
return 0;
}
-uint32_t bestleag_state::screen_update_bestleaw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+uint32_t bestleaw_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0,m_vregs[0x08/2]);
m_bg_tilemap->set_scrolly(0,m_vregs[0x0a/2]);
@@ -245,9 +242,8 @@ void bestleag_state::oki_bank_w(uint16_t data)
}
-/* Memory Map */
-void bestleag_state::bestleag_map(address_map &map)
+void bestleag_state::main_map(address_map &map)
{
map(0x000000, 0x03ffff).rom();
map(0x0d2000, 0x0d3fff).noprw(); // left over from the original game (only read / written in memory test)
@@ -346,15 +342,15 @@ static INPUT_PORTS_START( bestleag )
PORT_SERVICE_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW.B:8")
INPUT_PORTS_END
-/* GFX Decode */
+
static const gfx_layout bestleag_charlayout =
{
8,8,
RGN_FRAC(1,4),
4,
{ RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
- { 0, 1, 2, 3, 4, 5, 6, 7 },
- { 0*8, 2*8, 4*8, 6*8,1*8,3*8,5*8,7*8},
+ { STEP8(0, 1) },
+ { 0*8, 2*8, 4*8, 6*8, 1*8, 3*8, 5*8, 7*8},
8*8
};
@@ -364,9 +360,8 @@ static const gfx_layout bestleag_char16layout =
RGN_FRAC(1,4),
4,
{ RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
- { 0,1,2, 3, 4, 5, 6, 7,
- 128+0,128+1,128+2,128+3,128+4,128+5,128+6,128+7 },
- { 0*8,1*8,2*8,3*8,4*8,5*8,6*8,7*8,8*8,9*8,10*8,11*8,12*8,13*8,14*8,15*8 },
+ { STEP8(0, 1), STEP8(128, 1) },
+ { STEP16(0, 8) },
16*16
};
@@ -379,7 +374,7 @@ GFXDECODE_END
void bestleag_state::bestleag(machine_config &config)
{
M68000(config, m_maincpu, 12000000);
- m_maincpu->set_addrmap(AS_PROGRAM, &bestleag_state::bestleag_map);
+ m_maincpu->set_addrmap(AS_PROGRAM, &bestleag_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(bestleag_state::irq6_line_hold));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
@@ -387,7 +382,7 @@ void bestleag_state::bestleag(machine_config &config)
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 2*8, 30*8-1);
- screen.set_screen_update(FUNC(bestleag_state::screen_update_bestleag));
+ screen.set_screen_update(FUNC(bestleag_state::screen_update));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_bestleag);
@@ -401,14 +396,6 @@ void bestleag_state::bestleag(machine_config &config)
m_oki->add_route(ALL_OUTPUTS, "rspeaker", 1.00);
}
-void bestleag_state::bestleaw(machine_config &config)
-{
- bestleag(config);
- subdevice("screen")->set_screen_update(FUNC(bestleag_state::screen_update_bestleaw));
-}
-
-
-/* Rom Loading */
ROM_START( bestleag )
ROM_REGION( 0x40000, "maincpu", 0 ) /* 68000 Code */
@@ -478,7 +465,5 @@ ROM_END
} // anonymous namespace
-/* GAME drivers */
-
GAME( 1993, bestleag, bigstrik, bestleag, bestleag, bestleag_state, empty_init, ROT0, "bootleg", "Best League (bootleg of Big Striker, Italian Serie A)", MACHINE_NO_COCKTAIL | MACHINE_SUPPORTS_SAVE )
-GAME( 1993, bestleaw, bigstrik, bestleaw, bestleag, bestleag_state, empty_init, ROT0, "bootleg", "Best League (bootleg of Big Striker, World Cup)", MACHINE_NO_COCKTAIL | MACHINE_SUPPORTS_SAVE )
+GAME( 1993, bestleaw, bigstrik, bestleag, bestleag, bestleaw_state, empty_init, ROT0, "bootleg", "Best League (bootleg of Big Striker, World Cup)", MACHINE_NO_COCKTAIL | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/jaleco/ddayjlc.cpp b/src/mame/jaleco/ddayjlc.cpp
index cad226eb5f3..2d73f916ac9 100644
--- a/src/mame/jaleco/ddayjlc.cpp
+++ b/src/mame/jaleco/ddayjlc.cpp
@@ -2,16 +2,14 @@
// copyright-holders:Pierpaolo Prazzoli, Tomasz Slanina, Angelo Salese
/*
- D-DAY (c)Jaleco 1984
+D-DAY (c)Jaleco 1984
- driver by Pierpaolo Prazzoli, Tomasz Slanina and Angelo Salese
-
- TODO:
- - text colors most likely are hardwired but iirc hi score text has a different color? Needs a reference shot;
- - unused upper sprite color bank;
- - improve sound comms, sometimes BGM becomes silent;
- - hookup proper i8257 device;
- - identify & dump MCU;
+TODO:
+- text colors most likely are hardwired but iirc hi score text has a different color?
+ Needs a reference shot;
+- unused upper sprite color bank;
+- improve sound comms, sometimes BGM becomes silent;
+- identify & dump MCU;
-------------------------------------------------------
Is it 1984 or 1987 game ?
@@ -62,6 +60,7 @@ There's text inside rom "1987.07 BY ELS"
#include "emu.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
+#include "machine/i8257.h"
#include "sound/ay8910.h"
#include "emupal.h"
#include "screen.h"
@@ -84,7 +83,8 @@ class ddayjlc_state : public driver_device
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
- m_soundlatch(*this, "soundlatch")
+ m_soundlatch(*this, "soundlatch"),
+ m_dma(*this, "dma")
{ }
void ddayjlc(machine_config &config);
@@ -109,8 +109,6 @@ class ddayjlc_state : public driver_device
void bg2_w(uint8_t data);
void sound_w(uint8_t data);
void flip_screen_w(uint8_t data);
- void i8257_CH0_w(offs_t offset, uint8_t data);
- void i8257_LMSR_w(address_space &space, uint8_t data);
TILE_GET_INFO_MEMBER(get_tile_info_bg);
TILE_GET_INFO_MEMBER(get_tile_info_fg);
void ddayjlc_palette(palette_device &palette) const;
@@ -134,8 +132,6 @@ class ddayjlc_state : public driver_device
/* misc */
bool m_sound_nmi_enable = false;
bool m_main_nmi_enable = false;
- int32_t m_e00x_l[4]{};
- int32_t m_e00x_d[4][2]{};
uint8_t m_prot_addr = 0;
/* devices */
@@ -144,6 +140,14 @@ class ddayjlc_state : public driver_device
required_device m_gfxdecode;
required_device m_palette;
required_device m_soundlatch;
+ required_device m_dma;
+
+ uint8_t dma_mem_r(offs_t offset);
+ void dma_mem_w(offs_t offset, u8 data);
+ void hrq_w(int state);
+ u8 dma_r();
+ void dma_w(u8 data);
+ u8 m_dma_latch = 0;
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_foreground(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
@@ -360,35 +364,6 @@ void ddayjlc_state::flip_screen_w(uint8_t data)
flip_screen_set(data & 1);
}
-void ddayjlc_state::i8257_CH0_w(offs_t offset, uint8_t data)
-{
- m_e00x_d[offset][m_e00x_l[offset]] = data;
- m_e00x_l[offset] ^= 1;
-}
-
-void ddayjlc_state::i8257_LMSR_w(address_space &space, uint8_t data)
-{
- if (!data)
- {
- int32_t src = m_e00x_d[0][1] * 256 + m_e00x_d[0][0];
- int32_t dst = m_e00x_d[2][1] * 256 + m_e00x_d[2][0];
- int32_t size = (m_e00x_d[1][1] * 256 + m_e00x_d[1][0]) & 0x3ff;
- int32_t i;
-
- size++; //??
-
- for(i = 0; i < size; i++)
- space.write_byte(dst++, space.read_byte(src++));
-
- m_e00x_l[0] = 0;
- m_e00x_l[1] = 0;
- m_e00x_l[2] = 0;
- m_e00x_l[3] = 0;
- }
-}
-
-
-
void ddayjlc_state::main_map(address_map &map)
{
map(0x0000, 0x7fff).rom();
@@ -397,13 +372,16 @@ void ddayjlc_state::main_map(address_map &map)
map(0x9400, 0x97ff).ram().w(FUNC(ddayjlc_state::vram_w)).share("videoram");
map(0x9800, 0x9fff).ram().w(FUNC(ddayjlc_state::bgvram_w)).share("bgram"); /* 9800-981f - videoregs */
map(0xa000, 0xdfff).bankr("bank1").nopw();
- map(0xe000, 0xe003).w(FUNC(ddayjlc_state::i8257_CH0_w));
- map(0xe008, 0xe008).nopw(); // i8257 control byte
+ map(0xe000, 0xe008).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write));
map(0xf000, 0xf000).w(FUNC(ddayjlc_state::sound_w));
map(0xf100, 0xf100).nopw(); // sound related (f/f irq trigger?)
map(0xf080, 0xf080).portr("P2").w(FUNC(ddayjlc_state::char_bank_w));
map(0xf081, 0xf081).w(FUNC(ddayjlc_state::flip_screen_w));
- map(0xf083, 0xf083).w(FUNC(ddayjlc_state::i8257_LMSR_w));
+ // fn originally marked "LMSR"
+ map(0xf083, 0xf083).lw8(NAME([this] (u8 data) {
+ m_dma->dreq1_w(BIT(data, 0));
+ m_dma->dreq0_w(BIT(data, 0));
+ }));
map(0xf084, 0xf084).w(FUNC(ddayjlc_state::bg0_w));
map(0xf085, 0xf085).w(FUNC(ddayjlc_state::bg1_w));
map(0xf086, 0xf086).w(FUNC(ddayjlc_state::bg2_w));
@@ -543,12 +521,6 @@ void ddayjlc_state::machine_start()
save_item(NAME(m_sound_nmi_enable));
save_item(NAME(m_main_nmi_enable));
save_item(NAME(m_prot_addr));
-
- save_item(NAME(m_e00x_l));
- save_item(NAME(m_e00x_d[0]));
- save_item(NAME(m_e00x_d[1]));
- save_item(NAME(m_e00x_d[2]));
- save_item(NAME(m_e00x_d[3]));
}
void ddayjlc_state::machine_reset()
@@ -558,13 +530,6 @@ void ddayjlc_state::machine_reset()
m_sound_nmi_enable = false;
m_main_nmi_enable = false;
m_prot_addr = 0;
-
- for (int i = 0; i < 4; i++)
- {
- m_e00x_l[i] = 0;
- m_e00x_d[i][0] = 0;
- m_e00x_d[i][1] = 0;
- }
}
void ddayjlc_state::ddayjlc_palette(palette_device &palette) const
@@ -599,6 +564,38 @@ void ddayjlc_state::ddayjlc_palette(palette_device &palette) const
palette.set_pen_color(0x203, rgb_t(0xff, 0xff, 0xff));
}
+uint8_t ddayjlc_state::dma_mem_r(offs_t offset)
+{
+ address_space &program = m_maincpu->space(AS_PROGRAM);
+
+ return program.read_byte(offset);
+}
+
+void ddayjlc_state::dma_mem_w(offs_t offset, u8 data)
+{
+ address_space &program = m_maincpu->space(AS_PROGRAM);
+
+ program.write_byte(offset, data);
+}
+
+void ddayjlc_state::hrq_w(int state)
+{
+ m_maincpu->set_input_line(Z80_INPUT_LINE_BUSRQ, state);
+
+ // TODO: why we need this?
+ m_dma->hlda_w(state);
+}
+
+u8 ddayjlc_state::dma_r()
+{
+ return m_dma_latch;
+}
+
+void ddayjlc_state::dma_w(u8 data)
+{
+ m_dma_latch = data;
+}
+
void ddayjlc_state::ddayjlc(machine_config &config)
{
/* basic machine hardware */
@@ -610,6 +607,14 @@ void ddayjlc_state::ddayjlc(machine_config &config)
config.set_maximum_quantum(attotime::from_hz(6000));
+ I8257(config, m_dma, 12000000/3);
+ m_dma->out_hrq_cb().set(FUNC(ddayjlc_state::hrq_w));
+ m_dma->in_memr_cb().set(FUNC(ddayjlc_state::dma_mem_r));
+ m_dma->out_memw_cb().set(FUNC(ddayjlc_state::dma_mem_w));
+ m_dma->in_ior_cb<1>().set(FUNC(ddayjlc_state::dma_r));
+ m_dma->out_iow_cb<0>().set(FUNC(ddayjlc_state::dma_w));
+ m_dma->set_reverse_rw_mode(true);
+
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
diff --git a/src/mame/layout/lnux4004.lay b/src/mame/layout/lnux4004.lay
new file mode 100644
index 00000000000..6b69528fed1
--- /dev/null
+++ b/src/mame/layout/lnux4004.lay
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index df67a643bbd..de30cacb256 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -19767,6 +19767,9 @@ gsz80 // Grant Searle's Simple Z-80 Machine
@source:homebrew/homez80.cpp
homez80 //
+@source:homebrew/linux4004.cpp
+lnux4004
+
@source:homebrew/lft_chiptune.cpp
powernin // Power Ninja Action Challenge, by [lft] (2009)
hwchiptn // The Hardware Chiptune Project, by [lft] and kryo (2007)
@@ -20290,6 +20293,7 @@ genius6b // (c) 1997
happyskl // (c) 2000?
iqblocka // (c) 1996
iqblockf // (c) 1996
+jking103a // (c) 1999
lhzb2 // (c) 1998
lhzb2a // (c) 1998
mgcs // (c) 1998
@@ -20375,6 +20379,7 @@ lhzb3in1 // (c) 200?
lhzbgqb // (c) 2010
mghammer // (c) 2015
qhzb // (c) 2007
+super70s // (c) 200?
@source:igs/igspoker.cpp
chleague // (c) 199? IGS
@@ -27721,6 +27726,9 @@ triviayp // (c) 1984
triviaes4 // (c) 1988 (Maibesa hardware)
triviaes5 // (c) 19?? (Maibesa hardware)
+@source:midway/cashline.cpp
+cashline // (c) 1981 Bally/Sente
+
@source:midway/gridlee.cpp
gridlee // [1983 Videa] prototype - no copyright notice
diff --git a/src/mame/midway/cashline.cpp b/src/mame/midway/cashline.cpp
new file mode 100644
index 00000000000..fa329319cd7
--- /dev/null
+++ b/src/mame/midway/cashline.cpp
@@ -0,0 +1,186 @@
+// license:BSD-3-Clause
+// copyright-holders:
+/*
+ Skeleton driver for Bally/Sente "Cashline" slot machine.
+ Six reels, three up, three down.
+ Large 6 digits 7 segments (plus dot) display up, a smaller 12 digits 7 segments display down,
+ plus another two digits 7 sements display as credits counter.
+
+ There are no dip switches for hoppers, instead you can insert "KEY" mini PCBs on a small
+ socket on the drivers PCB that shorts contacts TS4, TS5, TS6, TS7, TZ4, TZ5, TZ6 and TZ7.
+ On the dumped machine, there was a KEY inserted named "KEY 3" that configures:
+ -Hopper 1 = 0.10 €
+ -Hopper 2 = 1.00 €
+ -Double/Nothing = NO
+ -Coin acceptor = 0.10 = yes, 0.20 = yes, 0.50 = yes, 1.00 = yes, 2.00 = yes
+
+
+ Drivers PCB _________
+ | KEY |
+ |Mini PCB|
+ ______|||||||___||||______| |___|||||||________________|||||||_______________
+ | ||||||| |||| | | ||||||| ||||||| |
+ --- |________| |
+ --- ______ |
+ --- L7805CV |
+ | __________ __________ |
+ | |M74HC245B1 |M74HC165B1 |
+ --- __________ |
+ --- |74HC4051N| |
+ --- ______ __________ |
+ | TC426CPA |M74HC123B1 |
+ --- __________ |
+ --- |ULN2803A_| __________ __________ __________ |
+ --- __________ __________ M74HC4094B1 M74HC4094B1 |ULN2803A_| |
+ --- M74HC4094B1 |M74HC107B1 |
+ |___________________________________________________________________________________|
+
+
+ Reels control PCB
+ _______________________________________________________________________________________
+ | |
+ | ·· ·· ·· |
+ --- ·· ·· ·· |
+ --- ·· ____________ ·· ____________ ____________ ·· |
+ --- ·· |___L6219___| ·· |___L6219___| |___L6219___| ·· |
+ | ·· ·· ·· |
+ --- ·· ·· ·· |
+ --- ___________ ___________ |
+ --- |AT89C2051_| |M74HC165B1| |
+ | Xtal 11.050 MHz |
+ | __________ __________ __________ __________ __________ __________ __________ |
+ | |M74HC245B1 |M74HC123B1 |M74HC107B1 |M74HC165B1 M74HC4094B1 |ULN2804A_| |74HC4051N| |
+ | ______ __________ |
+ |L780SCV 5163/010101/BN M74HC4094B1 |
+ |______________________________________________________________________________________|
+
+
+ Sound PCB
+ ______________________________________________________________________________________________________
+ | ____ __________ |
+ --- ___________ |___| |M74HC02B1| |
+ --- |__________| __________________ _|_
+ | ___________ ··· | YM2149F | __________ __________ ··· __________ _|_
+ --- |M74HC574B1| ··· |_________________| |M74HC393B1 |74HC4015N| ··· |MX7224KN_| |
+ --- ___________ ___________ ··· __________________ ________ __________ ··· _____ _|_
+ --- |__L4974A__| |__________| ··· | 68C681CP | |SG531P_| |_________| ··· |____| _|_
+ --- |_________________| 3.6864 MHz __________ _|_
+ | |M74HC32B1| |CD74AC138E |
+ --- _____ _____ _____ _____ _|_
+ --- TC428CPA |____| |____| |____| _|_
+ |_____|||||__||||||__········__·····_____LED_LED___||||__·····__||||||||_____···________|||||__|||||__|
+ ||||| |||||| |||| |||||||| ||||| |||||
+
+
+ CPU PCB
+ __________________________________________________________________________________
+ | ___________ ______________ ______________ |
+ | |M74HC245B1| | EPROM 1 | | KM681000CLP | BATT |
+ | ___________ |______________| |_____________| 3 VOLTS |
+ | |M74HC245B1| ______________ ______________ |
+ | ... | EPROM 2 | | KM681000CLP | ... ___________ |
+ | ... |______________| |_____________| ... |_RTC62421_| |
+ | ______ ... _____________ ___________ ___________ ... ___________ |
+ ||SG531P ... |MC68EC000FN12||M74HC32B1_| |M74HC245B1| ... |MAX691CPE_| |
+ | 12 MHz ... | | ___________ ___________ ... ___________ |
+ | ... | ||CD74AC138E| |M74HC573B1| ... |M74HC32B1_| |
+ | ___________ | | ___________ ___________ ___________ ___________ |
+ | |M74HC573B1| |_____________||M74HC08B1_| |M74HC10B1_| |M74HC32B1_| |M74HC21B1_| |
+ |_________________________________________________________________________________|
+
+
+ Coin acceptor PCB (Azkoyen L60K)
+ ___________________________________________
+ | ____ ______ ··· ____ |
+ | HCF4069 | Xtal| ___________ | DIPSx4 |
+ | |6 MHz| |MHS | |___| |
+ | ___ S-80C51CCMA-12 ____ |
+ | ADC0804LCN | | | | |
+ | | | |__________| |___| |
+ | | | _________________ |
+ |___ |__| | EPROM | ____ |
+ ||HC00A |________________| L7805CV |
+ ||__| _____ |
+ | MC14099B |
+ | |
+ | |
+ | ::::: |
+ |__________________________________________|
+*/
+
+#include "emu.h"
+#include "cpu/m68000/m68000.h"
+#include "cpu/mcs51/mcs51.h"
+#include "machine/msm6242.h"
+#include "machine/mc68681.h"
+#include "sound/ay8910.h"
+#include "speaker.h"
+
+
+namespace {
+
+class cashline_state : public driver_device
+{
+public:
+ cashline_state( const machine_config &mconfig, device_type type, const char *tag ) :
+ driver_device( mconfig, type, tag ),
+ m_maincpu( *this, "maincpu" ),
+ m_coincpu( *this, "coincpu" )
+ { }
+
+ void cashline( machine_config &config );
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ required_device m_maincpu;
+ required_device m_coincpu;
+};
+
+void cashline_state::machine_start()
+{
+}
+
+void cashline_state::machine_reset()
+{
+}
+
+static INPUT_PORTS_START( cashline )
+INPUT_PORTS_END
+
+void cashline_state::cashline( machine_config &config )
+{
+ M68000( config, m_maincpu, 12_MHz_XTAL ); // MC68EC000FN12
+
+ RTC62421(config, "rtc", 32.768_kHz_XTAL);
+
+ // Sound hardware
+ SPEAKER( config, "mono" ).front_center();
+
+ YM2149( config, "ym", 3.6864_MHz_XTAL / 12).add_route(ALL_OUTPUTS, "mono", 0.3 );
+
+ XR68C681( config, "duart", 3.6864_MHz_XTAL );
+
+ // Coin acceptor
+ I80C51(config, m_coincpu, 6_MHz_XTAL); // MHS S-80C51CCMA-12
+}
+
+ROM_START( cashline )
+ ROM_REGION( 0x100000, "maincpu", 0 )
+ ROM_LOAD( "cash_line_t2_2.10_i_m-164_b-1981.bin", 0x00000, 0x80000, CRC(780e96b2) SHA1(778e1bdb1087e628c158ee0aa9fa119bc6304bc7) )
+ ROM_LOAD( "cash_line_t2_2.10_ii_m-164_b-1981.bin", 0x80000, 0x80000, CRC(61665c58) SHA1(62e813dc8967233bfd4ff64236081cc57fc502f1) )
+
+ ROM_REGION( 0x000800, "reels", 0 )
+ ROM_LOAD( "m2_at89c2051_reels.u12", 0x00000, 0x00800, NO_DUMP ) // Protected
+
+ ROM_REGION( 0x010000, "coincpu", 0 )
+ ROM_LOAD( "497a_azkoyen_l60k_27c512.bin", 0x00000, 0x10000, CRC(6ef809c7) SHA1(3ba632bc1f33e1f22a50a70e56cac7cfdae391c2) )
+ROM_END
+
+
+} // anonymous namespace
+
+
+// YEAR NAME PARENT MACHINE INPUT CLASS INIT ROTATION COMPANY FULLNAME FLAGS
+GAME( 1981, cashline, 0, cashline, cashline, cashline_state, empty_init, ROT0, "Bally/Sente", "Cashline", MACHINE_IS_SKELETON_MECHANICAL )
diff --git a/src/mame/skeleton/bullion2.cpp b/src/mame/skeleton/bullion2.cpp
index 5f10d805866..70d3d307398 100644
--- a/src/mame/skeleton/bullion2.cpp
+++ b/src/mame/skeleton/bullion2.cpp
@@ -140,4 +140,4 @@ ROM_END
// YEAR NAME PARENT MACHINE INPUT CLASS INIT ROTATION COMPANY FULLNAME FLAGS
-GAME( 1984, bullion2, 0, bullion2, bullion2, bullion2_state, empty_init, ROT0, "Inder", "Bullion 2", MACHINE_IS_SKELETON )
+GAME( 1984, bullion2, 0, bullion2, bullion2, bullion2_state, empty_init, ROT0, "Inder", "Bullion 2", MACHINE_IS_SKELETON_MECHANICAL )
diff --git a/src/mame/taito/taito_f2.cpp b/src/mame/taito/taito_f2.cpp
index 14729256412..7e9b249ca67 100644
--- a/src/mame/taito/taito_f2.cpp
+++ b/src/mame/taito/taito_f2.cpp
@@ -5386,6 +5386,8 @@ ROM_START( qcrayon ) /* Quiz Crayon */
ROM_REGION( 0x200000, "sprites", 0 ) /* OBJ */
ROM_LOAD16_BYTE( "d55-05", 0x000000, 0x100000, CRC(f0e59902) SHA1(44d93e0e9622a98796a128a0273065947f586a1d) )
ROM_LOAD16_BYTE( "d55-04", 0x000001, 0x100000, CRC(412975ce) SHA1(32058a87947d6b6cdc8b147ddfcf359792f9c9fc) )
+ // also seen with a single mask ROM containing the same content:
+ //ROM_LOAD( "d55-06", 0x000000, 0x200000, CRC(26db21b3) SHA1(78dab15a585b7180acd170f618947728a2ca022d) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound cpu */
ROM_LOAD( "d55-15", 0x00000, 0x10000, CRC(ba782eff) SHA1(ce24654db49b9694e444e93b9a8d529a86729e03) )