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