mirror of
https://github.com/holub/mame
synced 2025-06-04 03:46:29 +03:00
misc/sttechno.cpp: Implement driver for Kato's Shamisen Brothers. (#11929)
* machine/intelfsh.cpp: Implemented fast mode for Fujitsu flash. * bus/ata/atapihle.cpp: Made DMA ready configurable. * sound/stt_sa1.cpp: Emulated STT-SA1 PCM sample playback. Systems promoted to working ----------------------------- Shamisen Brothers Vol 1 (V1.01K) [Windy Fairy, Taro, angeryer]
This commit is contained in:
parent
451d2ed743
commit
32e13b0f3c
@ -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",
|
||||
|
@ -968,6 +968,19 @@ if (SOUNDS["SP0250"]~=null) then
|
||||
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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
190
src/devices/sound/stt_sa1.cpp
Normal file
190
src/devices/sound/stt_sa1.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/devices/sound/stt_sa1.h
Normal file
57
src/devices/sound/stt_sa1.h
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
@ -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 )
|
622
src/mame/misc/sttechno.cpp
Normal file
622
src/mame/misc/sttechno.cpp
Normal file
@ -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 )
|
Loading…
Reference in New Issue
Block a user