summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/bus.lua4
-rw-r--r--scripts/src/sound.lua13
-rw-r--r--src/devices/bus/ata/atapicdr.cpp6
-rw-r--r--src/devices/bus/ata/atapicdr.h2
-rw-r--r--src/devices/bus/ata/atapihle.cpp11
-rw-r--r--src/devices/bus/ata/atapihle.h5
-rw-r--r--src/devices/machine/intelfsh.cpp39
-rw-r--r--src/devices/machine/intelfsh.h9
-rw-r--r--src/devices/sound/stt_sa1.cpp190
-rw-r--r--src/devices/sound/stt_sa1.h57
-rw-r--r--src/mame/mame.lst6
-rw-r--r--src/mame/misc/shambros.cpp110
-rw-r--r--src/mame/misc/sttechno.cpp622
13 files changed, 948 insertions, 126 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 13d50f2e0e2..cb9463a2afc 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -506,10 +506,10 @@ if (BUSES["ATA"]~=null) then
MAME_DIR .. "src/devices/bus/ata/cp2024.h",
MAME_DIR .. "src/devices/bus/ata/cr589.cpp",
MAME_DIR .. "src/devices/bus/ata/cr589.h",
- MAME_DIR .. "src/devices/bus/ata/hdd.cpp",
- MAME_DIR .. "src/devices/bus/ata/hdd.h",
MAME_DIR .. "src/devices/bus/ata/gdrom.cpp",
MAME_DIR .. "src/devices/bus/ata/gdrom.h",
+ MAME_DIR .. "src/devices/bus/ata/hdd.cpp",
+ MAME_DIR .. "src/devices/bus/ata/hdd.h",
MAME_DIR .. "src/devices/bus/ata/px320a.cpp",
MAME_DIR .. "src/devices/bus/ata/px320a.h",
MAME_DIR .. "src/devices/bus/ata/zip100.cpp",
diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua
index ed9652835b2..fe1b86137cd 100644
--- a/scripts/src/sound.lua
+++ b/scripts/src/sound.lua
@@ -969,6 +969,19 @@ end
---------------------------------------------------
+-- ST-Techno custom sound chip
+--@src/devices/sound/stt_sa1.h,SOUNDS["STT_SA1"] = true
+---------------------------------------------------
+
+if (SOUNDS["STT_SA1"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/sound/stt_sa1.cpp",
+ MAME_DIR .. "src/devices/sound/stt_sa1.h",
+ }
+end
+
+
+---------------------------------------------------
-- S14001A speech synthesizer
--@src/devices/sound/s14001a.h,SOUNDS["S14001A"] = true
---------------------------------------------------
diff --git a/src/devices/bus/ata/atapicdr.cpp b/src/devices/bus/ata/atapicdr.cpp
index 9d2be8d51c5..61a55bca4c2 100644
--- a/src/devices/bus/ata/atapicdr.cpp
+++ b/src/devices/bus/ata/atapicdr.cpp
@@ -22,7 +22,7 @@ atapi_cdrom_device::atapi_cdrom_device(const machine_config &mconfig, const char
atapi_cdrom_device::atapi_cdrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
atapi_hle_device(mconfig, type, tag, owner, clock),
device_ata_interface(mconfig, *this),
- ultra_dma_mode(0)
+ m_ultra_dma_mode(0)
{
}
@@ -98,14 +98,14 @@ void atapi_cdrom_device::device_start()
m_identify_buffer[ 49 ] = 0x0600; // Word 49=Capabilities, IORDY may be disabled (bit_10), LBA Supported mandatory (bit_9)
- m_identify_buffer[ 88 ] = ultra_dma_mode;
+ m_identify_buffer[ 88 ] = m_ultra_dma_mode;
atapi_hle_device::device_start();
}
void atapi_cdrom_device::set_ultra_dma_mode(uint16_t mode)
{
- ultra_dma_mode = mode;
+ m_ultra_dma_mode = mode;
}
void atapi_cdrom_device::device_reset()
diff --git a/src/devices/bus/ata/atapicdr.h b/src/devices/bus/ata/atapicdr.h
index a967fc52bf5..16c4a171517 100644
--- a/src/devices/bus/ata/atapicdr.h
+++ b/src/devices/bus/ata/atapicdr.h
@@ -56,7 +56,7 @@ protected:
virtual void ExecCommand() override;
u32 m_sequence_counter;
bool m_media_change;
- uint16_t ultra_dma_mode;
+ uint16_t m_ultra_dma_mode;
private:
// ata_hle_device_base implementation
diff --git a/src/devices/bus/ata/atapihle.cpp b/src/devices/bus/ata/atapihle.cpp
index 8b2f3fd0548..cb5712f69b3 100644
--- a/src/devices/bus/ata/atapihle.cpp
+++ b/src/devices/bus/ata/atapihle.cpp
@@ -6,7 +6,8 @@
atapi_hle_device::atapi_hle_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
ata_hle_device_base(mconfig, type, tag, owner, clock),
m_packet(0),
- m_data_size(0)
+ m_data_size(0),
+ m_is_ready(false)
{
}
@@ -22,6 +23,14 @@ void atapi_hle_device::device_reset()
ata_hle_device_base::device_reset();
}
+void atapi_hle_device::set_is_ready(bool state)
+{
+ if (has_running_machine() && (machine().phase() >= machine_phase::RESET))
+ throw emu_fatalerror("Static ready state should only be set during configuration");
+
+ m_is_ready = state;
+}
+
void atapi_hle_device::process_buffer()
{
if (m_packet)
diff --git a/src/devices/bus/ata/atapihle.h b/src/devices/bus/ata/atapihle.h
index 80a194afa62..8cfe47710f5 100644
--- a/src/devices/bus/ata/atapihle.h
+++ b/src/devices/bus/ata/atapihle.h
@@ -46,6 +46,8 @@ public:
PACKET_COMMAND_RESPONSE_DRQ_50US
};
+ void set_is_ready(bool state);
+
protected:
atapi_hle_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -55,7 +57,7 @@ protected:
virtual int sector_length() override { return ATAPI_BUFFER_LENGTH; }
virtual void process_buffer() override;
virtual void fill_buffer() override;
- virtual bool is_ready() override { return false; }
+ virtual bool is_ready() override { return m_is_ready; }
virtual void signature() override;
virtual void process_command() override;
virtual void finished_command() override;
@@ -70,6 +72,7 @@ private:
int m_packet;
int m_data_size;
+ bool m_is_ready;
static constexpr int ATAPI_BUFFER_LENGTH = 0xf800;
};
diff --git a/src/devices/machine/intelfsh.cpp b/src/devices/machine/intelfsh.cpp
index 4ec5315b47b..f0376b80d71 100644
--- a/src/devices/machine/intelfsh.cpp
+++ b/src/devices/machine/intelfsh.cpp
@@ -41,6 +41,7 @@ enum
FM_WRITEPAGEATMEL,
FM_WRITEBUFFER1, // part 1 of write to buffer sequence
FM_WRITEBUFFER2, // part 2 of write to buffer sequence
+ FM_FAST_RESET,
};
@@ -93,6 +94,7 @@ DEFINE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device, "amd_29f
DEFINE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device, "amd_29f800b_16bit", "AMD 29F800B Flash (16-bit)")
DEFINE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device, "amd_29lv200t", "AMD 29LV200T Flash")
DEFINE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device, "mbm29f160te", "Fujitsu MBM29F160TE Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29F160TE_16BIT,fujitsu_29f160te_16bit_device,"mbm29f160te_16bit", "Fujitsu MBM29F160TE Flash (16-bit)")
DEFINE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device, "mbm29f016a", "Fujitsu MBM29F016A Flash")
DEFINE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device, "mbm29dl164bd", "Fujitsu MBM29DL164BD Flash")
DEFINE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device, "mbm29lv002tc", "Fujitsu MBM29LV002TC Flash")
@@ -157,7 +159,8 @@ intelfsh_device::intelfsh_device(const machine_config &mconfig, device_type type
m_flash_mode(FM_NORMAL),
m_flash_master_lock(false),
m_timer(nullptr),
- m_bank(0)
+ m_bank(0),
+ m_fast_mode(false)
{
assert(bits == 8 || bits == 16);
assert(size != 0);
@@ -176,6 +179,9 @@ intel_28f016s5_device::intel_28f016s5_device(const machine_config &mconfig, cons
fujitsu_29f160te_device::fujitsu_29f160te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: intelfsh8_device(mconfig, FUJITSU_29F160TE, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xd2) { m_top_boot_sector = true; }
+fujitsu_29f160te_16bit_device::fujitsu_29f160te_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh16_device(mconfig, FUJITSU_29F160TE_16BIT, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xd2) { m_top_boot_sector = true; m_sector_is_4k = true; }
+
fujitsu_29f016a_device::fujitsu_29f016a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: intelfsh8_device(mconfig, FUJITSU_29F016A, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xad) { }
@@ -314,6 +320,7 @@ void intelfsh_device::device_start()
save_item( NAME(m_status) );
save_item( NAME(m_flash_mode) );
save_item( NAME(m_flash_master_lock) );
+ save_item( NAME(m_fast_mode) );
save_pointer( &m_data[0], "m_data", m_size);
}
@@ -548,8 +555,11 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
case 0xff: // reset chip mode
m_flash_mode = FM_NORMAL;
break;
- case 0x90: // read ID
- m_flash_mode = FM_READID;
+ case 0x90:
+ if ( m_fast_mode && m_maker_id == MFG_FUJITSU ) // reset from fast mode (when fast mode is enabled)
+ m_flash_mode = FM_FAST_RESET;
+ else // read ID
+ m_flash_mode = FM_READID;
break;
case 0x40:
case 0x10: // program
@@ -576,6 +586,12 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
case 0x70: // read status
m_flash_mode = FM_READSTATUS;
break;
+ case 0xa0: // fast program (fast mode must be enabled)
+ if ( m_fast_mode && m_maker_id == MFG_FUJITSU )
+ m_flash_mode = FM_BYTEPROGRAM;
+ else
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
+ break;
case 0xaa: // AMD ID select part 1
if( ( address & 0xfff ) == 0x555 )
{
@@ -591,10 +607,10 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
if ( m_maker_id == MFG_INTEL && m_device_id >= 0x14 && m_device_id <= 0x16 )
m_flash_mode = FM_WRITEBUFFER1;
else
- logerror( "Unknown flash mode byte %x\n", data & 0xff );
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
break;
default:
- logerror( "Unknown flash mode byte %x\n", data & 0xff );
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
break;
}
break;
@@ -701,6 +717,12 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
{
m_flash_mode = FM_NORMAL;
}
+ // Fast mode
+ else if( ( ( address & 0xfff ) == 0xaaa || ( address & 0xfff ) == 0x555 ) && ( data & 0xff ) == 0x20 )
+ {
+ m_flash_mode = FM_NORMAL;
+ m_fast_mode = true;
+ }
else
{
logerror( "unexpected %08x=%02x in FM_READAMDID2\n", address, data & 0xff );
@@ -1075,5 +1097,12 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
m_bank = data & 0xff;
m_flash_mode = FM_NORMAL;
break;
+ case FM_FAST_RESET:
+ if ( ( data & 0xff ) == 0xf0 || ( data & 0xff ) == 0 ) {
+ m_fast_mode = false;
+ m_flash_mode = FM_NORMAL;
+ } else
+ logerror( "unexpected %08x=%02x in FM_FAST_RESET:\n", address, data & 0xff );
+ break;
}
}
diff --git a/src/devices/machine/intelfsh.h b/src/devices/machine/intelfsh.h
index 711523bebe4..168b5e7baa0 100644
--- a/src/devices/machine/intelfsh.h
+++ b/src/devices/machine/intelfsh.h
@@ -62,6 +62,8 @@ protected:
uint8_t m_write_buffer[32];
uint32_t m_write_buffer_start_address;
uint32_t m_write_buffer_count;
+
+ bool m_fast_mode;
};
@@ -267,6 +269,12 @@ public:
};
// 16-bit variants
+class fujitsu_29f160te_16bit_device : public intelfsh16_device
+{
+public:
+ fujitsu_29f160te_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
class sharp_lh28f400_device : public intelfsh16_device
{
public:
@@ -365,6 +373,7 @@ DECLARE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device)
DECLARE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device)
DECLARE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device)
DECLARE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29F160TE_16BIT,fujitsu_29f160te_16bit_device)
DECLARE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device)
DECLARE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device)
DECLARE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device)
diff --git a/src/devices/sound/stt_sa1.cpp b/src/devices/sound/stt_sa1.cpp
new file mode 100644
index 00000000000..efd9e49e163
--- /dev/null
+++ b/src/devices/sound/stt_sa1.cpp
@@ -0,0 +1,190 @@
+// license:BSD-3-Clause
+// copyright-holders:windyfairy
+/*
+ ST-Techno STT-SA1 PCM sound chip
+ Originally implemented in an FPGA
+*/
+#include "emu.h"
+#include "stt_sa1.h"
+
+// #define VERBOSE (LOG_GENERAL)
+// #define LOG_OUTPUT_STREAM std::cout
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(STT_SA1, stt_sa1_device, "stt_sa1", "ST-Techno STT-SA1 Sound")
+
+stt_sa1_device::stt_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, STT_SA1, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , device_rom_interface(mconfig, *this)
+ , m_stream(nullptr)
+{
+}
+
+void stt_sa1_device::enable_w(uint16_t data)
+{
+ m_enabled = data != 0;
+}
+
+uint16_t stt_sa1_device::read(offs_t offset, uint16_t mem_mask)
+{
+ offset &= 0x7f;
+
+ return m_regs[offset]; // TODO: Should this return addr_cur for regs 1 and 2 instead?
+}
+
+void stt_sa1_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset &= 0x7f;
+ const int v = offset >> 4;
+ const int reg = offset & 0xf;
+
+ m_regs[offset] = data;
+
+ switch (reg) {
+ case 1:
+ m_voice[v].addr_start = m_voice[v].addr_cur = (m_voice[v].addr_cur & 0xffff0000000) | (uint64_t(data) << 12);
+ LOG("voice %d: start = %08llx\n", v, m_voice[v].addr_cur >> 12);
+ break;
+ case 2:
+ m_voice[v].addr_start = m_voice[v].addr_cur = (m_voice[v].addr_cur & 0x0000ffff000) | (uint64_t(data & 0x7fff) << 28);
+ m_voice[v].is_looped = BIT(data, 15) != 0;
+ LOG("voice %d: start = %08llx, is_looped = %d\n", v, m_voice[v].addr_cur >> 12, m_voice[v].is_looped);
+ break;
+
+ case 3:
+ m_voice[v].freq = data;
+ LOG("voice %d: step = %08x\n", v, m_voice[v].freq);
+ break;
+
+ case 4:
+ m_voice[v].addr_start = (m_voice[v].addr_start & 0xffff0000000) | (uint64_t(data) << 12);
+ LOG("voice %d: addr_start = %08llx\n", v, m_voice[v].addr_start >> 12);
+ break;
+ case 5:
+ m_voice[v].addr_start = (m_voice[v].addr_start & 0x0000ffff000) | (uint64_t(data) << 28);
+ LOG("voice %d: addr_start = %08llx\n", v, m_voice[v].addr_start >> 12);
+ break;
+
+ case 6:
+ m_voice[v].addr_end = (m_voice[v].addr_end & 0xffff0000000) | (uint64_t(data) << 12);
+ LOG("voice %d: addr_end = %08llx\n", v, m_voice[v].addr_end >> 12);
+ break;
+ case 7:
+ m_voice[v].addr_end = (m_voice[v].addr_end & 0x0000ffff000) | (uint64_t(data) << 28);
+ LOG("voice %d: addr_end = %08llx\n", v, m_voice[v].addr_end >> 12);
+ break;
+
+ case 0x0b:
+ m_voice[v].vol_l = data;
+ LOG("voice %d: vol_l = %08x\n", v, m_voice[v].vol_l);
+ break;
+ case 0x0c:
+ m_voice[v].vol_r = data;
+ LOG("voice %d: vol_r = %08x\n", v, m_voice[v].vol_r);
+ break;
+
+ default:
+ LOG("Unknown register usage: voice %d, register %x, data %04x\n", v, reg, data);
+ break;
+ }
+}
+
+uint16_t stt_sa1_device::key_r()
+{
+ if (!m_enabled)
+ return 0;
+
+ if (!machine().side_effects_disabled())
+ m_stream->update();
+
+ return m_keyctrl;
+}
+
+void stt_sa1_device::key_w(uint16_t data)
+{
+ if (!m_enabled)
+ return;
+
+ const u16 prev = m_keyctrl;
+
+ m_stream->update();
+
+ m_keyctrl = data;
+
+ for (int v = 0; v < 8; v++) {
+ if (BIT(m_keyctrl, v) && !BIT(prev, v)) {
+ // keyon
+ m_voice[v].enabled = true;
+ m_voice[v].addr_cur = m_voice[v].addr_start;
+ } else if (!BIT(m_keyctrl, v) && BIT(prev, v)) {
+ // keyoff
+ m_voice[v].enabled = false;
+ }
+ }
+}
+
+void stt_sa1_device::device_start()
+{
+ m_stream = stream_alloc(0, 2, clock() / 448);
+
+ save_item(STRUCT_MEMBER(m_voice, addr_start));
+ save_item(STRUCT_MEMBER(m_voice, addr_cur));
+ save_item(STRUCT_MEMBER(m_voice, addr_end));
+ save_item(STRUCT_MEMBER(m_voice, vol_l));
+ save_item(STRUCT_MEMBER(m_voice, vol_r));
+ save_item(STRUCT_MEMBER(m_voice, freq));
+ save_item(STRUCT_MEMBER(m_voice, is_looped));
+ save_item(STRUCT_MEMBER(m_voice, enabled));
+ save_item(NAME(m_keyctrl));
+ save_item(NAME(m_regs));
+ save_item(NAME(m_enabled));
+}
+
+void stt_sa1_device::device_reset()
+{
+ m_enabled = false;
+
+ std::fill(std::begin(m_regs), std::end(m_regs), 0);
+
+ for (int i = 0; i < 8; i++) {
+ m_voice[i].addr_start = 0;
+ m_voice[i].addr_cur = 0;
+ m_voice[i].addr_end = 0;
+ m_voice[i].vol_l = 0;
+ m_voice[i].vol_r = 0;
+ m_voice[i].freq = 0;
+ m_voice[i].is_looped = false;
+ m_voice[i].enabled = false;
+ }
+}
+
+void stt_sa1_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ outputs[0].fill(0);
+ outputs[1].fill(0);
+
+ for (int v = 0; v < 8; v++) {
+ voice_t &voice = m_voice[v];
+
+ for (int i = 0; i < outputs[0].samples() && voice.enabled; i++) {
+ const offs_t offset = voice.addr_cur >> 12;
+ const int sample = s8(read_byte(offset)) << 8;
+
+ voice.addr_cur += voice.freq;
+
+ outputs[0].add_int(i, (sample * voice.vol_l) >> 16, 32768 * 8);
+ outputs[1].add_int(i, (sample * voice.vol_r) >> 16, 32768 * 8);
+
+ if (voice.addr_cur >= voice.addr_end) {
+ if (!voice.is_looped) {
+ voice.enabled = false;
+ m_keyctrl &= ~(1 << v);
+ } else {
+ voice.addr_cur = voice.addr_start;
+ }
+ }
+ }
+ }
+}
diff --git a/src/devices/sound/stt_sa1.h b/src/devices/sound/stt_sa1.h
new file mode 100644
index 00000000000..8436c2f7f6c
--- /dev/null
+++ b/src/devices/sound/stt_sa1.h
@@ -0,0 +1,57 @@
+// license:BSD-3-Clause
+// copyright-holders:windyfairy
+#ifndef MAME_SOUND_STT_SA1_H
+#define MAME_SOUND_STT_SA1_H
+
+#pragma once
+
+#include "dirom.h"
+
+class stt_sa1_device : public device_t,
+ public device_sound_interface,
+ public device_rom_interface<24, 1, 0, ENDIANNESS_LITTLE>
+{
+public:
+ static constexpr feature_type imperfect_features() { return feature::SOUND; } // unemulated and/or unverified effects and envelopes
+
+ stt_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void enable_w(uint16_t data);
+
+ uint16_t read(offs_t offset, uint16_t mem_mask = ~0);
+ void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+ uint16_t key_r();
+ void key_w(uint16_t data);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ struct voice_t {
+ uint64_t addr_start;
+ uint64_t addr_end;
+ uint64_t addr_cur;
+ uint16_t vol_l;
+ uint16_t vol_r;
+ uint16_t freq;
+ bool is_looped;
+ bool enabled;
+ };
+
+ sound_stream *m_stream;
+
+ voice_t m_voice[8];
+ uint16_t m_keyctrl; // Key on/off control bit
+
+ uint16_t m_regs[128];
+
+ bool m_enabled;
+};
+
+DECLARE_DEVICE_TYPE(STT_SA1, stt_sa1_device)
+
+#endif // MAME_SOUND_STT_SA1_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 25c16ce3d40..c7603355ee9 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -31684,9 +31684,6 @@ version4v // (c) 2006 Amcoe
version4v2 // (c) 2006 Amcoe
version4v3 // (c) 2006 Amcoe
-@source:misc/shambros.cpp
-shambros
-
@source:misc/shangkid.cpp
chinhero // (c) 1984 Taiyo
chinhero2 // (c) 1984 Taiyo
@@ -31834,6 +31831,9 @@ stop
@source:misc/strkzn.cpp
strkzn // (c) 1994 Purple Star
+@source:misc/sttechno.cpp
+shambros
+
@source:misc/stuntair.cpp
stuntair // (c) 1983 Nuova Videotron
diff --git a/src/mame/misc/shambros.cpp b/src/mame/misc/shambros.cpp
deleted file mode 100644
index 3370380c066..00000000000
--- a/src/mame/misc/shambros.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:
-
-/*
-Kato's STV01 MainPCB Rev. C
-
-
-Only known game: Shamisen Brothers Vol 1 (2003)
-The game was also ported for Namco System 10
-
-The dumper only had the CD-ROM.
-A low quality picture of the PCB found on the internet shows:
-- M68K-based processor
-- program ROM
-- multiple flash chips
-- 3 FPGAs
-- Mitsumi CD drive
-
-TODO: only a placeholder for the CD dump for now
-*/
-
-#include "emu.h"
-
-#include "cpu/m68000/m68000.h"
-
-#include "emupal.h"
-#include "screen.h"
-#include "speaker.h"
-
-
-namespace {
-
-class shambros_state : public driver_device
-{
-public:
- shambros_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag)
- {}
-
- void shambros(machine_config &config) ATTR_COLD;
-
-private:
- uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
-};
-
-
-uint32_t shambros_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- return 0;
-}
-
-
-static INPUT_PORTS_START( shambros )
- PORT_START("IN0")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
-
- PORT_START("IN1")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
-
- // no dips on PCB
-INPUT_PORTS_END
-
-
-void shambros_state::shambros(machine_config &config)
-{
- M68000(config, "maincpu", 12'000'000); // exact type not known, XTAL unreadable
-
- // all wrong
- screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(60);
- screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
- screen.set_size(64*8, 32*8);
- screen.set_visarea_full();
- screen.set_screen_update(FUNC(shambros_state::screen_update));
- screen.set_palette("palette");
-
- PALETTE(config, "palette").set_entries(0x100); // wrong
-
- SPEAKER(config, "mono").front_center();
-}
-
-
-ROM_START( shambros )
- ROM_REGION(0x20000, "maincpu", 0)
- ROM_LOAD( "g112 v1.01.prg", 0x00000, 0x20000, NO_DUMP ) // actual size unknown
-
- // numerous undumped flash ROMs
-
- DISK_REGION( "cdrom" )
- DISK_IMAGE( "sb01-100", 0, SHA1(abd1d61871bcb4635acc691e35ec386823763ba2) )
-ROM_END
-
-} // anonymous namespace
-
-
-GAME( 2003, shambros, 0, shambros, shambros, shambros_state, empty_init, ROT0, "Kato's", "Shamisen Brothers Vol 1", MACHINE_IS_SKELETON )
diff --git a/src/mame/misc/sttechno.cpp b/src/mame/misc/sttechno.cpp
new file mode 100644
index 00000000000..ce82454e008
--- /dev/null
+++ b/src/mame/misc/sttechno.cpp
@@ -0,0 +1,622 @@
+// license:BSD-3-Clause
+// copyright-holders:windyfairy
+
+/*
+Only known game: Shamisen Brothers Vol 1 (2003)
+The game was also ported for Namco System 10
+
+Kato's STV01 MainPCB Rev. C
+ST-Techno PCB
+------------------------------------------------------------------------------------------
+| |
+| ------------- |
+| U18 U47 U45 U40 U39 U37 U31 | | |
+| | U6 | U30 |
+| U48 U44 U41 U38 U33 U32 | STT-SA1 | |
+| U19 | | |
+| U4 ------------- |
+| U27 U3 --------- U35 |
+| U5 U14 X2 | U36 | |
+| U13 | | U42 |
+| VR1 U16 ------------ --------- |
+| --------- | | ----------------------- |
+| | U29 | U17 | U15 | | U46 PRG ROM | |
+| | | | STT-GA1 | ----------------------- |
+| | | | | C |
+| | | ------------ -------- N |
+| | | U11 X1 | U34 | 1 |
+| | | U2 | GLU | |
+| | | | | |
+| --------- -------- |
+| |
+| U61 U1 U60 U43 U49 |
+| RESET |
+| |-----| (EDGE) |--| EDGE |------| CN3 CN2 |
+------| |--------| |------------------------------------| |---------------------
+
+X1: 33.3333 MHz
+X2: 42.95454 MHz
+
+U1 (TD62083F): Toshiba TD62083AF, 8ch high current darlington sink driver
+U2, U3, U4 (AM29F160): Fujitsu MBM29F160TE-70, 16 Megabit (2 M x 8-Bit/1 M x 16-Bit)
+U5 (BU9480): 9480F, 16-bit stereo D/A converter
+U6: STT-SA1, markings scratched off but patterns are similar to an Actel FPGA and is also 208 pins. Sound chip
+U11 (CXD1178Q): Sony CXD1178Q, 8-bit RGB 3-channel D/A converter
+U13, U14: Taiwan Memory Technology T14M256A, 32k x 8 high speed CMOS SRAM
+U15: STT-GA1 (custom chip? has heatsink), likely an FPGA, 240 pin. Graphics chip
+U16, U17 (T224160B): Taiwan Memory Technology T224160B, 256k x 16 DRAM
+U18, U19, U27 (NJM2904): 2904 2148B JRC, single-supply dual operational amplifier
+U29 (TA8210): Under large heatsink, sound amplifier?
+U30 (TA48M025F): 48M025F, three-terminal low dropout voltage regulator
+U31, U32, U33, U37, U38, U39, U40, U41, U44, U45, U47, U48 (HY628400): Toshiba TC554001, 512k x 8 SRAM
+U34 (GLU): Actel A54SX08A, 208 pin
+U35, U42 (HY628100): Hyundai HY628100B 0045A LT1-70, 128k x 8 CMOS SRAM
+U36 (68HC000): Toshiba TMP68HC000F-16
+U43 (PST594C): Mitsumi PST594C, system reset monolithic IC
+U45 (PRG ROM): MX A9630 27C4100DC-12 MR38674-1, labeled G112 V1.01
+U49: 74HC14A
+U60 (ST232ABD): MAX232A CSE 0107
+U61: Toshiba TD62064AF, 4ch high current darlington sink driver
+
+CN1: 40 pin IDE connector for CD-ROM
+CN2: 3 pin header, unused
+CN3: USB connector (JVS?)
+
+VR1: Sound pot
+
+CD-ROM: Mitsumi FX5400W ATAPI CD-ROM drive
+
+EDGE: EDGE28P x2side (56P) P=3.96mm connector. Not JAMMA.
+ Solder Side | Parts Side
+ GND - A | | 1 - GND
+ GND - B | | 2 - GND
+ +5V - C | | 3 - +5V
+ +5V - D | | 4 - +5V
+ +12V - E | | 5 - +12V
+ KEY - F | | 6 - KEY
+ METER2 - H | | 7 - METER1
+ LOCKOUT2 - J | | 8 - LOCKOUT1
+ COIN SW2 - K | | 9 - COIN SW1
+ 1P BG(-) - L | | 10 - 1P BG(+)
+ 2P BG(-) - M | | 11 - 2P BG(+)
+ VIDEO G - N | | 12 - VIDEO R
+VIDEO SYNC - P | | 13 - VIDEO B
+SERVICE SW - R | | 14 - VIDEO GND
+ EXT. IN - S | | 15 - TEST SW
+ 2P START - T | | 16 - 1P START
+ 2P UP - U | | 17 - 1P UP
+ 2P MID - V | | 18 - 1P MID
+ 2P LOW - W | | 19 - 1P LOW
+ 2P SHOT - X | | 20 - 1P SHOT
+ 2P DETECT - Y | | 21 - 1P DETECT
+ UP LAMP - Z | | 22 - SEL UP
+ DOWN LAMP - a | | 23 - SEL DOWN
+DECI. LAMP - b | | 24 - SEL DECI.
+ EXT. OUT0 - c | | 25 - COIN LAMP1
+ EXT. OUT1 - d | | 26 - COIN LAMP2
+ GND - e | | 27 - GND
+ GND - f | | 28 - GND
+
+
+Notes:
+- V1.00K is on the CD (pgx.bin) so it's known to exist
+- Unknown exactly where RS232 is connected. Likely candidates are JVS, EXT IN/OUT (unused according to manual), or CN2
+- You must send the command "4g63" before the terminal debugger will respond to any commands. Send "h" to see list of most commands.
+*/
+
+#include "emu.h"
+
+#include "bus/ata/ataintf.h"
+#include "bus/ata/atapicdr.h"
+#include "bus/rs232/null_modem.h"
+#include "bus/rs232/pty.h"
+#include "bus/rs232/rs232.h"
+#include "bus/rs232/terminal.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/i8251.h"
+#include "machine/intelfsh.h"
+#include "machine/timer.h"
+#include "sound/stt_sa1.h"
+
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+
+#define LOG_VIDEO_DISPLAY (1U << 1)
+#define LOG_UART (1U << 2)
+
+// #define VERBOSE (LOG_GENERAL | LOG_UART)
+// #define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+namespace {
+
+class sttechno_state : public driver_device, public device_serial_interface
+{
+public:
+ sttechno_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , device_serial_interface(mconfig, *this)
+ , m_maincpu(*this, "maincpu")
+ , m_ata(*this, "ata")
+ , m_flash(*this, "flash%u", 1)
+ , m_video_flash(*this, "video_flash")
+ , m_sound(*this, "pcm_sound")
+ , m_rs232(*this, "rs232")
+ , m_sttga1_ram_obj(*this, "sttga1_ram_obj")
+ , m_sttga1_ram_pal(*this, "sttga1_ram_pal")
+ , m_sound_ram(*this, "sound_ram")
+ {
+ }
+
+ void shambros(machine_config &config) ATTR_COLD;
+
+protected:
+ virtual void machine_start() override ATTR_COLD;
+ virtual void machine_reset() override ATTR_COLD;
+
+ virtual void tra_callback() override;
+ virtual void rcv_complete() override;
+
+private:
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ void cpu_map(address_map &map) ATTR_COLD;
+ void sound_map(address_map &map) ATTR_COLD;
+
+ void bank_w(uint16_t data);
+ void bank_write_enable_w(uint16_t data);
+
+ void data_w(offs_t offset, uint16_t data);
+ uint16_t data_r(offs_t offset);
+
+ void uart_data_w(uint16_t data);
+ uint16_t uart_data_r();
+
+ uint16_t uart_txrdy_r();
+
+ void uart_config_w(uint16_t data);
+
+ void ata_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t ata_cs0_r(offs_t offset, uint16_t mem_mask = ~0);
+
+ void ata_control_w(uint16_t data);
+
+ uint16_t video_unk_r();
+ void sttga1_video_flash_w(offs_t offset, uint16_t data);
+ uint16_t sttga1_video_flash_r(offs_t offset);
+ void sttga1_video_flash_write_enable_w(offs_t offset, uint16_t data);
+ void sttga1_enabled_w(offs_t offset, uint16_t data);
+
+ void sound_device_enable_w(offs_t offset, uint16_t data);
+
+ TIMER_DEVICE_CALLBACK_MEMBER(irq6_timer);
+
+ required_device<cpu_device> m_maincpu;
+ required_device<ata_interface_device> m_ata;
+ required_device_array<intelfsh16_device, 2> m_flash;
+ required_device<intelfsh16_device> m_video_flash;
+ required_device<stt_sa1_device> m_sound;
+ required_device<rs232_port_device> m_rs232;
+
+ required_shared_ptr<uint16_t> m_sttga1_ram_obj;
+ required_shared_ptr<uint16_t> m_sttga1_ram_pal;
+ required_shared_ptr<uint16_t> m_sound_ram;
+
+ uint16_t m_bank;
+ uint16_t m_flash_write_enabled;
+
+ bool m_sttga1_video_flash_write_enable;
+ bool m_sttga1_enabled;
+
+ uint8_t m_uart_rx;
+ bool m_uart_rx_busy;
+
+ bool m_ata_enabled;
+};
+
+void sttechno_state::machine_start()
+{
+ save_item(NAME(m_bank));
+ save_item(NAME(m_flash_write_enabled));
+ save_item(NAME(m_sttga1_video_flash_write_enable));
+ save_item(NAME(m_sttga1_enabled));
+ save_item(NAME(m_uart_rx));
+ save_item(NAME(m_uart_rx_busy));
+ save_item(NAME(m_ata_enabled));
+
+ // TODO: Exact parameters for the UART are unknown
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+ set_rate(115200);
+}
+
+void sttechno_state::machine_reset()
+{
+ receive_register_reset();
+ transmit_register_reset();
+
+ m_bank = 0;
+ m_flash_write_enabled = 0;
+
+ m_sttga1_video_flash_write_enable = false;
+ m_sttga1_enabled = false;
+
+ m_uart_rx = 0;
+ m_uart_rx_busy = false;
+
+ m_ata_enabled = false;
+}
+
+uint32_t sttechno_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+
+ if (!m_sttga1_enabled)
+ return 0;
+
+ // Use second half of OBJ RAM as the list to be rendered
+ for (int offset = 0x2000; offset < 0x4000; offset += 4) {
+ const uint16_t x = m_sttga1_ram_obj[offset] & 0x1ff;
+ const uint16_t y = m_sttga1_ram_obj[offset+1] & 0x1ff;
+ const uint16_t transparency = (BIT(m_sttga1_ram_obj[offset+1], 10, 5) / 31.0) * 255;
+
+ const uint8_t palidx = BIT(m_sttga1_ram_obj[offset+2], 0, 6);
+ const uint8_t unk = BIT(m_sttga1_ram_obj[offset+2], 6, 2);
+ const uint8_t tiles_w = BIT(m_sttga1_ram_obj[offset+2], 8, 3) + 1;
+ const uint8_t xflip = BIT(m_sttga1_ram_obj[offset+2], 11); // these aren't confirmed and don't seem to actually be used, but I think they are flipped bit flags based on the code
+ const uint8_t tiles_h = BIT(m_sttga1_ram_obj[offset+2], 12, 3) + 1;
+ const uint8_t yflip = BIT(m_sttga1_ram_obj[offset+2], 15);
+
+ const uint32_t char_offset_base = BIT(m_sttga1_ram_obj[offset+3], 0, 14) * 0x100;
+ const bool is_transparent = BIT(m_sttga1_ram_obj[offset+3], 14) && transparency != 255;
+ const bool is_last = BIT(m_sttga1_ram_obj[offset+3], 15);
+
+ LOGMASKED(LOG_VIDEO_DISPLAY, "%04x: x[%04x] y[%04x] unk[%x] pal[%02x] w[%02x] h[%02x] xflip[%d] yflip[%d] char_offset_base[%08x] trans[%d %04x] is_last[%d] | obj[%04x]\n", offset, x, y, unk, palidx, tiles_w, tiles_h, xflip, yflip, char_offset_base, is_transparent, transparency, is_last, m_sttga1_ram_obj[offset+2]);
+
+ if (is_last) {
+ LOGMASKED(LOG_VIDEO_DISPLAY, "end of list\n");
+ break;
+ }
+
+ for (int tile_x = 0; tile_x < tiles_h; tile_x++) {
+ for (int tile_y = 0; tile_y < tiles_w; tile_y++) {
+ for (int pix_y = 0; pix_y < 16; pix_y++) {
+ for (int pix_x = 0; pix_x < 16; pix_x++) {
+ const int ty = (y + tile_x * 16 + pix_y) % 512; // 512x512 framebuffer size, must be wrapped
+ const int tx = (x + (tile_y * 16) + pix_x) % 512;
+
+ if (!cliprect.contains(tx, ty))
+ continue;
+
+ uint16_t *const pix = &bitmap.pix(ty, tx);
+ const uint32_t char_offset = char_offset_base + (tile_x * (0x100 * tiles_w)) + (tile_y * 0x100) + (pix_y * 16) + pix_x;
+ const uint16_t char_data = m_video_flash->read_raw(char_offset / 2);
+ const int colidx = BIT(char_data, 8 * (1 - (char_offset & 1)), 8);
+ uint16_t color = m_sttga1_ram_pal[palidx * 0x100 + colidx];
+
+ if (colidx == 0)
+ continue;
+
+ pix[0] = is_transparent ? alpha_blend_r16(pix[0], color, transparency) : color;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(sttechno_state::irq6_timer)
+{
+ // IRQ 6 is responsible for incrementing the in-game song sync timer
+ // If the IRQ is too fast or too slow then it affects a lot of gameplay-related things: the measure markers, the note placements, the timing judgements
+ // The animation during the gameplay where the character on the right side jumps up and down is also based on this IRQ
+ m_maincpu->set_input_line(6, HOLD_LINE);
+}
+
+void sttechno_state::bank_w(uint16_t data)
+{
+ m_bank = data;
+}
+
+void sttechno_state::bank_write_enable_w(uint16_t data)
+{
+ // Only appears to be used for banks 3 and 4
+ // For bank 3 it'll write 1, for bank 4 it'll write 2
+ // The game typically enables write, writes data, then immediately clears the write flag
+ m_flash_write_enabled = data;
+}
+
+void sttechno_state::data_w(offs_t offset, uint16_t data)
+{
+ if (m_bank >= 0 && m_bank <= 2) {
+ const offs_t offs = offset + (0x100000 * m_bank);
+ if (offs < 0x100 / 2)
+ m_sound->write(offs, data);
+ else
+ m_sound_ram[offs] = swapendian_int16(data);
+ } else if (m_bank == 3) {
+ if (BIT(m_flash_write_enabled, 0))
+ m_flash[0]->write(offset, data);
+ } else if (m_bank == 4) {
+ if (BIT(m_flash_write_enabled, 1))
+ m_flash[1]->write(offset, data);
+ }
+}
+
+uint16_t sttechno_state::data_r( offs_t offset)
+{
+ if (m_bank >= 0 && m_bank <= 2) {
+ const offs_t offs = offset + (0x100000 * m_bank);
+ if (offs < 0x100 / 2)
+ return m_sound->read(offs);
+ else
+ return swapendian_int16(m_sound_ram[offs]);
+ } else if (m_bank == 3) {
+ return m_flash[0]->read(offset);
+ } else if (m_bank == 4) {
+ return m_flash[1]->read(offset);
+ }
+
+ return 0;
+}
+
+void sttechno_state::uart_data_w(uint16_t data)
+{
+ LOGMASKED(LOG_UART, "uart_data_w %04x\n", data);
+ transmit_register_setup(data & 0xff);
+}
+
+uint16_t sttechno_state::uart_data_r()
+{
+ uint16_t r = m_uart_rx;
+
+ if (!machine().side_effects_disabled()) {
+ m_uart_rx = 0;
+ m_maincpu->set_input_line(4, CLEAR_LINE);
+ m_uart_rx_busy = false;
+ }
+
+ return r;
+}
+
+void sttechno_state::tra_callback()
+{
+ m_rs232->write_txd(transmit_register_get_data_bit());
+}
+
+void sttechno_state::rcv_complete()
+{
+ receive_register_extract();
+ m_uart_rx = get_received_char();
+ m_uart_rx_busy = true;
+
+ m_maincpu->set_input_line(4, ASSERT_LINE);
+}
+
+uint16_t sttechno_state::uart_txrdy_r()
+{
+ // Polled before writing to uart_data_w
+ return !m_uart_rx_busy && is_transmit_register_empty() && !is_receive_register_full();
+}
+
+void sttechno_state::uart_config_w(uint16_t data)
+{
+ // 0x49 is written here
+ LOGMASKED(LOG_UART, "uart_config_w %04x\n", data);
+}
+
+void sttechno_state::ata_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if (!m_ata_enabled)
+ return;
+
+ m_ata->cs0_w(offset, data, mem_mask);
+}
+
+uint16_t sttechno_state::ata_cs0_r(offs_t offset, uint16_t mem_mask)
+{
+ if (!m_ata_enabled)
+ return 0;
+
+ return m_ata->cs0_r(offset, mem_mask);
+}
+
+void sttechno_state::ata_control_w(uint16_t data)
+{
+ if (data & 0x8000) {
+ // TODO: CD-ROM hardware reset
+ return;
+ }
+
+ m_ata_enabled = (data & 3) != 0;
+}
+
+uint16_t sttechno_state::video_unk_r()
+{
+ // This gets called at two points:
+ // - Every time before the OBJ RAM gets updated
+ // - Every time before setting FM_BYTEPROGRAM for the flash
+
+ if (m_sttga1_video_flash_write_enable)
+ return 0;
+
+ // HACK: Copy the OBJ data into the unused second half of the OBJ RAM for rendering
+ // This helps fix some small graphical glitches (sound test menu's text flicker, flickering during initial installation when programming the video flash)
+ if (!machine().side_effects_disabled())
+ std::copy_n(std::begin(m_sttga1_ram_obj), 0x2000, std::begin(m_sttga1_ram_obj) + 0x2000);
+
+ return 0;
+}
+
+void sttechno_state::sttga1_video_flash_w(offs_t offset, uint16_t data)
+{
+ if (!m_sttga1_video_flash_write_enable)
+ return;
+
+ m_video_flash->write(offset, data);
+}
+
+uint16_t sttechno_state::sttga1_video_flash_r(offs_t offset)
+{
+ return m_video_flash->read(offset);
+}
+
+void sttechno_state::sttga1_video_flash_write_enable_w(offs_t offset, uint16_t data)
+{
+ // If it's set to 1 then 0xa00000 addresses flash, and if it's 0 then it addresses RAM?
+ m_sttga1_video_flash_write_enable = data != 0;
+}
+
+void sttechno_state::sttga1_enabled_w(offs_t offset, uint16_t data)
+{
+ // Set to either 0 or 3 based on enabled status
+ m_sttga1_enabled = data != 0;
+}
+
+void sttechno_state::cpu_map(address_map &map)
+{
+ map(0x000000, 0x07ffff).rom().nopw(); // unchecked null pointer makes the game spam a ton of writes to 0x00000c-0x00000e sometimes
+ map(0x200000, 0x3fffff).ram();
+
+ map(0x400000, 0x400001).r(FUNC(sttechno_state::video_unk_r));
+
+ map(0x500000, 0x500001).portr("IN1");
+ map(0x500002, 0x500003).portr("IN2");
+ map(0x500004, 0x500005).portw("OUT1");
+ map(0x500006, 0x500007).portw("OUT2");
+ map(0x500020, 0x500021).rw(m_sound, FUNC(stt_sa1_device::key_r), FUNC(stt_sa1_device::key_w));
+ map(0x500022, 0x500023).w(m_sound, FUNC(stt_sa1_device::enable_w));
+ map(0x500024, 0x500025).w(FUNC(sttechno_state::bank_w));
+ map(0x500026, 0x500027).w(FUNC(sttechno_state::bank_write_enable_w));
+
+ map(0x600000, 0x600001).rw(FUNC(sttechno_state::uart_data_r), FUNC(sttechno_state::uart_data_w));
+ map(0x600002, 0x600003).r(FUNC(sttechno_state::uart_txrdy_r));
+ map(0x600004, 0x600005).w(FUNC(sttechno_state::uart_config_w));
+
+ map(0x70000c, 0x70000d).nopw(); // 2 is written here before CD-ROM commands are sent?
+ map(0x700010, 0x70001f).rw(FUNC(sttechno_state::ata_cs0_r), FUNC(sttechno_state::ata_cs0_w));
+ map(0x700020, 0x700021).w(FUNC(sttechno_state::ata_control_w));
+
+ // Additionally, 0x100000 bytes for other RAM (framebuffer etc?)
+ map(0x800000, 0x807fff).ram().share(m_sttga1_ram_obj); // OBJ RAM
+ map(0x808000, 0x80ffff).ram().share(m_sttga1_ram_pal); // Palette RAM, 0x200 per palette
+ // 810000-81001f region contains some other registers which look like video display configuration registers but I'm not sure how to read it
+ map(0x810016, 0x810017).w(FUNC(sttechno_state::sttga1_enabled_w));
+ map(0x810018, 0x810019).w(FUNC(sttechno_state::sttga1_video_flash_write_enable_w));
+
+ map(0xa00000, 0xbfffff).rw(FUNC(sttechno_state::sttga1_video_flash_r), FUNC(sttechno_state::sttga1_video_flash_w));
+
+ map(0xc00000, 0xdfffff).rw(FUNC(sttechno_state::data_r), FUNC(sttechno_state::data_w));
+}
+
+void sttechno_state::sound_map(address_map &map)
+{
+ map(0x000000, 0x5fffff).ram().share(m_sound_ram);
+ map(0x600000, 0x7fffff).r(m_flash[0], FUNC(intelfsh16_device::read_raw));
+ map(0x800000, 0x9fffff).r(m_flash[1], FUNC(intelfsh16_device::read_raw));
+}
+
+
+static INPUT_PORTS_START( shambros )
+ PORT_START("IN1")
+ PORT_BIT( 0x3f00, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Neck Upper") // 1P UP
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("Neck Center") // 1P MID
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("Neck Lower") // 1P LOW
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("Bachi") // 1P SHOT
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("Neck Upper") // 2P UP
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_PLAYER(2) PORT_NAME("Neck Center") // 2P MID
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_PLAYER(2) PORT_NAME("Neck Lower") // 2P LOW
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_PLAYER(2) PORT_NAME("Bachi") // 2P SHOT
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_CUSTOM ) // 1P DETECT
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_CUSTOM ) // 2P DETECT
+
+ PORT_START("IN2")
+ PORT_BIT( 0xfe43, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) // Select up
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) // Select down
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_START ) // Enter
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_COIN1 ) // Coin
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_SERVICE1 ) // Service button
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_SERVICE ) // Test menu button
+
+ PORT_START( "OUT1" )
+ PORT_BIT( 0xfffa, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_OUTPUT ) // Coin meter
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_OUTPUT ) // Coin lockout
+
+ PORT_START( "OUT2" )
+ PORT_BIT( 0xfff8, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_OUTPUT ) // SEL UP
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_OUTPUT ) // SEL DOWN
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_OUTPUT ) // SEL DECI.
+INPUT_PORTS_END
+
+static DEVICE_INPUT_DEFAULTS_START(debug_terminal)
+ DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_115200)
+ DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_115200)
+ DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_8)
+ DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_NONE)
+ DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1)
+DEVICE_INPUT_DEFAULTS_END
+
+
+static void sttechno_debug_serial_devices(device_slot_interface &device)
+{
+ device.option_add("null_modem", NULL_MODEM);
+ device.option_add("pty", PSEUDO_TERMINAL);
+ device.option_add("terminal", SERIAL_TERMINAL);
+}
+
+void sttechno_state::shambros(machine_config &config)
+{
+ M68000(config, m_maincpu, XTAL(42'954'545) / 2); // divisor guessed, anything slower and the game stops functioning (timer flickers, CD-ROM reads are too slow)
+ m_maincpu->set_addrmap(AS_PROGRAM, &sttechno_state::cpu_map);
+
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_raw(XTAL(42'954'545) / 6, 456, 0, 336, 262, 0, 240); // guessed
+ screen.set_screen_update(FUNC(sttechno_state::screen_update));
+ screen.screen_vblank().set_inputline(m_maincpu, M68K_IRQ_2);
+ screen.set_palette("palette");
+
+ PALETTE(config, "palette", palette_device::BGR_555);
+
+ ATA_INTERFACE(config, m_ata).options(ata_devices, "cdrom", nullptr, true);
+ m_ata->slot(0).set_option_machine_config("cdrom", [] (device_t *device) { downcast<atapi_cdrom_device &>(*device).set_is_ready(true); });
+
+ FUJITSU_29F160TE_16BIT(config, m_flash[0]);
+ FUJITSU_29F160TE_16BIT(config, m_flash[1]);
+ FUJITSU_29F160TE_16BIT(config, m_video_flash);
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ STT_SA1(config, m_sound, XTAL(42'954'545) / 3);
+ m_sound->set_addrmap(0, &sttechno_state::sound_map);
+ m_sound->add_route(0, "lspeaker", 1.0);
+ m_sound->add_route(1, "rspeaker", 1.0);
+ TIMER(config, "irq6_timer").configure_periodic(FUNC(sttechno_state::irq6_timer), attotime::from_hz(XTAL(42'954'545) / 3 / 448 / 128)); // probably some interrupt?
+
+ RS232_PORT(config, m_rs232, sttechno_debug_serial_devices, nullptr);
+ m_rs232->set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(debug_terminal));
+ m_rs232->set_option_device_input_defaults("pty", DEVICE_INPUT_DEFAULTS_NAME(debug_terminal));
+ m_rs232->set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(debug_terminal));
+ m_rs232->rxd_handler().set(FUNC(sttechno_state::rx_w));
+}
+
+
+ROM_START( shambros )
+ ROM_REGION(0x80000, "maincpu", 0)
+ ROM_LOAD16_WORD_SWAP( "g112 v1.01.u46", 0x00000, 0x80000, CRC(6e13bcde) SHA1(189b0052083717030ca868b95b9d43e1faaf9695) )
+
+ DISK_REGION( "ata:0:cdrom" )
+ DISK_IMAGE( "sb01-100", 0, SHA1(abd1d61871bcb4635acc691e35ec386823763ba2) )
+ROM_END
+
+} // anonymous namespace
+
+
+GAME( 2003, shambros, 0, shambros, shambros, sttechno_state, empty_init, ROT0, "Kato's", "Shamisen Brothers Vol 1 (V1.01K)", MACHINE_IMPERFECT_TIMING )