summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/bus/a2bus/pc_xporter.cpp255
-rw-r--r--src/devices/bus/a2bus/pc_xporter.h53
-rw-r--r--src/devices/bus/coleco/exp.cpp2
-rw-r--r--src/devices/bus/coleco/exp.h2
-rw-r--r--src/devices/bus/megadrive/md_slot.cpp2
-rw-r--r--src/devices/bus/sms_ctrl/joypad.cpp17
-rw-r--r--src/devices/bus/sms_ctrl/joypad.h2
-rw-r--r--src/devices/bus/sms_ctrl/lphaser.cpp8
-rw-r--r--src/devices/bus/sms_ctrl/paddle.cpp19
-rw-r--r--src/devices/bus/sms_ctrl/paddle.h2
-rw-r--r--src/devices/bus/sms_ctrl/rfu.cpp18
-rw-r--r--src/devices/bus/sms_ctrl/rfu.h2
-rw-r--r--src/devices/bus/sms_ctrl/sports.cpp58
-rw-r--r--src/devices/bus/sms_ctrl/sportsjp.cpp23
-rw-r--r--src/devices/bus/sms_exp/gender.cpp14
-rw-r--r--src/devices/cpu/sm510/sm510op.cpp2
-rw-r--r--src/emu/emuopts.cpp55
-rw-r--r--src/emu/luaengine.cpp11
-rw-r--r--src/emu/luaengine.h1
-rw-r--r--src/emu/machine.cpp2
-rw-r--r--src/emu/mame.cpp33
-rw-r--r--src/emu/rendlay.cpp6
-rw-r--r--src/emu/rendutil.cpp85
-rw-r--r--src/emu/rendutil.h1
-rw-r--r--src/emu/ui/sliders.cpp19
-rw-r--r--src/emu/ui/ui.cpp66
-rw-r--r--src/emu/ui/ui.h4
-rw-r--r--src/emu/ui/utils.h88
-rw-r--r--src/lib/netlist/devices/nld_mm5837.cpp2
-rw-r--r--src/lib/netlist/devices/nld_system.cpp1
-rw-r--r--src/lib/netlist/macro/nlm_ttl74xx.cpp2
-rw-r--r--src/lib/netlist/nl_base.cpp5
-rw-r--r--src/lib/netlist/nl_base.h22
-rw-r--r--src/lib/netlist/nl_util.h4
-rw-r--r--src/lib/netlist/plib/pfmtlog.h4
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.h144
-rw-r--r--src/lib/netlist/solver/nld_ms_direct.h222
-rw-r--r--src/lib/netlist/solver/nld_ms_direct1.h38
-rw-r--r--src/lib/netlist/solver/nld_ms_direct2.h20
-rw-r--r--src/lib/netlist/solver/nld_ms_direct_lu.h53
-rw-r--r--src/lib/netlist/solver/nld_ms_gmres.h44
-rw-r--r--src/lib/netlist/solver/nld_ms_sm.h674
-rw-r--r--src/lib/netlist/solver/nld_ms_sor.h13
-rw-r--r--src/lib/netlist/solver/nld_ms_sor_mat.h17
-rw-r--r--src/lib/netlist/solver/nld_solver.cpp66
-rw-r--r--src/lib/netlist/solver/nld_solver.h141
-rw-r--r--src/mame/audio/irem.cpp9
-rw-r--r--src/mame/drivers/apple2e.cpp2
-rw-r--r--src/mame/drivers/chihiro.cpp6
-rw-r--r--src/mame/drivers/crimfght.cpp94
-rw-r--r--src/mame/drivers/eolith.cpp8
-rw-r--r--src/mame/drivers/hh_hmcs40.cpp4
-rw-r--r--src/mame/drivers/mcr3.cpp370
-rw-r--r--src/mame/drivers/spartanxtec.cpp441
-rw-r--r--src/mame/drivers/spyhuntertec.cpp795
-rw-r--r--src/mame/drivers/toki.cpp44
-rw-r--r--src/mame/drivers/tourvis.cpp5
-rw-r--r--src/mame/includes/mcr3.h6
-rw-r--r--src/mame/includes/xbox.h9
-rw-r--r--src/mame/machine/xbox.cpp95
-rw-r--r--src/mame/mame.lst8
-rw-r--r--src/mame/video/mcr3.cpp48
-rw-r--r--src/osd/modules/file/posixfile.cpp14
-rw-r--r--src/osd/modules/file/posixptty.cpp7
-rw-r--r--src/osd/modules/font/font_sdl.cpp2
-rw-r--r--src/osd/modules/render/bgfx/chainentry.cpp2
-rw-r--r--src/osd/modules/render/drawbgfx.cpp233
-rw-r--r--src/osd/modules/render/drawbgfx.h12
-rw-r--r--src/osd/sdl/sdldir.cpp2
-rw-r--r--src/osd/sdl/sdlmain.cpp6
-rw-r--r--src/osd/sdl/sdlos_unix.cpp8
-rw-r--r--src/osd/sdl/sdlprefix.h4
72 files changed, 3302 insertions, 1254 deletions
diff --git a/src/devices/bus/a2bus/pc_xporter.cpp b/src/devices/bus/a2bus/pc_xporter.cpp
new file mode 100644
index 00000000000..2a5f9b38acf
--- /dev/null
+++ b/src/devices/bus/a2bus/pc_xporter.cpp
@@ -0,0 +1,255 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ pcxporter.cpp
+
+ Implementation of the Applied Engineering PC Transporter card
+ Preliminary version by R. Belmont
+
+ The PC Transporter is basically a PC-XT on an Apple II card.
+ Features include:
+ - V30 CPU @ 4.77 MHz
+ - 768K of RAM, which defines the V30 address space from 0x00000 to 0xBFFFF
+ and is fully read/writable by the Apple's CPU.
+ - Usual XT hardware, mostly inside custom ASICs. There's a discrete
+ NEC uPD71054 (i8254-compatible PIT) though.
+ - CGA-compatible video, output to a separate CGA monitor or NTSC-compliant analog
+ RGB monitor (e.g. the IIgs RGB monitor).
+ - XT-compatible keyboard interface.
+ - PC-style floppy controller: supports 360K 5.25" disks and 720K 3.5" disks
+ - HDD controller which is redirected to a file on the Apple's filesystem
+
+ The V30 BIOS is downloaded by the Apple; the Apple also writes text to the CGA screen prior to
+ the V30's being launched.
+
+ The board was developed by The Engineering Department, a company made up mostly of early Apple
+ engineers including Apple /// designer Dr. Wendall Sander and ProDOS creator Dick Huston.
+
+ Software and user documentation at:
+ http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/CPU/AE%20PC%20Transporter/
+
+ Notes:
+ Registers live at CFxx; access CFFF to clear C800 reservation,
+ then read Cn00 to map C800-CFFF first.
+
+ PC RAM from 0xA0000-0xAFFFF is where the V30 BIOS is downloaded,
+ plus used for general storage by the system.
+ RAM from 0xB0000-0xBFFFF is the CGA framebuffer as usual.
+
+ CF00: PC memory pointer (bits 0-7)
+ CF01: PC memory pointer (bits 8-15)
+ CF02: PC memory pointer (bits 16-23)
+ CF03: read/write PC memory at the pointer and increment the pointer
+ CF04: read/write PC memory at the pointer and *don't* increment the pointer
+
+ TODO:
+ - A2 probably also can access the V30's I/O space: where's that at? CF0E/CF0F
+ are suspects...
+ - There's likely A2 ROM at CnXX and C800-CBFF to support the "Slinky" memory
+ expansion card emulation function inside one of the custom ASICs. Need to
+ dump this...
+
+*********************************************************************/
+
+#include "pc_xporter.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_PCXPORTER = &device_creator<a2bus_pcxporter_device>;
+
+static MACHINE_CONFIG_FRAGMENT( pcxporter )
+MACHINE_CONFIG_END
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor a2bus_pcxporter_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcxporter );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a2bus_pcxporter_device::a2bus_pcxporter_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_a2bus_card_interface(mconfig, *this)
+{
+}
+
+a2bus_pcxporter_device::a2bus_pcxporter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A2BUS_PCXPORTER, "Applied Engineering PC Transporter", tag, owner, clock, "a2pcxport", __FILE__),
+ device_a2bus_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_pcxporter_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ memset(m_ram, 0, 768*1024);
+ memset(m_regs, 0, 0x400);
+ m_offset = 0;
+
+ save_item(NAME(m_ram));
+ save_item(NAME(m_regs));
+ save_item(NAME(m_offset));
+}
+
+void a2bus_pcxporter_device::device_reset()
+{
+}
+
+
+/*-------------------------------------------------
+ read_c0nx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+UINT8 a2bus_pcxporter_device::read_c0nx(address_space &space, UINT8 offset)
+{
+ switch (offset)
+ {
+ default:
+ printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc());
+ break;
+ }
+
+ return 0xff;
+}
+
+
+/*-------------------------------------------------
+ write_c0nx - called for writes to this card's c0nx space
+-------------------------------------------------*/
+
+void a2bus_pcxporter_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data)
+{
+ switch (offset)
+ {
+ default:
+ printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc());
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ read_cnxx - called for reads from this card's cnxx space
+-------------------------------------------------*/
+
+UINT8 a2bus_pcxporter_device::read_cnxx(address_space &space, UINT8 offset)
+{
+ // read only to trigger C800?
+ return 0xff;
+}
+
+void a2bus_pcxporter_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data)
+{
+ printf("Write %02x to cn%02x (PC=%x)\n", data, offset, space.device().safe_pc());
+}
+
+/*-------------------------------------------------
+ read_c800 - called for reads from this card's c800 space
+-------------------------------------------------*/
+
+UINT8 a2bus_pcxporter_device::read_c800(address_space &space, UINT16 offset)
+{
+// printf("Read C800 at %x\n", offset + 0xc800);
+
+ if (offset < 0x400)
+ {
+ return 0xff;
+ }
+ else
+ {
+ UINT8 rv;
+
+ switch (offset)
+ {
+ case 0x700:
+ return m_offset & 0xff;
+
+ case 0x701:
+ return (m_offset >> 8) & 0xff;
+
+ case 0x702:
+ return (m_offset >> 16) & 0xff;
+
+ case 0x703: // read with increment
+ rv = m_ram[m_offset];
+ m_offset++;
+ return rv;
+
+ case 0x704: // read w/o increment
+ rv = m_ram[m_offset];
+ return rv;
+ }
+
+ return m_regs[offset];
+ }
+}
+
+/*-------------------------------------------------
+ write_c800 - called for writes to this card's c800 space
+-------------------------------------------------*/
+void a2bus_pcxporter_device::write_c800(address_space &space, UINT16 offset, UINT8 data)
+{
+ if (offset < 0x400)
+ {
+ }
+ else
+ {
+ switch (offset)
+ {
+ case 0x700:
+ m_offset &= ~0xff;
+ m_offset |= data;
+// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc());
+ break;
+
+ case 0x701:
+ m_offset &= ~0xff00;
+ m_offset |= (data<<8);
+// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc());
+ break;
+
+ case 0x702:
+ m_offset &= ~0xff0000;
+ m_offset |= (data<<16);
+// printf("offset now %x (PC=%x)\n", m_offset, space.device().safe_pc());
+ break;
+
+ case 0x703: // write w/increment
+ m_ram[m_offset] = data;
+ m_offset++;
+ break;
+
+ case 0x704: // write w/o increment
+ m_ram[m_offset] = data;
+ break;
+
+ default:
+ printf("%02x to C800 at %x\n", data, offset + 0xc800);
+ m_regs[offset] = data;
+ break;
+ }
+ }
+}
diff --git a/src/devices/bus/a2bus/pc_xporter.h b/src/devices/bus/a2bus/pc_xporter.h
new file mode 100644
index 00000000000..7126439a265
--- /dev/null
+++ b/src/devices/bus/a2bus/pc_xporter.h
@@ -0,0 +1,53 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ pc_xporter.h
+
+ Implementation of the Applied Engineering PC Transporter card
+
+*********************************************************************/
+
+#pragma once
+
+#include "emu.h"
+#include "a2bus.h"
+#include "machine/genpc.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a2bus_pcxporter_device:
+ public device_t,
+ public device_a2bus_card_interface
+{
+public:
+ // construction/destruction
+ a2bus_pcxporter_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+ a2bus_pcxporter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // overrides of standard a2bus slot functions
+ virtual UINT8 read_c0nx(address_space &space, UINT8 offset) override;
+ virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data) override;
+ virtual UINT8 read_cnxx(address_space &space, UINT8 offset) override;
+ virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data) override;
+ virtual UINT8 read_c800(address_space &space, UINT16 offset) override;
+ virtual void write_c800(address_space &space, UINT16 offset, UINT8 data) override;
+
+private:
+ UINT8 m_ram[768*1024];
+ UINT8 m_regs[0x400];
+ UINT32 m_offset;
+};
+
+// device type definition
+extern const device_type A2BUS_PCXPORTER;
+
diff --git a/src/devices/bus/coleco/exp.cpp b/src/devices/bus/coleco/exp.cpp
index 53953f82859..2b2093f2b1d 100644
--- a/src/devices/bus/coleco/exp.cpp
+++ b/src/devices/bus/coleco/exp.cpp
@@ -38,7 +38,7 @@ void device_colecovision_cartridge_interface::rom_alloc(size_t size)
{
if (m_rom == nullptr)
{
- m_rom = device().machine().memory().region_alloc("coleco_cart:rom", size, 1, ENDIANNESS_LITTLE)->base();
+ m_rom = device().machine().memory().region_alloc(":coleco_cart:rom", size, 1, ENDIANNESS_LITTLE)->base();
m_rom_size = size;
}
}
diff --git a/src/devices/bus/coleco/exp.h b/src/devices/bus/coleco/exp.h
index e64e3c8d6d1..09511c5357f 100644
--- a/src/devices/bus/coleco/exp.h
+++ b/src/devices/bus/coleco/exp.h
@@ -88,7 +88,7 @@ protected:
virtual bool is_creatable() const override { return 0; }
virtual bool must_be_loaded() const override { return 0; }
virtual bool is_reset_on_load() const override { return 1; }
- virtual const char *image_interface() const override { return "coleco_cart"; }
+ virtual const char *image_interface() const override { return ":coleco_cart"; }
virtual const char *file_extensions() const override { return "rom,col,bin"; }
virtual const option_guide *create_option_guide() const override { return nullptr; }
diff --git a/src/devices/bus/megadrive/md_slot.cpp b/src/devices/bus/megadrive/md_slot.cpp
index f44e0597cd4..5a496ac124a 100644
--- a/src/devices/bus/megadrive/md_slot.cpp
+++ b/src/devices/bus/megadrive/md_slot.cpp
@@ -87,7 +87,7 @@ void device_md_cart_interface::rom_alloc(size_t size, const char *tag)
{
if (m_rom == nullptr)
{
- m_rom = (UINT16 *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_LITTLE)->base();
+ m_rom = (UINT16 *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_BIG)->base();
m_rom_size = size;
}
}
diff --git a/src/devices/bus/sms_ctrl/joypad.cpp b/src/devices/bus/sms_ctrl/joypad.cpp
index b2537453c6a..99ca264cec4 100644
--- a/src/devices/bus/sms_ctrl/joypad.cpp
+++ b/src/devices/bus/sms_ctrl/joypad.cpp
@@ -2,7 +2,22 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Control Pad"/generic joystick emulation
+ Sega Mark III "Joypad" / Master System "Control Pad" emulation
+
+
+Release data from the Sega Retro project:
+
+- Joypad:
+
+ Year: 1985 Country/region: JP Model code: SJ-152
+
+- Control Pad:
+
+ Year: 1986 Country/region: US Model code: 3020
+ Year: 1987 Country/region: JP Model code: 3020
+ Year: 1987 Country/region: EU Model code: ?
+ Year: 1989 Country/region: BR Model code: 011770
+ Year: 1989 Country/region: KR Model code: ?
**********************************************************************/
diff --git a/src/devices/bus/sms_ctrl/joypad.h b/src/devices/bus/sms_ctrl/joypad.h
index a67dd5f78b0..d8028bef6c3 100644
--- a/src/devices/bus/sms_ctrl/joypad.h
+++ b/src/devices/bus/sms_ctrl/joypad.h
@@ -2,7 +2,7 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Control Pad"/generic joystick emulation
+ Sega Mark III "Joypad" / Master System "Control Pad" emulation
**********************************************************************/
diff --git a/src/devices/bus/sms_ctrl/lphaser.cpp b/src/devices/bus/sms_ctrl/lphaser.cpp
index 7c1056da5f0..8a49c9a1554 100644
--- a/src/devices/bus/sms_ctrl/lphaser.cpp
+++ b/src/devices/bus/sms_ctrl/lphaser.cpp
@@ -4,6 +4,14 @@
Sega Master System "Light Phaser" (light gun) emulation
+
+Release data from the Sega Retro project:
+
+ Year: 1986 Country/region: US Model code: 3050
+ Year: 1987 Country/region: EU Model code: ?
+ Year: 1989 Country/region: BR Model code: 010470
+ Year: 198? Country/region: KR Model code: ?
+
**********************************************************************/
#include "lphaser.h"
diff --git a/src/devices/bus/sms_ctrl/paddle.cpp b/src/devices/bus/sms_ctrl/paddle.cpp
index 5486c9a50bd..ec5acd4a5ee 100644
--- a/src/devices/bus/sms_ctrl/paddle.cpp
+++ b/src/devices/bus/sms_ctrl/paddle.cpp
@@ -2,7 +2,24 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Paddle Control" emulation
+ Sega Mark III "Paddle Control" emulation
+
+
+Release data from the Sega Retro project:
+
+ Year: 1987 Country/region: JP Model code: HPD-200
+
+Notes:
+
+ The main chip contained in the device is labeled 315-5243.
+
+ The Paddle Control was only released in Japan. To work with the device,
+ paddle games need to detect the system region as Japanese, else they switch
+ to a different mode that uses the TH line as output to select which nibble
+ of the X axis will be read. This other mode is similar to how the US Sports
+ Pad works, so on an Export system, paddle games are somewhat playable with
+ that device, though it needs to be used inverted and the trackball needs to
+ be moved slowly, else the software for the paddle think it's moving backward.
**********************************************************************/
diff --git a/src/devices/bus/sms_ctrl/paddle.h b/src/devices/bus/sms_ctrl/paddle.h
index 8e092d63afe..fae7a93fb19 100644
--- a/src/devices/bus/sms_ctrl/paddle.h
+++ b/src/devices/bus/sms_ctrl/paddle.h
@@ -2,7 +2,7 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Paddle Control" emulation
+ Sega Mark III "Paddle Control" emulation
**********************************************************************/
diff --git a/src/devices/bus/sms_ctrl/rfu.cpp b/src/devices/bus/sms_ctrl/rfu.cpp
index 0ccc5ae4e9c..3c27307c137 100644
--- a/src/devices/bus/sms_ctrl/rfu.cpp
+++ b/src/devices/bus/sms_ctrl/rfu.cpp
@@ -2,12 +2,22 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Rapid Fire Unit" emulation
+ Sega SG-1000/Mark-III/SMS "Rapid Fire Unit" emulation
-**********************************************************************/
-// This emulated device is the version released by Sega. In Brazil, Tec Toy
-// released a version that does not have any switch to turn on/off auto-repeat.
+Release data from the Sega Retro project:
+
+ Year: 1985 Country/region: JP Model code: RF-150
+ Year: 1987 Country/region: US Model code: 3046
+ Year: 1988 Country/region: EU Model code: MK-3046-50
+ Year: 1989 Country/region: BR Model code: 011050
+
+Notes:
+
+ This emulated device is the version released by Sega. In Brazil, Tec Toy
+ released a version that does not have any switch to turn on/off auto-repeat.
+
+**********************************************************************/
#include "rfu.h"
diff --git a/src/devices/bus/sms_ctrl/rfu.h b/src/devices/bus/sms_ctrl/rfu.h
index adc9a3443ba..6a56b06ae3a 100644
--- a/src/devices/bus/sms_ctrl/rfu.h
+++ b/src/devices/bus/sms_ctrl/rfu.h
@@ -2,7 +2,7 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Sega Master System "Rapid Fire Unit" emulation
+ Sega SG-1000/Mark-III/SMS "Rapid Fire Unit" emulation
**********************************************************************/
diff --git a/src/devices/bus/sms_ctrl/sports.cpp b/src/devices/bus/sms_ctrl/sports.cpp
index 77356cec41f..b4bd54d81a1 100644
--- a/src/devices/bus/sms_ctrl/sports.cpp
+++ b/src/devices/bus/sms_ctrl/sports.cpp
@@ -4,29 +4,43 @@
Sega Master System "Sports Pad" (US model) emulation
-**********************************************************************/
-// The games designed for the US model of the Sports Pad controller use the
-// TH line of the controller port to select which nibble, of the two axis
-// bytes, will be read at a time. The Japanese cartridge Sports Pad Soccer
-// uses a different mode, because the Sega Mark III lacks the TH line, so
-// there is a different Sports Pad model released in Japan (see sportsjp.c).
-
-// The Japanese SMS has the TH line connected, but doesn't report TH input
-// on port 0xDD. However, a magazine raffled the US Sports Pad along with a
-// Great Ice Hockey cartridge, in Japanese format, to owners of that console.
-// So, Great Ice Hockey seems to just need TH pin as output to work, while
-// other games designed for the US Sports Pad don't work on the Japanese SMS.
-
-// It was discovered that games designed for the Paddle Controller, released
-// in Japan, switch to a mode incompatible with the original Paddle when
-// detect the system region as Export. Similar to how the US model of the
-// Sports Pad works, that mode uses the TH line as output to select which
-// nibble of the X axis will be read. So, on an Export console version, paddle
-// games are somewhat playable with the US Sport Pad model, though it needs to
-// be used inverted and the trackball needs to be moved slowly, else the
-// software for the paddle think it's moving backward.
-// See http://mametesters.org/view.php?id=5872 for discussion.
+Release data from the Sega Retro project:
+
+ Year: 1987 Country/region: US Model code: 3040
+
+TODO:
+
+- For low-level emulation, a device for the TMP42C66P, a Toshiba 4bit
+ microcontroller, needs to be created, but a dump of its internal ROM
+ seems to be required.
+- Auto-repeat and Control/Sports mode switches are not emulated.
+
+Notes:
+
+ Games designed for the US model of the Sports Pad controller use the
+ TH line of the controller port to select which nibble, of the two axis
+ bytes, will be read at a time. The Japanese cartridge Sports Pad Soccer
+ uses a different mode, because the Sega Mark III lacks the TH line, so
+ there is a different Sports Pad model released in Japan (see sportsjp.c).
+
+ The Japanese SMS has the TH line connected, but doesn't report TH input
+ on port 0xDD. However, a magazine raffled the US Sports Pad along with a
+ Great Ice Hockey cartridge, in Japanese format, to owners of that console.
+ So, Great Ice Hockey seems to just need TH pin as output to work, while
+ other games designed for the US Sports Pad don't work on the Japanese SMS.
+
+ It was discovered that games designed for the Paddle Controller, released
+ in Japan, switch to a mode incompatible with the original Paddle when
+ detect the system region as Export. Similar to how the US model of the
+ Sports Pad works, that mode uses the TH line as output to select which
+ nibble of the X axis will be read. So, on an Export console version,
+ paddle games are somewhat playable with the US Sport Pad model, though it
+ needs to be used inverted and the trackball needs to be moved slowly, else
+ the software for the paddle think it's moving backward.
+ See http://mametesters.org/view.php?id=5872 for discussion.
+
+**********************************************************************/
#include "sports.h"
diff --git a/src/devices/bus/sms_ctrl/sportsjp.cpp b/src/devices/bus/sms_ctrl/sportsjp.cpp
index 16c5198721c..ca2c3de1748 100644
--- a/src/devices/bus/sms_ctrl/sportsjp.cpp
+++ b/src/devices/bus/sms_ctrl/sportsjp.cpp
@@ -4,12 +4,25 @@
Sega Master System "Sports Pad" (Japanese model) emulation
-**********************************************************************/
-// The Japanese Sports Pad controller is only required to play the cartridge
-// Sports Pad Soccer, released in Japan. It uses a different mode than the
-// used by the US model, due to the missing TH line on Sega Mark III
-// controller ports.
+Release data from the Sega Retro project:
+
+ Year: 1988 Country/region: JP Model code: SP-500
+
+TODO:
+
+- For low-level emulation, a device for the TMP42C66P, a Toshiba 4bit
+ microcontroller, needs to be created, but a dump of its internal ROM
+ seems to be required.
+
+Notes:
+
+ The Japanese Sports Pad controller is only required to play the cartridge
+ Sports Pad Soccer, released in Japan. It uses a different mode than the
+ used by the US model, due to the missing TH line on Sega Mark III
+ controller ports.
+
+**********************************************************************/
#include "sportsjp.h"
diff --git a/src/devices/bus/sms_exp/gender.cpp b/src/devices/bus/sms_exp/gender.cpp
index 3de8961050c..49ccc50e24e 100644
--- a/src/devices/bus/sms_exp/gender.cpp
+++ b/src/devices/bus/sms_exp/gender.cpp
@@ -4,14 +4,14 @@
Sega Master System "Gender Adapter" emulation
-**********************************************************************/
+The Gender Adapter is not an official Sega product. It is produced since 2006
+by the SMSPower website to permit to plug a cartridge on the expansion slot
+on any SMS 1 model. This includes the Japanese SMS, which has FM sound, so
+it is a way to get FM music of western cartridges that have FM code but were
+not released in Japan. Some games have compatibility issues, confirmed on the
+real hardware, when run plugged-in to the SMS expansion slot.
-// The Gender Adapter is not an official Sega product. It is produced by the
-// SMSPower website to permit to plug a cartridge on the expansion slot on any
-// SMS 1 model. This includes the Japanese SMS, which has FM sound, so it is
-// a way to get FM music of western cartridges that have FM code but were not
-// released in Japan. Some games have compatibility issues, confirmed on the
-// real hardware, when run plugged-in to the SMS expansion slot.
+**********************************************************************/
#include "gender.h"
diff --git a/src/devices/cpu/sm510/sm510op.cpp b/src/devices/cpu/sm510/sm510op.cpp
index c2d0658ba6f..3f0659bac16 100644
--- a/src/devices/cpu/sm510/sm510op.cpp
+++ b/src/devices/cpu/sm510/sm510op.cpp
@@ -67,7 +67,7 @@ void sm510_base_device::op_lb()
UINT8 hi = 0;
switch (m_bl)
{
- case 0: hi = 3; break;
+ case 0: hi = 0; break;
case 1: hi = 0; break;
case 2: hi = 0; break;
case 3: hi = 3; break;
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp
index 35a8fae6333..e5906562d2a 100644
--- a/src/emu/emuopts.cpp
+++ b/src/emu/emuopts.cpp
@@ -376,6 +376,9 @@ void emu_options::remove_device_options()
remove_entry(*curentry);
}
+ // take also care of ramsize options
+ set_default_value(OPTION_RAMSIZE, "");
+
// reset counters
m_slot_options = 0;
m_device_options = 0;
@@ -541,20 +544,66 @@ void emu_options::set_system_name(const char *name)
{
// remember the original system name
std::string old_system_name(system_name());
+ bool new_system = old_system_name.compare(name)!=0;
// if the system name changed, fix up the device options
- if (old_system_name.compare(name)!=0)
+ if (new_system)
{
// first set the new name
std::string error;
set_value(OPTION_SYSTEMNAME, name, OPTION_PRIORITY_CMDLINE, error);
assert(error.empty());
- // remove any existing device options and then add them afresh
+ // remove any existing device options
remove_device_options();
- while (add_slot_options()) { }
+ }
+
+ // get the new system
+ const game_driver *cursystem = system();
+ if (cursystem == nullptr)
+ return;
+
+ if (*software_name() != 0)
+ {
+ std::string sw_load(software_name());
+ std::string sw_list, sw_name, sw_part, sw_instance, option_errors, error_string;
+ int left = sw_load.find_first_of(':');
+ int middle = sw_load.find_first_of(':', left + 1);
+ int right = sw_load.find_last_of(':');
+
+ sw_list = sw_load.substr(0, left - 1);
+ sw_name = sw_load.substr(left + 1, middle - left - 1);
+ sw_part = sw_load.substr(middle + 1, right - middle - 1);
+ sw_instance = sw_load.substr(right + 1);
+ sw_load.assign(sw_load.substr(0, right));
+
+ // look up the software part
+ machine_config config(*cursystem, *this);
+ software_list_device *swlist = software_list_device::find_by_name(config, sw_list.c_str());
+ software_info *swinfo = swlist != nullptr ? swlist->find(sw_name.c_str()) : nullptr;
+ software_part *swpart = swinfo != nullptr ? swinfo->find_part(sw_part.c_str()) : nullptr;
// then add the options
+ if (new_system)
+ {
+ while (add_slot_options(swpart)) { }
+ add_device_options();
+ }
+
+ set_value(OPTION_SOFTWARENAME, sw_name.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
+ if (exists(sw_instance.c_str()))
+ set_value(sw_instance.c_str(), sw_load.c_str(), OPTION_PRIORITY_SUBCMD, error_string);
+
+ int num;
+ do {
+ num = options_count();
+ update_slot_options(swpart);
+ } while(num != options_count());
+ }
+ else if (new_system)
+ {
+ // add the options afresh
+ while (add_slot_options()) { }
add_device_options();
int num;
do {
diff --git a/src/emu/luaengine.cpp b/src/emu/luaengine.cpp
index 0cf57ef61c0..fbd2e64fc76 100644
--- a/src/emu/luaengine.cpp
+++ b/src/emu/luaengine.cpp
@@ -245,6 +245,16 @@ int lua_engine::l_emu_romname(lua_State *L)
}
//-------------------------------------------------
+// emu_softname - returns softlist name
+//-------------------------------------------------
+
+int lua_engine::l_emu_softname(lua_State *L)
+{
+ lua_pushstring(L, luaThis->machine().options().software_name());
+ return 1;
+}
+
+//-------------------------------------------------
// emu_pause/emu_unpause - pause/unpause game
//-------------------------------------------------
@@ -1418,6 +1428,7 @@ void lua_engine::initialize()
.addCFunction ("app_version", l_emu_app_version )
.addCFunction ("gamename", l_emu_gamename )
.addCFunction ("romname", l_emu_romname )
+ .addCFunction ("softname", l_emu_softname )
.addCFunction ("keypost", l_emu_keypost )
.addCFunction ("hook_output", l_emu_hook_output )
.addCFunction ("sethook", l_emu_set_hook )
diff --git a/src/emu/luaengine.h b/src/emu/luaengine.h
index 19c362c66a2..2f0f4ad7a34 100644
--- a/src/emu/luaengine.h
+++ b/src/emu/luaengine.h
@@ -106,6 +106,7 @@ private:
static int l_emu_time(lua_State *L);
static int l_emu_gamename(lua_State *L);
static int l_emu_romname(lua_State *L);
+ static int l_emu_softname(lua_State *L);
static int l_emu_keypost(lua_State *L);
static int l_emu_hook_output(lua_State *L);
static int l_emu_exit(lua_State *L);
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index 7c465be0cd8..d76ad49676d 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -356,7 +356,7 @@ int running_machine::run(bool firstrun)
ui().initialize(*this);
// display the startup screens
- ui().display_startup_screens(firstrun, false);
+ ui().display_startup_screens(firstrun);
// perform a soft reset -- this takes us to the running phase
soft_reset();
diff --git a/src/emu/mame.cpp b/src/emu/mame.cpp
index 9232ee9443f..9e872c7a96f 100644
--- a/src/emu/mame.cpp
+++ b/src/emu/mame.cpp
@@ -251,40 +251,9 @@ int machine_manager::execute()
// check the state of the machine
if (m_new_driver_pending)
{
- std::string old_system_name(m_options.system_name());
- bool new_system = (old_system_name.compare(m_new_driver_pending->name)!=0);
- // first: if we scheduled a new system, remove device options of the old system
- // notice that, if we relaunch the same system, there is no effect on the emulation
- if (new_system)
- m_options.remove_device_options();
- // second: set up new system name (and the related device options)
+ // set up new system name and adjust device options accordingly
m_options.set_system_name(m_new_driver_pending->name);
- // third: if we scheduled a new system, take also care of ramsize options
- if (new_system)
- {
- std::string error_string;
- m_options.set_value(OPTION_RAMSIZE, "", OPTION_PRIORITY_CMDLINE, error_string);
- }
firstrun = true;
- if (m_options.software_name())
- {
- std::string sw_load(m_options.software_name());
- std::string sw_list, sw_name, sw_part, sw_instance, option_errors, error_string;
- int left = sw_load.find_first_of(':');
- int middle = sw_load.find_first_of(':', left + 1);
- int right = sw_load.find_last_of(':');
-
- sw_list = sw_load.substr(0, left - 1);
- sw_name = sw_load.substr(left + 1, middle - left - 1);
- sw_part = sw_load.substr(middle + 1, right - middle - 1);
- sw_instance = sw_load.substr(right + 1);
- sw_load.assign(sw_load.substr(0, right));
-
- char arg[] = "mame";
- char *argv = &arg[0];
- m_options.set_value(OPTION_SOFTWARENAME, sw_name.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
- m_options.parse_slot_devices(1, &argv, option_errors, sw_instance.c_str(), sw_load.c_str());
- }
}
else
{
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index a69ea831e44..41fffd964aa 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -1303,7 +1303,7 @@ void layout_element::component::draw_beltreel(running_machine &machine, bitmap_a
//-------------------------------------------------
-// load_bitmap - load a PNG file with artwork for
+// load_bitmap - load a PNG/JPG file with artwork for
// a component
//-------------------------------------------------
@@ -1317,6 +1317,10 @@ void layout_element::component::load_bitmap()
if (m_bitmap[0].valid() && !m_alphafile[0].empty())
render_load_png(m_bitmap[0], *m_file[0], m_dirname.c_str(), m_alphafile[0].c_str(), true);
+ // PNG failed, let's try JPG
+ if (!m_bitmap[0].valid())
+ render_load_jpeg(m_bitmap[0], *m_file[0], m_dirname.c_str(), m_imagefile[0].c_str());
+
// if we can't load the bitmap, allocate a dummy one and report an error
if (!m_bitmap[0].valid())
{
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index 4c49c6c8a62..eed35713a92 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -12,7 +12,7 @@
#include "rendutil.h"
#include "png.h"
-
+#include "libjpeg/jpeglib.h"
/***************************************************************************
FUNCTION PROTOTYPES
@@ -524,6 +524,89 @@ void render_line_to_quad(const render_bounds *bounds, float width, render_bounds
/*-------------------------------------------------
+ render_load_jpeg - load a JPG file into a
+ bitmap
+-------------------------------------------------*/
+
+void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
+{
+ // deallocate previous bitmap
+ bitmap.reset();
+
+ // define file's full name
+ std::string fname;
+
+ if (dirname == nullptr)
+ fname = filename;
+ else
+ fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
+
+ osd_file::error filerr = file.open(fname.c_str());
+
+ if (filerr != osd_file::error::NONE)
+ return;
+
+ // define standard JPEG structures
+ jpeg_decompress_struct cinfo;
+ jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+ // allocates a buffer for the image
+ UINT64 jpg_size = file.size();
+ unsigned char *jpg_buffer = global_alloc_array(unsigned char, jpg_size + 100);
+
+ // read data from the file and set them in the buffer
+ file.read(jpg_buffer, jpg_size);
+ jpeg_mem_src(&cinfo, jpg_buffer, jpg_size);
+
+ // read JPEG header and start decompression
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // allocates the destination bitmap
+ int w = cinfo.output_width;
+ int h = cinfo.output_height;
+ int s = cinfo.output_components;
+ bitmap.allocate(w, h);
+
+ // allocates a buffer to receive the information and copy them into the bitmap
+ int row_stride = cinfo.output_width * cinfo.output_components;
+ JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
+ buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
+
+ while ( cinfo.output_scanline < cinfo.output_height )
+ {
+ int j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
+
+ if (s == 1)
+ for (int i = 0; i < w; ++i)
+ bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
+
+ else if (s == 3)
+ for (int i = 0; i < w; ++i)
+ bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from %s file.\n", fname.c_str());
+ bitmap.reset();
+ break;
+ }
+ }
+
+ // finish decompression and frees the memory
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ file.close();
+ free(buffer[0]);
+ free(buffer);
+ global_free_array(jpg_buffer);
+}
+
+
+/*-------------------------------------------------
render_load_png - load a PNG file into a
bitmap
-------------------------------------------------*/
diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h
index 34a9c2ef75c..bdf01592307 100644
--- a/src/emu/rendutil.h
+++ b/src/emu/rendutil.h
@@ -25,6 +25,7 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
int render_clip_line(render_bounds *bounds, const render_bounds *clip);
int render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
void render_line_to_quad(const render_bounds *bounds, float width, render_bounds *bounds0, render_bounds *bounds1);
+void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename);
bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing = false);
diff --git a/src/emu/ui/sliders.cpp b/src/emu/ui/sliders.cpp
index 86f85bd0026..25dd8afa06d 100644
--- a/src/emu/ui/sliders.cpp
+++ b/src/emu/ui/sliders.cpp
@@ -44,6 +44,9 @@ void ui_menu_sliders::handle()
const slider_state *slider = (const slider_state *)menu_event->itemref;
INT32 curvalue = (*slider->update)(machine(), slider->arg, nullptr, SLIDER_NOCHANGE);
INT32 increment = 0;
+ bool alt_pressed = machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT);
+ bool ctrl_pressed = machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL);
+ bool shift_pressed = machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT);
switch (menu_event->iptkey)
{
@@ -57,11 +60,13 @@ void ui_menu_sliders::handle()
/* decrease value */
case IPT_UI_LEFT:
- if (machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT))
+ if (alt_pressed && shift_pressed)
increment = -1;
- else if (machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT))
+ if (alt_pressed)
+ increment = -(curvalue - slider->minval);
+ else if (shift_pressed)
increment = (slider->incval > 10) ? -(slider->incval / 10) : -1;
- else if (machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL))
+ else if (ctrl_pressed)
increment = -slider->incval * 10;
else
increment = -slider->incval;
@@ -69,11 +74,13 @@ void ui_menu_sliders::handle()
/* increase value */
case IPT_UI_RIGHT:
- if (machine().input().code_pressed(KEYCODE_LALT) || machine().input().code_pressed(KEYCODE_RALT))
+ if (alt_pressed && shift_pressed)
increment = 1;
- else if (machine().input().code_pressed(KEYCODE_LSHIFT) || machine().input().code_pressed(KEYCODE_RSHIFT))
+ if (alt_pressed)
+ increment = slider->maxval - curvalue;
+ else if (shift_pressed)
increment = (slider->incval > 10) ? (slider->incval / 10) : 1;
- else if (machine().input().code_pressed(KEYCODE_LCONTROL) || machine().input().code_pressed(KEYCODE_RCONTROL))
+ else if (ctrl_pressed)
increment = slider->incval * 10;
else
increment = slider->incval;
diff --git a/src/emu/ui/ui.cpp b/src/emu/ui/ui.cpp
index cc8b18c8154..0b15f24edc6 100644
--- a/src/emu/ui/ui.cpp
+++ b/src/emu/ui/ui.cpp
@@ -359,9 +359,9 @@ UINT32 ui_manager::set_handler(ui_callback callback, UINT32 param)
// various startup screens
//-------------------------------------------------
-void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer)
+void ui_manager::display_startup_screens(bool first_time)
{
- const int maxstate = 4;
+ const int maxstate = 3;
int str = machine().options().seconds_to_run();
bool show_gameinfo = !machine().options().skip_gameinfo();
bool show_warnings = true, show_mandatory_fileman = true;
@@ -370,11 +370,11 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer)
// disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver,
// or if we are debugging
if (!first_time || (str > 0 && str < 60*5) || &machine().system() == &GAME_NAME(___empty) || (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
- show_gameinfo = show_warnings = show_disclaimer = show_mandatory_fileman = FALSE;
+ show_gameinfo = show_warnings = show_mandatory_fileman = FALSE;
#if defined(EMSCRIPTEN)
// also disable for the JavaScript port since the startup screens do not run asynchronously
- show_gameinfo = show_warnings = show_disclaimer = FALSE;
+ show_gameinfo = show_warnings = FALSE;
#endif
// loop over states
@@ -388,14 +388,9 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer)
switch (state)
{
case 0:
- if (show_disclaimer && disclaimer_string(messagebox_text).length() > 0)
- set_handler(handler_messagebox_ok, 0);
- break;
-
- case 1:
if (show_warnings && warnings_string(messagebox_text).length() > 0)
{
- set_handler(handler_messagebox_ok, 0);
+ set_handler(handler_messagebox_anykey, 0);
if (machine().system().flags & (MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_COLORS | MACHINE_REQUIRES_ARTWORK | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_KEYBOARD | MACHINE_NO_SOUND))
messagebox_backcolor = UI_YELLOW_COLOR;
if (machine().system().flags & (MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_MECHANICAL))
@@ -403,12 +398,12 @@ void ui_manager::display_startup_screens(bool first_time, bool show_disclaimer)
}
break;
- case 2:
+ case 1:
if (show_gameinfo && game_info_astring(messagebox_text).length() > 0)
set_handler(handler_messagebox_anykey, 0);
break;
- case 3:
+ case 2:
if (show_mandatory_fileman && machine().image().mandatory_scan(messagebox_text).length() > 0)
{
std::string warning;
@@ -1033,22 +1028,6 @@ bool ui_manager::show_timecode_total()
***************************************************************************/
//-------------------------------------------------
-// disclaimer_string - print the disclaimer
-// text to the given buffer
-//-------------------------------------------------
-
-std::string &ui_manager::disclaimer_string(std::string &str)
-{
- str = string_format(
- _("Usage of emulators in conjunction with ROMs you don't own is forbidden by copyright law.\n\n"
- "IF YOU ARE NOT LEGALLY ENTITLED TO PLAY \"%1$s\" ON THIS EMULATOR, PRESS ESC.\n\n"
- "Otherwise, type OK or move the joystick left then right to continue"),
- machine().system().description);
- return str;
-}
-
-
-//-------------------------------------------------
// warnings_string - print the warning flags
// text to the given buffer
//-------------------------------------------------
@@ -1174,7 +1153,7 @@ std::string &ui_manager::warnings_string(std::string &str)
}
// add the 'press OK' string
- str.append(_("\n\nType OK or move the joystick left then right to continue"));
+ str.append(_("\n\nPress any key to continue"));
return str;
}
@@ -1317,35 +1296,6 @@ UINT32 ui_manager::handler_messagebox(running_machine &machine, render_container
//-------------------------------------------------
-// handler_messagebox_ok - displays the current
-// messagebox_text string and waits for an OK
-//-------------------------------------------------
-
-UINT32 ui_manager::handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state)
-{
- // draw a standard message window
- machine.ui().draw_text_box(container, messagebox_text.c_str(), JUSTIFY_LEFT, 0.5f, 0.5f, messagebox_backcolor);
-
- // an 'O' or left joystick kicks us to the next state
- if (state == 0 && (machine.input().code_pressed_once(KEYCODE_O) || machine.ui_input().pressed(IPT_UI_LEFT)))
- state++;
-
- // a 'K' or right joystick exits the state
- else if (state == 1 && (machine.input().code_pressed_once(KEYCODE_K) || machine.ui_input().pressed(IPT_UI_RIGHT)))
- state = UI_HANDLER_CANCEL;
-
- // if the user cancels, exit out completely
- else if (machine.ui_input().pressed(IPT_UI_CANCEL))
- {
- machine.schedule_exit();
- state = UI_HANDLER_CANCEL;
- }
-
- return state;
-}
-
-
-//-------------------------------------------------
// handler_messagebox_anykey - displays the
// current messagebox_text string and waits for
// any keypress
diff --git a/src/emu/ui/ui.h b/src/emu/ui/ui.h
index c50d444120e..ea117a74d82 100644
--- a/src/emu/ui/ui.h
+++ b/src/emu/ui/ui.h
@@ -129,7 +129,7 @@ public:
// methods
void initialize(running_machine &machine);
UINT32 set_handler(ui_callback callback, UINT32 param);
- void display_startup_screens(bool first_time, bool show_disclaimer);
+ void display_startup_screens(bool first_time);
void set_startup_text(const char *text, bool force);
void update_and_render(render_container *container);
render_font *get_font();
@@ -213,12 +213,10 @@ private:
static slider_state *slider_current;
// text generators
- std::string &disclaimer_string(std::string &buffer);
std::string &warnings_string(std::string &buffer);
// UI handlers
static UINT32 handler_messagebox(running_machine &machine, render_container *container, UINT32 state);
- static UINT32 handler_messagebox_ok(running_machine &machine, render_container *container, UINT32 state);
static UINT32 handler_messagebox_anykey(running_machine &machine, render_container *container, UINT32 state);
static UINT32 handler_ingame(running_machine &machine, render_container *container, UINT32 state);
static UINT32 handler_load_save(running_machine &machine, render_container *container, UINT32 state);
diff --git a/src/emu/ui/utils.h b/src/emu/ui/utils.h
index a8737fb2e6b..81107c0911c 100644
--- a/src/emu/ui/utils.h
+++ b/src/emu/ui/utils.h
@@ -14,8 +14,7 @@
#define __UI_UTILS_H__
#include "osdepend.h"
-#include "render.h"
-#include "libjpeg/jpeglib.h"
+#include "rendutil.h"
#define MAX_CHAR_INFO 256
#define MAX_CUST_FILTER 8
@@ -255,90 +254,5 @@ char* chartrimcarriage(char str[]);
const char* strensure(const char* s);
-// jpeg loader
-template <typename _T>
-void render_load_jpeg(_T &bitmap, emu_file &file, const char *dirname, const char *filename)
-{
- // deallocate previous bitmap
- bitmap.reset();
-
- bitmap_format format = bitmap.format();
-
- // define file's full name
- std::string fname;
-
- if (dirname == nullptr)
- fname = filename;
- else
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
-
- osd_file::error filerr = file.open(fname.c_str());
-
- if (filerr != osd_file::error::NONE)
- return;
-
- // define standard JPEG structures
- jpeg_decompress_struct cinfo;
- jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
-
- // allocates a buffer for the image
- UINT64 jpg_size = file.size();
- unsigned char *jpg_buffer = global_alloc_array(unsigned char, jpg_size + 100);
-
- // read data from the file and set them in the buffer
- file.read(jpg_buffer, jpg_size);
- jpeg_mem_src(&cinfo, jpg_buffer, jpg_size);
-
- // read JPEG header and start decompression
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // allocates the destination bitmap
- int w = cinfo.output_width;
- int h = cinfo.output_height;
- int s = cinfo.output_components;
- bitmap.allocate(w, h);
-
- // allocates a buffer to receive the information and copy them into the bitmap
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
- buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
-
- while ( cinfo.output_scanline < cinfo.output_height )
- {
- int j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
-
- if (s == 1)
- for (int i = 0; i < w; ++i)
- if (format == BITMAP_FORMAT_ARGB32)
- bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
- else
- bitmap.pix32(j, i) = rgb_t(buffer[0][i], buffer[0][i], buffer[0][i]);
-
- else if (s == 3)
- for (int i = 0; i < w; ++i)
- if (format == BITMAP_FORMAT_ARGB32)
- bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- else
- bitmap.pix32(j, i) = rgb_t(buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
-
- else
- {
- osd_printf_info("Error! Cannot read JPEG data from %s file.\n", fname.c_str());
- break;
- }
- }
-
- // finish decompression and frees the memory
- jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- file.close();
- free(buffer[0]);
- free(buffer);
- global_free_array(jpg_buffer);
-}
#endif /* __UI_UTILS_H__ */
diff --git a/src/lib/netlist/devices/nld_mm5837.cpp b/src/lib/netlist/devices/nld_mm5837.cpp
index 7f7ab6f8660..82e774b4923 100644
--- a/src/lib/netlist/devices/nld_mm5837.cpp
+++ b/src/lib/netlist/devices/nld_mm5837.cpp
@@ -5,7 +5,7 @@
*
*/
-#include <solver/nld_solver.h>
+#include <solver/nld_matrix_solver.h>
#include "nld_mm5837.h"
#include "nl_setup.h"
diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp
index dbf6926437d..e861bf05171 100644
--- a/src/lib/netlist/devices/nld_system.cpp
+++ b/src/lib/netlist/devices/nld_system.cpp
@@ -6,6 +6,7 @@
*/
#include <solver/nld_solver.h>
+#include <solver/nld_matrix_solver.h>
#include "nld_system.h"
NETLIB_NAMESPACE_DEVICES_START()
diff --git a/src/lib/netlist/macro/nlm_ttl74xx.cpp b/src/lib/netlist/macro/nlm_ttl74xx.cpp
index de42f26d730..49fea3c55c8 100644
--- a/src/lib/netlist/macro/nlm_ttl74xx.cpp
+++ b/src/lib/netlist/macro/nlm_ttl74xx.cpp
@@ -84,7 +84,7 @@ NETLIST_START(TTL74XX_lib)
TT_FAMILY("74XX")
TRUTHTABLE_END()
- TRUTHTABLE_START(TTL_7400_NAND, 2, 1, 0, "+A,B")
+ TRUTHTABLE_START(TTL_7400_NAND, 2, 1, 0, "A,B")
TT_HEAD("A,B|Q ")
TT_LINE("0,X|1|22")
TT_LINE("X,0|1|22")
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
index 6ea052b4132..7afa0285ef8 100644
--- a/src/lib/netlist/nl_base.cpp
+++ b/src/lib/netlist/nl_base.cpp
@@ -5,7 +5,8 @@
*
*/
-#include <solver/nld_solver.h>
+#include <solver/nld_matrix_solver.h>
+
#include <cstring>
#include <algorithm>
@@ -840,10 +841,10 @@ ATTR_COLD void core_terminal_t::set_net(net_t &anet)
ATTR_COLD terminal_t::terminal_t()
: analog_t(TERMINAL)
+, m_otherterm(NULL)
, m_Idr1(NULL)
, m_go1(NULL)
, m_gt1(NULL)
-, m_otherterm(NULL)
{
}
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index 24f2cde585a..52a91704607 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -551,10 +551,6 @@ namespace netlist
ATTR_COLD terminal_t();
- nl_double *m_Idr1; // drive current
- nl_double *m_go1; // conductance for Voltage from other term
- nl_double *m_gt1; // conductance for total conductance
-
terminal_t *m_otherterm;
ATTR_HOT void set(const nl_double G)
@@ -581,19 +577,31 @@ namespace netlist
ATTR_HOT void schedule_solve();
ATTR_HOT void schedule_after(const netlist_time &after);
+ void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr)
+ {
+ m_gt1 = gt;
+ m_go1 = go;
+ m_Idr1 = Idr;
+ }
+
protected:
virtual void save_register() override;
virtual void reset() override;
private:
- ATTR_HOT void set_ptr(nl_double *ptr, const nl_double val)
+ ATTR_HOT void set_ptr(nl_double *ptr, const nl_double val)
{
if (ptr != NULL && *ptr != val)
{
*ptr = val;
}
}
- };
+
+ nl_double *m_Idr1; // drive current
+ nl_double *m_go1; // conductance for Voltage from other term
+ nl_double *m_gt1; // conductance for total conductance
+
+};
// -----------------------------------------------------------------------------
@@ -1054,7 +1062,7 @@ namespace netlist
ATTR_HOT nl_double INPANALOG(const analog_input_t &inp) const { return inp.Q_Analog(); }
- ATTR_HOT nl_double TERMANALOG(const terminal_t &term) const { return term.net().as_analog().Q_Analog(); }
+ ATTR_HOT nl_double TERMANALOG(const terminal_t &term) const { return term.net().Q_Analog(); }
ATTR_HOT void OUTANALOG(analog_output_t &out, const nl_double val)
{
diff --git a/src/lib/netlist/nl_util.h b/src/lib/netlist/nl_util.h
index bb5a564dd74..87ec2270231 100644
--- a/src/lib/netlist/nl_util.h
+++ b/src/lib/netlist/nl_util.h
@@ -41,8 +41,8 @@ private:
public:
ATTR_HOT inline static float exp(const float x) { return std::exp(x); }
- ATTR_HOT inline static double abs(const double x) { return std::abs(x); }
- ATTR_HOT inline static float abs(const float x) { return std::abs(x); }
+ ATTR_HOT inline static double abs(const double x) { return std::fabs(x); }
+ ATTR_HOT inline static float abs(const float x) { return std::fabs(x); }
ATTR_HOT inline static double log(const double x) { return std::log(x); }
ATTR_HOT inline static float log(const float x) { return std::log(x); }
#if defined(_MSC_VER) && _MSC_VER < 1800
diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h
index 7a63d14fc3a..d72bdc6ce6b 100644
--- a/src/lib/netlist/plib/pfmtlog.h
+++ b/src/lib/netlist/plib/pfmtlog.h
@@ -110,6 +110,10 @@ public:
ATTR_COLD P & e(const double x, const char *f = "") { format_element(f, "", "e", x); return static_cast<P &>(*this); }
ATTR_COLD P & g(const double x, const char *f = "") { format_element(f, "", "g", x); return static_cast<P &>(*this); }
+ ATTR_COLD P &operator ()(const float x, const char *f = "") { format_element(f, "", "f", x); return static_cast<P &>(*this); }
+ ATTR_COLD P & e(const float x, const char *f = "") { format_element(f, "", "e", x); return static_cast<P &>(*this); }
+ ATTR_COLD P & g(const float x, const char *f = "") { format_element(f, "", "g", x); return static_cast<P &>(*this); }
+
ATTR_COLD P &operator ()(const char *x, const char *f = "") { format_element(f, "", "s", x); return static_cast<P &>(*this); }
ATTR_COLD P &operator ()(char *x, const char *f = "") { format_element(f, "", "s", x); return static_cast<P &>(*this); }
ATTR_COLD P &operator ()(const void *x, const char *f = "") { format_element(f, "", "p", x); return static_cast<P &>(*this); }
diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h
new file mode 100644
index 00000000000..715eab6756a
--- /dev/null
+++ b/src/lib/netlist/solver/nld_matrix_solver.h
@@ -0,0 +1,144 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * nld_matrix_solver.h
+ *
+ */
+
+#ifndef NLD_MATRIX_SOLVER_H_
+#define NLD_MATRIX_SOLVER_H_
+
+#include "solver/nld_solver.h"
+
+NETLIB_NAMESPACE_DEVICES_START()
+
+class terms_t
+{
+ P_PREVENT_COPYING(terms_t)
+
+ public:
+ ATTR_COLD terms_t() : m_railstart(0)
+ {}
+
+ ATTR_COLD void clear()
+ {
+ m_term.clear();
+ m_net_other.clear();
+ m_gt.clear();
+ m_go.clear();
+ m_Idr.clear();
+ m_other_curanalog.clear();
+ }
+
+ ATTR_COLD void add(terminal_t *term, int net_other, bool sorted);
+
+ inline unsigned count() { return m_term.size(); }
+
+ inline terminal_t **terms() { return m_term.data(); }
+ inline int *net_other() { return m_net_other.data(); }
+ inline nl_double *gt() { return m_gt.data(); }
+ inline nl_double *go() { return m_go.data(); }
+ inline nl_double *Idr() { return m_Idr.data(); }
+ inline nl_double **other_curanalog() { return m_other_curanalog.data(); }
+
+ ATTR_COLD void set_pointers();
+
+ unsigned m_railstart;
+
+ pvector_t<unsigned> m_nz; /* all non zero for multiplication */
+ pvector_t<unsigned> m_nzrd; /* non zero right of the diagonal for elimination, may include RHS element */
+ pvector_t<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */
+private:
+ pvector_t<terminal_t *> m_term;
+ pvector_t<int> m_net_other;
+ pvector_t<nl_double> m_go;
+ pvector_t<nl_double> m_gt;
+ pvector_t<nl_double> m_Idr;
+ pvector_t<nl_double *> m_other_curanalog;
+};
+
+class matrix_solver_t : public device_t
+{
+public:
+ typedef pvector_t<matrix_solver_t *> list_t;
+ typedef core_device_t::list_t dev_list_t;
+
+ enum eSolverType
+ {
+ GAUSSIAN_ELIMINATION,
+ GAUSS_SEIDEL
+ };
+
+ matrix_solver_t(const eSolverType type, const solver_parameters_t *params);
+ virtual ~matrix_solver_t();
+
+ void setup(analog_net_t::list_t &nets) { vsetup(nets); }
+
+ netlist_time solve_base();
+
+ netlist_time solve();
+
+ inline bool is_dynamic() const { return m_dynamic_devices.size() > 0; }
+ inline bool is_timestep() const { return m_step_devices.size() > 0; }
+
+ void update_forced();
+ void update_after(const netlist_time after)
+ {
+ m_Q_sync.net().reschedule_in_queue(after);
+ }
+
+ /* netdevice functions */
+ virtual void update() override;
+ virtual void start() override;
+ virtual void reset() override;
+
+ ATTR_COLD int get_net_idx(net_t *net);
+
+ eSolverType type() const { return m_type; }
+ plog_base<NL_DEBUG> &log() { return netlist().log(); }
+
+ virtual void log_stats();
+
+protected:
+
+ ATTR_COLD void setup_base(analog_net_t::list_t &nets);
+ void update_dynamic();
+
+ virtual void add_term(int net_idx, terminal_t *term) = 0;
+ virtual void vsetup(analog_net_t::list_t &nets) = 0;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) = 0;
+ virtual netlist_time compute_next_timestep() = 0;
+
+ pvector_t<analog_net_t *> m_nets;
+ pvector_t<analog_output_t *> m_inps;
+
+ int m_stat_calculations;
+ int m_stat_newton_raphson;
+ int m_stat_vsolver_calls;
+ int m_iterative_fail;
+ int m_iterative_total;
+
+ const solver_parameters_t &m_params;
+
+ inline nl_double current_timestep() { return m_cur_ts; }
+private:
+
+ netlist_time m_last_step;
+ nl_double m_cur_ts;
+ dev_list_t m_step_devices;
+ dev_list_t m_dynamic_devices;
+
+ logic_input_t m_fb_sync;
+ logic_output_t m_Q_sync;
+
+ void step(const netlist_time &delta);
+
+ void update_inputs();
+
+ const eSolverType m_type;
+};
+
+
+NETLIB_NAMESPACE_DEVICES_END()
+
+#endif /* NLD_MS_DIRECT_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_direct.h b/src/lib/netlist/solver/nld_ms_direct.h
index bdcec31ad44..6911e6aa360 100644
--- a/src/lib/netlist/solver/nld_ms_direct.h
+++ b/src/lib/netlist/solver/nld_ms_direct.h
@@ -13,11 +13,18 @@
#include "solver/nld_solver.h"
#include "solver/vector_base.h"
+/* Disabling dynamic allocation gives a ~10% boost in performance
+ * This flag has been added to support continuous storage for arrays
+ * going forward in case we implement cuda solvers in the future.
+ */
+#define NL_USE_DYNAMIC_ALLOCATION (0)
+
+
NETLIB_NAMESPACE_DEVICES_START()
//#define nl_ext_double __float128 // slow, very slow
//#define nl_ext_double long double // slightly slower
-#define nl_ext_double double
+#define nl_ext_double nl_double
template <unsigned m_N, unsigned _storage_N>
class matrix_solver_direct_t: public matrix_solver_t
@@ -32,48 +39,57 @@ public:
virtual void vsetup(analog_net_t::list_t &nets) override;
virtual void reset() override { matrix_solver_t::reset(); }
- ATTR_HOT inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
-
- ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson);
-
protected:
virtual void add_term(int net_idx, terminal_t *term) override;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
+ int solve_non_dynamic(const bool newton_raphson);
- ATTR_HOT virtual nl_double vsolve() override;
+ inline const unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
- ATTR_HOT int solve_non_dynamic(const bool newton_raphson);
- ATTR_HOT void build_LE_A();
- ATTR_HOT void build_LE_RHS(nl_double * RESTRICT rhs);
- ATTR_HOT void LE_solve();
- ATTR_HOT void LE_back_subst(nl_double * RESTRICT x);
+ void build_LE_A();
+ void build_LE_RHS();
+ void LE_solve();
- /* Full LU back substitution, not used currently, in for future use */
+ template <typename T>
+ void LE_back_subst(T * RESTRICT x);
- ATTR_HOT void LE_back_subst_full(nl_double * RESTRICT x);
+ template <typename T>
+ T delta(const T * RESTRICT V);
- ATTR_HOT nl_double delta(const nl_double * RESTRICT V);
- ATTR_HOT void store(const nl_double * RESTRICT V);
+ template <typename T>
+ void store(const T * RESTRICT V);
- /* bring the whole system to the current time
- * Don't schedule a new calculation time. The recalculation has to be
- * triggered by the caller after the netlist element was changed.
- */
- ATTR_HOT nl_double compute_next_timestep();
+ virtual netlist_time compute_next_timestep() override;
+#if (NL_USE_DYNAMIC_ALLOCATION)
template <typename T1, typename T2>
- inline nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; }
-
- ATTR_ALIGN nl_double m_RHS[_storage_N];
+ inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r * m_pitch + c]; }
+ template <typename T1>
+ inline nl_ext_double &RHS(const T1 &r) { return m_A[r * m_pitch + N()]; }
+#else
+ template <typename T1, typename T2>
+ inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
+ template <typename T1>
+ inline nl_ext_double &RHS(const T1 &r) { return m_A[r][N()]; }
+#endif
ATTR_ALIGN nl_double m_last_RHS[_storage_N]; // right hand side - contains currents
ATTR_ALIGN nl_double m_last_V[_storage_N];
- terms_t **m_terms;
+ terms_t * m_terms[_storage_N];
terms_t *m_rails_temp;
private:
- ATTR_ALIGN nl_ext_double m_A[_storage_N][((_storage_N + 7) / 8) * 8];
+ static const std::size_t m_pitch = (((_storage_N + 1) + 7) / 8) * 8;
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ ATTR_ALIGN nl_ext_double * RESTRICT m_A;
+#else
+ ATTR_ALIGN nl_ext_double m_A[_storage_N][m_pitch];
+ ATTR_ALIGN nl_ext_double m_B[_storage_N][m_pitch];
+#endif
+ //ATTR_ALIGN nl_ext_double m_RHSx[_storage_N];
const unsigned m_dim;
+
};
// ----------------------------------------------------------------------------------------
@@ -87,12 +103,14 @@ matrix_solver_direct_t<m_N, _storage_N>::~matrix_solver_direct_t()
{
pfree(m_terms[k]);
}
- pfree_array(m_terms);
pfree_array(m_rails_temp);
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ pfree_array(m_A);
+#endif
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep()
+netlist_time matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep()
{
nl_double new_solver_timestep = m_params.m_max_timestep;
@@ -121,13 +139,15 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timeste
if (new_net_timestep < new_solver_timestep)
new_solver_timestep = new_net_timestep;
+
+ m_last_V[k] = n->Q_Analog();
}
if (new_solver_timestep < m_params.m_min_timestep)
new_solver_timestep = m_params.m_min_timestep;
}
//if (new_solver_timestep > 10.0 * hn)
// new_solver_timestep = 10.0 * hn;
- return new_solver_timestep;
+ return netlist_time::from_double(new_solver_timestep);
}
template <unsigned m_N, unsigned _storage_N>
@@ -166,7 +186,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
m_rails_temp[k].clear();
}
- matrix_solver_t::setup(nets);
+ matrix_solver_t::setup_base(nets);
for (unsigned k = 0; k < N(); k++)
{
@@ -249,19 +269,23 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
}
}
- for (unsigned j = 0; j < N(); j++)
+ for (unsigned i = 0; i < t->m_railstart; i++)
{
- for (unsigned i = 0; i < t->m_railstart; i++)
- {
- if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1))
- t->m_nzrd.push_back(other[i]);
- if (!t->m_nz.contains(other[i]))
- t->m_nz.push_back(other[i]);
- }
+ if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1))
+ t->m_nzrd.push_back(other[i]);
+ if (!t->m_nz.contains(other[i]))
+ t->m_nz.push_back(other[i]);
}
+
+ /* Add RHS element */
+ if (!t->m_nzrd.contains(N()))
+ t->m_nzrd.push_back(N());
+
+ /* and sort */
psort_list(t->m_nzrd);
t->m_nz.push_back(k); // add diagonal
+
psort_list(t->m_nz);
}
@@ -304,7 +328,6 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
/*
* save states
*/
- save(NLNAME(m_RHS));
save(NLNAME(m_last_RHS));
save(NLNAME(m_last_V));
@@ -312,6 +335,8 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
{
pstring num = pfmt("{1}")(k);
+ save(RHS(k), "RHS" + num);
+
save(m_terms[k]->go(),"GO" + num, m_terms[k]->count());
save(m_terms[k]->gt(),"GT" + num, m_terms[k]->count());
save(m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
@@ -321,7 +346,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
+void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
{
const unsigned iN = N();
for (unsigned k = 0; k < iN; k++)
@@ -350,7 +375,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs)
+void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS()
{
const unsigned iN = N();
for (unsigned k = 0; k < iN; k++)
@@ -370,12 +395,12 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double *
//rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog();
rhsk_b = rhsk_b + go[i] * *other_cur_analog[i];
- rhs[k] = rhsk_a + rhsk_b;
+ RHS(k) = rhsk_a + rhsk_b;
}
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
+void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
{
const unsigned kN = N();
@@ -395,10 +420,10 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
if (maxrow != i)
{
/* Swap the maxrow and ith row */
- for (unsigned k = 0; k < kN; k++) {
+ for (unsigned k = 0; k < kN + 1; k++) {
std::swap(A(i,k), A(maxrow,k));
}
- std::swap(m_RHS[i], m_RHS[maxrow]);
+ //std::swap(RHS(i), RHS(maxrow));
}
/* FIXME: Singular matrix? */
const nl_double f = 1.0 / A(i,i);
@@ -410,14 +435,18 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
const nl_double f1 = - A(j,i) * f;
if (f1 != NL_FCONST(0.0))
{
- nl_double * RESTRICT pi = &m_A[i][i+1];
- nl_double * RESTRICT pj = &m_A[j][i+1];
+ const nl_double * RESTRICT pi = &A(i,i+1);
+ nl_double * RESTRICT pj = &A(j,i+1);
+#if 1
+ vec_add_mult_scalar(kN-i,pi,f1,pj);
+#else
vec_add_mult_scalar(kN-i-1,pj,f1,pi);
//for (unsigned k = i+1; k < kN; k++)
// pj[k] = pj[k] + pi[k] * f1;
//for (unsigned k = i+1; k < kN; k++)
//A(j,k) += A(i,k) * f1;
- m_RHS[j] += m_RHS[i] * f1;
+ RHS(j) += RHS(i) * f1;
+#endif
}
}
}
@@ -436,23 +465,18 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
{
const unsigned j = pb[jb];
const nl_double f1 = - A(j,i) * f;
-#if 0
- nl_double * RESTRICT pi = &m_A[i][i+1];
- nl_double * RESTRICT pj = &m_A[j][i+1];
- vec_add_mult_scalar(kN-i-1,pi,f1,pj);
-#else
for (unsigned k = 0; k < e; k++)
A(j,p[k]) += A(i,p[k]) * f1;
-#endif
- m_RHS[j] += m_RHS[i] * f1;
+ //RHS(j) += RHS(i) * f1;
}
}
}
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
- nl_double * RESTRICT x)
+template <typename T>
+void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
+ T * RESTRICT x)
{
const unsigned kN = N();
@@ -461,68 +485,36 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
{
for (int j = kN - 1; j >= 0; j--)
{
- nl_double tmp = 0;
+ T tmp = 0;
for (unsigned k = j+1; k < kN; k++)
tmp += A(j,k) * x[k];
- x[j] = (m_RHS[j] - tmp) / A(j,j);
+ x[j] = (RHS(j) - tmp) / A(j,j);
}
}
else
{
for (int j = kN - 1; j >= 0; j--)
{
- nl_double tmp = 0;
+ T tmp = 0;
const unsigned *p = m_terms[j]->m_nzrd.data();
- const unsigned e = m_terms[j]->m_nzrd.size();
+ const unsigned e = m_terms[j]->m_nzrd.size() - 1; /* exclude RHS element */
for (unsigned k = 0; k < e; k++)
{
const unsigned pk = p[k];
tmp += A(j,pk) * x[pk];
}
- x[j] = (m_RHS[j] - tmp) / A(j,j);
+ x[j] = (RHS(j) - tmp) / A(j,j);
}
}
}
-template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst_full(
- nl_double * RESTRICT x)
-{
- const unsigned kN = N();
-
- /* back substitution */
-
- // int ip;
- // ii=-1
-
- //for (int i=0; i < kN; i++)
- // x[i] = m_RHS[i];
-
- for (int i=0; i < kN; i++)
- {
- //ip=indx[i]; USE_PIVOT_SEARCH
- //sum=b[ip];
- //b[ip]=b[i];
- double sum=m_RHS[i];//x[i];
- for (int j=0; j < i; j++)
- sum -= A(i,j) * x[j];
- x[i]=sum;
- }
- for (int i=kN-1; i >= 0; i--)
- {
- double sum=x[i];
- for (int j = i+1; j < kN; j++)
- sum -= A(i,j)*x[j];
- x[i] = sum / A(i,i);
- }
-
-}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta(
- const nl_double * RESTRICT V)
+template <typename T>
+T matrix_solver_direct_t<m_N, _storage_N>::delta(
+ const T * RESTRICT V)
{
/* FIXME: Ideally we should also include currents (RHS) here. This would
* need a revaluation of the right hand side after voltages have been updated
@@ -530,15 +522,16 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta(
*/
const unsigned iN = this->N();
- nl_double cerr = 0;
+ T cerr = 0;
for (unsigned i = 0; i < iN; i++)
- cerr = std::max(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog));
+ cerr = std::fmax(cerr, nl_math::abs(V[i] - (T) this->m_nets[i]->m_cur_Analog));
return cerr;
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store(
- const nl_double * RESTRICT V)
+template <typename T>
+void matrix_solver_direct_t<m_N, _storage_N>::store(
+ const T * RESTRICT V)
{
for (unsigned i = 0, iN=N(); i < iN; i++)
{
@@ -546,19 +539,13 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store(
}
}
-template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::vsolve()
-{
- this->solve_base(this);
- return this->compute_next_timestep();
-}
-
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
+int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
{
nl_double new_V[_storage_N]; // = { 0.0 };
+ this->LE_solve();
this->LE_back_subst(new_V);
if (newton_raphson)
@@ -577,18 +564,15 @@ ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNU
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
this->build_LE_A();
- this->build_LE_RHS(m_last_RHS);
+ this->build_LE_RHS();
for (unsigned i=0, iN=N(); i < iN; i++)
- m_RHS[i] = m_last_RHS[i];
-
- this->LE_solve();
+ m_last_RHS[i] = RHS(i);
this->m_stat_calculations++;
-
return this->solve_non_dynamic(newton_raphson);
}
@@ -597,9 +581,10 @@ matrix_solver_direct_t<m_N, _storage_N>::matrix_solver_direct_t(const solver_par
: matrix_solver_t(GAUSSIAN_ELIMINATION, params)
, m_dim(size)
{
- m_terms = palloc_array(terms_t *, N());
m_rails_temp = palloc_array(terms_t, N());
-
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ m_A = palloc_array(nl_ext_double, N() * m_pitch);
+#endif
for (unsigned k = 0; k < N(); k++)
{
m_terms[k] = palloc(terms_t);
@@ -613,9 +598,10 @@ matrix_solver_direct_t<m_N, _storage_N>::matrix_solver_direct_t(const eSolverTyp
: matrix_solver_t(type, params)
, m_dim(size)
{
- m_terms = palloc_array(terms_t *, N());
m_rails_temp = palloc_array(terms_t, N());
-
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ m_A = palloc_array(nl_ext_double, N() * m_pitch);
+#endif
for (unsigned k = 0; k < N(); k++)
{
m_terms[k] = palloc(terms_t);
diff --git a/src/lib/netlist/solver/nld_ms_direct1.h b/src/lib/netlist/solver/nld_ms_direct1.h
index fe5a439a9db..ab19c92a4cb 100644
--- a/src/lib/netlist/solver/nld_ms_direct1.h
+++ b/src/lib/netlist/solver/nld_ms_direct1.h
@@ -20,43 +20,33 @@ public:
matrix_solver_direct1_t(const solver_parameters_t *params)
: matrix_solver_direct_t<1, 1>(params, 1)
{}
- ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson);
-protected:
- ATTR_HOT virtual nl_double vsolve() override;
-private:
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
+
};
// ----------------------------------------------------------------------------------------
// matrix_solver - Direct1
// ----------------------------------------------------------------------------------------
-ATTR_HOT nl_double matrix_solver_direct1_t::vsolve()
-{
- solve_base<matrix_solver_direct1_t>(this);
- return this->compute_next_timestep();
-}
-
-ATTR_HOT inline int matrix_solver_direct1_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
+inline int matrix_solver_direct1_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
{
- analog_net_t *net = m_nets[0];
this->build_LE_A();
- this->build_LE_RHS(m_RHS);
+ this->build_LE_RHS();
//NL_VERBOSE_OUT(("{1} {2}\n", new_val, m_RHS[0] / m_A[0][0]);
- nl_double new_val = m_RHS[0] / A(0,0);
+ nl_double new_val[1] = { RHS(0) / A(0,0) };
- nl_double e = (new_val - net->Q_Analog());
- nl_double cerr = nl_math::abs(e);
-
- net->m_cur_Analog = new_val;
-
- if (is_dynamic() && (cerr > m_params.m_accuracy))
+ if (is_dynamic())
{
- return 2;
+ nl_double err = this->delta(new_val);
+ store(new_val);
+ if (err > m_params.m_accuracy )
+ return 2;
+ else
+ return 1;
}
- else
- return 1;
-
+ store(new_val);
+ return 1;
}
NETLIB_NAMESPACE_DEVICES_END()
diff --git a/src/lib/netlist/solver/nld_ms_direct2.h b/src/lib/netlist/solver/nld_ms_direct2.h
index 06f00302d3c..2488e573bf2 100644
--- a/src/lib/netlist/solver/nld_ms_direct2.h
+++ b/src/lib/netlist/solver/nld_ms_direct2.h
@@ -20,26 +20,18 @@ public:
matrix_solver_direct2_t(const solver_parameters_t *params)
: matrix_solver_direct_t<2, 2>(params, 2)
{}
- ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson);
-protected:
- ATTR_HOT virtual nl_double vsolve() override;
-private:
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
+
};
// ----------------------------------------------------------------------------------------
// matrix_solver - Direct2
// ----------------------------------------------------------------------------------------
-ATTR_HOT nl_double matrix_solver_direct2_t::vsolve()
-{
- solve_base<matrix_solver_direct2_t>(this);
- return this->compute_next_timestep();
-}
-
-ATTR_HOT inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
+inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
{
build_LE_A();
- build_LE_RHS(m_RHS);
+ build_LE_RHS();
const nl_double a = A(0,0);
const nl_double b = A(0,1);
@@ -47,8 +39,8 @@ ATTR_HOT inline int matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED cons
const nl_double d = A(1,1);
nl_double new_val[2];
- new_val[1] = (a * m_RHS[1] - c * m_RHS[0]) / (a * d - b * c);
- new_val[0] = (m_RHS[0] - b * new_val[1]) / a;
+ new_val[1] = (a * RHS(1) - c * RHS(0)) / (a * d - b * c);
+ new_val[0] = (RHS(0) - b * new_val[1]) / a;
if (is_dynamic())
{
diff --git a/src/lib/netlist/solver/nld_ms_direct_lu.h b/src/lib/netlist/solver/nld_ms_direct_lu.h
index 07b3b9cb568..2109b0f3e41 100644
--- a/src/lib/netlist/solver/nld_ms_direct_lu.h
+++ b/src/lib/netlist/solver/nld_ms_direct_lu.h
@@ -33,18 +33,16 @@ public:
virtual void vsetup(analog_net_t::list_t &nets) override;
virtual void reset() override { matrix_solver_t::reset(); }
- ATTR_HOT inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
+ inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
- ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson);
+ inline int vsolve_non_dynamic(const bool newton_raphson);
protected:
virtual void add_term(int net_idx, terminal_t *term) override;
- ATTR_HOT virtual nl_double vsolve() override;
-
- ATTR_HOT int solve_non_dynamic(const bool newton_raphson);
- ATTR_HOT void build_LE_A();
- ATTR_HOT void build_LE_RHS(nl_double * RESTRICT rhs);
+ int solve_non_dynamic(const bool newton_raphson);
+ void build_LE_A();
+ void build_LE_RHS(nl_double * RESTRICT rhs);
template<unsigned k>
void LEk()
@@ -68,7 +66,7 @@ protected:
}
}
- ATTR_HOT void LE_solve()
+ void LE_solve()
{
const unsigned kN = N();
unsigned sk = 1;
@@ -127,15 +125,15 @@ protected:
}
}
}
- ATTR_HOT void LE_back_subst(nl_double * RESTRICT x);
- ATTR_HOT nl_double delta(const nl_double * RESTRICT V);
- ATTR_HOT void store(const nl_double * RESTRICT V);
+ void LE_back_subst(nl_double * RESTRICT x);
+ nl_double delta(const nl_double * RESTRICT V);
+ void store(const nl_double * RESTRICT V);
/* bring the whole system to the current time
* Don't schedule a new calculation time. The recalculation has to be
* triggered by the caller after the netlist element was changed.
*/
- ATTR_HOT nl_double compute_next_timestep();
+ nl_double compute_next_timestep();
template <typename T1, typename T2>
inline nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; }
@@ -171,7 +169,7 @@ matrix_solver_direct_t<m_N, _storage_N>::~matrix_solver_direct_t()
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep()
+nl_double matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep()
{
nl_double new_solver_timestep = m_params.m_max_timestep;
@@ -245,7 +243,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
m_rails_temp[k].clear();
}
- matrix_solver_t::setup(nets);
+ matrix_solver_t::setup_base(nets);
for (unsigned k = 0; k < N(); k++)
{
@@ -373,7 +371,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
+void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
{
const unsigned iN = N();
for (unsigned k = 0; k < iN; k++)
@@ -399,7 +397,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_A()
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs)
+void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double * RESTRICT rhs)
{
const unsigned iN = N();
for (unsigned k = 0; k < iN; k++)
@@ -427,7 +425,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::build_LE_RHS(nl_double *
#else
// Crout algo
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
+void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
{
const unsigned kN = N();
@@ -509,7 +507,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
#endif
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
+void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
nl_double * RESTRICT x)
{
const unsigned kN = N();
@@ -543,7 +541,7 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta(
+nl_double matrix_solver_direct_t<m_N, _storage_N>::delta(
const nl_double * RESTRICT V)
{
/* FIXME: Ideally we should also include currents (RHS) here. This would
@@ -554,12 +552,12 @@ ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::delta(
const unsigned iN = this->N();
nl_double cerr = 0;
for (unsigned i = 0; i < iN; i++)
- cerr = std::max(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog));
+ cerr = std::fmax(cerr, nl_math::abs(V[i] - this->m_nets[i]->m_cur_Analog));
return cerr;
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store(
+void matrix_solver_direct_t<m_N, _storage_N>::store(
const nl_double * RESTRICT V)
{
for (unsigned i = 0, iN=N(); i < iN; i++)
@@ -568,16 +566,9 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::store(
}
}
-template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_direct_t<m_N, _storage_N>::vsolve()
-{
- this->solve_base(this);
- return this->compute_next_timestep();
-}
-
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
+int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
{
nl_double new_V[_storage_N]; // = { 0.0 };
@@ -599,7 +590,7 @@ ATTR_HOT int matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNU
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
this->build_LE_A();
this->build_LE_RHS(m_last_RHS);
@@ -607,8 +598,6 @@ ATTR_HOT inline int matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(
for (unsigned i=0, iN=N(); i < iN; i++)
m_RHS[i] = m_last_RHS[i];
- this->LE_solve();
-
return this->solve_non_dynamic(newton_raphson);
}
diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h
index 0ae7f5eab56..6ff0d43f421 100644
--- a/src/lib/netlist/solver/nld_ms_gmres.h
+++ b/src/lib/netlist/solver/nld_ms_gmres.h
@@ -54,13 +54,11 @@ public:
}
virtual void vsetup(analog_net_t::list_t &nets) override;
- ATTR_HOT virtual int vsolve_non_dynamic(const bool newton_raphson);
-protected:
- ATTR_HOT virtual nl_double vsolve() override;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
private:
- int solve_ilu_gmres(nl_double * RESTRICT x, nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy);
+ int solve_ilu_gmres(nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy);
pvector_t<int> m_term_cr[_storage_N];
@@ -126,14 +124,7 @@ void matrix_solver_GMRES_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets)
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_GMRES_t<m_N, _storage_N>::vsolve()
-{
- this->solve_base(this);
- return this->compute_next_timestep();
-}
-
-template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
const unsigned iN = this->N();
@@ -166,6 +157,7 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c
const nl_double * const * RESTRICT other_cur_analog = this->m_terms[k]->other_curanalog();
l_V[k] = new_V[k] = this->m_nets[k]->m_cur_Analog;
+
for (unsigned i = 0; i < term_count; i++)
{
gtot_t = gtot_t + gt[i];
@@ -189,7 +181,7 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c
mat.ia[iN] = mat.nz_num;
const nl_double accuracy = this->m_params.m_accuracy;
-#if 1
+
int mr = _storage_N;
if (_storage_N > 3 )
mr = (int) sqrt(iN);
@@ -197,19 +189,12 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c
int iter = 4;
int gsl = solve_ilu_gmres(new_V, RHS, iter, mr, accuracy);
int failed = mr * iter;
-#else
- int failed = 6;
- //int gsl = tt_ilu_cr(new_V, RHS, failed, accuracy);
- int gsl = tt_gs_cr(new_V, RHS, failed, accuracy);
-#endif
+
this->m_iterative_total += gsl;
this->m_stat_calculations++;
if (gsl>=failed)
{
- //for (int k = 0; k < iN; k++)
- // this->m_nets[k]->m_cur_Analog = new_V[k];
- // Fallback to direct solver ...
this->m_iterative_fail++;
return matrix_solver_direct_t<m_N, _storage_N>::vsolve_non_dynamic(newton_raphson);
}
@@ -235,17 +220,18 @@ ATTR_HOT inline int matrix_solver_GMRES_t<m_N, _storage_N>::vsolve_non_dynamic(c
}
}
-static inline void givens_mult( const nl_double c, const nl_double s, nl_double * RESTRICT g0, nl_double * RESTRICT g1 )
+template <typename T>
+inline void givens_mult( const T c, const T s, T & g0, T & g1 )
{
- const double tg0 = c * *g0 - s * *g1;
- const double tg1 = s * *g0 + c * *g1;
+ const T tg0 = c * g0 - s * g1;
+ const T tg1 = s * g0 + c * g1;
- *g0 = tg0;
- *g1 = tg1;
+ g0 = tg0;
+ g1 = tg1;
}
template <unsigned m_N, unsigned _storage_N>
-int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRICT x, nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy)
+int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy)
{
/*-------------------------------------------------------------------------
* The code below was inspired by code published by John Burkardt under
@@ -351,7 +337,7 @@ int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRIC
vec_scale(n, m_v[k1], NL_FCONST(1.0) / m_ht[k1][k]);
for (unsigned j = 0; j < k; j++)
- givens_mult(m_c[j], m_s[j], &m_ht[j][k], &m_ht[j+1][k]);
+ givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]);
mu = std::sqrt(std::pow(m_ht[k][k], 2) + std::pow(m_ht[k1][k], 2));
@@ -360,7 +346,7 @@ int matrix_solver_GMRES_t<m_N, _storage_N>::solve_ilu_gmres (nl_double * RESTRIC
m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[k1][k];
m_ht[k1][k] = 0.0;
- givens_mult(m_c[k], m_s[k], &m_g[k], &m_g[k1]);
+ givens_mult(m_c[k], m_s[k], m_g[k], m_g[k1]);
rho = std::abs(m_g[k1]);
diff --git a/src/lib/netlist/solver/nld_ms_sm.h b/src/lib/netlist/solver/nld_ms_sm.h
new file mode 100644
index 00000000000..7336e060510
--- /dev/null
+++ b/src/lib/netlist/solver/nld_ms_sm.h
@@ -0,0 +1,674 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * nld_ms_direct.h
+ *
+ *
+ * Sherman-Morrison Solver
+ *
+ * Computes the updated inverse of A given that the change in A is
+ *
+ * A <- A + (u x v) u,v vectors
+ *
+ * In this specific implementation, u is a unit vector specifying the row which
+ * changed. Thus v contains the changed column.
+ *
+ * Than z = A⁻¹ u , w = transpose(A⁻¹) v , lambda = v z
+ *
+ * A⁻¹ <- 1.0 / (1.0 + lambda) * (z x w)
+ *
+ * The approach is iterative and applied for each row changed.
+ *
+ * The performance for a typical circuit like kidniki compared to Gaussian
+ * elimination is poor:
+ *
+ * a) The code needs to be run for each row change.
+ * b) The inverse of A typically is fully occupied.
+ *
+ * It may have advantages for circuits with a high number of elements and only
+ * few dynamic/active components.
+ *
+ */
+
+#ifndef NLD_MS_SM_H_
+#define NLD_MS_SM_H_
+
+#include <algorithm>
+
+#include "solver/nld_solver.h"
+#include "solver/vector_base.h"
+
+NETLIB_NAMESPACE_DEVICES_START()
+
+//#define nl_ext_double __float128 // slow, very slow
+//#define nl_ext_double long double // slightly slower
+#define nl_ext_double nl_double
+
+template <unsigned m_N, unsigned _storage_N>
+class matrix_solver_sm_t: public matrix_solver_t
+{
+public:
+
+ matrix_solver_sm_t(const solver_parameters_t *params, const int size);
+ matrix_solver_sm_t(const eSolverType type, const solver_parameters_t *params, const int size);
+
+ virtual ~matrix_solver_sm_t();
+
+ virtual void vsetup(analog_net_t::list_t &nets) override;
+ virtual void reset() override { matrix_solver_t::reset(); }
+
+protected:
+ virtual void add_term(int net_idx, terminal_t *term) override;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
+ int solve_non_dynamic(const bool newton_raphson);
+
+ inline const unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
+
+ void build_LE_A();
+ void build_LE_RHS();
+ void LE_invert();
+
+ template <typename T>
+ void LE_compute_x(T * RESTRICT x);
+
+ template <typename T>
+ T delta(const T * RESTRICT V);
+
+ template <typename T>
+ void store(const T * RESTRICT V);
+
+ virtual netlist_time compute_next_timestep() override;
+
+ template <typename T1, typename T2>
+ inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
+ template <typename T1, typename T2>
+ inline nl_ext_double &W(const T1 &r, const T2 &c) { return m_W[r][c]; }
+ template <typename T1, typename T2>
+ inline nl_ext_double &Ainv(const T1 &r, const T2 &c) { return m_Ainv[r][c]; }
+ template <typename T1>
+ inline nl_ext_double &RHS(const T1 &r) { return m_RHS[r]; }
+
+
+ template <typename T1, typename T2>
+ inline nl_ext_double &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; }
+ template <typename T1, typename T2>
+ inline nl_ext_double &lAinv(const T1 &r, const T2 &c) { return m_lAinv[r][c]; }
+
+ ATTR_ALIGN nl_double m_last_RHS[_storage_N]; // right hand side - contains currents
+ ATTR_ALIGN nl_double m_last_V[_storage_N];
+
+ terms_t * m_terms[_storage_N];
+ terms_t *m_rails_temp;
+
+private:
+ static const std::size_t m_pitch = ((( _storage_N) + 7) / 8) * 8;
+ ATTR_ALIGN nl_ext_double m_A[_storage_N][m_pitch];
+ ATTR_ALIGN nl_ext_double m_Ainv[_storage_N][m_pitch];
+ ATTR_ALIGN nl_ext_double m_W[_storage_N][m_pitch];
+ ATTR_ALIGN nl_ext_double m_RHS[_storage_N]; // right hand side - contains currents
+
+ ATTR_ALIGN nl_ext_double m_lA[_storage_N][m_pitch];
+ ATTR_ALIGN nl_ext_double m_lAinv[_storage_N][m_pitch];
+
+ //ATTR_ALIGN nl_ext_double m_RHSx[_storage_N];
+
+ const unsigned m_dim;
+
+};
+
+// ----------------------------------------------------------------------------------------
+// matrix_solver_direct
+// ----------------------------------------------------------------------------------------
+
+template <unsigned m_N, unsigned _storage_N>
+matrix_solver_sm_t<m_N, _storage_N>::~matrix_solver_sm_t()
+{
+ for (unsigned k = 0; k < N(); k++)
+ {
+ pfree(m_terms[k]);
+ }
+ pfree_array(m_rails_temp);
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ pfree_array(m_A);
+#endif
+}
+
+template <unsigned m_N, unsigned _storage_N>
+netlist_time matrix_solver_sm_t<m_N, _storage_N>::compute_next_timestep()
+{
+ nl_double new_solver_timestep = m_params.m_max_timestep;
+
+ if (m_params.m_dynamic)
+ {
+ /*
+ * FIXME: We should extend the logic to use either all nets or
+ * only output nets.
+ */
+ for (unsigned k = 0, iN=N(); k < iN; k++)
+ {
+ analog_net_t *n = m_nets[k];
+
+ const nl_double DD_n = (n->Q_Analog() - m_last_V[k]);
+ const nl_double hn = current_timestep();
+
+ nl_double DD2 = (DD_n / hn - n->m_DD_n_m_1 / n->m_h_n_m_1) / (hn + n->m_h_n_m_1);
+ nl_double new_net_timestep;
+
+ n->m_h_n_m_1 = hn;
+ n->m_DD_n_m_1 = DD_n;
+ if (nl_math::abs(DD2) > NL_FCONST(1e-30)) // avoid div-by-zero
+ new_net_timestep = nl_math::sqrt(m_params.m_lte / nl_math::abs(NL_FCONST(0.5)*DD2));
+ else
+ new_net_timestep = m_params.m_max_timestep;
+
+ if (new_net_timestep < new_solver_timestep)
+ new_solver_timestep = new_net_timestep;
+
+ m_last_V[k] = n->Q_Analog();
+ }
+ if (new_solver_timestep < m_params.m_min_timestep)
+ new_solver_timestep = m_params.m_min_timestep;
+ }
+ //if (new_solver_timestep > 10.0 * hn)
+ // new_solver_timestep = 10.0 * hn;
+ return netlist_time::from_double(new_solver_timestep);
+}
+
+template <unsigned m_N, unsigned _storage_N>
+ATTR_COLD void matrix_solver_sm_t<m_N, _storage_N>::add_term(int k, terminal_t *term)
+{
+ if (term->m_otherterm->net().isRailNet())
+ {
+ m_rails_temp[k].add(term, -1, false);
+ }
+ else
+ {
+ int ot = get_net_idx(&term->m_otherterm->net());
+ if (ot>=0)
+ {
+ m_terms[k]->add(term, ot, true);
+ }
+ /* Should this be allowed ? */
+ else // if (ot<0)
+ {
+ m_rails_temp[k].add(term, ot, true);
+ log().fatal("found term with missing othernet {1}\n", term->name());
+ }
+ }
+}
+
+
+template <unsigned m_N, unsigned _storage_N>
+ATTR_COLD void matrix_solver_sm_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets)
+{
+ if (m_dim < nets.size())
+ log().fatal("Dimension {1} less than {2}", m_dim, nets.size());
+
+ for (unsigned k = 0; k < N(); k++)
+ {
+ m_terms[k]->clear();
+ m_rails_temp[k].clear();
+ }
+
+ matrix_solver_t::setup_base(nets);
+
+ for (unsigned k = 0; k < N(); k++)
+ {
+ m_terms[k]->m_railstart = m_terms[k]->count();
+ for (unsigned i = 0; i < m_rails_temp[k].count(); i++)
+ this->m_terms[k]->add(m_rails_temp[k].terms()[i], m_rails_temp[k].net_other()[i], false);
+
+ m_rails_temp[k].clear(); // no longer needed
+ m_terms[k]->set_pointers();
+ }
+
+#if 1
+
+ /* Sort in descending order by number of connected matrix voltages.
+ * The idea is, that for Gauss-Seidel algo the first voltage computed
+ * depends on the greatest number of previous voltages thus taking into
+ * account the maximum amout of information.
+ *
+ * This actually improves performance on popeye slightly. Average
+ * GS computations reduce from 2.509 to 2.370
+ *
+ * Smallest to largest : 2.613
+ * Unsorted : 2.509
+ * Largest to smallest : 2.370
+ *
+ * Sorting as a general matrix pre-conditioning is mentioned in
+ * literature but I have found no articles about Gauss Seidel.
+ *
+ * For Gaussian Elimination however increasing order is better suited.
+ * FIXME: Even better would be to sort on elements right of the matrix diagonal.
+ *
+ */
+
+ int sort_order = (type() == GAUSS_SEIDEL ? 1 : -1);
+
+ for (unsigned k = 0; k < N() / 2; k++)
+ for (unsigned i = 0; i < N() - 1; i++)
+ {
+ if ((m_terms[i]->m_railstart - m_terms[i+1]->m_railstart) * sort_order < 0)
+ {
+ std::swap(m_terms[i], m_terms[i+1]);
+ std::swap(m_nets[i], m_nets[i+1]);
+ }
+ }
+
+ for (unsigned k = 0; k < N(); k++)
+ {
+ int *other = m_terms[k]->net_other();
+ for (unsigned i = 0; i < m_terms[k]->count(); i++)
+ if (other[i] != -1)
+ other[i] = get_net_idx(&m_terms[k]->terms()[i]->m_otherterm->net());
+ }
+
+#endif
+
+ /* create a list of non zero elements right of the diagonal
+ * These list anticipate the population of array elements by
+ * Gaussian elimination.
+ */
+ for (unsigned k = 0; k < N(); k++)
+ {
+ terms_t * t = m_terms[k];
+ /* pretty brutal */
+ int *other = t->net_other();
+
+ t->m_nz.clear();
+
+ if (k==0)
+ t->m_nzrd.clear();
+ else
+ {
+ t->m_nzrd = m_terms[k-1]->m_nzrd;
+ unsigned j=0;
+ while(j < t->m_nzrd.size())
+ {
+ if (t->m_nzrd[j] < k + 1)
+ t->m_nzrd.remove_at(j);
+ else
+ j++;
+ }
+ }
+
+ for (unsigned i = 0; i < t->m_railstart; i++)
+ {
+ if (!t->m_nzrd.contains(other[i]) && other[i] >= (int) (k + 1))
+ t->m_nzrd.push_back(other[i]);
+ if (!t->m_nz.contains(other[i]))
+ t->m_nz.push_back(other[i]);
+ }
+
+ /* and sort */
+ psort_list(t->m_nzrd);
+
+ t->m_nz.push_back(k); // add diagonal
+
+ psort_list(t->m_nz);
+ }
+
+ /* create a list of non zero elements below diagonal k
+ * This should reduce cache misses ...
+ */
+
+ bool touched[_storage_N][_storage_N] = { { false } };
+ for (unsigned k = 0; k < N(); k++)
+ {
+ m_terms[k]->m_nzbd.clear();
+ for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++)
+ touched[k][m_terms[k]->m_nz[j]] = true;
+ }
+
+ for (unsigned k = 0; k < N(); k++)
+ {
+ for (unsigned row = k + 1; row < N(); row++)
+ {
+ if (touched[row][k])
+ {
+ if (!m_terms[k]->m_nzbd.contains(row))
+ m_terms[k]->m_nzbd.push_back(row);
+ for (unsigned col = k; col < N(); col++)
+ if (touched[k][col])
+ touched[row][col] = true;
+ }
+ }
+ }
+
+ if (0)
+ for (unsigned k = 0; k < N(); k++)
+ {
+ pstring line = pfmt("{1}")(k, "3");
+ for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++)
+ line += pfmt(" {1}")(m_terms[k]->m_nzrd[j], "3");
+ log().verbose("{1}", line);
+ }
+
+ /*
+ * save states
+ */
+ save(NLNAME(m_last_RHS));
+ save(NLNAME(m_last_V));
+
+ for (unsigned k = 0; k < N(); k++)
+ {
+ pstring num = pfmt("{1}")(k);
+
+ save(RHS(k), "RHS" + num);
+
+ save(m_terms[k]->go(),"GO" + num, m_terms[k]->count());
+ save(m_terms[k]->gt(),"GT" + num, m_terms[k]->count());
+ save(m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
+ }
+
+}
+
+
+template <unsigned m_N, unsigned _storage_N>
+void matrix_solver_sm_t<m_N, _storage_N>::build_LE_A()
+{
+ const unsigned iN = N();
+ for (unsigned k = 0; k < iN; k++)
+ {
+ for (unsigned i=0; i < iN; i++)
+ A(k,i) = 0.0;
+
+ const unsigned terms_count = m_terms[k]->count();
+ const unsigned railstart = m_terms[k]->m_railstart;
+ const nl_double * RESTRICT gt = m_terms[k]->gt();
+
+ {
+ nl_double akk = 0.0;
+ for (unsigned i = 0; i < terms_count; i++)
+ akk += gt[i];
+
+ A(k,k) = akk;
+ }
+
+ const nl_double * RESTRICT go = m_terms[k]->go();
+ const int * RESTRICT net_other = m_terms[k]->net_other();
+
+ for (unsigned i = 0; i < railstart; i++)
+ A(k,net_other[i]) -= go[i];
+ }
+}
+
+template <unsigned m_N, unsigned _storage_N>
+void matrix_solver_sm_t<m_N, _storage_N>::build_LE_RHS()
+{
+ const unsigned iN = N();
+ for (unsigned k = 0; k < iN; k++)
+ {
+ nl_double rhsk_a = 0.0;
+ nl_double rhsk_b = 0.0;
+
+ const int terms_count = m_terms[k]->count();
+ const nl_double * RESTRICT go = m_terms[k]->go();
+ const nl_double * RESTRICT Idr = m_terms[k]->Idr();
+ const nl_double * const * RESTRICT other_cur_analog = m_terms[k]->other_curanalog();
+
+ for (int i = 0; i < terms_count; i++)
+ rhsk_a = rhsk_a + Idr[i];
+
+ for (int i = m_terms[k]->m_railstart; i < terms_count; i++)
+ //rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog();
+ rhsk_b = rhsk_b + go[i] * *other_cur_analog[i];
+
+ RHS(k) = rhsk_a + rhsk_b;
+ }
+}
+
+template <unsigned m_N, unsigned _storage_N>
+void matrix_solver_sm_t<m_N, _storage_N>::LE_invert()
+{
+ const unsigned kN = N();
+
+ for (unsigned i = 0; i < kN; i++)
+ {
+ for (unsigned j = 0; j < kN; j++)
+ {
+ W(i,j) = lA(i,j) = A(i,j);
+ Ainv(i,j) = 0.0;
+ }
+ Ainv(i,i) = 1.0;
+ }
+ /* down */
+ for (unsigned i = 0; i < kN; i++)
+ {
+ /* FIXME: Singular matrix? */
+ const nl_double f = 1.0 / W(i,i);
+ const unsigned * RESTRICT const p = m_terms[i]->m_nzrd.data();
+ const unsigned e = m_terms[i]->m_nzrd.size();
+
+ /* Eliminate column i from row j */
+
+ const unsigned * RESTRICT const pb = m_terms[i]->m_nzbd.data();
+ const unsigned eb = m_terms[i]->m_nzbd.size();
+ for (unsigned jb = 0; jb < eb; jb++)
+ {
+ const unsigned j = pb[jb];
+ const nl_double f1 = - W(j,i) * f;
+ if (f1 != 0.0)
+ {
+ for (unsigned k = 0; k < e; k++)
+ W(j,p[k]) += W(i,p[k]) * f1;
+ for (unsigned k = 0; k <= i; k ++)
+ Ainv(j,k) += Ainv(i,k) * f1;
+ }
+ }
+ }
+ /* up */
+ for (int i = kN - 1; i >= 0; i--)
+ {
+ /* FIXME: Singular matrix? */
+ const nl_double f = 1.0 / W(i,i);
+ for (int j = i - 1; j>=0; j--)
+ {
+ const nl_double f1 = - W(j,i) * f;
+ if (f1 != 0.0)
+ {
+ for (unsigned k = i; k < kN; k++)
+ W(j,k) += W(i,k) * f1;
+ for (unsigned k = 0; k < kN; k++)
+ Ainv(j,k) += Ainv(i,k) * f1;
+ }
+ }
+ for (unsigned k = 0; k < kN; k++)
+ {
+ Ainv(i,k) *= f;
+ lAinv(i,k) = Ainv(i,k);
+ }
+ }
+}
+
+template <unsigned m_N, unsigned _storage_N>
+template <typename T>
+void matrix_solver_sm_t<m_N, _storage_N>::LE_compute_x(
+ T * RESTRICT x)
+{
+ const unsigned kN = N();
+
+ for (int i=0; i<kN; i++)
+ x[i] = 0.0;
+
+ for (int k=0; k<kN; k++)
+ {
+ const nl_double f = RHS(k);
+
+ for (int i=0; i<kN; i++)
+ x[i] += Ainv(i,k) * f;
+ }
+}
+
+
+template <unsigned m_N, unsigned _storage_N>
+template <typename T>
+T matrix_solver_sm_t<m_N, _storage_N>::delta(
+ const T * RESTRICT V)
+{
+ /* FIXME: Ideally we should also include currents (RHS) here. This would
+ * need a revaluation of the right hand side after voltages have been updated
+ * and thus belong into a different calculation. This applies to all solvers.
+ */
+
+ const unsigned iN = this->N();
+ T cerr = 0;
+ for (unsigned i = 0; i < iN; i++)
+ cerr = std::fmax(cerr, nl_math::abs(V[i] - (T) this->m_nets[i]->m_cur_Analog));
+ return cerr;
+}
+
+template <unsigned m_N, unsigned _storage_N>
+template <typename T>
+void matrix_solver_sm_t<m_N, _storage_N>::store(
+ const T * RESTRICT V)
+{
+ for (unsigned i = 0, iN=N(); i < iN; i++)
+ {
+ this->m_nets[i]->m_cur_Analog = V[i];
+ }
+}
+
+
+template <unsigned m_N, unsigned _storage_N>
+int matrix_solver_sm_t<m_N, _storage_N>::solve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
+{
+ static const bool incremental = true;
+ static uint cnt = 0;
+
+ nl_double new_V[_storage_N]; // = { 0.0 };
+
+ if (0 || ((cnt % 200) == 0))
+ {
+ /* complete calculation */
+ this->LE_invert();
+ }
+ else
+ {
+ const auto iN = N();
+
+ if (not incremental)
+ {
+ for (int row = 0; row < iN; row ++)
+ for (int k = 0; k < iN; k++)
+ Ainv(row,k) = lAinv(row, k);
+ }
+ for (int row = 0; row < iN; row ++)
+ {
+ nl_double v[m_pitch] = {0};
+ unsigned cols[m_pitch];
+ unsigned colcount = 0;
+
+ auto &nz = m_terms[row]->m_nz;
+ for (auto & col : nz)
+ {
+ v[col] = A(row,col) - lA(row,col);
+ if (incremental)
+ lA(row,col) = A(row,col);
+ if (v[col] != 0.0)
+ cols[colcount++] = col;
+ }
+
+ if (colcount > 0)
+ {
+ nl_double lamba = 0.0;
+ nl_double w[m_pitch] = {0};
+ nl_double z[m_pitch];
+ /* compute w and lamba */
+ for (unsigned i = 0; i < iN; i++)
+ z[i] = Ainv(i, row); /* u is row'th column */
+
+ for (unsigned j = 0; j < colcount; j++)
+ lamba += v[cols[j]] * z[cols[j]];
+
+ for (unsigned j=0; j<colcount; j++)
+ {
+ auto col = cols[j];
+ auto f = v[col];
+ for (unsigned k = 0; k < iN; k++)
+ w[k] += Ainv(col,k) * f; /* Transpose(Ainv) * v */
+ }
+
+ lamba = -1.0 / (1.0 + lamba);
+ for (int i=0; i<iN; i++)
+ {
+ const nl_double f = lamba * z[i];
+ if (f != 0.0)
+ for (int k = 0; k < iN; k++)
+ Ainv(i,k) += f * w[k];
+ }
+ }
+
+ }
+ }
+
+ cnt++;
+
+ this->LE_compute_x(new_V);
+
+ if (newton_raphson)
+ {
+ nl_double err = delta(new_V);
+
+ store(new_V);
+
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
+ else
+ {
+ store(new_V);
+ return 1;
+ }
+}
+
+template <unsigned m_N, unsigned _storage_N>
+inline int matrix_solver_sm_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+{
+ this->build_LE_A();
+ this->build_LE_RHS();
+
+ for (unsigned i=0, iN=N(); i < iN; i++)
+ m_last_RHS[i] = RHS(i);
+
+ this->m_stat_calculations++;
+ return this->solve_non_dynamic(newton_raphson);
+}
+
+template <unsigned m_N, unsigned _storage_N>
+matrix_solver_sm_t<m_N, _storage_N>::matrix_solver_sm_t(const solver_parameters_t *params, const int size)
+: matrix_solver_t(GAUSSIAN_ELIMINATION, params)
+, m_dim(size)
+{
+ m_rails_temp = palloc_array(terms_t, N());
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ m_A = palloc_array(nl_ext_double, N() * m_pitch);
+#endif
+ for (unsigned k = 0; k < N(); k++)
+ {
+ m_terms[k] = palloc(terms_t);
+ m_last_RHS[k] = 0.0;
+ m_last_V[k] = 0.0;
+ }
+}
+
+template <unsigned m_N, unsigned _storage_N>
+matrix_solver_sm_t<m_N, _storage_N>::matrix_solver_sm_t(const eSolverType type, const solver_parameters_t *params, const int size)
+: matrix_solver_t(type, params)
+, m_dim(size)
+{
+ m_rails_temp = palloc_array(terms_t, N());
+#if (NL_USE_DYNAMIC_ALLOCATION)
+ m_A = palloc_array(nl_ext_double, N() * m_pitch);
+#endif
+ for (unsigned k = 0; k < N(); k++)
+ {
+ m_terms[k] = palloc(terms_t);
+ m_last_RHS[k] = 0.0;
+ m_last_V[k] = 0.0;
+ }
+}
+
+NETLIB_NAMESPACE_DEVICES_END()
+
+#endif /* NLD_MS_DIRECT_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_sor.h b/src/lib/netlist/solver/nld_ms_sor.h
index 556e9fddd7f..1805b23a9d0 100644
--- a/src/lib/netlist/solver/nld_ms_sor.h
+++ b/src/lib/netlist/solver/nld_ms_sor.h
@@ -33,9 +33,7 @@ public:
virtual ~matrix_solver_SOR_t() {}
virtual void vsetup(analog_net_t::list_t &nets) override;
- ATTR_HOT virtual int vsolve_non_dynamic(const bool newton_raphson);
-protected:
- ATTR_HOT virtual nl_double vsolve() override;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
private:
nl_double m_lp_fact;
@@ -54,14 +52,7 @@ void matrix_solver_SOR_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets)
}
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_SOR_t<m_N, _storage_N>::vsolve()
-{
- this->solve_base(this);
- return this->compute_next_timestep();
-}
-
-template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT inline int matrix_solver_SOR_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+int matrix_solver_SOR_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
const unsigned iN = this->N();
bool resched = false;
diff --git a/src/lib/netlist/solver/nld_ms_sor_mat.h b/src/lib/netlist/solver/nld_ms_sor_mat.h
index 4312c3039be..a4fce8dec2a 100644
--- a/src/lib/netlist/solver/nld_ms_sor_mat.h
+++ b/src/lib/netlist/solver/nld_ms_sor_mat.h
@@ -37,9 +37,7 @@ public:
virtual void vsetup(analog_net_t::list_t &nets) override;
- ATTR_HOT inline int vsolve_non_dynamic(const bool newton_raphson);
-protected:
- ATTR_HOT virtual nl_double vsolve() override;
+ virtual int vsolve_non_dynamic(const bool newton_raphson) override;
private:
nl_double m_Vdelta[_storage_N];
@@ -65,9 +63,10 @@ void matrix_solver_SOR_mat_t<m_N, _storage_N>::vsetup(analog_net_t::list_t &nets
this->save(NLNAME(m_Vdelta));
}
-
+#if 0
+//FIXME: move to solve_base
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve()
+nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve()
{
/*
* enable linear prediction on first newton pass
@@ -111,9 +110,10 @@ ATTR_HOT nl_double matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve()
return this->compute_next_timestep();
}
+#endif
template <unsigned m_N, unsigned _storage_N>
-ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
/* The matrix based code looks a lot nicer but actually is 30% slower than
* the optimized code which works directly on the data structures.
@@ -129,7 +129,7 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic
int resched_cnt = 0;
this->build_LE_A();
- this->build_LE_RHS(this->m_RHS);
+ this->build_LE_RHS();
#if 0
static int ws_cnt = 0;
@@ -184,7 +184,7 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic
for (unsigned i = 0; i < e; i++)
Idrive = Idrive + this->A(k,p[i]) * new_v[p[i]];
- const nl_double delta = m_omega * (this->m_RHS[k] - Idrive) / this->A(k,k);
+ const nl_double delta = m_omega * (this->RHS(k) - Idrive) / this->A(k,k);
cerr = std::max(cerr, nl_math::abs(delta));
new_v[k] += delta;
}
@@ -204,7 +204,6 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic
//this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS");
this->m_gs_fail++;
- this->LE_solve();
return matrix_solver_direct_t<m_N, _storage_N>::solve_non_dynamic(newton_raphson);
}
else {
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp
index 3c8b0f4a663..388f21bda77 100644
--- a/src/lib/netlist/solver/nld_solver.cpp
+++ b/src/lib/netlist/solver/nld_solver.cpp
@@ -31,23 +31,27 @@
#include <iostream>
#include <algorithm>
+//#include "nld_twoterm.h"
+#include "nl_lists.h"
+
+#if HAS_OPENMP
+#include "omp.h"
+#endif
+
#include "nld_solver.h"
+#include "nld_matrix_solver.h"
+
#if 1
#include "nld_ms_direct.h"
#else
#include "nld_ms_direct_lu.h"
#endif
+#include "nld_ms_sm.h"
#include "nld_ms_direct1.h"
#include "nld_ms_direct2.h"
#include "nld_ms_sor.h"
#include "nld_ms_sor_mat.h"
#include "nld_ms_gmres.h"
-//#include "nld_twoterm.h"
-#include "nl_lists.h"
-
-#if HAS_OPENMP
-#include "omp.h"
-#endif
NETLIB_NAMESPACE_DEVICES_START()
@@ -79,9 +83,7 @@ ATTR_COLD void terms_t::set_pointers()
{
for (unsigned i = 0; i < count(); i++)
{
- m_term[i]->m_gt1 = &m_gt[i];
- m_term[i]->m_go1 = &m_go[i];
- m_term[i]->m_Idr1 = &m_Idr[i];
+ m_term[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]);
m_other_curanalog[i] = &m_term[i]->m_otherterm->net().m_cur_Analog;
}
}
@@ -107,7 +109,7 @@ ATTR_COLD matrix_solver_t::~matrix_solver_t()
m_inps.clear_and_free();
}
-ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets)
+ATTR_COLD void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
{
log().debug("New solver setup\n");
@@ -187,14 +189,14 @@ ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets)
}
-ATTR_HOT void matrix_solver_t::update_inputs()
+void matrix_solver_t::update_inputs()
{
// avoid recursive calls. Inputs are updated outside this call
for (std::size_t i=0; i<m_inps.size(); i++)
m_inps[i]->set_Q(m_inps[i]->m_proxied_net->Q_Analog());
}
-ATTR_HOT void matrix_solver_t::update_dynamic()
+void matrix_solver_t::update_dynamic()
{
/* update all non-linear devices */
for (std::size_t i=0; i < m_dynamic_devices.size(); i++)
@@ -224,29 +226,28 @@ ATTR_COLD void matrix_solver_t::reset()
ATTR_COLD void matrix_solver_t::update()
{
- const nl_double new_timestep = solve();
+ const netlist_time new_timestep = solve();
- if (m_params.m_dynamic && is_timestep() && new_timestep > 0)
- m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(new_timestep));
+ if (m_params.m_dynamic && is_timestep() && new_timestep > netlist_time::zero)
+ m_Q_sync.net().reschedule_in_queue(new_timestep);
}
ATTR_COLD void matrix_solver_t::update_forced()
{
- ATTR_UNUSED const nl_double new_timestep = solve();
+ ATTR_UNUSED const netlist_time new_timestep = solve();
if (m_params.m_dynamic && is_timestep())
m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(m_params.m_min_timestep));
}
-ATTR_HOT void matrix_solver_t::step(const netlist_time delta)
+void matrix_solver_t::step(const netlist_time &delta)
{
const nl_double dd = delta.as_double();
for (std::size_t k=0; k < m_step_devices.size(); k++)
m_step_devices[k]->step_time(dd);
}
-template<class C >
-void matrix_solver_t::solve_base(C *p)
+netlist_time matrix_solver_t::solve_base()
{
m_stat_vsolver_calls++;
if (is_dynamic())
@@ -257,7 +258,7 @@ void matrix_solver_t::solve_base(C *p)
{
update_dynamic();
// Gauss-Seidel will revert to Gaussian elemination if steps exceeded.
- this_resched = p->vsolve_non_dynamic(true);
+ this_resched = this->vsolve_non_dynamic(true);
newton_loops++;
} while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
@@ -271,11 +272,12 @@ void matrix_solver_t::solve_base(C *p)
}
else
{
- p->vsolve_non_dynamic(false);
+ this->vsolve_non_dynamic(false);
}
+ return this->compute_next_timestep();
}
-ATTR_HOT nl_double matrix_solver_t::solve()
+netlist_time matrix_solver_t::solve()
{
const netlist_time now = netlist().time();
const netlist_time delta = now - m_last_step;
@@ -283,7 +285,7 @@ ATTR_HOT nl_double matrix_solver_t::solve()
// We are already up to date. Avoid oscillations.
// FIXME: Make this a parameter!
if (delta < netlist_time::from_nsec(1)) // 20000
- return -1.0;
+ return netlist_time::from_nsec(0);
/* update all terminals for new time step */
m_last_step = now;
@@ -291,7 +293,7 @@ ATTR_HOT nl_double matrix_solver_t::solve()
step(delta);
- const nl_double next_time_step = vsolve();
+ const netlist_time next_time_step = solve_base();
update_inputs();
return next_time_step;
@@ -307,7 +309,7 @@ ATTR_COLD int matrix_solver_t::get_net_idx(net_t *net)
void matrix_solver_t::log_stats()
{
- //if (this->m_stat_calculations != 0 && this->m_params.m_log_stats)
+ if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats)
{
log().verbose("==============================================");
log().verbose("Solver {1}", this->name());
@@ -360,7 +362,7 @@ NETLIB_START(solver)
/* automatic time step */
register_param("DYNAMIC_TS", m_dynamic, 0);
- register_param("LTE", m_lte, 5e-5); // diff/timestep
+ register_param("DYNAMIC_LTE", m_lte, 5e-5); // diff/timestep
register_param("MIN_TIMESTEP", m_min_timestep, 1e-6); // nl_double timestep resolution
register_param("LOG_STATS", m_log_stats, 1); // nl_double timestep resolution
@@ -429,7 +431,7 @@ NETLIB_UPDATE(solver)
for (auto & solver : m_mat_solvers)
if (solver->is_timestep())
// Ignore return value
- ATTR_UNUSED const nl_double ts = solver->solve();
+ ATTR_UNUSED const netlist_time ts = solver->solve();
#endif
/* step circuit */
@@ -457,7 +459,13 @@ matrix_solver_t * NETLIB_NAME(solver)::create_solver(int size, const bool use_sp
}
else if (pstring("MAT").equals(m_iterative_solver))
{
- typedef matrix_solver_direct_t<m_N,_storage_N> solver_mat;
+ typedef matrix_solver_sm_t<m_N,_storage_N> solver_mat;
+ return palloc(solver_mat(&m_params, size));
+ }
+ else if (pstring("SM").equals(m_iterative_solver))
+ {
+ /* Sherman-Morrison Formula */
+ typedef matrix_solver_sm_t<m_N,_storage_N> solver_mat;
return palloc(solver_mat(&m_params, size));
}
else if (pstring("SOR").equals(m_iterative_solver))
@@ -620,7 +628,7 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
register_sub(pfmt("Solver_{1}")(m_mat_solvers.size()), *ms);
- ms->vsetup(grp);
+ ms->setup(grp);
m_mat_solvers.push_back(ms);
diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h
index 06a98d063c6..6d08e0bbb73 100644
--- a/src/lib/netlist/solver/nld_solver.h
+++ b/src/lib/netlist/solver/nld_solver.h
@@ -48,134 +48,7 @@ struct solver_parameters_t
};
-class terms_t
-{
- P_PREVENT_COPYING(terms_t)
-
- public:
- ATTR_COLD terms_t() : m_railstart(0)
- {}
-
- ATTR_COLD void clear()
- {
- m_term.clear();
- m_net_other.clear();
- m_gt.clear();
- m_go.clear();
- m_Idr.clear();
- m_other_curanalog.clear();
- }
-
- ATTR_COLD void add(terminal_t *term, int net_other, bool sorted);
-
- ATTR_HOT inline unsigned count() { return m_term.size(); }
-
- ATTR_HOT inline terminal_t **terms() { return m_term.data(); }
- ATTR_HOT inline int *net_other() { return m_net_other.data(); }
- ATTR_HOT inline nl_double *gt() { return m_gt.data(); }
- ATTR_HOT inline nl_double *go() { return m_go.data(); }
- ATTR_HOT inline nl_double *Idr() { return m_Idr.data(); }
- ATTR_HOT inline nl_double **other_curanalog() { return m_other_curanalog.data(); }
-
- ATTR_COLD void set_pointers();
-
- unsigned m_railstart;
-
- pvector_t<unsigned> m_nz; /* all non zero for multiplication */
- pvector_t<unsigned> m_nzrd; /* non zero right of the diagonal for elimination */
- pvector_t<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */
-private:
- pvector_t<terminal_t *> m_term;
- pvector_t<int> m_net_other;
- pvector_t<nl_double> m_go;
- pvector_t<nl_double> m_gt;
- pvector_t<nl_double> m_Idr;
- pvector_t<nl_double *> m_other_curanalog;
-};
-
-class matrix_solver_t : public device_t
-{
-public:
- typedef pvector_t<matrix_solver_t *> list_t;
- typedef core_device_t::list_t dev_list_t;
-
- enum eSolverType
- {
- GAUSSIAN_ELIMINATION,
- GAUSS_SEIDEL
- };
-
- ATTR_COLD matrix_solver_t(const eSolverType type, const solver_parameters_t *params);
- virtual ~matrix_solver_t();
-
- virtual void vsetup(analog_net_t::list_t &nets) = 0;
-
- template<class C>
- void solve_base(C *p);
-
- ATTR_HOT nl_double solve();
-
- ATTR_HOT inline bool is_dynamic() { return m_dynamic_devices.size() > 0; }
- ATTR_HOT inline bool is_timestep() { return m_step_devices.size() > 0; }
-
- ATTR_HOT void update_forced();
- ATTR_HOT inline void update_after(const netlist_time after)
- {
- m_Q_sync.net().reschedule_in_queue(after);
- }
-
- /* netdevice functions */
- ATTR_HOT virtual void update() override;
- virtual void start() override;
- virtual void reset() override;
-
- ATTR_COLD int get_net_idx(net_t *net);
-
- inline eSolverType type() const { return m_type; }
- plog_base<NL_DEBUG> &log() { return netlist().log(); }
-
- virtual void log_stats();
-
-protected:
-
- ATTR_COLD void setup(analog_net_t::list_t &nets);
- ATTR_HOT void update_dynamic();
-
- // should return next time step
- ATTR_HOT virtual nl_double vsolve() = 0;
-
- virtual void add_term(int net_idx, terminal_t *term) = 0;
-
- pvector_t<analog_net_t *> m_nets;
- pvector_t<analog_output_t *> m_inps;
-
- int m_stat_calculations;
- int m_stat_newton_raphson;
- int m_stat_vsolver_calls;
- int m_iterative_fail;
- int m_iterative_total;
-
- const solver_parameters_t &m_params;
-
- ATTR_HOT inline nl_double current_timestep() { return m_cur_ts; }
-private:
-
- netlist_time m_last_step;
- nl_double m_cur_ts;
- dev_list_t m_step_devices;
- dev_list_t m_dynamic_devices;
-
- logic_input_t m_fb_sync;
- logic_output_t m_Q_sync;
-
- ATTR_HOT void step(const netlist_time delta);
-
- ATTR_HOT void update_inputs();
-
- const eSolverType m_type;
-};
-
-
+class matrix_solver_t;
class NETLIB_NAME(solver) : public device_t
{
@@ -188,13 +61,13 @@ public:
ATTR_COLD void post_start();
ATTR_COLD void stop() override;
- ATTR_HOT inline nl_double gmin() { return m_gmin.Value(); }
+ inline nl_double gmin() { return m_gmin.Value(); }
protected:
- ATTR_HOT void update() override;
- ATTR_HOT void start() override;
- ATTR_HOT void reset() override;
- ATTR_HOT void update_param() override;
+ void update() override;
+ void start() override;
+ void reset() override;
+ void update_param() override;
logic_input_t m_fb_step;
logic_output_t m_Q_step;
@@ -217,7 +90,7 @@ protected:
param_logic_t m_log_stats;
- matrix_solver_t::list_t m_mat_solvers;
+ pvector_t<matrix_solver_t *> m_mat_solvers;
private:
solver_parameters_t m_params;
diff --git a/src/mame/audio/irem.cpp b/src/mame/audio/irem.cpp
index 0020c880c30..0a7469091fc 100644
--- a/src/mame/audio/irem.cpp
+++ b/src/mame/audio/irem.cpp
@@ -419,11 +419,14 @@ NETLIST_START(kidniki_interface)
PARAM(Solver.NR_LOOPS, 300)
PARAM(Solver.GS_LOOPS, 1)
PARAM(Solver.GS_THRESHOLD, 6)
- //PARAM(Solver.ITERATIVE, "SOR")
+ PARAM(Solver.ITERATIVE, "SOR")
//PARAM(Solver.ITERATIVE, "MAT")
- PARAM(Solver.ITERATIVE, "GMRES")
- PARAM(Solver.PARALLEL, 1)
+ //PARAM(Solver.ITERATIVE, "GMRES")
+ PARAM(Solver.PARALLEL, 0)
PARAM(Solver.SOR_FACTOR, 1.00)
+ PARAM(Solver.DYNAMIC_TS, 0)
+ PARAM(Solver.DYNAMIC_LTE, 5e-4)
+ PARAM(Solver.MIN_TIMESTEP, 20e-6)
#else
SOLVER(Solver, 12000)
PARAM(Solver.ACCURACY, 1e-8)
diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp
index 7727c74379f..27b3dd0fc59 100644
--- a/src/mame/drivers/apple2e.cpp
+++ b/src/mame/drivers/apple2e.cpp
@@ -144,6 +144,7 @@ Address bus A0-A11 is Y0-Y11
#include "bus/a2bus/timemasterho.h"
#include "bus/a2bus/mouse.h"
#include "bus/a2bus/ezcgi.h"
+#include "bus/a2bus/pc_xporter.h"
#include "bus/a2bus/a2eauxslot.h"
#include "bus/a2bus/a2estd80col.h"
#include "bus/a2bus/a2eext80col.h"
@@ -3188,6 +3189,7 @@ static SLOT_INTERFACE_START(apple2_cards)
SLOT_INTERFACE("ezcgi9938", A2BUS_EZCGI_9938) /* E-Z Color Graphics Interface (TMS9938) */
SLOT_INTERFACE("ezcgi9958", A2BUS_EZCGI_9958) /* E-Z Color Graphics Interface (TMS9958) */
// SLOT_INTERFACE("magicmusician", A2BUS_MAGICMUSICIAN) /* Magic Musician Card */
+ SLOT_INTERFACE("pcxport", A2BUS_PCXPORTER) /* Applied Engineering PC Transporter */
SLOT_INTERFACE_END
static SLOT_INTERFACE_START(apple2eaux_cards)
diff --git a/src/mame/drivers/chihiro.cpp b/src/mame/drivers/chihiro.cpp
index 5cd8a9dd229..c63b2043d53 100644
--- a/src/mame/drivers/chihiro.cpp
+++ b/src/mame/drivers/chihiro.cpp
@@ -240,8 +240,8 @@ Notes:
24LC64 - Microchip 24LC64 64K I2C Serial EEPROM (SOIC8)
24LC024 - Microchip 24LC024 2K I2C Serial EEPROM (SOIC8)
M68AF127B - ST Microelectronics 1Mbit (128K x8), 5V Asynchronous SRAM (SOP32)
- AN2131QC - Cypress AN2131 EZ-USB-Family 8051-based High-Speed USB IC's (QFP80)
- AN2131SC / (QFP44)
+ AN2131QC - Cypress AN2131 EZ-USB-Family 8051-based High-Speed USB IC's (QFP80) firmware in IC11
+ AN2131SC / (QFP44) firmware in IC32
ADM3222 - Analog Devices ADM3222 High-Speed, +3.3V, 2-Channel RS232/V.28 Interface Device (SOIC20)
SN65240 - Texas Instruments SN65240 USB Port Transient Suppressor (SOIC8)
BA7623 - Rohm BA7623 75-Ohm driver IC with 3 internal circuits (SOIC8)
@@ -572,7 +572,7 @@ static const struct {
UINT32 address;
UINT8 write_byte;
} modify[16];
-} hacks[2] = { { "chihiro", { { 0x6a79f, 0x01 }, { 0x6a7a0, 0x00 }, { 0x6b575, 0x00 }, { 0x6b576, 0x00 }, { 0x6b5af, 0x75 }, { 0x6b78a, 0x75 }, { 0x6b7ca, 0x00 }, { 0x6b7b8, 0x00 }, { 0x8f5b2, 0x75 }, { 0x79a9e, 0x74 }, { 0x79b80, 0x74 }, { 0x79b97, 0x74 }, { 0, 0 } } },
+} hacks[2] = { { "chihiro", { { 0x6a79f/*3f79f*/, 0x01 }, { 0x6a7a0/*3f7a0*/, 0x00 }, { 0x6b575/*40575*/, 0x00 }, { 0x6b576/*40576*/, 0x00 }, { 0x6b5af/*405af*/, 0x75 }, { 0x6b78a/*4078a*/, 0x75 }, { 0x6b7ca/*407ca*/, 0x00 }, { 0x6b7b8/*407b8*/, 0x00 }, { 0x8f5b2, 0x75 }, { 0x79a9e/*2ea9e*/, 0x74 }, { 0x79b80/*2eb80*/, 0x74 }, { 0x79b97/*2eb97*/, 0x74 }, { 0, 0 } } },
{ "outr2", { { 0x12e4cf, 0x01 }, { 0x12e4d0, 0x00 }, { 0x4793e, 0x01 }, { 0x4793f, 0x00 }, { 0x47aa3, 0x01 }, { 0x47aa4, 0x00 }, { 0x14f2b6, 0x84 }, { 0x14f2d1, 0x75 }, { 0x8732f, 0x7d }, { 0x87384, 0x7d }, { 0x87388, 0xeb }, { 0, 0 } } } };
void chihiro_state::hack_usb()
diff --git a/src/mame/drivers/crimfght.cpp b/src/mame/drivers/crimfght.cpp
index 460e133caa6..d2d96443c6d 100644
--- a/src/mame/drivers/crimfght.cpp
+++ b/src/mame/drivers/crimfght.cpp
@@ -134,8 +134,8 @@ static INPUT_PORTS_START( crimfght )
PORT_DIPSETTING( 0x0b, DEF_STR( 1C_5C ))
PORT_DIPSETTING( 0x0a, DEF_STR( 1C_6C ))
PORT_DIPSETTING( 0x09, DEF_STR( 1C_7C ))
- PORT_DIPSETTING( 0x00, "Void")
- PORT_DIPNAME(0xf0, 0x00, "Coin B (unused)") PORT_DIPLOCATION("SW1:5,6,7,8")
+ PORT_DIPSETTING( 0x00, DEF_STR( Free_Play ))
+ PORT_DIPNAME(0xf0, 0xf0, "Coin B") PORT_DIPLOCATION("SW1:5,6,7,8")
PORT_DIPSETTING( 0x20, DEF_STR( 4C_1C ))
PORT_DIPSETTING( 0x50, DEF_STR( 3C_1C ))
PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C ))
@@ -151,11 +151,14 @@ static INPUT_PORTS_START( crimfght )
PORT_DIPSETTING( 0xb0, DEF_STR( 1C_5C ))
PORT_DIPSETTING( 0xa0, DEF_STR( 1C_6C ))
PORT_DIPSETTING( 0x90, DEF_STR( 1C_7C ))
- PORT_DIPSETTING( 0x00, "Void")
+ PORT_DIPSETTING( 0x00, DEF_STR( Unused ))
PORT_START("DSW2")
- PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW2:1")
- PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW2:2")
+ PORT_DIPNAME( 0x03, 0x02, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2")
+ PORT_DIPSETTING( 0x03, "1" )
+ PORT_DIPSETTING( 0x02, "2" )
+ PORT_DIPSETTING( 0x01, "3" )
+ PORT_DIPSETTING( 0x00, "4" )
PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW2:3")
PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW2:4")
PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW2:5")
@@ -178,63 +181,74 @@ static INPUT_PORTS_START( crimfght )
PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_CUSTOM_MEMBER(DEVICE_SELF, crimfght_state, system_r, NULL)
PORT_START("P1")
- KONAMI8_B12_UNK(1)
+ KONAMI8_B123_START(1)
PORT_START("P2")
- KONAMI8_B12_UNK(2)
+ KONAMI8_B123_START(2)
PORT_START("P3")
- KONAMI8_B12_UNK(3)
+ PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("P4")
- KONAMI8_B12_UNK(4)
+ PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("SYSTEM")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_COIN1)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_COIN2)
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_COIN3)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_COIN4)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNKNOWN)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_SERVICE1)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_SERVICE2)
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_SERVICE3)
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_SERVICE4)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNKNOWN)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN)
INPUT_PORTS_END
-static INPUT_PORTS_START( crimfghtj )
+static INPUT_PORTS_START( crimfghtu )
PORT_INCLUDE( crimfght )
PORT_MODIFY("DSW1")
- KONAMI_COINAGE_LOC(DEF_STR( Free_Play ), "No Coin B", SW1)
- /* "No Coin B" = coins produce sound, but no effect on coin counter */
+ PORT_DIPNAME(0xf0, 0x00, "Coin B (Unused)") PORT_DIPLOCATION("SW1:5,6,7,8")
+ PORT_DIPSETTING( 0x20, DEF_STR( 4C_1C ))
+ PORT_DIPSETTING( 0x50, DEF_STR( 3C_1C ))
+ PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C ))
+ PORT_DIPSETTING( 0x40, DEF_STR( 3C_2C ))
+ PORT_DIPSETTING( 0x10, DEF_STR( 4C_3C ))
+ PORT_DIPSETTING( 0xf0, DEF_STR( 1C_1C ))
+ PORT_DIPSETTING( 0x30, DEF_STR( 3C_4C ))
+ PORT_DIPSETTING( 0x70, DEF_STR( 2C_3C ))
+ PORT_DIPSETTING( 0xe0, DEF_STR( 1C_2C ))
+ PORT_DIPSETTING( 0x60, DEF_STR( 2C_5C ))
+ PORT_DIPSETTING( 0xd0, DEF_STR( 1C_3C ))
+ PORT_DIPSETTING( 0xc0, DEF_STR( 1C_4C ))
+ PORT_DIPSETTING( 0xb0, DEF_STR( 1C_5C ))
+ PORT_DIPSETTING( 0xa0, DEF_STR( 1C_6C ))
+ PORT_DIPSETTING( 0x90, DEF_STR( 1C_7C ))
+ PORT_DIPSETTING( 0x00, DEF_STR( Unused ))
PORT_MODIFY("DSW2")
- PORT_DIPNAME( 0x03, 0x02, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2")
- PORT_DIPSETTING( 0x03, "1" )
- PORT_DIPSETTING( 0x02, "2" )
- PORT_DIPSETTING( 0x01, "3" )
- PORT_DIPSETTING( 0x00, "4" )
+ PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW2:1")
+ PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW2:2")
- PORT_MODIFY("P1")
- KONAMI8_B123_START(1)
+ PORT_MODIFY("P1")
+ KONAMI8_B12_UNK(1)
- PORT_MODIFY("P2")
- KONAMI8_B123_START(2)
+ PORT_MODIFY("P2")
+ KONAMI8_B12_UNK(2)
- PORT_MODIFY("P3")
- PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_MODIFY("P3")
+ KONAMI8_B12_UNK(3)
- PORT_MODIFY("P4")
- PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_MODIFY("P4")
+ KONAMI8_B12_UNK(4)
PORT_MODIFY("SYSTEM")
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN3 )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN4 )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE3 )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE4 )
INPUT_PORTS_END
-
/***************************************************************************
Machine Driver
@@ -344,7 +358,7 @@ MACHINE_CONFIG_END
ROM_START( crimfght )
ROM_REGION( 0x20000, "maincpu", 0 ) /* code + banked roms */
- ROM_LOAD( "821l02.f24", 0x00000, 0x20000, CRC(588e7da6) SHA1(285febb3bcca31f82b34af3695a59eafae01cd30) )
+ ROM_LOAD( "821r02.f24", 0x00000, 0x20000, CRC(4ecdd923) SHA1(78e5260c4bb9b18d7818fb6300d7e1d3a577fb63) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */
ROM_LOAD( "821l01.h4", 0x0000, 0x8000, CRC(0faca89e) SHA1(21c9c6d736b398a29e8709e1187c5bf3cacdc99d) )
@@ -386,9 +400,9 @@ ROM_START( crimfghtj )
ROM_LOAD( "821k03.e5", 0x00000, 0x40000, CRC(fef8505a) SHA1(5c5121609f69001838963e961cb227d6b64e4f5f) )
ROM_END
-ROM_START( crimfght2 )
+ROM_START( crimfghtu )
ROM_REGION( 0x20000, "maincpu", 0 ) /* code + banked roms */
- ROM_LOAD( "821r02.f24", 0x00000, 0x20000, CRC(4ecdd923) SHA1(78e5260c4bb9b18d7818fb6300d7e1d3a577fb63) )
+ ROM_LOAD( "821l02.f24", 0x00000, 0x20000, CRC(588e7da6) SHA1(285febb3bcca31f82b34af3695a59eafae01cd30) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */
ROM_LOAD( "821l01.h4", 0x0000, 0x8000, CRC(0faca89e) SHA1(21c9c6d736b398a29e8709e1187c5bf3cacdc99d) )
@@ -414,6 +428,6 @@ ROM_END
***************************************************************************/
-GAME( 1989, crimfght, 0, crimfght, crimfght, driver_device, 0, ROT0, "Konami", "Crime Fighters (US 4 players)", MACHINE_SUPPORTS_SAVE )
-GAME( 1989, crimfght2, crimfght, crimfght, crimfghtj, driver_device,0, ROT0, "Konami", "Crime Fighters (World 2 Players)", MACHINE_SUPPORTS_SAVE )
-GAME( 1989, crimfghtj, crimfght, crimfght, crimfghtj, driver_device,0, ROT0, "Konami", "Crime Fighters (Japan 2 Players)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, crimfght, 0, crimfght, crimfght, driver_device, 0, ROT0, "Konami", "Crime Fighters (World 2 players)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, crimfghtu, crimfght, crimfght, crimfghtu, driver_device,0, ROT0, "Konami", "Crime Fighters (US 4 Players)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, crimfghtj, crimfght, crimfght, crimfght, driver_device,0, ROT0, "Konami", "Crime Fighters (Japan 2 Players)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/eolith.cpp b/src/mame/drivers/eolith.cpp
index 101d6788365..80879dbb7ae 100644
--- a/src/mame/drivers/eolith.cpp
+++ b/src/mame/drivers/eolith.cpp
@@ -36,7 +36,8 @@
1999 - Land Breaker (pcb ver 3.03) (MCU internal flash dump is missing)
1999 - Land Breaker (pcb ver 3.02)
1999 - New Hidden Catch (pcb ver 3.02)
- 1999 - Penfan Girls
+ 1999 - Penfan Girls (set 1, pcb ver 3.03)
+ 1999 - Penfan Girls (set 2, pcb ver 3.03P)
2000 - Hidden Catch 3 (v. 1.00 / pcb ver 3.05)
2001 - Fortress 2 Blue Arcade (v. 1.01 / pcb ver 3.05)
2001 - Fortress 2 Blue Arcade (v. 1.00 / pcb ver 3.05)
@@ -1199,8 +1200,9 @@ ROM_START( penfana )
ROM_LOAD32_WORD_SWAP( "11.u11", 0x1400002, 0x200000, CRC(ddcd2bae) SHA1(c4fa5ebbaf801a7f06222150658033955966fe1b) )
ROM_LOAD32_WORD_SWAP( "12.u17", 0x1800000, 0x200000, CRC(2eed0f64) SHA1(3b9e65e41d8699a93ea74225ba12a3f66ecba11d) )
ROM_LOAD32_WORD_SWAP( "13.u12", 0x1800002, 0x200000, CRC(cc3068a8) SHA1(0022fad5a4d36678d35e99092c870f2b99d3d8d4) )
- ROM_LOAD32_WORD_SWAP( "14.u18", 0x1c00000, 0x200000, CRC(20a9a08e) SHA1(fe4071cdf78d362bccaee92cdc70c66f7e30f817) ) // not checked by rom check
- ROM_LOAD32_WORD_SWAP( "15.u13", 0x1c00002, 0x200000, CRC(872fa9c4) SHA1(4902faa97c9a3a9671cfefc6a711cfcd25f2d6bc) ) // not checked by rom check
+ // The 3.03P version doesn't even have these populated
+ //ROM_LOAD32_WORD_SWAP( "14.u18", 0x1c00000, 0x200000, CRC(20a9a08e) SHA1(fe4071cdf78d362bccaee92cdc70c66f7e30f817) ) // not checked by rom check
+ //ROM_LOAD32_WORD_SWAP( "15.u13", 0x1c00002, 0x200000, CRC(872fa9c4) SHA1(4902faa97c9a3a9671cfefc6a711cfcd25f2d6bc) ) // not checked by rom check
ROM_REGION( 0x008000, "soundcpu", 0 ) /* Sound (80c301) CPU Code */
ROM_LOAD( "pfg.u111", 0x0000, 0x8000, CRC(79012474) SHA1(09a2d5705d7bc52cc2d1644c87c1e31ee44813ef) )
diff --git a/src/mame/drivers/hh_hmcs40.cpp b/src/mame/drivers/hh_hmcs40.cpp
index acf581c19b5..783f16be481 100644
--- a/src/mame/drivers/hh_hmcs40.cpp
+++ b/src/mame/drivers/hh_hmcs40.cpp
@@ -1035,7 +1035,7 @@ INPUT_CHANGED_MEMBER(bzaxxon_state::input_changed)
static MACHINE_CONFIG_START( bzaxxon, bzaxxon_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", HD38800, 400000) // approximation
+ MCFG_CPU_ADD("maincpu", HD38800, 450000) // approximation
MCFG_HMCS40_WRITE_R_CB(0, WRITE8(bzaxxon_state, plate_w))
MCFG_HMCS40_WRITE_R_CB(1, WRITE8(bzaxxon_state, plate_w))
MCFG_HMCS40_WRITE_R_CB(2, WRITE8(bzaxxon_state, plate_w))
@@ -4087,7 +4087,7 @@ CONS( 1979, bmboxing, 0, 0, bmboxing, bmboxing, driver_device, 0, "Bambi
CONS( 1982, bfriskyt, 0, 0, bfriskyt, bfriskyt, driver_device, 0, "Bandai", "Frisky Tom (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
CONS( 1981, packmon, 0, 0, packmon, packmon, driver_device, 0, "Bandai", "Packri Monster", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
CONS( 1982, msthawk, 0, 0, msthawk, msthawk, driver_device, 0, "Bandai (Mattel license)", "Star Hawk (Mattel)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
-CONS( 1982, bzaxxon, 0, 0, bzaxxon, bzaxxon, driver_device, 0, "Bandai", "Zaxxon (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK | MACHINE_NOT_WORKING )
+CONS( 1982, bzaxxon, 0, 0, bzaxxon, bzaxxon, driver_device, 0, "Bandai", "Zaxxon (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
CONS( 1983, zackman, 0, 0, zackman, zackman, driver_device, 0, "Bandai", "Zackman", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
CONS( 1983, bpengo, 0, 0, bpengo, bpengo, driver_device, 0, "Bandai", "Pengo (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
CONS( 1983, bbtime, 0, 0, bbtime, bbtime, driver_device, 0, "Bandai", "Burger Time (Bandai)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK )
diff --git a/src/mame/drivers/mcr3.cpp b/src/mame/drivers/mcr3.cpp
index 150e0f54b32..3d2bc6b2d5b 100644
--- a/src/mame/drivers/mcr3.cpp
+++ b/src/mame/drivers/mcr3.cpp
@@ -535,51 +535,6 @@ static ADDRESS_MAP_START( spyhunt_portmap, AS_IO, 8, mcr3_state )
ADDRESS_MAP_END
-
-WRITE8_MEMBER(mcr3_state::spyhuntpr_fd00_w)
-{
-}
-
-static ADDRESS_MAP_START( spyhuntpr_map, AS_PROGRAM, 8, mcr3_state )
- ADDRESS_MAP_UNMAP_HIGH
- AM_RANGE(0xa800, 0xa8ff) AM_RAM // the ROM is a solid fill in these areas, and they get tested as RAM, I think they moved the 'real' scroll regs here
- AM_RANGE(0xa900, 0xa9ff) AM_RAM
-
- AM_RANGE(0x0000, 0xdfff) AM_ROM
-
-
-
-
- AM_RANGE(0xe000, 0xe7ff) AM_RAM_WRITE(spyhunt_videoram_w) AM_SHARE("videoram")
- AM_RANGE(0xe800, 0xebff) AM_MIRROR(0x0400) AM_RAM_WRITE(spyhunt_alpharam_w) AM_SHARE("spyhunt_alpha")
- AM_RANGE(0xf000, 0xf7ff) AM_RAM //AM_SHARE("nvram")
- AM_RANGE(0xf800, 0xf9ff) AM_RAM AM_SHARE("spriteram")
- AM_RANGE(0xfa00, 0xfa7f) AM_MIRROR(0x0180) AM_RAM_WRITE(spyhuntpr_paletteram_w) AM_SHARE("paletteram")
-
- AM_RANGE(0xfc00, 0xfc00) AM_READ_PORT("DSW0")
- AM_RANGE(0xfc01, 0xfc01) AM_READ_PORT("DSW1")
- AM_RANGE(0xfc02, 0xfc02) AM_READ_PORT("IN2")
- AM_RANGE(0xfc03, 0xfc03) AM_READ_PORT("IN3")
-
- AM_RANGE(0xfd00, 0xfd00) AM_WRITE( spyhuntpr_fd00_w )
-
- AM_RANGE(0xfe00, 0xffff) AM_RAM // a modified copy of spriteram for this hw??
-ADDRESS_MAP_END
-
-WRITE8_MEMBER(mcr3_state::spyhuntpr_port04_w)
-{
-}
-
-static ADDRESS_MAP_START( spyhuntpr_portmap, AS_IO, 8, mcr3_state )
- ADDRESS_MAP_UNMAP_HIGH
- ADDRESS_MAP_GLOBAL_MASK(0xff)
- AM_RANGE(0x04, 0x04) AM_WRITE(spyhuntpr_port04_w)
- AM_RANGE(0x84, 0x86) AM_WRITE(spyhunt_scroll_value_w)
- AM_RANGE(0xe0, 0xe0) AM_WRITENOP // was watchdog
-// AM_RANGE(0xe8, 0xe8) AM_WRITENOP
- AM_RANGE(0xf0, 0xf3) AM_DEVREADWRITE("ctc", z80ctc_device, read, write)
-ADDRESS_MAP_END
-
/*************************************
*
* Port definitions
@@ -979,109 +934,6 @@ static INPUT_PORTS_START( spyhunt )
PORT_BIT( 0xff, 0x74, IPT_PADDLE ) PORT_MINMAX(0x34,0xb4) PORT_SENSITIVITY(40) PORT_KEYDELTA(10)
INPUT_PORTS_END
-static INPUT_PORTS_START( spyhuntpr )
- PORT_START("DSW0")
- PORT_DIPNAME( 0x01, 0x01, "DSW0-01" )
- PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x02, 0x02, "DSW0-02" )
- PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x04, 0x04, "DSW0-04" )
- PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x08, 0x08, "DSW0-08" )
- PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x10, 0x10, "DSW0-10" )
- PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x20, 0x20, "DSW0-20" )
- PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x40, 0x40, "DSW0-40" )
- PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x80, 0x80, "DSW0-80" )
- PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
-
- PORT_START("DSW1")
- PORT_DIPNAME( 0x01, 0x01, "DSW1-01" )
- PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x02, 0x02, "DSW1-02" )
- PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_SERVICE( 0x04, IP_ACTIVE_LOW )
- PORT_DIPNAME( 0x08, 0x08, "DSW1-08" )
- PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x10, 0x10, "DSW1-10" )
- PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x20, 0x20, "DSW1-20" )
- PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x40, 0x40, "DSW1-40" )
- PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
- PORT_DIPNAME( 0x80, 0x80, "DSW1-80" )
- PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x00, DEF_STR( On ) )
-
- PORT_START("IN2")
- PORT_DIPNAME( 0x0001, 0x0001, "2" )
- PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0002, 0x0002, "start" ) // start
- PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0004, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0008, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0010, 0x0010, "handbrake?" )
- PORT_DIPSETTING( 0x0010, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0020, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0040, 0x0040, "pedal inverse" )
- PORT_DIPSETTING( 0x0040, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0080, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
-
- PORT_START("IN3")
- PORT_DIPNAME( 0x0001, 0x0001, "3" )
- PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0004, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0008, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0010, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) )
- PORT_DIPSETTING( 0x0020, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0040, 0x0040, "coin" ) // coin?
- PORT_DIPSETTING( 0x0040, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0080, 0x0080, "machineguns" ) // machine guns
- PORT_DIPSETTING( 0x0080, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
-INPUT_PORTS_END
/* not verified, no manual found */
static INPUT_PORTS_START( crater )
@@ -1206,52 +1058,6 @@ static const gfx_layout spyhunt_alphalayout =
16*8
};
-static const gfx_layout spyhuntpr_alphalayout =
-{
- 16,8,
- RGN_FRAC(1,1),
- 2,
- { 0, 4},
- { 0, 0, 1, 1, 2, 2, 3, 3, 8, 8, 9, 9, 10, 10, 11, 11 },
- { 0, 2*8, 4*8, 6*8, 8*8, 10*8, 12*8, 14*8 },
- 16*8
-};
-
-
-const gfx_layout spyhuntpr_sprite_layout =
-{
- 32,16,
- RGN_FRAC(1,4),
- 4,
- { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
- { 6,7, 4,5, 2,3, 0,1, 14,15, 12,13, 10,11, 8,9, 22,23, 20,21, 18,19, 16,17, 30,31, 28,29, 26,27, 24,25 },
- { 0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32,8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32 },
-
- 16*32
-};
-
-
-static const UINT32 spyhuntp_charlayout_xoffset[64] =
-{
- 0x0000*8,0x0000*8, 0x0000*8+1,0x0000*8+1, 0x0000*8+2,0x0000*8+2, 0x0000*8+3,0x0000*8+3, 0x0000*8+4,0x0000*8+4, 0x0000*8+5,0x0000*8+5, 0x0000*8+6,0x0000*8+6, 0x0000*8+7,0x0000*8+7,
- 0x1000*8,0x1000*8, 0x1000*8+1,0x1000*8+1, 0x1000*8+2,0x1000*8+2, 0x1000*8+3,0x1000*8+3, 0x1000*8+4,0x1000*8+4, 0x1000*8+5,0x1000*8+5, 0x1000*8+6,0x1000*8+6, 0x1000*8+7,0x1000*8+7,
- 0x2000*8,0x2000*8, 0x2000*8+1,0x2000*8+1, 0x2000*8+2,0x2000*8+2, 0x2000*8+3,0x2000*8+3, 0x2000*8+4,0x2000*8+4, 0x2000*8+5,0x2000*8+5, 0x2000*8+6,0x2000*8+6, 0x2000*8+7,0x2000*8+7,
- 0x3000*8,0x3000*8, 0x3000*8+1,0x3000*8+1, 0x3000*8+2,0x3000*8+2, 0x3000*8+3,0x3000*8+3, 0x3000*8+4,0x3000*8+4, 0x3000*8+5,0x3000*8+5, 0x3000*8+6,0x3000*8+6, 0x3000*8+7,0x3000*8+7,
-};
-
-
-static const gfx_layout spyhuntpr_charlayout =
-{
- 64,16,
- RGN_FRAC(1,8),
- 4,
- { 0*8, 0x4000*8 + 2*8, 0x4000*8 + 0*8, 2*8 },
- EXTENDED_XOFFS,
- { 0*8, 4*8, 8*8, 12*8, 16*8, 20*8, 24*8, 28*8, 1*8, 5*8, 9*8, 13*8, 17*8, 21*8, 25*8, 29*8 },
- 32*8,
- spyhuntp_charlayout_xoffset,
- nullptr
-};
static GFXDECODE_START( mcr3 )
GFXDECODE_SCALE( "gfx1", 0, mcr_bg_layout, 0, 4, 2, 2 )
@@ -1265,11 +1071,6 @@ static GFXDECODE_START( spyhunt )
GFXDECODE_ENTRY( "gfx3", 0, spyhunt_alphalayout, 4*16, 1 )
GFXDECODE_END
-static GFXDECODE_START( spyhuntpr )
- GFXDECODE_ENTRY( "gfx1", 0, spyhuntpr_charlayout, 3*16, 1 )
- GFXDECODE_ENTRY( "gfx2", 0, spyhuntpr_sprite_layout, 0*16, 4 )
- GFXDECODE_ENTRY( "gfx3", 0, spyhuntpr_alphalayout, 4*16, 1 )
-GFXDECODE_END
/*************************************
*
@@ -1379,78 +1180,6 @@ MACHINE_CONFIG_END
-static ADDRESS_MAP_START( spyhuntpr_sound_map, AS_PROGRAM, 8, mcr3_state )
- AM_RANGE(0x0000, 0x1fff) AM_ROM
- AM_RANGE(0x8000, 0x83ff) AM_RAM
-// AM_RANGE(0xfe00, 0xffff) AM_RAM
-ADDRESS_MAP_END
-
-static ADDRESS_MAP_START( spyhuntpr_sound_portmap, AS_IO, 8, mcr3_state )
- ADDRESS_MAP_UNMAP_HIGH
- ADDRESS_MAP_GLOBAL_MASK(0xff)
-
- AM_RANGE(0x12, 0x13) AM_DEVWRITE("ay1", ay8912_device, address_data_w)
- AM_RANGE(0x14, 0x15) AM_DEVWRITE("ay2", ay8912_device, address_data_w)
- AM_RANGE(0x18, 0x19) AM_DEVWRITE("ay3", ay8912_device, address_data_w)
-
-ADDRESS_MAP_END
-
-
-
-static MACHINE_CONFIG_START( spyhuntpr, mcr3_state )
-
-// note: no ctc, no nvram
-// 2*z80, 3*ay8912
-
- /* basic machine hardware */
- MCFG_CPU_ADD("maincpu", Z80, MASTER_CLOCK/4)
- MCFG_CPU_PROGRAM_MAP(spyhuntpr_map)
- MCFG_CPU_IO_MAP(spyhuntpr_portmap)
- MCFG_CPU_CONFIG(mcr_daisy_chain)
- MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", mcr3_state, mcr_interrupt, "screen", 0, 1)
-
- MCFG_DEVICE_ADD("ctc", Z80CTC, MASTER_CLOCK/4 /* same as "maincpu" */)
- MCFG_Z80CTC_INTR_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0))
- MCFG_Z80CTC_ZC0_CB(DEVWRITELINE("ctc", z80ctc_device, trg1))
-
- //MCFG_WATCHDOG_VBLANK_INIT(16)
- MCFG_MACHINE_START_OVERRIDE(mcr3_state,mcr)
- MCFG_MACHINE_RESET_OVERRIDE(mcr3_state,mcr)
-
-// MCFG_NVRAM_ADD_0FILL("nvram")
-
- /* video hardware */
- MCFG_SCREEN_ADD("screen", RASTER)
- MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK)
- MCFG_SCREEN_REFRESH_RATE(60)
- MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
- MCFG_SCREEN_SIZE(30*16, 30*8)
- MCFG_SCREEN_VISIBLE_AREA(0, 30*16-1, 0, 30*8-1)
- MCFG_SCREEN_UPDATE_DRIVER(mcr3_state, screen_update_spyhuntpr)
- MCFG_SCREEN_PALETTE("palette")
-
- MCFG_GFXDECODE_ADD("gfxdecode", "palette", spyhuntpr)
- MCFG_PALETTE_ADD("palette", 64+4)
-
- MCFG_PALETTE_INIT_OWNER(mcr3_state,spyhunt)
- MCFG_VIDEO_START_OVERRIDE(mcr3_state,spyhuntpr)
-
-
- MCFG_CPU_ADD("audiocpu", Z80, 3000000 )
- MCFG_CPU_PROGRAM_MAP(spyhuntpr_sound_map)
- MCFG_CPU_IO_MAP(spyhuntpr_sound_portmap)
-// MCFG_CPU_PERIODIC_INT_DRIVER(mcr3_state, irq0_line_hold, 4*60)
-
- MCFG_SPEAKER_STANDARD_MONO("mono")
-
- MCFG_SOUND_ADD("ay1", AY8912, 3000000/2) // AY-3-8912
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
- MCFG_SOUND_ADD("ay2", AY8912, 3000000/2) // "
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
- MCFG_SOUND_ADD("ay3", AY8912, 3000000/2) // "
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
-
-MACHINE_CONFIG_END
@@ -1729,93 +1458,6 @@ ROM_START( spyhuntp )
ROM_END
-ROM_START( spyhuntpr )
- ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_LOAD( "1.bin", 0x0000, 0x4000, CRC(2a2f77cb) SHA1(e1b74c951efb2a49bef0507ab3268b274515f339) )
- ROM_LOAD( "2.bin", 0x4000, 0x4000, CRC(00778aff) SHA1(7c0b24c393f841e8379d4bba57ba502e3d2512f9) )
- ROM_LOAD( "3.bin", 0x8000, 0x4000, CRC(2183b4af) SHA1(2b958afc40b26c9bc8d5254b0600426649f4ebf0) )
- ROM_LOAD( "4.bin", 0xc000, 0x2000, CRC(3ea6a65c) SHA1(1320ce17044307ed3c4f2459631a9aa1734f1f30) )
-
- ROM_REGION( 0x10000, "audiocpu", 0 )
- ROM_LOAD( "5.bin", 0x0000, 0x2000, CRC(33fe2829) SHA1(e6950dbf681242bf23542ca6604e62eacb431101) )
-
-
- ROM_REGION( 0x08000, "gfx1", 0 )
- ROM_LOAD32_BYTE( "6.bin", 0x0000, 0x200, CRC(6b76f46a) SHA1(4b398084c42a60fcfa4a9bf14f844e36a3f42723) )
- ROM_CONTINUE(0x0001, 0x200)
- ROM_CONTINUE(0x0800, 0x200)
- ROM_CONTINUE(0x0801, 0x200)
- ROM_CONTINUE(0x1000, 0x200)
- ROM_CONTINUE(0x1001, 0x200)
- ROM_CONTINUE(0x1800, 0x200)
- ROM_CONTINUE(0x1801, 0x200)
- ROM_CONTINUE(0x2000, 0x200)
- ROM_CONTINUE(0x2001, 0x200)
- ROM_CONTINUE(0x2800, 0x200)
- ROM_CONTINUE(0x2801, 0x200)
- ROM_CONTINUE(0x3000, 0x200)
- ROM_CONTINUE(0x3001, 0x200)
- ROM_CONTINUE(0x3800, 0x200)
- ROM_CONTINUE(0x3801, 0x200)
- ROM_LOAD32_BYTE( "7.bin", 0x0002, 0x200, CRC(085bd7a7) SHA1(c35c309b6c6485baec54d4434dea44abf4d48f41) )
- ROM_CONTINUE(0x0003, 0x200)
- ROM_CONTINUE(0x0802, 0x200)
- ROM_CONTINUE(0x0803, 0x200)
- ROM_CONTINUE(0x1002, 0x200)
- ROM_CONTINUE(0x1003, 0x200)
- ROM_CONTINUE(0x1802, 0x200)
- ROM_CONTINUE(0x1803, 0x200)
- ROM_CONTINUE(0x2002, 0x200)
- ROM_CONTINUE(0x2003, 0x200)
- ROM_CONTINUE(0x2802, 0x200)
- ROM_CONTINUE(0x2803, 0x200)
- ROM_CONTINUE(0x3002, 0x200)
- ROM_CONTINUE(0x3003, 0x200)
- ROM_CONTINUE(0x3802, 0x200)
- ROM_CONTINUE(0x3803, 0x200)
- ROM_LOAD32_BYTE( "8.bin", 0x4000, 0x200, CRC(e699b329) SHA1(cb4b8c7b6fa1cb1144a18f1442dc3b267c408914) )
- ROM_CONTINUE(0x4001, 0x200)
- ROM_CONTINUE(0x4800, 0x200)
- ROM_CONTINUE(0x4801, 0x200)
- ROM_CONTINUE(0x5000, 0x200)
- ROM_CONTINUE(0x5001, 0x200)
- ROM_CONTINUE(0x5800, 0x200)
- ROM_CONTINUE(0x5801, 0x200)
- ROM_CONTINUE(0x6000, 0x200)
- ROM_CONTINUE(0x6001, 0x200)
- ROM_CONTINUE(0x6800, 0x200)
- ROM_CONTINUE(0x6801, 0x200)
- ROM_CONTINUE(0x7000, 0x200)
- ROM_CONTINUE(0x7001, 0x200)
- ROM_CONTINUE(0x7800, 0x200)
- ROM_CONTINUE(0x7801, 0x200)
- ROM_LOAD32_BYTE( "9.bin", 0x4002, 0x200, CRC(6d462ec7) SHA1(0ff37f75b0eeceb86177a3f7c93834d5c0e24515) )
- ROM_CONTINUE(0x4003, 0x200)
- ROM_CONTINUE(0x4802, 0x200)
- ROM_CONTINUE(0x4803, 0x200)
- ROM_CONTINUE(0x5002, 0x200)
- ROM_CONTINUE(0x5003, 0x200)
- ROM_CONTINUE(0x5802, 0x200)
- ROM_CONTINUE(0x5803, 0x200)
- ROM_CONTINUE(0x6002, 0x200)
- ROM_CONTINUE(0x6003, 0x200)
- ROM_CONTINUE(0x6802, 0x200)
- ROM_CONTINUE(0x6803, 0x200)
- ROM_CONTINUE(0x7002, 0x200)
- ROM_CONTINUE(0x7003, 0x200)
- ROM_CONTINUE(0x7802, 0x200)
- ROM_CONTINUE(0x7803, 0x200)
-
- ROM_REGION( 0x10000, "gfx2", ROMREGION_INVERT )
- ROM_LOAD( "10.bin", 0x00000, 0x4000, CRC(6f9fd416) SHA1(a51c86e5b22c91fc44673f53400b58af40b18065) )
- ROM_LOAD( "11.bin", 0x04000, 0x4000, CRC(75526ffe) SHA1(ff1adf6f9b6595114d0bd06b72d9eb7bbf70144d) )
- ROM_LOAD( "12.bin", 0x08000, 0x4000, CRC(82ee7a4d) SHA1(184720de76680275bf7c4a171f03a0ce771d91fc) )
- ROM_LOAD( "13.bin", 0x0c000, 0x4000, CRC(0cc592a3) SHA1(b3563bde83432cdbaedb88d4d222da30bf679b08) )
-
-
- ROM_REGION( 0x01000, "gfx3", 0 )
- ROM_LOAD( "14.bin", 0x00000, 0x1000, CRC(87a4c130) SHA1(7792afdc36b0f3bd51c387d04d38f60c85fd2e93) )
-ROM_END
ROM_START( crater )
@@ -1976,16 +1618,7 @@ DRIVER_INIT_MEMBER(mcr3_state,spyhunt)
m_spyhunt_scroll_offset = 16;
}
-DRIVER_INIT_MEMBER(mcr3_state,spyhuntpr)
-{
- mcr_common_init();
-// machine().device<midway_ssio_device>("ssio")->set_custom_input(1, 0x60, read8_delegate(FUNC(mcr3_state::spyhunt_ip1_r),this));
-// machine().device<midway_ssio_device>("ssio")->set_custom_input(2, 0xff, read8_delegate(FUNC(mcr3_state::spyhunt_ip2_r),this));
-// machine().device<midway_ssio_device>("ssio")->set_custom_output(4, 0xff, write8_delegate(FUNC(mcr3_state::spyhunt_op4_w),this));
- m_spyhunt_sprite_color_mask = 0x00;
- m_spyhunt_scroll_offset = 16;
-}
DRIVER_INIT_MEMBER(mcr3_state,crater)
{
@@ -2036,6 +1669,3 @@ GAMEL(1983, spyhuntp, spyhunt, mcrsc_csd, spyhunt, mcr3_state, spyhunt, ROT9
GAME( 1984, crater, 0, mcrscroll, crater, mcr3_state, crater, ORIENTATION_FLIP_X, "Bally Midway", "Crater Raider", MACHINE_SUPPORTS_SAVE )
GAMEL(1985, turbotag, 0, mcrsc_csd, turbotag, mcr3_state, turbotag, ROT90, "Bally Midway", "Turbo Tag (prototype)", MACHINE_SUPPORTS_SAVE, layout_turbotag )
-// very different hardware, probably bootleg despite the license text printed on the PCB, similar to '1942p' in 1942.c. Probably should be put in separate driver.
-// PCB made by Tecfri for Recreativos Franco S.A. in Spain, has Bally Midway logo, and licensing text on the PCB. Board is dated '85' so seems to be a low-cost rebuild? it is unclear if it made it to market.
-GAME (1983, spyhuntpr,spyhunt, spyhuntpr, spyhuntpr,mcr3_state, spyhuntpr,ROT90, "Bally Midway (Recreativos Franco S.A. license)", "Spy Hunter (Spain, Tecfri / Recreativos Franco S.A. PCB)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/spartanxtec.cpp b/src/mame/drivers/spartanxtec.cpp
new file mode 100644
index 00000000000..e6e31577864
--- /dev/null
+++ b/src/mame/drivers/spartanxtec.cpp
@@ -0,0 +1,441 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+/*
+
+Kung-Fu Master / Spartan X (Tecfri bootleg)
+single PCB with 2x Z80
+similar looking to the '1942p' and 'spyhuntpr' PCBs
+
+
+P2 inputs don't work in 'cocktail' mode (maybe it's just unsupported on this PCB?)
+
+DIPS etc. are near the 2nd CPU, should it be reading them?
+
+visible area is 16 lines less than the original, otherwise you get bad sprites
+but I think this is probably correct.
+
+some sprites are a bit glitchy when entering playfield (see title screen)
+probably an original bug?
+
+*/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "includes/iremipt.h"
+#include "sound/ay8910.h"
+
+class spartanxtec_state : public driver_device
+{
+public:
+ spartanxtec_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_m62_tileram(*this, "m62_tileram"),
+ m_spriteram(*this, "spriteram"),
+ m_scroll_lo(*this, "scroll_lo"),
+ m_scroll_hi(*this, "scroll_hi"),
+ m_maincpu(*this, "maincpu"),
+ m_audiocpu(*this, "audiocpu"),
+ m_palette(*this, "palette"),
+ m_gfxdecode(*this, "gfxdecode")
+ { }
+
+ required_shared_ptr<UINT8> m_m62_tileram;
+ required_shared_ptr<UINT8> m_spriteram;
+ required_shared_ptr<UINT8> m_scroll_lo;
+ required_shared_ptr<UINT8> m_scroll_hi;
+ required_device<cpu_device> m_maincpu;
+ required_device<cpu_device> m_audiocpu;
+
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+ virtual void video_start() override;
+ void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
+ UINT32 screen_update_spartanxtec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ DECLARE_PALETTE_INIT(spartanxtec);
+
+ tilemap_t* m_bg_tilemap;
+ DECLARE_WRITE8_MEMBER(kungfum_tileram_w);
+ TILE_GET_INFO_MEMBER(get_kungfum_bg_tile_info);
+ DECLARE_WRITE8_MEMBER(spartanxtec_soundlatch_w);
+ DECLARE_WRITE8_MEMBER(a801_w);
+ DECLARE_WRITE8_MEMBER(sound_irq_ack);
+ DECLARE_WRITE8_MEMBER(irq_ack);
+
+ required_device<palette_device> m_palette;
+ required_device<gfxdecode_device> m_gfxdecode;
+
+
+};
+
+
+
+
+WRITE8_MEMBER(spartanxtec_state::kungfum_tileram_w)
+{
+ m_m62_tileram[offset] = data;
+ m_bg_tilemap->mark_tile_dirty(offset & 0x7ff);
+}
+
+
+TILE_GET_INFO_MEMBER(spartanxtec_state::get_kungfum_bg_tile_info)
+{
+ int code;
+ int color;
+ int flags;
+ code = m_m62_tileram[tile_index];
+ color = m_m62_tileram[tile_index + 0x800];
+ flags = 0;
+ if ((color & 0x20))
+ {
+ flags |= TILE_FLIPX;
+ }
+ SET_TILE_INFO_MEMBER(0, code | ((color & 0xc0)<< 2), color & 0x1f, flags);
+
+ /* is the following right? */
+ if ((tile_index / 64) < 6 || ((color & 0x1f) >> 1) > 0x0c)
+ tileinfo.category = 1;
+ else
+ tileinfo.category = 0;
+}
+
+void spartanxtec_state::video_start()
+{
+ m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spartanxtec_state::get_kungfum_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+ m_bg_tilemap->set_scroll_rows(32);
+}
+
+
+void spartanxtec_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ gfx_element *gfx = m_gfxdecode->gfx(1);
+
+ for (int i = 0; i < 0x400; i += 4)
+ {
+ int x = m_spriteram[i+2]+128;
+ int y = (224-m_spriteram[i+1])&0xff;
+ int code = m_spriteram[i+0];
+ int attr = m_spriteram[i+3];
+ code |= (attr & 0xc0) << 2;
+
+ int colour = attr & 0x1f;
+ int flipx = attr & 0x20;
+ int flipy = 0;
+
+ gfx->transpen(bitmap,cliprect,code,colour,flipx,flipy,x,y,7);
+
+ }
+
+
+}
+
+
+UINT32 spartanxtec_state::screen_update_spartanxtec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ // there are 4 sets of scroll registers
+ // how to split them isn't clear, 4 groups of 8 rows would be logical
+ // but only 6 rows should use the first scroll register and the
+ // remaining 2 rows scroll values from there can't wrap onto the bottom
+ // as that doesn't work. (breaks bottom 2 lines of playfield scroll)
+ // HOWEVER sprites are also broken in that area, so I think this bootleg
+ // probably just displays less lines.
+
+
+ for (int i = 0; i < 32; i++)
+ {
+ int scrollval;
+
+ scrollval = m_scroll_lo[i/8] | (m_scroll_hi[i/8] << 8);
+
+ m_bg_tilemap->set_scrollx((i-2)&0xff, scrollval+28-128);
+ }
+
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ draw_sprites(bitmap, cliprect);
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 1, 0);
+
+ return 0;
+}
+
+
+
+
+WRITE8_MEMBER(spartanxtec_state::spartanxtec_soundlatch_w)
+{
+ soundlatch_byte_w(space, 0, data);
+ m_audiocpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE);
+}
+
+WRITE8_MEMBER(spartanxtec_state::a801_w)
+{
+ if (data != 0xf0) printf("a801_w %02x\n", data);
+}
+
+WRITE8_MEMBER(spartanxtec_state::irq_ack)
+{
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+}
+
+
+static ADDRESS_MAP_START( spartanxtec_map, AS_PROGRAM, 8, spartanxtec_state )
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ AM_RANGE(0xc400, 0xc7ff) AM_RAM AM_SHARE("spriteram")
+
+ AM_RANGE(0x8000, 0x8000) AM_WRITE(spartanxtec_soundlatch_w)
+
+ AM_RANGE(0x8100, 0x8100) AM_READ_PORT("DSW1")
+ AM_RANGE(0x8101, 0x8101) AM_READ_PORT("DSW2")
+ AM_RANGE(0x8102, 0x8102) AM_READ_PORT("SYSTEM")
+ AM_RANGE(0x8103, 0x8103) AM_READ_PORT("P1")
+
+ AM_RANGE(0x8200, 0x8200) AM_WRITE(irq_ack)
+
+ AM_RANGE(0xA801, 0xA801) AM_WRITE(a801_w)
+
+ AM_RANGE(0xa900, 0xa903) AM_RAM AM_SHARE("scroll_lo")
+ AM_RANGE(0xa980, 0xa983) AM_RAM AM_SHARE("scroll_hi")
+
+ AM_RANGE(0xd000, 0xdfff) AM_RAM_WRITE(kungfum_tileram_w) AM_SHARE("m62_tileram")
+
+ AM_RANGE(0xe000, 0xefff) AM_RAM
+
+ADDRESS_MAP_END
+
+
+
+WRITE8_MEMBER(spartanxtec_state::sound_irq_ack)
+{
+ m_audiocpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+}
+
+
+static ADDRESS_MAP_START( spartanxtec_sound_map, AS_PROGRAM, 8, spartanxtec_state )
+
+ AM_RANGE(0x0000, 0x0fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_RAM
+
+ AM_RANGE(0xc000, 0xc000) AM_READ(soundlatch_byte_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( spartanxtec_sound_io, AS_IO, 8, spartanxtec_state )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x0000, 0x0000) AM_WRITE( sound_irq_ack )
+
+ AM_RANGE(0x0012, 0x0013) AM_DEVWRITE("ay3", ay8910_device, address_data_w)
+ AM_RANGE(0x0012, 0x0012) AM_DEVREAD("ay3", ay8910_device, data_r)
+
+ AM_RANGE(0x0014, 0x0015) AM_DEVWRITE("ay1", ay8910_device, address_data_w)
+ AM_RANGE(0x0014, 0x0014) AM_DEVREAD("ay1", ay8910_device, data_r)
+
+ AM_RANGE(0x0018, 0x0019) AM_DEVWRITE("ay2", ay8910_device, address_data_w)
+ AM_RANGE(0x0018, 0x0018) AM_DEVREAD("ay2", ay8910_device, data_r)
+ADDRESS_MAP_END
+
+
+
+
+static INPUT_PORTS_START( spartanxtec )
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Easy ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( Hard ) )
+ PORT_DIPNAME( 0x02, 0x02, "Energy Loss" ) PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING( 0x02, "Slow" )
+ PORT_DIPSETTING( 0x00, "Fast" )
+ PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:3,4")
+ PORT_DIPSETTING( 0x08, "2" )
+ PORT_DIPSETTING( 0x0c, "3" )
+ PORT_DIPSETTING( 0x04, "4" )
+ PORT_DIPSETTING( 0x00, "5" )
+ /* Manual says that only coin mode 1 is available and SW2:3 should be always OFF */
+ /* However, coin mode 2 works perfectly. */
+ IREM_Z80_COINAGE_TYPE_3_LOC(SW1)
+
+ PORT_START("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW2:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW2:2")
+ PORT_DIPSETTING( 0x00, DEF_STR( Upright ) )
+ PORT_DIPSETTING( 0x02, "Cocktail (invalid?)" )
+ PORT_DIPNAME( 0x04, 0x04, "Coin Mode" ) PORT_DIPLOCATION("SW2:3")
+ PORT_DIPSETTING( 0x04, "Mode 1" )
+ PORT_DIPSETTING( 0x00, "Mode 2" )
+ /* In slowmo mode, press 2 to slow game speed */
+ PORT_DIPNAME( 0x08, 0x08, "Slow Motion Mode (Cheat)" ) PORT_DIPLOCATION("SW2:4")
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ /* In freeze mode, press 2 to stop and 1 to restart */
+ PORT_DIPNAME( 0x10, 0x10, "Freeze (Cheat)" ) PORT_DIPLOCATION("SW2:5")
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ /* In level selection mode, press 1 to select and 2 to restart */
+ PORT_DIPNAME( 0x20, 0x20, "Level Selection Mode (Cheat)" ) PORT_DIPLOCATION("SW2:6")
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Invulnerability (Cheat)" ) PORT_DIPLOCATION("SW2:7")
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_SERVICE_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW2:8" )
+
+ PORT_START("SYSTEM")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_IMPULSE(19)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* probably unused */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* probably unused */
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 )
+INPUT_PORTS_END
+
+
+static const gfx_layout tiles8x8_layout =
+{
+ 8,8,
+ RGN_FRAC(1,3),
+ 3,
+ { RGN_FRAC(0,3),RGN_FRAC(1,3),RGN_FRAC(2,3) },
+ { 0,1,2,3,4,5,6,7 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8
+};
+
+static const gfx_layout tiles16x16_layout =
+{
+ 16,16,
+ RGN_FRAC(1,3),
+ 3,
+ { RGN_FRAC(0,3),RGN_FRAC(1,3),RGN_FRAC(2,3) },
+ { 0,1,2,3,4,5,6,7, 128, 129, 130, 131, 132, 133, 134, 135 },
+ { 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 },
+ 32*8
+};
+
+
+static GFXDECODE_START( news )
+ GFXDECODE_ENTRY( "gfx1", 0, tiles8x8_layout, 0x100, 32 )
+ GFXDECODE_ENTRY( "gfx2", 0, tiles16x16_layout, 0, 32 )
+GFXDECODE_END
+
+
+
+void spartanxtec_state::machine_start()
+{
+}
+
+void spartanxtec_state::machine_reset()
+{
+}
+
+PALETTE_INIT_MEMBER(spartanxtec_state, spartanxtec)
+{
+ // todo, proper weights for this bootleg PCB
+ const UINT8 *color_prom = memregion("cprom")->base();
+ for (int i = 0; i < 0x200; i++)
+ {
+ int r, g, b;
+
+ b = (color_prom[i+0x000]&0x0f)<<4;
+ g = (color_prom[i+0x200]&0x0f)<<4;
+ r = (color_prom[i+0x400]&0x0f)<<4;
+
+ palette.set_pen_color(i, rgb_t(r,g,b));
+ }
+}
+
+
+
+static MACHINE_CONFIG_START( spartanxtec, spartanxtec_state )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", Z80,4000000) /* ? MHz */
+ MCFG_CPU_PROGRAM_MAP(spartanxtec_map)
+ MCFG_CPU_VBLANK_INT_DRIVER("screen", spartanxtec_state, irq0_line_assert)
+
+ MCFG_CPU_ADD("audiocpu", Z80,4000000)
+ MCFG_CPU_PROGRAM_MAP(spartanxtec_sound_map)
+ MCFG_CPU_IO_MAP(spartanxtec_sound_io)
+ MCFG_CPU_PERIODIC_INT_DRIVER(spartanxtec_state, irq0_line_assert, 1000) // controls speed of music
+// MCFG_CPU_VBLANK_INT_DRIVER("screen", spartanxtec_state, irq0_line_hold)
+
+ /* video hardware */
+ // todo, proper screen timings for this bootleg PCB - as visible area is less it's probably ~60hz, not 55
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1790))
+ MCFG_SCREEN_SIZE(64*8, 32*8)
+ MCFG_SCREEN_VISIBLE_AREA((64*8-256)/2, 64*8-(64*8-256)/2-1, 0*8, 32*8-1-16)
+ MCFG_SCREEN_UPDATE_DRIVER(spartanxtec_state, screen_update_spartanxtec)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_PALETTE_ADD("palette", 0x200)
+ MCFG_PALETTE_INIT_OWNER(spartanxtec_state,spartanxtec)
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", news)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("ay1", AY8910, 1000000)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_SOUND_ADD("ay2", AY8910, 1000000)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_SOUND_ADD("ay3", AY8910, 1000000)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+MACHINE_CONFIG_END
+
+
+
+ROM_START( spartanxtec )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "1.bin", 0x00000, 0x04000, CRC(d5d6cddf) SHA1(baaec83be455bf2267d51ea2a2c1fcda22f27bd5) )
+ ROM_LOAD( "2.bin", 0x04000, 0x04000, CRC(2803bb72) SHA1(d0f93c61f3f08fb866e2a4617a7824e72f61c97f) )
+
+ ROM_REGION( 0x10000, "audiocpu", 0 )
+ ROM_LOAD( "3.bin", 0x00000, 0x01000, CRC(9a18af94) SHA1(1644295aa0c837dced5934360e41d77e0a93ccd1) )
+
+ ROM_REGION( 0x6000, "gfx1", ROMREGION_INVERT )
+ ROM_LOAD( "5.bin", 0x00000, 0x0800, CRC(8a3d2978) SHA1(e50ba8d63e894c6a555d92c3144682be68f111b0))
+ ROM_CONTINUE(0x1000, 0x0800)
+ ROM_CONTINUE(0x0800, 0x0800)
+ ROM_CONTINUE(0x1800, 0x0800)
+ ROM_LOAD( "6.bin", 0x02000, 0x0800, CRC(b1570b6b) SHA1(380a692309690e6ff6b57fda657192fff95167e0) )
+ ROM_CONTINUE(0x3000, 0x0800)
+ ROM_CONTINUE(0x2800, 0x0800)
+ ROM_CONTINUE(0x3800, 0x0800)
+ ROM_LOAD( "4.bin", 0x04000, 0x0800, CRC(b55672ef) SHA1(7bd556a76e130be1262aa7db09df84c6463ce9ef) )
+ ROM_CONTINUE(0x5000, 0x0800)
+ ROM_CONTINUE(0x4800, 0x0800)
+ ROM_CONTINUE(0x5800, 0x0800)
+
+ ROM_REGION( 0x18000, "gfx2", ROMREGION_INVERT )
+ ROM_LOAD( "7.bin", 0x00000, 0x08000, CRC(aa897e30) SHA1(90b3b316800be106d3baa6783ca894703f369d4e) )
+ ROM_LOAD( "8.bin", 0x08000, 0x08000, CRC(98a1803b) SHA1(3edfc45c289f850b07a0231ce0b792cbec6fb245) )
+ ROM_LOAD( "9.bin", 0x10000, 0x08000, CRC(e3bf0d73) SHA1(4562422c07399e240081792b96b9018d1e7dd97b) )
+
+ ROM_REGION( 0x600, "cprom", 0 )
+ // first half of all of these is empty
+ ROM_LOAD( "4_MCM7643_82s137.BIN", 0x0000, 0x0200, CRC(548a0ab1) SHA1(e414b61feba73bcc1a53e17c848aceea3b8100e7) ) ROM_CONTINUE(0x0000,0x0200)
+ ROM_LOAD( "5_MCM7643_82s137.BIN", 0x0200, 0x0200, CRC(a678480e) SHA1(515fa2b09c666a46dc145313eda3c465afff4451) ) ROM_CONTINUE(0x0200,0x0200)
+ ROM_LOAD( "6_MCM7643_82s137.BIN", 0x0400, 0x0200, CRC(5a707f85) SHA1(35932daf453787780550464b78465581e1ef35e1) ) ROM_CONTINUE(0x0400,0x0200)
+
+ ROM_REGION( 0x18000, "timing", 0 ) // i think
+ ROM_LOAD( "7_82s147.BIN", 0x0000, 0x0200, CRC(54a9e294) SHA1(d44d21ab8141bdfe697fd303cdc1b5c4177909bc) )
+
+ ROM_REGION( 0x18000, "unkprom", 0 ) // just linear increasing value
+ ROM_LOAD( "1_tbp24s10_82s129.BIN", 0x0000, 0x0100, CRC(b6135ee0) SHA1(248a978987cff86c2bbad10ef332f63a6abd5bee) )
+ ROM_LOAD( "2_tbp24s10_82s129.BIN", 0x0000, 0x0100, CRC(b6135ee0) SHA1(248a978987cff86c2bbad10ef332f63a6abd5bee) )
+ROM_END
+
+
+
+GAME( 1987, spartanxtec, kungfum, spartanxtec, spartanxtec, driver_device, 0, ROT0, "bootleg (Tecfri)", "Spartan X (Tecfri hardware bootleg)", 0 )
+
diff --git a/src/mame/drivers/spyhuntertec.cpp b/src/mame/drivers/spyhuntertec.cpp
new file mode 100644
index 00000000000..783dc87905c
--- /dev/null
+++ b/src/mame/drivers/spyhuntertec.cpp
@@ -0,0 +1,795 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+/*
+
+Spy Hunter(Tecfri bootleg)
+single PCB with 2x Z80
+
+significant changes compared to original HW
+
+Very different hardware, probably bootleg despite the license text printed on the PCB, similar to '1942p' and 'spartanxtec.cpp'
+PCB made by Tecfri for Recreativos Franco S.A. in Spain, has Bally Midway logo, and licensing text on the PCB.
+Board is dated '85' so seems to be a low-cost rebuild? it is unclear if it made it to market.
+
+non-interlaced
+
+sound system appears to be the same as 'spartanxtec.cpp'
+
+analog inputs seem to be read by the sound CPU, with serial communication
+
+*/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "sound/ay8910.h"
+
+
+#define MASTER_CLOCK XTAL_20MHz // ??
+
+class spyhuntertec_state : public driver_device
+{
+public:
+ spyhuntertec_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_audiocpu(*this, "audiocpu"),
+ m_videoram(*this, "videoram"),
+ m_spriteram(*this, "spriteram"),
+ m_spriteram2(*this, "spriteram2"),
+ m_paletteram(*this, "paletteram"),
+ m_spyhunt_alpharam(*this, "spyhunt_alpha"),
+ m_palette(*this, "palette"),
+ m_gfxdecode(*this, "gfxdecode"),
+ m_screen(*this, "screen")
+ { }
+
+
+ required_device<cpu_device> m_audiocpu;
+ required_shared_ptr<UINT8> m_videoram;
+ required_shared_ptr<UINT8> m_spriteram;
+ required_shared_ptr<UINT8> m_spriteram2;
+ required_shared_ptr<UINT8> m_paletteram;
+ required_shared_ptr<UINT8> m_spyhunt_alpharam;
+
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+ virtual void video_start() override;
+ void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
+ UINT32 screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+
+ required_device<palette_device> m_palette;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_device<screen_device> m_screen;
+
+ UINT8 m_spyhunt_sprite_color_mask;
+ INT16 m_spyhunt_scroll_offset;
+ INT16 m_spyhunt_scrollx;
+ INT16 m_spyhunt_scrolly;
+
+ int mcr_cocktail_flip;
+
+ tilemap_t *m_alpha_tilemap;
+ tilemap_t *m_bg_tilemap;
+ DECLARE_WRITE8_MEMBER(spyhuntertec_paletteram_w);
+ DECLARE_DRIVER_INIT(spyhuntertec);
+// DECLARE_VIDEO_START(spyhuntertec);
+// UINT32 screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ DECLARE_WRITE8_MEMBER(spyhuntertec_port04_w);
+ DECLARE_WRITE8_MEMBER(spyhuntertec_fd00_w);
+ DECLARE_WRITE8_MEMBER(spyhuntertec_portf0_w);
+
+ DECLARE_WRITE8_MEMBER(spyhunt_videoram_w);
+ DECLARE_WRITE8_MEMBER(spyhunt_alpharam_w);
+ DECLARE_WRITE8_MEMBER(spyhunt_scroll_value_w);
+ DECLARE_WRITE8_MEMBER(sound_irq_ack);
+
+
+ DECLARE_WRITE8_MEMBER(ay1_porta_w);
+ DECLARE_READ8_MEMBER(ay1_porta_r);
+
+ DECLARE_WRITE8_MEMBER(ay2_porta_w);
+ DECLARE_READ8_MEMBER(ay2_porta_r);
+
+ DECLARE_READ8_MEMBER(spyhuntertec_in2_r);
+ DECLARE_READ8_MEMBER(spyhuntertec_in3_r);
+
+ TILEMAP_MAPPER_MEMBER(spyhunt_bg_scan);
+ TILE_GET_INFO_MEMBER(spyhunt_get_bg_tile_info);
+ TILE_GET_INFO_MEMBER(spyhunt_get_alpha_tile_info);
+ void mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced);
+
+
+};
+
+WRITE8_MEMBER(spyhuntertec_state::ay1_porta_w)
+{
+// printf("ay1_porta_w %02x\n", data);
+}
+
+READ8_MEMBER(spyhuntertec_state::ay1_porta_r)
+{
+// printf("ay1_porta_r\n");
+ return 0;
+}
+
+
+
+WRITE8_MEMBER(spyhuntertec_state::ay2_porta_w)
+{
+// printf("ay2_porta_w %02x\n", data);
+}
+
+READ8_MEMBER(spyhuntertec_state::ay2_porta_r)
+{
+// read often, even if port is set to output mode
+// maybe latches something?
+// printf("ay2_porta_r\n");
+ return rand();
+}
+
+WRITE8_MEMBER(spyhuntertec_state::spyhunt_videoram_w)
+{
+ UINT8 *videoram = m_videoram;
+ videoram[offset] = data;
+ m_bg_tilemap->mark_tile_dirty(offset);
+}
+
+
+WRITE8_MEMBER(spyhuntertec_state::spyhunt_alpharam_w)
+{
+ m_spyhunt_alpharam[offset] = data;
+ m_alpha_tilemap->mark_tile_dirty(offset);
+}
+
+
+WRITE8_MEMBER(spyhuntertec_state::spyhunt_scroll_value_w)
+{
+ switch (offset)
+ {
+ case 0:
+ /* low 8 bits of horizontal scroll */
+ m_spyhunt_scrollx = (m_spyhunt_scrollx & ~0xff) | data;
+ break;
+
+ case 1:
+ /* upper 3 bits of horizontal scroll and upper 1 bit of vertical scroll */
+ m_spyhunt_scrollx = (m_spyhunt_scrollx & 0xff) | ((data & 0x07) << 8);
+ m_spyhunt_scrolly = (m_spyhunt_scrolly & 0xff) | ((data & 0x80) << 1);
+ break;
+
+ case 2:
+ /* low 8 bits of vertical scroll */
+ m_spyhunt_scrolly = (m_spyhunt_scrolly & ~0xff) | data;
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_paletteram_w)
+{
+ m_paletteram[offset] = data;
+ offset = (offset & 0x0f) | (offset & 0x60) >> 1;
+
+ int r = (data & 0x07) >> 0;
+ int g = (data & 0x38) >> 3;
+ int b = (data & 0xc0) >> 6;
+
+ m_palette->set_pen_color(offset^0xf, rgb_t(r<<5,g<<5,b<<6));
+}
+
+
+TILEMAP_MAPPER_MEMBER(spyhuntertec_state::spyhunt_bg_scan)
+{
+ /* logical (col,row) -> memory offset */
+ return (row & 0x0f) | ((col & 0x3f) << 4) | ((row & 0x10) << 6);
+}
+
+
+TILE_GET_INFO_MEMBER(spyhuntertec_state::spyhunt_get_bg_tile_info)
+{
+ UINT8 *videoram = m_videoram;
+ int data = videoram[tile_index];
+ int code = (data & 0x3f) | ((data >> 1) & 0x40);
+ SET_TILE_INFO_MEMBER(0, code, 0, (data & 0x40) ? TILE_FLIPY : 0);
+}
+
+
+TILE_GET_INFO_MEMBER(spyhuntertec_state::spyhunt_get_alpha_tile_info)
+{
+ SET_TILE_INFO_MEMBER(2, m_spyhunt_alpharam[tile_index], 0, 0);
+}
+
+
+
+void spyhuntertec_state::video_start()
+{
+ /* initialize the background tilemap */
+ m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spyhuntertec_state::spyhunt_get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(spyhuntertec_state::spyhunt_bg_scan),this), 64,16, 64,32);
+
+ /* initialize the text tilemap */
+ m_alpha_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(spyhuntertec_state::spyhunt_get_alpha_tile_info),this), TILEMAP_SCAN_COLS, 16,8, 32,32);
+ m_alpha_tilemap->set_transparent_pen(0);
+ m_alpha_tilemap->set_scrollx(0, 16);
+
+ save_item(NAME(m_spyhunt_sprite_color_mask));
+ save_item(NAME(m_spyhunt_scrollx));
+ save_item(NAME(m_spyhunt_scrolly));
+ save_item(NAME(m_spyhunt_scroll_offset));
+}
+
+
+
+
+void spyhuntertec_state::mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced)
+{
+ UINT8 *spriteram = m_spriteram;
+ int offs;
+
+ m_screen->priority().fill(1, cliprect);
+
+ /* loop over sprite RAM */
+ for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
+ {
+ int code, color, flipx, flipy, sx, sy, flags;
+
+ /* skip if zero */
+ if (spriteram[offs] == 0)
+ continue;
+
+/*
+ monoboard:
+ flags.d0 -> ICG0~ -> PCG0~/PCG2~/PCG4~/PCG6~ -> bit 4 of linebuffer
+ flags.d1 -> ICG1~ -> PCG1~/PCG3~/PCG5~/PCG7~ -> bit 5 of linebuffer
+ flags.d2 -> IPPR -> PPR0 /PPR1 /PPR2 /PPR3 -> bit 6 of linebuffer
+ flags.d3 -> IRA15 ----------------------------> address line 15 of FG ROMs
+ flags.d4 -> HFLIP
+ flags.d5 -> VFLIP
+
+*/
+
+ /* extract the bits of information */
+ flags = spriteram[offs + 1];
+ code = spriteram[offs + 2] + 256 * ((flags >> 3) & 0x01);
+ color = ~flags & color_mask;
+ flipx = flags & 0x10;
+ flipy = flags & 0x20;
+ sx = (spriteram[offs + 3] - 3) * 2;
+ sy = (241 - spriteram[offs]);
+
+ if (interlaced == 1) sy *= 2;
+
+ code ^= code_xor;
+
+ sx += dx;
+ sy += dy;
+
+ /* sprites use color 0 for background pen and 8 for the 'under tile' pen.
+ The color 8 is used to cover over other sprites. */
+ if (!mcr_cocktail_flip)
+ {
+ /* first draw the sprite, visible */
+ m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, flipx, flipy, sx, sy,
+ screen.priority(), 0x00, 0x0101);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, flipx, flipy, sx, sy,
+ screen.priority(), 0x02, 0xfeff);
+ }
+ else
+ {
+ /* first draw the sprite, visible */
+ m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, !flipx, !flipy, 480 - sx, 452 - sy,
+ screen.priority(), 0x00, 0x0101);
+
+ /* then draw the mask, behind the background but obscuring following sprites */
+ m_gfxdecode->gfx(1)->prio_transmask(bitmap,cliprect, code, color, !flipx, !flipy, 480 - sx, 452 - sy,
+ screen.priority(), 0x02, 0xfeff);
+ }
+ }
+}
+
+
+UINT32 spyhuntertec_state::screen_update_spyhuntertec(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ /* for every character in the Video RAM, check if it has been modified */
+ /* since last time and update it accordingly. */
+ m_bg_tilemap->set_scrollx(0, m_spyhunt_scrollx * 2 + m_spyhunt_scroll_offset);
+ m_bg_tilemap->set_scrolly(0, m_spyhunt_scrolly * 2);
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+
+ /* draw the sprites */
+ mcr3_update_sprites(screen, bitmap, cliprect, m_spyhunt_sprite_color_mask, 0, -12, 0, 0);
+
+ /* render any characters on top */
+ m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+
+
+WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_fd00_w)
+{
+// printf("%04x spyhuntertec_fd00_w %02x\n", space.device().safe_pc(), data);
+ soundlatch_byte_w(space, 0, data);
+ m_audiocpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE);
+}
+
+READ8_MEMBER(spyhuntertec_state::spyhuntertec_in2_r)
+{
+ // it writes 04 / 14 to the sound latch (spyhuntertec_fd00_w) before
+ // reading bit 6 here a minimum of 32 times.
+ // seems to be how it reads the analog controls? probably via sound CPU??
+
+ /* note, these commands trigger a read from ay2_porta on the sound cpu side, followed by 2 writes
+
+ a52a spyhuntertec_fd00_w 14
+ ay2_porta_r
+ ay2_porta_w 80
+ ay2_porta_w 00
+ a52a spyhuntertec_fd00_w 04
+ ay2_porta_r
+ ay2_porta_w 81
+ ay2_porta_w 01
+ */
+
+ /*
+
+ -- input reading code here
+ A388: 3E 14 ld a,$14
+ A38A: 28 04 jr z,$A390
+ A38C: DD 23 inc ix
+ A38E: 3E 04 ld a,$04
+ A390: CD 20 A5 call $A520 << write command to sub-cpu
+
+ -- delay loop / timeout loop for reading result? value of b doesn't get used in the end
+ A393: 06 1F ld b,$1F << loop counter
+ A395: 21 02 FC ld hl,$FC02
+ loopstart:
+ A398: CB 76 bit 6,(hl)
+ A39A: 28 06 jr z,$A3A2 to dest2
+ A39C: 10 FA djnz $A398 (to loopstart)
+
+ A39E: 06 0F ld b,$0F <
+ A3A0: 18 1E jr $A3C0 to dest 3
+
+ dest2:
+ A3A2: 06 33 ld b,$33 << loop counter
+ loop2start:
+ A3A4: CB 76 bit 6,(hl)
+ A3A6: 20 11 jr nz,$A3B9 (to outofloop)
+ A3A8: CB 76 bit 6,(hl)
+ A3AA: 00 nop
+ A3AB: CB 76 bit 6,(hl)
+ A3AD: 20 0A jr nz,$A3B9 (to outofloop)
+ A3AF: 10 F3 djnz $A3A4 (to loop2start)
+
+ A3B1: 00 nop
+ A3B2: 00 nop
+ A3B3: 00 nop
+ A3B4: 00 nop
+ A3B5: 00 nop
+ A3B6: 00 nop
+ A3B7: 00 nop
+ A3B8: 00 nop
+
+ outofloop:
+ A3B9: 78 ld a,b
+ A3BA: FE 20 cp $20
+ A3BC: 38 02 jr c,$A3C0
+ A3BE: 06 1F ld b,$1F
+
+ dest3:
+ A3C0: 21 B6 A6 ld hl,$A6B6
+ ...
+
+
+ */
+
+ UINT8 ret = ioport("IN2")->read();
+// printf("%04x spyhuntertec_in2_r\n", space.device().safe_pc());
+ return ret;
+}
+
+READ8_MEMBER(spyhuntertec_state::spyhuntertec_in3_r)
+{
+ UINT8 ret = ioport("IN3")->read();
+// printf("%04x spyhuntertec_in3_r\n", space.device().safe_pc());
+ return ret;
+}
+
+static ADDRESS_MAP_START( spyhuntertec_map, AS_PROGRAM, 8, spyhuntertec_state )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0xa800, 0xa8ff) AM_RAM // the ROM is a solid fill in these areas, and they get tested as RAM, I think they moved the 'real' scroll regs here
+ AM_RANGE(0xa900, 0xa9ff) AM_RAM
+
+ AM_RANGE(0x0000, 0xdfff) AM_ROM
+
+ AM_RANGE(0xe000, 0xe7ff) AM_RAM_WRITE(spyhunt_videoram_w) AM_SHARE("videoram")
+ AM_RANGE(0xe800, 0xebff) AM_MIRROR(0x0400) AM_RAM_WRITE(spyhunt_alpharam_w) AM_SHARE("spyhunt_alpha")
+ AM_RANGE(0xf000, 0xf7ff) AM_RAM //AM_SHARE("nvram")
+ AM_RANGE(0xf800, 0xf9ff) AM_RAM AM_SHARE("spriteram") // origional spriteram
+ AM_RANGE(0xfa00, 0xfa7f) AM_MIRROR(0x0180) AM_RAM_WRITE(spyhuntertec_paletteram_w) AM_SHARE("paletteram")
+
+ AM_RANGE(0xfc00, 0xfc00) AM_READ_PORT("DSW0")
+ AM_RANGE(0xfc01, 0xfc01) AM_READ_PORT("DSW1")
+ AM_RANGE(0xfc02, 0xfc02) AM_READ(spyhuntertec_in2_r)
+ AM_RANGE(0xfc03, 0xfc03) AM_READ(spyhuntertec_in3_r)
+
+ AM_RANGE(0xfd00, 0xfd00) AM_WRITE( spyhuntertec_fd00_w )
+
+ AM_RANGE(0xfe00, 0xffff) AM_RAM AM_SHARE("spriteram2") // actual spriteram for this hw??
+ADDRESS_MAP_END
+
+WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_port04_w)
+{
+}
+
+WRITE8_MEMBER(spyhuntertec_state::spyhuntertec_portf0_w)
+{
+ // 0x08 on startup, then 0x03, probably CTC leftovers from the original.
+ if ((data != 0x03) && (data != 0x08)) printf("spyhuntertec_portf0_w %02x\n", data);
+}
+
+static ADDRESS_MAP_START( spyhuntertec_portmap, AS_IO, 8, spyhuntertec_state )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x04, 0x04) AM_WRITE(spyhuntertec_port04_w)
+ AM_RANGE(0x84, 0x86) AM_WRITE(spyhunt_scroll_value_w)
+ AM_RANGE(0xe0, 0xe0) AM_WRITENOP // was watchdog
+// AM_RANGE(0xe8, 0xe8) AM_WRITENOP
+ AM_RANGE(0xf0, 0xf0) AM_WRITE( spyhuntertec_portf0_w )
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( spyhuntertec_sound_map, AS_PROGRAM, 8, spyhuntertec_state )
+ AM_RANGE(0x0000, 0x1fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_RAM
+
+ AM_RANGE(0xc000, 0xc000) AM_READ(soundlatch_byte_r)
+ADDRESS_MAP_END
+
+
+WRITE8_MEMBER(spyhuntertec_state::sound_irq_ack)
+{
+ m_audiocpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+}
+
+static ADDRESS_MAP_START( spyhuntertec_sound_portmap, AS_IO, 8, spyhuntertec_state )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+
+ AM_RANGE(0x00, 0x00) AM_WRITE(sound_irq_ack)
+
+ AM_RANGE(0x0012, 0x0013) AM_DEVWRITE("ay3", ay8910_device, address_data_w)
+ AM_RANGE(0x0012, 0x0012) AM_DEVREAD("ay3", ay8910_device, data_r)
+
+ AM_RANGE(0x0014, 0x0015) AM_DEVWRITE("ay1", ay8910_device, address_data_w)
+ AM_RANGE(0x0014, 0x0014) AM_DEVREAD("ay1", ay8910_device, data_r)
+
+ AM_RANGE(0x0018, 0x0019) AM_DEVWRITE("ay2", ay8910_device, address_data_w) // data written to port a
+ AM_RANGE(0x0018, 0x0018) AM_DEVREAD("ay2", ay8910_device, data_r) // actually read
+
+ADDRESS_MAP_END
+
+
+
+static INPUT_PORTS_START( spyhuntertec )
+ PORT_START("DSW0")
+ PORT_DIPNAME( 0x01, 0x01, "DSW0-01" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "DSW0-02" )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, "DSW0-04" )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "DSW0-08" )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, "DSW0-10" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "DSW0-20" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "DSW0-40" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "DSW0-80" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, "DSW1-01" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "DSW1-02" )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_SERVICE( 0x04, IP_ACTIVE_LOW )
+ PORT_DIPNAME( 0x08, 0x08, "DSW1-08" )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, "DSW1-10" )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "DSW1-20" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "DSW1-40" )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "DSW1-80" )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("IN2")
+ PORT_DIPNAME( 0x0001, 0x0001, "2" )
+ PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0002, 0x0002, "start" ) // start
+ PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0004, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0008, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0010, 0x0010, "handbrake?" )
+ PORT_DIPSETTING( 0x0010, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0020, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0040, 0x0040, "pedal inverse" )
+ PORT_DIPSETTING( 0x0040, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0080, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+
+ PORT_START("IN3")
+ PORT_DIPNAME( 0x0001, 0x0001, "3" )
+ PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0004, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0008, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0010, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x0020, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0040, 0x0040, "coin" ) // coin?
+ PORT_DIPSETTING( 0x0040, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0080, 0x0080, "machineguns" ) // machine guns
+ PORT_DIPSETTING( 0x0080, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+static const gfx_layout spyhuntertec_alphalayout =
+{
+ 16,8,
+ RGN_FRAC(1,1),
+ 2,
+ { 0, 4},
+ { 0, 0, 1, 1, 2, 2, 3, 3, 8, 8, 9, 9, 10, 10, 11, 11 },
+ { 0, 2*8, 4*8, 6*8, 8*8, 10*8, 12*8, 14*8 },
+ 16*8
+};
+
+
+const gfx_layout spyhuntertec_sprite_layout =
+{
+ 32,16,
+ RGN_FRAC(1,4),
+ 4,
+ { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
+ { 6,7, 4,5, 2,3, 0,1, 14,15, 12,13, 10,11, 8,9, 22,23, 20,21, 18,19, 16,17, 30,31, 28,29, 26,27, 24,25 },
+ { 0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32,8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32 },
+
+ 16*32
+};
+
+
+static const UINT32 spyhuntp_charlayout_xoffset[64] =
+{
+ 0x0000*8,0x0000*8, 0x0000*8+1,0x0000*8+1, 0x0000*8+2,0x0000*8+2, 0x0000*8+3,0x0000*8+3, 0x0000*8+4,0x0000*8+4, 0x0000*8+5,0x0000*8+5, 0x0000*8+6,0x0000*8+6, 0x0000*8+7,0x0000*8+7,
+ 0x1000*8,0x1000*8, 0x1000*8+1,0x1000*8+1, 0x1000*8+2,0x1000*8+2, 0x1000*8+3,0x1000*8+3, 0x1000*8+4,0x1000*8+4, 0x1000*8+5,0x1000*8+5, 0x1000*8+6,0x1000*8+6, 0x1000*8+7,0x1000*8+7,
+ 0x2000*8,0x2000*8, 0x2000*8+1,0x2000*8+1, 0x2000*8+2,0x2000*8+2, 0x2000*8+3,0x2000*8+3, 0x2000*8+4,0x2000*8+4, 0x2000*8+5,0x2000*8+5, 0x2000*8+6,0x2000*8+6, 0x2000*8+7,0x2000*8+7,
+ 0x3000*8,0x3000*8, 0x3000*8+1,0x3000*8+1, 0x3000*8+2,0x3000*8+2, 0x3000*8+3,0x3000*8+3, 0x3000*8+4,0x3000*8+4, 0x3000*8+5,0x3000*8+5, 0x3000*8+6,0x3000*8+6, 0x3000*8+7,0x3000*8+7,
+};
+
+
+static const gfx_layout spyhuntertec_charlayout =
+{
+ 64,16,
+ RGN_FRAC(1,8),
+ 4,
+ { 0*8, 0x4000*8 + 2*8, 0x4000*8 + 0*8, 2*8 },
+ EXTENDED_XOFFS,
+ { 0*8, 4*8, 8*8, 12*8, 16*8, 20*8, 24*8, 28*8, 1*8, 5*8, 9*8, 13*8, 17*8, 21*8, 25*8, 29*8 },
+ 32*8,
+ spyhuntp_charlayout_xoffset,
+ nullptr
+};
+
+
+static GFXDECODE_START( spyhuntertec )
+ GFXDECODE_ENTRY( "gfx1", 0, spyhuntertec_charlayout, 3*16, 1 )
+ GFXDECODE_ENTRY( "gfx2", 0, spyhuntertec_sprite_layout, 0*16, 4 )
+ GFXDECODE_ENTRY( "gfx3", 0, spyhuntertec_alphalayout, 4*16, 1 )
+GFXDECODE_END
+
+
+
+void spyhuntertec_state::machine_start()
+{
+}
+
+void spyhuntertec_state::machine_reset()
+{
+}
+
+
+
+
+static MACHINE_CONFIG_START( spyhuntertec, spyhuntertec_state )
+
+// note: no ctc, no nvram
+// 2*z80, 3*ay8912
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", Z80, MASTER_CLOCK/4)
+ MCFG_CPU_PROGRAM_MAP(spyhuntertec_map)
+ MCFG_CPU_IO_MAP(spyhuntertec_portmap)
+ MCFG_CPU_VBLANK_INT_DRIVER("screen", spyhuntertec_state, irq0_line_hold)
+
+ /* video hardware */
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
+ MCFG_SCREEN_SIZE(30*16, 30*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, 30*16-1, 0, 30*8-1)
+ MCFG_SCREEN_UPDATE_DRIVER(spyhuntertec_state, screen_update_spyhuntertec)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", spyhuntertec)
+ MCFG_PALETTE_ADD("palette", 64+4)
+
+// MCFG_PALETTE_INIT_OWNER(spyhuntertec_state,spyhunt)
+
+
+ MCFG_CPU_ADD("audiocpu", Z80, 4000000 )
+ MCFG_CPU_PROGRAM_MAP(spyhuntertec_sound_map)
+ MCFG_CPU_IO_MAP(spyhuntertec_sound_portmap)
+ MCFG_CPU_PERIODIC_INT_DRIVER(spyhuntertec_state, irq0_line_assert, 1000)
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("ay1", AY8912, 3000000/2) // AY-3-8912
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_AY8910_PORT_A_READ_CB(READ8(spyhuntertec_state, ay1_porta_r))
+ MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(spyhuntertec_state, ay1_porta_w))
+
+ MCFG_SOUND_ADD("ay2", AY8912, 3000000/2) // "
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_AY8910_PORT_A_READ_CB(READ8(spyhuntertec_state, ay2_porta_r))
+ MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(spyhuntertec_state, ay2_porta_w))
+
+ MCFG_SOUND_ADD("ay3", AY8912, 3000000/2) // "
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+MACHINE_CONFIG_END
+
+
+
+
+ROM_START( spyhuntpr )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "1.bin", 0x0000, 0x4000, CRC(2a2f77cb) SHA1(e1b74c951efb2a49bef0507ab3268b274515f339) )
+ ROM_LOAD( "2.bin", 0x4000, 0x4000, CRC(00778aff) SHA1(7c0b24c393f841e8379d4bba57ba502e3d2512f9) )
+ ROM_LOAD( "3.bin", 0x8000, 0x4000, CRC(2183b4af) SHA1(2b958afc40b26c9bc8d5254b0600426649f4ebf0) )
+ ROM_LOAD( "4.bin", 0xc000, 0x2000, CRC(3ea6a65c) SHA1(1320ce17044307ed3c4f2459631a9aa1734f1f30) )
+
+ ROM_REGION( 0x10000, "audiocpu", 0 )
+ ROM_LOAD( "5.bin", 0x0000, 0x2000, CRC(33fe2829) SHA1(e6950dbf681242bf23542ca6604e62eacb431101) )
+
+
+ ROM_REGION( 0x08000, "gfx1", 0 )
+ ROM_LOAD32_BYTE( "6.bin", 0x0000, 0x200, CRC(6b76f46a) SHA1(4b398084c42a60fcfa4a9bf14f844e36a3f42723) )
+ ROM_CONTINUE(0x0001, 0x200)
+ ROM_CONTINUE(0x0800, 0x200)
+ ROM_CONTINUE(0x0801, 0x200)
+ ROM_CONTINUE(0x1000, 0x200)
+ ROM_CONTINUE(0x1001, 0x200)
+ ROM_CONTINUE(0x1800, 0x200)
+ ROM_CONTINUE(0x1801, 0x200)
+ ROM_CONTINUE(0x2000, 0x200)
+ ROM_CONTINUE(0x2001, 0x200)
+ ROM_CONTINUE(0x2800, 0x200)
+ ROM_CONTINUE(0x2801, 0x200)
+ ROM_CONTINUE(0x3000, 0x200)
+ ROM_CONTINUE(0x3001, 0x200)
+ ROM_CONTINUE(0x3800, 0x200)
+ ROM_CONTINUE(0x3801, 0x200)
+ ROM_LOAD32_BYTE( "7.bin", 0x0002, 0x200, CRC(085bd7a7) SHA1(c35c309b6c6485baec54d4434dea44abf4d48f41) )
+ ROM_CONTINUE(0x0003, 0x200)
+ ROM_CONTINUE(0x0802, 0x200)
+ ROM_CONTINUE(0x0803, 0x200)
+ ROM_CONTINUE(0x1002, 0x200)
+ ROM_CONTINUE(0x1003, 0x200)
+ ROM_CONTINUE(0x1802, 0x200)
+ ROM_CONTINUE(0x1803, 0x200)
+ ROM_CONTINUE(0x2002, 0x200)
+ ROM_CONTINUE(0x2003, 0x200)
+ ROM_CONTINUE(0x2802, 0x200)
+ ROM_CONTINUE(0x2803, 0x200)
+ ROM_CONTINUE(0x3002, 0x200)
+ ROM_CONTINUE(0x3003, 0x200)
+ ROM_CONTINUE(0x3802, 0x200)
+ ROM_CONTINUE(0x3803, 0x200)
+ ROM_LOAD32_BYTE( "8.bin", 0x4000, 0x200, CRC(e699b329) SHA1(cb4b8c7b6fa1cb1144a18f1442dc3b267c408914) )
+ ROM_CONTINUE(0x4001, 0x200)
+ ROM_CONTINUE(0x4800, 0x200)
+ ROM_CONTINUE(0x4801, 0x200)
+ ROM_CONTINUE(0x5000, 0x200)
+ ROM_CONTINUE(0x5001, 0x200)
+ ROM_CONTINUE(0x5800, 0x200)
+ ROM_CONTINUE(0x5801, 0x200)
+ ROM_CONTINUE(0x6000, 0x200)
+ ROM_CONTINUE(0x6001, 0x200)
+ ROM_CONTINUE(0x6800, 0x200)
+ ROM_CONTINUE(0x6801, 0x200)
+ ROM_CONTINUE(0x7000, 0x200)
+ ROM_CONTINUE(0x7001, 0x200)
+ ROM_CONTINUE(0x7800, 0x200)
+ ROM_CONTINUE(0x7801, 0x200)
+ ROM_LOAD32_BYTE( "9.bin", 0x4002, 0x200, CRC(6d462ec7) SHA1(0ff37f75b0eeceb86177a3f7c93834d5c0e24515) )
+ ROM_CONTINUE(0x4003, 0x200)
+ ROM_CONTINUE(0x4802, 0x200)
+ ROM_CONTINUE(0x4803, 0x200)
+ ROM_CONTINUE(0x5002, 0x200)
+ ROM_CONTINUE(0x5003, 0x200)
+ ROM_CONTINUE(0x5802, 0x200)
+ ROM_CONTINUE(0x5803, 0x200)
+ ROM_CONTINUE(0x6002, 0x200)
+ ROM_CONTINUE(0x6003, 0x200)
+ ROM_CONTINUE(0x6802, 0x200)
+ ROM_CONTINUE(0x6803, 0x200)
+ ROM_CONTINUE(0x7002, 0x200)
+ ROM_CONTINUE(0x7003, 0x200)
+ ROM_CONTINUE(0x7802, 0x200)
+ ROM_CONTINUE(0x7803, 0x200)
+
+ ROM_REGION( 0x10000, "gfx2", ROMREGION_INVERT )
+ ROM_LOAD( "10.bin", 0x00000, 0x4000, CRC(6f9fd416) SHA1(a51c86e5b22c91fc44673f53400b58af40b18065) )
+ ROM_LOAD( "11.bin", 0x04000, 0x4000, CRC(75526ffe) SHA1(ff1adf6f9b6595114d0bd06b72d9eb7bbf70144d) )
+ ROM_LOAD( "12.bin", 0x08000, 0x4000, CRC(82ee7a4d) SHA1(184720de76680275bf7c4a171f03a0ce771d91fc) )
+ ROM_LOAD( "13.bin", 0x0c000, 0x4000, CRC(0cc592a3) SHA1(b3563bde83432cdbaedb88d4d222da30bf679b08) )
+
+
+ ROM_REGION( 0x01000, "gfx3", 0 )
+ ROM_LOAD( "14.bin", 0x00000, 0x1000, CRC(87a4c130) SHA1(7792afdc36b0f3bd51c387d04d38f60c85fd2e93) )
+ROM_END
+
+DRIVER_INIT_MEMBER(spyhuntertec_state,spyhuntertec)
+{
+ m_spyhunt_sprite_color_mask = 0x00;
+ m_spyhunt_scroll_offset = 16;
+}
+
+
+GAME (1983, spyhuntpr,spyhunt, spyhuntertec, spyhuntertec,spyhuntertec_state, spyhuntertec,ROT90, "Bally Midway (Recreativos Franco S.A. license)", "Spy Hunter (Spain, Tecfri / Recreativos Franco S.A. PCB)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/toki.cpp b/src/mame/drivers/toki.cpp
index 5799e0d239c..46d0ef11f0f 100644
--- a/src/mame/drivers/toki.cpp
+++ b/src/mame/drivers/toki.cpp
@@ -542,6 +542,47 @@ ROM_START( toki )
ROM_END
+ROM_START( tokip )
+ ROM_REGION( 0x60000, "maincpu", 0 ) /* 6*64k for 68000 code */
+ ROM_LOAD16_BYTE( "6 10-M", 0x00000, 0x20000, CRC(91b554a3) SHA1(ab003e82552eba381099eb2d00577f952cad42f7) ) // different
+ ROM_LOAD16_BYTE( "4 10-K", 0x00001, 0x20000, CRC(404220f7) SHA1(f614692d05f1280cbe801fe0486a611f38b5e866) ) // different
+ ROM_LOAD16_BYTE( "5 12-M", 0x40000, 0x10000, CRC(d6a82808) SHA1(9fcd3e97f7eaada5374347383dc8a6cea2378f7f) )
+ ROM_LOAD16_BYTE( "3 12-K", 0x40001, 0x10000, CRC(a01a5b10) SHA1(76d6da114105402aab9dd5167c0c00a0bddc3bba) )
+
+ ROM_REGION( 0x20000, "audiocpu", 0 ) /* Z80 code, banked data */
+ ROM_LOAD( "8 3-M", 0x00000, 0x02000, CRC(6c87c4c5) SHA1(d76822bcde3d42afae72a0945b6acbf3c6a1d955) ) /* encrypted */
+ ROM_LOAD( "7 7-M", 0x10000, 0x10000, CRC(a67969c4) SHA1(99781fbb005b6ba4a19a9cc83c8b257a3b425fa6) ) /* banked stuff */
+
+ ROM_REGION( 0x020000, "gfx1", 0 )
+ ROM_LOAD( "1 5-C", 0x000000, 0x10000, CRC(fd0ff303) SHA1(e861b8efd7b3050b95a7d9ff1732bb9641e4dbcc) ) /* chars */ // different
+ ROM_LOAD( "2 3-C", 0x010000, 0x10000, CRC(86e87e48) SHA1(29634d8c58ef7195cd0ce166f1b7fae01bbc110b) )
+
+ ROM_REGION( 0x100000, "gfx2", 0 )
+ ROM_LOAD16_BYTE( "OBJ 1-0.ROM10", 0x00000, 0x20000, CRC(a027bd8e) SHA1(33cc4ae75332ab35df1c03f74db8cb17f2749ead) )
+ ROM_LOAD16_BYTE( "OBJ 1-1.ROM9", 0x00001, 0x20000, CRC(43a767ea) SHA1(bfc879ff714828f7a1b8f784db8728c91287ed20) )
+ ROM_LOAD16_BYTE( "OBJ 1-2.ROM12", 0x40000, 0x20000, CRC(1aecc9d8) SHA1(e7a79783e71de472f07761f9dc71f2a78e629676) )
+ ROM_LOAD16_BYTE( "OBJ 1-3.ROM11", 0x40001, 0x20000, CRC(d65c0c6d) SHA1(6b895ce06dae1ecc21c64993defbb3be6b6f8ac2) )
+ ROM_LOAD16_BYTE( "OBJ 2-0.ROM14", 0x80000, 0x20000, CRC(cedaccaf) SHA1(82f135c9f6a51e49df543e370861918d582a7923) )
+ ROM_LOAD16_BYTE( "OBJ 2-1.ROM13", 0x80001, 0x20000, CRC(013f539b) SHA1(d62c048a95b9c331cedc5343f70947bb50e49c87) )
+ ROM_LOAD16_BYTE( "OBJ 2-2.ROM16", 0xc0000, 0x20000, CRC(6a8e6e22) SHA1(a6144201e9a18aa46f65957694653a40071d92d4) )
+ ROM_LOAD16_BYTE( "OBJ 2-3.ROM15", 0xc0001, 0x20000, CRC(25d9a16c) SHA1(059d1e2e874bb41f8ef576e0cf33bdbffb57ddc0) )
+
+ ROM_REGION( 0x080000, "gfx3", 0 )
+ ROM_LOAD16_BYTE( "BACK 1-0.ROM5", 0x00000, 0x20000, CRC(fac7e32f) SHA1(13f789c209aa6a6866dfc5a83ca68d83271b12c6) )
+ ROM_LOAD16_BYTE( "BACK 1-1.ROM6", 0x00001, 0x20000 ,CRC(ee1135d6) SHA1(299bb3f82d6ded4f401fb407e298842a47a45b1d) )
+ ROM_LOAD16_BYTE( "BACK 1-2.ROM7", 0x40000, 0x20000, CRC(78db8d57) SHA1(a03bb854205c410c05d9a82f20354370c0af0bda) )
+ ROM_LOAD16_BYTE( "BACK 1-3.ROM8", 0x40001, 0x20000, CRC(d719de71) SHA1(decbb5213d97f75b80ae74e4ccf2ff465d1dfad9) )
+
+ ROM_REGION( 0x080000, "gfx4", 0 )
+ ROM_LOAD16_BYTE( "BACK 2-0.ROM1", 0x00000, 0x20000, CRC(949d8025) SHA1(919821647d1bfd0b5b35afcb1c76fddc51a74854))
+ ROM_LOAD16_BYTE( "BACK 2-1.ROM2", 0x00001, 0x20000, CRC(4b28b4b4) SHA1(22e5d9098069833ab1dcc89abe07f9ade1b00459) )
+ ROM_LOAD16_BYTE( "BACK 2-2.ROM3", 0x40000, 0x20000, CRC(1aa9a5cf) SHA1(305101589f6f56584c8147456dbb4360eaa31fef) )
+ ROM_LOAD16_BYTE( "BACK 2-3.ROM4", 0x40001, 0x20000, CRC(6759571f) SHA1(bff3a73ed33c236b38425570f3eb0bbf9a3ca84c) )
+
+ ROM_REGION( 0x40000, "oki", 0 ) /* ADPCM samples */
+ ROM_LOAD( "9 1-M", 0x00000, 0x20000, CRC(ae7a6b8b) SHA1(1d410f91354ffd1774896b2e64f20a2043607805) ) //
+ROM_END
+
ROM_START( tokia )
ROM_REGION( 0x60000, "maincpu", 0 ) /* 6*64k for 68000 code */
ROM_LOAD16_BYTE( "6.m10", 0x00000, 0x20000, CRC(03d726b1) SHA1(bbe3a1ea1943cd73b821b3de4d5bf3dfbffd2168) )
@@ -912,6 +953,9 @@ DRIVER_INIT_MEMBER(toki_state,jujuba)
GAME( 1989, toki, 0, tokie, toki, toki_state, toki, ROT0, "TAD Corporation", "Toki (World, set 1)", MACHINE_SUPPORTS_SAVE )
GAME( 1989, tokiu, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, tokip, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, prototype?)", MACHINE_SUPPORTS_SAVE )
+
+
// these 3 are all the same revision, only the region byte differs
GAME( 1989, tokia, toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation", "Toki (World, set 2)", MACHINE_SUPPORTS_SAVE )
GAME( 1989, tokiua,toki, tokie, toki, toki_state, toki, ROT0, "TAD Corporation (Fabtek license)", "Toki (US, set 2)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/tourvis.cpp b/src/mame/drivers/tourvis.cpp
index 769171d5b2f..153c8f6e2ce 100644
--- a/src/mame/drivers/tourvis.cpp
+++ b/src/mame/drivers/tourvis.cpp
@@ -92,13 +92,12 @@
USA Pro Basketball
Veigues
* Vigilante
- # Volfied
+ Volfied
W-Ring
Winning Shot
Xevious
* Denotes Not Dumped
-# Denotes Redump Needed
_______________________________________________________________________________________________________________________________________________
| |
@@ -1008,7 +1007,7 @@ ROM_END
/* Volfied - Taito */
ROM_START(tvvolfd)
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD( "tourv_volfd.bin", 0x00000, 0x100000, BAD_DUMP CRC(c33efba5) SHA1(41ad4f85e551321487be61e2adbeae67e65c47de) )
+ ROM_LOAD( "tourv_volfd.bin", 0x00000, 0x100000, CRC(6349113d) SHA1(b413342122409ea4ed981bd5077285cdcf337890) )
TOURVISION_BIOS
ROM_END
diff --git a/src/mame/includes/mcr3.h b/src/mame/includes/mcr3.h
index dbfcb3529e9..18e2b688d09 100644
--- a/src/mame/includes/mcr3.h
+++ b/src/mame/includes/mcr3.h
@@ -33,7 +33,6 @@ public:
tilemap_t *m_bg_tilemap;
tilemap_t *m_alpha_tilemap;
- DECLARE_WRITE8_MEMBER(spyhuntpr_paletteram_w);
DECLARE_WRITE8_MEMBER(mcr3_videoram_w);
DECLARE_WRITE8_MEMBER(spyhunt_videoram_w);
DECLARE_WRITE8_MEMBER(spyhunt_alpharam_w);
@@ -67,7 +66,6 @@ public:
DECLARE_DRIVER_INIT(maxrpm);
DECLARE_DRIVER_INIT(rampage);
DECLARE_DRIVER_INIT(spyhunt);
- DECLARE_DRIVER_INIT(spyhuntpr);
DECLARE_DRIVER_INIT(sarge);
TILE_GET_INFO_MEMBER(mcrmono_get_bg_tile_info);
TILEMAP_MAPPER_MEMBER(spyhunt_bg_scan);
@@ -75,14 +73,10 @@ public:
TILE_GET_INFO_MEMBER(spyhunt_get_alpha_tile_info);
DECLARE_VIDEO_START(mcrmono);
DECLARE_VIDEO_START(spyhunt);
- DECLARE_VIDEO_START(spyhuntpr);
DECLARE_PALETTE_INIT(spyhunt);
UINT32 screen_update_mcr3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
UINT32 screen_update_spyhunt(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- UINT32 screen_update_spyhuntpr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void mcr3_update_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int color_mask, int code_xor, int dx, int dy, int interlaced);
void mcr_common_init();
- DECLARE_WRITE8_MEMBER(spyhuntpr_port04_w);
- DECLARE_WRITE8_MEMBER(spyhuntpr_fd00_w);
};
diff --git a/src/mame/includes/xbox.h b/src/mame/includes/xbox.h
index 5022fda6b7b..0dd37a23405 100644
--- a/src/mame/includes/xbox.h
+++ b/src/mame/includes/xbox.h
@@ -261,7 +261,7 @@ class ohci_function_device {
public:
ohci_function_device(running_machine &machine);
void execute_reset();
- int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size) ;
+ int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size);
protected:
virtual int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { return -1; };
virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) { return 0; };
@@ -269,6 +269,8 @@ protected:
virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) { return 0; };
virtual int handle_set_descriptor_request(int endpoint, USBSetupPacket *setup) { return 0; };
virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; };
+ virtual void handle_status_stage(int endpoint) { return; };
+ virtual int handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) { return 0; };
void add_device_descriptor(const USBStandardDeviceDescriptor &descriptor);
void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor);
@@ -297,6 +299,7 @@ protected:
int configurationvalue;
UINT8 *descriptors;
int descriptors_pos;
+ bool wantstatuscallback;
USBStandardDeviceDescriptor device_descriptor;
std::forward_list<usb_device_configuration *> configurations;
std::forward_list<usb_device_string *> device_strings;
@@ -323,6 +326,8 @@ class ohci_hlean2131qc_device: public ohci_function_device
public:
ohci_hlean2131qc_device(running_machine &machine);
int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override;
+ int handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) override;
+ void set_region_base(UINT8 *data);
private:
static const USBStandardDeviceDescriptor devdesc;
static const USBStandardConfigurationDescriptor condesc;
@@ -340,6 +345,8 @@ private:
static const UINT8 strdesc0[];
static const UINT8 strdesc1[];
static const UINT8 strdesc2[];
+ int maximum_send;
+ UINT8 *region;
};
class ohci_hlean2131sc_device : public ohci_function_device
diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp
index 8924adf9cbf..295347c1d06 100644
--- a/src/mame/machine/xbox.cpp
+++ b/src/mame/machine/xbox.cpp
@@ -984,6 +984,7 @@ ohci_function_device::ohci_function_device(running_machine &machine)
endpoints[e].position = nullptr;
}
endpoints[0].type = ControlEndpoint;
+ wantstatuscallback = false;
settingaddress = false;
configurationvalue = 0;
selected_configuration = nullptr;
@@ -1253,13 +1254,22 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
if (pid == SetupPid) {
USBSetupPacket *p=(USBSetupPacket *)buffer;
+ // control transfers are done in 3 stages: first the setup stage, then an optional data stage, then a status stage
+ // so there are 3 cases:
+ // 1- control transfer with a data stage where the host sends data to the device
+ // in this case the sequence of pids transferred is control pid, data out pid, data in pid
+ // 2- control transfer with a data stage where the host receives data from the device
+ // in this case the sequence of pids transferred is control pid, data in pid, data out pid
+ // 3- control transfer without a data stage
+ // in this case the sequence of pids transferred is control pid, data in pid
// define direction 0:host->device 1:device->host
- // case == 1, IN data stage and OUT status stage
- // case == 0, OUT data stage and IN status stage
- // data stage is optional, IN status stage
+ // direction == 1 -> IN data stage and OUT status stage
+ // direction == 0 -> OUT data stage and IN status stage
+ // data stage not present -> IN status stage
endpoints[endpoint].controldirection = (p->bmRequestType & 128) >> 7;
endpoints[endpoint].controltype = (p->bmRequestType & 0x60) >> 5;
endpoints[endpoint].controlrecipient = p->bmRequestType & 0x1f;
+ wantstatuscallback = false;
if (endpoint == 0) {
endpoints[endpoint].position = nullptr;
// number of byte to transfer in data stage (0 no data stage)
@@ -1341,23 +1351,26 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
return handle_nonstandard_request(endpoint, p);
}
else if (pid == InPid) {
- if (endpoint == 0) {
+ if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) {
// if no data has been transferred (except for the setup stage)
// and the lenght of this IN transaction is 0
// assume this is the status stage
- if ((size == 0) && (endpoints[endpoint].remain == 0)) {
- if (settingaddress == true)
+ if ((endpoints[endpoint].remain == 0) && (size == 0)) {
+ if ((endpoint == 0) && (settingaddress == true))
{
// set of address is active at end of status stage
address = newaddress;
settingaddress = false;
state = AddressState;
}
+ if (wantstatuscallback == true)
+ handle_status_stage(endpoint);
+ wantstatuscallback = false;
return 0;
}
// case ==1, give data
// case ==0, nothing
- // if device->host
+ // if device->host, since InPid then this is data stage
if (endpoints[endpoint].controldirection == DeviceToHost) {
// data stage
if (size > endpoints[endpoint].remain)
@@ -1367,15 +1380,22 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
endpoints[endpoint].position = endpoints[endpoint].position + size;
endpoints[endpoint].remain = endpoints[endpoint].remain - size;
}
+ else {
+ if (wantstatuscallback == true)
+ handle_status_stage(endpoint);
+ wantstatuscallback = false;
+ }
}
+ else if (endpoints[endpoint].type == BulkEndpoint)
+ return handle_bulk_pid(endpoint, pid, buffer, size);
else
return -1;
}
else if (pid == OutPid) {
- if (endpoint == 0) {
+ if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) {
// case ==1, nothing
// case ==0, give data
- // if host->device
+ // if host->device, since OutPid then this is data stage
if (endpoints[endpoint].controldirection == HostToDevice) {
// data stage
if (size > endpoints[endpoint].remain)
@@ -1385,7 +1405,14 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U
endpoints[endpoint].position = endpoints[endpoint].position + size;
endpoints[endpoint].remain = endpoints[endpoint].remain - size;
}
+ else {
+ if (wantstatuscallback == true)
+ handle_status_stage(endpoint);
+ wantstatuscallback = false;
+ }
}
+ else if (endpoints[endpoint].type == BulkEndpoint)
+ return handle_bulk_pid(endpoint, pid, buffer, size);
else
return -1;
}
@@ -1454,25 +1481,43 @@ ohci_hlean2131qc_device::ohci_hlean2131qc_device(running_machine &machine) :
add_device_descriptor(devdesc);
add_configuration_descriptor(condesc);
add_interface_descriptor(intdesc);
- add_endpoint_descriptor(enddesc81);
- add_endpoint_descriptor(enddesc82);
- add_endpoint_descriptor(enddesc83);
- add_endpoint_descriptor(enddesc84);
- add_endpoint_descriptor(enddesc85);
+ // it is important to add the endpoints in the same order they are found in the device firmware
add_endpoint_descriptor(enddesc01);
add_endpoint_descriptor(enddesc02);
add_endpoint_descriptor(enddesc03);
add_endpoint_descriptor(enddesc04);
add_endpoint_descriptor(enddesc05);
+ add_endpoint_descriptor(enddesc81);
+ add_endpoint_descriptor(enddesc82);
+ add_endpoint_descriptor(enddesc83);
+ add_endpoint_descriptor(enddesc84);
+ add_endpoint_descriptor(enddesc85);
add_string_descriptor(strdesc0);
add_string_descriptor(strdesc1);
add_string_descriptor(strdesc2);
+ maximum_send = 0;
+ region = nullptr;
+}
+
+void ohci_hlean2131qc_device::set_region_base(UINT8 *data)
+{
+ region = data;
}
int ohci_hlean2131qc_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup)
{
if (endpoint != 0)
return -1;
+ printf("Control request: %x %x %x %x %x %x %x\n\r", endpoint, endpoints[endpoint].controldirection, setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength);
+ //if ((setup->bRequest == 0x18) && (setup->wValue == 0x8000))
+ if (setup->bRequest == 0x17)
+ {
+ maximum_send = setup->wIndex;
+ if (maximum_send > 0x40)
+ maximum_send = 0x40;
+ endpoints[2].remain = maximum_send;
+ endpoints[2].position = region + 0x2000 + setup->wValue;
+ }
for (int n = 0; n < setup->wLength; n++)
endpoints[endpoint].buffer[n] = 0xa0 ^ n;
endpoints[endpoint].buffer[0] = 0;
@@ -1481,6 +1526,20 @@ int ohci_hlean2131qc_device::handle_nonstandard_request(int endpoint, USBSetupPa
return 0;
}
+int ohci_hlean2131qc_device::handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size)
+{
+ printf("Bulk request: %x %d %x\n\r", endpoint, pid, size);
+ if ((endpoint == 2) && (pid == InPid))
+ {
+ if (size > endpoints[2].remain)
+ size = endpoints[2].remain;
+ memcpy(buffer, endpoints[2].position, size);
+ endpoints[2].position = endpoints[3].position + size;
+ endpoints[2].remain = endpoints[3].remain - size;
+ }
+ return size;
+}
+
//pc20
const USBStandardDeviceDescriptor ohci_hlean2131sc_device::devdesc = { 0x12,0x01,0x0100,0x60,0x01,0x00,0x40,0x0CA3,0x0003,0x0110,0x01,0x02,0x00,0x01 };
const USBStandardConfigurationDescriptor ohci_hlean2131sc_device::condesc = { 0x09,0x02,0x003C,0x01,0x01,0x00,0x80,0x96 };
@@ -1501,12 +1560,13 @@ ohci_hlean2131sc_device::ohci_hlean2131sc_device(running_machine &machine) :
add_device_descriptor(devdesc);
add_configuration_descriptor(condesc);
add_interface_descriptor(intdesc);
- add_endpoint_descriptor(enddesc81);
- add_endpoint_descriptor(enddesc82);
- add_endpoint_descriptor(enddesc83);
+ // it is important to add the endpoints in the same order they are found in the device firmware
add_endpoint_descriptor(enddesc01);
add_endpoint_descriptor(enddesc02);
add_endpoint_descriptor(enddesc03);
+ add_endpoint_descriptor(enddesc81);
+ add_endpoint_descriptor(enddesc82);
+ add_endpoint_descriptor(enddesc83);
add_string_descriptor(strdesc0);
add_string_descriptor(strdesc1);
add_string_descriptor(strdesc2);
@@ -2221,6 +2281,7 @@ void xbox_base_state::machine_start()
ohcist.timer->enable(false);
//usb_device = new ohci_game_controller_device(machine());
usb_device = new ohci_hlean2131qc_device(machine());
+ usb_device->set_region_base(memregion(":others")->base()); // temporary, should be in chihiro
//usb_device = new ohci_hlean2131sc_device(machine());
usb_ohci_plug(1, usb_device); // test connect
#endif
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 2c65ae0d192..b689e94997f 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -9935,8 +9935,8 @@ crgolfc // (c) 1984 Nasco Japan
crgolfhi // (c) 1984 Nasco Japan
@source:crimfght.cpp
-crimfght // GX821 (c) 1989 (US)
-crimfght2 // GX821 (c) 1989 (World)
+crimfght // GX821 (c) 1989 (World)
+crimfghtu // GX821 (c) 1989 (US)
crimfghtj // GX821 (c) 1989 (Japan)
@source:crospang.cpp
@@ -16757,6 +16757,9 @@ spelunkrj // (c) 1985 licensed from Broderbund
yanchamr // (c) 1986 (Japan)
youjyudn // (c) 1986 (Japan)
+@source:spartanxtec.cpp
+spartanxtec
+
@source:m63.cpp
atomboy // M63 (c) 1985 Irem + Memetron license
atomboya // M63 (c) 1985 Irem + Memetron license
@@ -34978,6 +34981,7 @@ tokia // (c) 1989 Tad (World)
tokib // bootleg
tokiu // (c) 1989 Tad + Fabtek license (US)
tokiua // (c) 1989 Tad + Fabtek license (US)
+tokip
@source:tokyocop.cpp
tokyocop // (c) 2003 (Arcade TV Game List - P.168, Right, 19 from bottom)
diff --git a/src/mame/video/mcr3.cpp b/src/mame/video/mcr3.cpp
index 9385307c12f..ecd8b72a49a 100644
--- a/src/mame/video/mcr3.cpp
+++ b/src/mame/video/mcr3.cpp
@@ -125,40 +125,8 @@ VIDEO_START_MEMBER(mcr3_state,spyhunt)
save_item(NAME(m_spyhunt_scroll_offset));
}
-VIDEO_START_MEMBER(mcr3_state,spyhuntpr)
-{
- /* initialize the background tilemap */
- m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(mcr3_state::spyhunt_get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(mcr3_state::spyhunt_bg_scan),this), 64,16, 64,32);
- /* initialize the text tilemap */
- m_alpha_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(mcr3_state::spyhunt_get_alpha_tile_info),this), TILEMAP_SCAN_COLS, 16,8, 32,32);
- m_alpha_tilemap->set_transparent_pen(0);
- m_alpha_tilemap->set_scrollx(0, 16);
- save_item(NAME(m_spyhunt_sprite_color_mask));
- save_item(NAME(m_spyhunt_scrollx));
- save_item(NAME(m_spyhunt_scrolly));
- save_item(NAME(m_spyhunt_scroll_offset));
-}
-
-
-/*************************************
- *
- * Palette RAM writes
- *
- *************************************/
-
-WRITE8_MEMBER(mcr3_state::spyhuntpr_paletteram_w)
-{
- m_paletteram[offset] = data;
- offset = (offset & 0x0f) | (offset & 0x60) >> 1;
-
- int r = (data & 0x07) >> 0;
- int g = (data & 0x38) >> 3;
- int b = (data & 0xc0) >> 6;
-
- m_palette->set_pen_color(offset^0xf, rgb_t(r<<5,g<<5,b<<6));
-}
/*************************************
@@ -326,19 +294,3 @@ UINT32 mcr3_state::screen_update_spyhunt(screen_device &screen, bitmap_ind16 &bi
return 0;
}
-
-UINT32 mcr3_state::screen_update_spyhuntpr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- /* for every character in the Video RAM, check if it has been modified */
- /* since last time and update it accordingly. */
- m_bg_tilemap->set_scrollx(0, m_spyhunt_scrollx * 2 + m_spyhunt_scroll_offset);
- m_bg_tilemap->set_scrolly(0, m_spyhunt_scrolly * 2);
- m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
-
- /* draw the sprites */
- mcr3_update_sprites(screen, bitmap, cliprect, m_spyhunt_sprite_color_mask, 0, -12, 0, 0);
-
- /* render any characters on top */
- m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
- return 0;
-}
diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp
index a5e3fe6a54e..513a3cbfd70 100644
--- a/src/osd/modules/file/posixfile.cpp
+++ b/src/osd/modules/file/posixfile.cpp
@@ -88,7 +88,7 @@ public:
{
ssize_t result;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(__ANDROID__)
result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset)));
#elif defined(WIN32) || defined(SDLMAME_NO64BITIO)
if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0)
@@ -109,7 +109,7 @@ public:
{
ssize_t result;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(__ANDROID__)
result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset)));
#elif defined(WIN32) || defined(SDLMAME_NO64BITIO)
if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0)
@@ -130,7 +130,7 @@ public:
{
int result;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
result = ::ftruncate(m_fd, off_t(std::make_unsigned_t<off_t>(offset)));
#else
result = ::ftruncate64(m_fd, off64_t(offset));
@@ -236,7 +236,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
// attempt to open the file
int fd = -1;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
fd = ::open(dst.c_str(), access, 0666);
#else
fd = ::open64(dst.c_str(), access, 0666);
@@ -256,7 +256,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
// attempt to reopen the file
if (error == osd_file::error::NONE)
{
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
fd = ::open(dst.c_str(), access, 0666);
#else
fd = ::open64(dst.c_str(), access, 0666);
@@ -273,7 +273,7 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
}
// get the file size
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
struct stat st;
if (::fstat(fd, &st) < 0)
#else
@@ -340,7 +340,7 @@ int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UIN
osd_directory_entry *osd_stat(const std::string &path)
{
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
struct stat st;
int const err = ::stat(path.c_str(), &st);
#else
diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp
index b84838c0578..f7842574312 100644
--- a/src/osd/modules/file/posixptty.cpp
+++ b/src/osd/modules/file/posixptty.cpp
@@ -22,7 +22,7 @@
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <termios.h>
#include <libutil.h>
-#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__ANDROID__)
#include <termios.h>
#include <util.h>
#elif defined(__linux__) || defined(EMSCRIPTEN)
@@ -141,7 +141,10 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
::close(masterfd);
return errno_to_file_error(err);
}
-#else
+#elif defined(__ANDROID__)
+ int masterfd = -1, slavefd = -1;
+ char slavepath[PATH_MAX];
+#else
struct termios tios;
std::memset(&tios, 0, sizeof(tios));
::cfmakeraw(&tios);
diff --git a/src/osd/modules/font/font_sdl.cpp b/src/osd/modules/font/font_sdl.cpp
index c6f45635623..c5a73b0a541 100644
--- a/src/osd/modules/font/font_sdl.cpp
+++ b/src/osd/modules/font/font_sdl.cpp
@@ -8,7 +8,7 @@
#include "font_module.h"
#include "modules/osdmodule.h"
-#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU)
+#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_SOLARIS) && !defined(SDLMAME_HAIKU) && !defined(SDLMAME_ANDROID)
#include "corestr.h"
#include "corealloc.h"
diff --git a/src/osd/modules/render/bgfx/chainentry.cpp b/src/osd/modules/render/bgfx/chainentry.cpp
index ff56559e430..f3bbbb42378 100644
--- a/src/osd/modules/render/bgfx/chainentry.cpp
+++ b/src/osd/modules/render/bgfx/chainentry.cpp
@@ -179,7 +179,7 @@ bool bgfx_chain_entry::setup_view(int view, uint16_t screen_width, uint16_t scre
bx::mtxOrtho(projMat, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
bgfx::setViewTransform(view, nullptr, projMat);
- bgfx::setViewClear(view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00ff00ff, 1.0f, 0);
+ bgfx::setViewClear(view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0);
return true;
}
diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp
index 3ef04cbf5cf..d955f8c76f2 100644
--- a/src/osd/modules/render/drawbgfx.cpp
+++ b/src/osd/modules/render/drawbgfx.cpp
@@ -5,10 +5,6 @@
// drawbgfx.cpp - BGFX renderer
//
//============================================================
-#define __STDC_LIMIT_MACROS
-#define __STDC_FORMAT_MACROS
-#define __STDC_CONSTANT_MACROS
-
#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS)
// standard windows headers
#define WIN32_LEAN_AND_MEAN
@@ -65,6 +61,7 @@ const char* renderer_bgfx::WINDOW_PREFIX = "Window 0, ";
//============================================================
#define GIBBERISH (0)
+#define SCENE_VIEW (0)
//============================================================
// STATICS
@@ -95,7 +92,7 @@ static void* sdlNativeWindowHandle(SDL_Window* _window)
return wmi.info.win.window;
# elif BX_PLATFORM_STEAMLINK
return wmi.info.vivante.window;
-# elif BX_PLATFORM_EMSCRIPTEN
+# elif BX_PLATFORM_EMSCRIPTEN || BX_PLATFORM_ANDROID
return nullptr;
# endif // BX_PLATFORM_
}
@@ -304,8 +301,13 @@ void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, ScreenV
v0 += 0.5f / float(CACHE_SIZE);
UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255);
- float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 };
- float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 };
+ const float x0 = prim->bounds.x0;
+ const float x1 = prim->bounds.x1;
+ const float y0 = prim->bounds.y0;
+ const float y1 = prim->bounds.y1;
+
+ float x[4] = { x0, x1, x0, x1 };
+ float y[4] = { y0, y0, y1, y1 };
float u[4] = { u0, u1, u0, u1 };
float v[4] = { v0, v0, v1, v1 };
@@ -410,28 +412,6 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg
float u[4] = { prim->texcoords.tl.u, prim->texcoords.tr.u, prim->texcoords.bl.u, prim->texcoords.br.u };
float v[4] = { prim->texcoords.tl.v, prim->texcoords.tr.v, prim->texcoords.bl.v, prim->texcoords.br.v };
- if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_SWAP_XY)
- {
- std::swap(u[1], u[2]);
- std::swap(v[1], v[2]);
- }
-
- if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_FLIP_X)
- {
- std::swap(u[0], u[1]);
- std::swap(v[0], v[1]);
- std::swap(u[2], u[3]);
- std::swap(v[2], v[3]);
- }
-
- if (false)//PRIMFLAG_GET_TEXORIENT(prim->flags) & ORIENTATION_FLIP_Y)
- {
- std::swap(u[0], u[2]);
- std::swap(v[0], v[2]);
- std::swap(u[1], u[3]);
- std::swap(v[1], v[3]);
- }
-
vertex[0].m_x = x[0];
vertex[0].m_y = y[0];
vertex[0].m_z = 0;
@@ -480,7 +460,7 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg
m_screen_effect[blend]->submit(view);
}
-void renderer_bgfx::render_textured_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer)
+void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer)
{
ScreenVertex* vertex = reinterpret_cast<ScreenVertex*>(buffer->data);
@@ -547,7 +527,7 @@ void renderer_bgfx::render_textured_quad(int view, render_primitive* prim, bgfx:
UINT32 blend = PRIMFLAG_GET_BLENDMODE(prim->flags);
bgfx::setVertexBuffer(buffer);
bgfx::setTexture(0, effects[blend]->uniform("s_tex")->handle(), texture);
- effects[blend]->submit(view);
+ effects[blend]->submit(m_ui_view);
bgfx::destroyTexture(texture);
}
@@ -847,63 +827,29 @@ int renderer_bgfx::draw(int update)
s_current_view = 0;
}
- handle_screen_chains();
- int view_index = s_current_view;
+ m_ui_view = -1;
// Set view 0 default viewport.
osd_dim wdim = window().get_size();
m_width[window_index] = wdim.width();
m_height[window_index] = wdim.height();
- if (window_index == 0)
+ handle_screen_chains();
+
+ bool skip_frame = update_dimensions();
+ if (skip_frame)
{
- if ((m_dimensions != osd_dim(m_width[window_index], m_height[window_index])))
- {
- bgfx::reset(m_width[window_index], m_height[window_index], video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE);
- m_dimensions = osd_dim(m_width[window_index], m_height[window_index]);
- }
+ return 0;
}
- else
- {
- if ((m_dimensions != osd_dim(m_width[window_index], m_height[window_index])))
- {
- bgfx::reset(window().m_main->get_size().width(), window().m_main->get_size().height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE);
- delete m_framebuffer;
-#ifdef OSD_WINDOWS
- m_framebuffer = m_targets->create_backbuffer(window().m_hwnd, m_width[window_index], m_height[window_index]);
-#else
- m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(window().sdl_window()), m_width[window_index], m_height[window_index]);
-#endif
- bgfx::setViewFrameBuffer(view_index, m_framebuffer->target());
- m_dimensions = osd_dim(m_width[window_index], m_height[window_index]);
- bgfx::setViewClear(view_index
- , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
- , 0x00ff00ff
- , 1.0f
- , 0
- );
- bgfx::touch(view_index);
- bgfx::frame();
- return 0;
- }
- bgfx::setViewFrameBuffer(view_index, m_framebuffer->target());
+ if (s_current_view > m_max_view)
+ {
+ m_max_view = s_current_view;
+ }
+ else
+ {
+ s_current_view = m_max_view;
}
-
- bgfx::setViewSeq(view_index, true);
- bgfx::setViewRect(view_index, 0, 0, m_width[window_index], m_height[window_index]);
-
- // Setup view transform.
- float proj[16];
- bx::mtxOrtho(proj, 0.0f, m_width[window_index], m_height[window_index], 0.0f, 0.0f, 100.0f);
- bgfx::setViewTransform(view_index, nullptr, proj);
-
- bgfx::setViewClear(view_index
- , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
- , 0x000000ff
- , 1.0f
- , 0
- );
window().m_primlist->acquire_lock();
@@ -919,7 +865,7 @@ int renderer_bgfx::draw(int update)
bgfx::TransientVertexBuffer buffer;
allocate_buffer(prim, blend, &buffer);
- int32_t screen = 0;
+ int32_t screen = -1;
if (PRIMFLAG_GET_SCREENTEX(prim->flags))
{
for (screen = 0; screen < screens.size(); screen++)
@@ -935,13 +881,13 @@ int renderer_bgfx::draw(int update)
}
}
- buffer_status status = buffer_primitives(view_index, atlas_valid, &prim, &buffer, screen);
+ buffer_status status = buffer_primitives(atlas_valid, &prim, &buffer, screen);
if (status != BUFFER_EMPTY && status != BUFFER_SCREEN)
{
bgfx::setVertexBuffer(&buffer);
bgfx::setTexture(0, m_gui_effect[blend]->uniform("s_tex")->handle(), m_texture_cache->texture());
- m_gui_effect[blend]->submit(view_index);
+ m_gui_effect[blend]->submit(m_ui_view);
}
if (status != BUFFER_DONE && status != BUFFER_PRE_FLUSH)
@@ -954,7 +900,7 @@ int renderer_bgfx::draw(int update)
// This dummy draw call is here to make sure that view 0 is cleared
// if no other draw calls are submitted to view 0.
- bgfx::touch(view_index);
+ bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0);
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
@@ -963,12 +909,113 @@ int renderer_bgfx::draw(int update)
bgfx::frame();
}
- s_current_view++;
-
return 0;
}
-renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen)
+bool renderer_bgfx::update_dimensions()
+{
+ const uint32_t window_index = window().m_index;
+ const uint32_t width = m_width[window_index];
+ const uint32_t height = m_height[window_index];
+
+ if (window_index == 0)
+ {
+ if ((m_dimensions != osd_dim(width, height)))
+ {
+ bgfx::reset(width, height, video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE);
+ m_dimensions = osd_dim(width, height);
+ }
+ }
+ else
+ {
+ if ((m_dimensions != osd_dim(width, height)))
+ {
+ bgfx::reset(window().m_main->get_size().width(), window().m_main->get_size().height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE);
+ m_dimensions = osd_dim(width, height);
+
+ delete m_framebuffer;
+#ifdef OSD_WINDOWS
+ m_framebuffer = m_targets->create_backbuffer(window().m_hwnd, width, height);
+#else
+ m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(window().sdl_window()), width, height);
+#endif
+
+ bgfx::setViewFrameBuffer(s_current_view, m_framebuffer->target());
+ bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0);
+ bgfx::touch(s_current_view);
+ bgfx::frame();
+ return true;
+ }
+ }
+ return false;
+}
+
+void renderer_bgfx::setup_view(uint32_t view_index, bool screen)
+{
+ const uint32_t window_index = window().m_index;
+ const uint32_t width = m_width[window_index];
+ const uint32_t height = m_height[window_index];
+
+ if (window_index != 0)
+ {
+ bgfx::setViewFrameBuffer(view_index, m_framebuffer->target());
+ }
+
+ bgfx::setViewSeq(view_index, true);
+ bgfx::setViewRect(view_index, 0, 0, width, height);
+
+#if SCENE_VIEW
+ if (view_index == m_max_view)
+#endif
+ {
+ bgfx::setViewClear(view_index, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0);
+ }
+
+ setup_matrices(view_index, screen);
+}
+
+void renderer_bgfx::setup_matrices(uint32_t view_index, bool screen)
+{
+ const uint32_t window_index = window().m_index;
+ const uint32_t width = m_width[window_index];
+ const uint32_t height = m_height[window_index];
+
+ float proj[16];
+ float view[16];
+ if (screen)
+ {
+ static float offset = 0.0f;
+ offset += 0.5f;
+ float up[3] = { 0.0f, -1.0f, 0.0f };
+ float cam_z = width * 0.5f * (float(height) / float(width));
+ cam_z *= 1.05f;
+ float eye_height = height * 0.5f * 1.05f;
+ float at[3] = { width * 0.5f, height * 0.5f, 0.0f };
+ float eye[3] = { width * 0.5f, eye_height, cam_z };
+ bx::mtxLookAt(view, eye, at, up);
+
+ bx::mtxProj(proj, 90.0f, float(width) / float(height), 0.1f, 5000.0f);
+ }
+ else
+ {
+ bx::mtxIdentity(view);
+ bx::mtxOrtho(proj, 0.0f, width, height, 0.0f, 0.0f, 100.0f);
+ }
+
+ bgfx::setViewTransform(view_index, view, proj);
+}
+
+void renderer_bgfx::init_ui_view()
+{
+ if (m_ui_view < 0)
+ {
+ m_ui_view = s_current_view;
+ setup_view(m_ui_view, false);
+ s_current_view++;
+ }
+}
+
+renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen)
{
int vertices = 0;
@@ -978,6 +1025,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl
switch ((*prim)->type)
{
case render_primitive::LINE:
+ init_ui_view();
put_line((*prim)->bounds.x0, (*prim)->bounds.y0, (*prim)->bounds.x1, (*prim)->bounds.y1, 1.0f, u32Color((*prim)->color.r * 255, (*prim)->color.g * 255, (*prim)->color.b * 255, (*prim)->color.a * 255), (ScreenVertex*)buffer->data + vertices, 1.0f);
vertices += 30;
break;
@@ -985,6 +1033,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl
case render_primitive::QUAD:
if ((*prim)->texture.base == nullptr)
{
+ init_ui_view();
put_packed_quad(*prim, WHITE_HASH, (ScreenVertex*)buffer->data + vertices);
vertices += 6;
}
@@ -993,6 +1042,7 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl
const UINT32 hash = get_texture_hash(*prim);
if (atlas_valid && (*prim)->packable(PACKABLE_SIZE) && hash != 0 && m_hash_to_entry[hash].hash())
{
+ init_ui_view();
put_packed_quad(*prim, hash, (ScreenVertex*)buffer->data + vertices);
vertices += 6;
}
@@ -1005,12 +1055,21 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(int view, bool atl
if (PRIMFLAG_GET_SCREENTEX((*prim)->flags) && m_screen_chains.size() > window().m_index && screen < m_screen_chains[window().m_index].size())
{
- render_post_screen_quad(view, *prim, buffer, screen);
+#if SCENE_VIEW
+ setup_view(s_current_view, true);
+ render_post_screen_quad(s_current_view, *prim, buffer, screen);
+ s_current_view++;
+ m_ui_view = -1;
+#else
+ init_ui_view();
+ render_post_screen_quad(m_ui_view, *prim, buffer, screen);
+#endif
return BUFFER_SCREEN;
}
else
{
- render_textured_quad(view, *prim, buffer);
+ init_ui_view();
+ render_textured_quad(*prim, buffer);
return BUFFER_EMPTY;
}
}
diff --git a/src/osd/modules/render/drawbgfx.h b/src/osd/modules/render/drawbgfx.h
index 95cd613bb2f..823472f5c4a 100644
--- a/src/osd/modules/render/drawbgfx.h
+++ b/src/osd/modules/render/drawbgfx.h
@@ -30,6 +30,7 @@ public:
renderer_bgfx(osd_window *w)
: osd_renderer(w, FLAG_NONE)
, m_dimensions(0, 0)
+ , m_max_view(0)
{
}
virtual ~renderer_bgfx();
@@ -64,6 +65,11 @@ private:
void parse_screen_chains(std::string chain_str);
bgfx_chain* screen_chain(int32_t screen);
+ bool update_dimensions();
+ void setup_view(uint32_t view_index, bool screen);
+ void init_ui_view();
+ void setup_matrices(uint32_t view_index, bool screen);
+
void allocate_buffer(render_primitive *prim, UINT32 blend, bgfx::TransientVertexBuffer *buffer);
enum buffer_status
{
@@ -73,10 +79,10 @@ private:
BUFFER_EMPTY,
BUFFER_DONE
};
- buffer_status buffer_primitives(int view, bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);
+ buffer_status buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);
void process_screen_quad(int view, render_primitive* prim);
- void render_textured_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer);
+ void render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer);
void render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);
void put_packed_quad(render_primitive *prim, UINT32 hash, ScreenVertex* vertex);
@@ -117,6 +123,8 @@ private:
uint32_t m_width[16];
uint32_t m_height[16];
uint32_t m_white[16*16];
+ int32_t m_ui_view;
+ uint32_t m_max_view;
static const uint16_t CACHE_SIZE;
static const uint32_t PACKABLE_SIZE;
diff --git a/src/osd/sdl/sdldir.cpp b/src/osd/sdl/sdldir.cpp
index 439eb0a9792..abf1f126b94 100644
--- a/src/osd/sdl/sdldir.cpp
+++ b/src/osd/sdl/sdldir.cpp
@@ -50,7 +50,7 @@
#define INVPATHSEPCH '\\'
#endif
-#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_EMSCRIPTEN)
+#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_EMSCRIPTEN) || defined(SDLMAME_ANDROID)
typedef struct dirent sdl_dirent;
typedef struct stat sdl_stat;
#define sdl_readdir readdir
diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp
index ad71a48aa08..ef4c6b7c927 100644
--- a/src/osd/sdl/sdlmain.cpp
+++ b/src/osd/sdl/sdlmain.cpp
@@ -10,7 +10,7 @@
#ifdef SDLMAME_UNIX
-#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_EMSCRIPTEN))
+#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID))
#ifndef SDLMAME_HAIKU
#include <fontconfig/fontconfig.h>
#endif
@@ -202,7 +202,7 @@ int main(int argc, char *argv[])
#ifdef SDLMAME_UNIX
sdl_entered_debugger = 0;
-#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN))
+#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID))
FcInit();
#endif
#endif
@@ -216,7 +216,7 @@ int main(int argc, char *argv[])
}
#ifdef SDLMAME_UNIX
-#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN))
+#if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(SDLMAME_ANDROID))
if (!sdl_entered_debugger)
{
FcFini();
diff --git a/src/osd/sdl/sdlos_unix.cpp b/src/osd/sdl/sdlos_unix.cpp
index 23080512e91..82e11ebc07c 100644
--- a/src/osd/sdl/sdlos_unix.cpp
+++ b/src/osd/sdl/sdlos_unix.cpp
@@ -23,6 +23,12 @@
// MAME headers
#include "osdcore.h"
+#ifdef SDLMAME_ANDROID
+char *osd_get_clipboard_text(void)
+{
+ return nullptr;
+}
+#else
//============================================================
// osd_get_clipboard_text
//============================================================
@@ -40,3 +46,5 @@ char *osd_get_clipboard_text(void)
}
return result;
}
+
+#endif \ No newline at end of file
diff --git a/src/osd/sdl/sdlprefix.h b/src/osd/sdl/sdlprefix.h
index 2acc6a9d98e..9ba0001ccc5 100644
--- a/src/osd/sdl/sdlprefix.h
+++ b/src/osd/sdl/sdlprefix.h
@@ -70,6 +70,10 @@
struct _IO_FILE {}; //_IO_FILE is an opaque type in the emscripten libc which makes clang cranky
#endif
+#if defined(__ANDROID__)
+#define SDLMAME_ANDROID 1
+#endif
+
// fix for Ubuntu 8.10
#ifdef _FORTIFY_SOURCE
#undef _FORTIFY_SOURCE