ksys573.cpp, machine/k573mcr.cpp: Implemented JVS memory card reader device for System 573. (#7659)

This commit is contained in:
987123879113 2021-01-12 23:26:58 +09:00 committed by GitHub
parent cc70f78da6
commit ee6e82013d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 848 additions and 111 deletions

View File

@ -37,6 +37,7 @@ protected:
virtual bool analogs(uint8_t *&buf, uint8_t count);
virtual bool swoutputs(uint8_t count, const uint8_t *vals);
virtual bool swoutputs(uint8_t id, uint8_t val);
virtual int handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer);
required_device<jvs_host> host;
@ -45,7 +46,6 @@ private:
uint8_t jvs_address;
uint32_t jvs_reset_counter;
int handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer);
};
#endif // MAME_MACHINE_JVSDEV_H

View File

@ -352,6 +352,7 @@ G: gun mania only, drives air soft gun (this game uses real BB bullet)
#include "machine/adc083x.h"
#include "machine/bankdev.h"
#include "machine/ds2401.h"
#include "machine/jvshost.h"
#include "machine/linflash.h"
#include "machine/k573cass.h"
#include "machine/k573dio.h"
@ -370,11 +371,104 @@ G: gun mania only, drives air soft gun (this game uses real BB bullet)
#include "screen.h"
#include "speaker.h"
#define LOG_GENERAL (1 << 0)
#define LOG_CDROM (1 << 1)
#define LOG_CONTROL (1 << 2)
#define LOG_SECURITY (1 << 3)
#define LOG_JVS (1 << 4)
#define LOG_IOBOARD (1 << 5)
// #define VERBOSE (LOG_GENERAL | LOG_CDROM | LOG_CONTROL | LOG_SECURITY | LOG_JVS | LOG_IOBOARD)
// #define LOG_OUTPUT_STREAM std::cout
#define VERBOSE_LEVEL ( 0 )
#include "logmacro.h"
#define LOGCDROM(...) LOGMASKED(LOG_CDROM, __VA_ARGS__)
#define LOGCONTROL(...) LOGMASKED(LOG_CONTROL, __VA_ARGS__)
#define LOGSECURITY(...) LOGMASKED(LOG_SECURITY, __VA_ARGS__)
#define LOGJVS(...) LOGMASKED(LOG_JVS, __VA_ARGS__)
#define LOGIOBOARD(...) LOGMASKED(LOG_IOBOARD, __VA_ARGS__)
#define ATAPI_CYCLES_PER_SECTOR ( 5000 ) // plenty of time to allow DMA setup etc. BIOS requires this be at least 2000, individual games may vary.
/*
* Class declaration for sys573_jvs_host
*/
DECLARE_DEVICE_TYPE(SYS573_JVS_HOST, sys573_jvs_host)
class sys573_jvs_host : public jvs_host
{
public:
// construction/destruction
sys573_jvs_host(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void send_packet(uint8_t *data, int length);
int received_packet(uint8_t *buffer);
DECLARE_READ_LINE_MEMBER( jvs_sense_r );
private:
int output_buffer_size = 0;
};
DEFINE_DEVICE_TYPE(SYS573_JVS_HOST, sys573_jvs_host, "sys573_jvs_host", "JVS Host (System 573)")
sys573_jvs_host::sys573_jvs_host(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: jvs_host(mconfig, SYS573_JVS_HOST, tag, owner, clock)
{
output_buffer_size = 0;
}
READ_LINE_MEMBER( sys573_jvs_host::jvs_sense_r )
{
return !get_address_set_line();
}
int sys573_jvs_host::received_packet(uint8_t *buffer)
{
if (jvs_sense_r()) {
// The game will send the command twice to reset, but the command
// shouldn't return any data or else a "JVS SUBS RESET ERROR" appears
return 0;
}
uint32_t length;
const uint8_t *data;
get_raw_reply(data, length);
if (length > 0) {
// The games don't unescape the data in memory.
// This causes issues any time 0xe0 or 0xd0 shows up in
// the original response data and were escaped.
// Sending an unescaped "encoded" packet works perfectly
// in-game.
uint8_t checksum = std::accumulate(data, data + length, 0);
buffer[0] = 0xe0;
memcpy(buffer + 1, data, length);
buffer[length+1] = checksum;
buffer[length+2] = 0;
length += 2;
commit_encoded();
}
return (int)length;
}
void sys573_jvs_host::send_packet(uint8_t *data, int length)
{
while (length > 0)
{
push(*data);
data++;
length--;
}
commit_raw();
}
class ksys573_state : public driver_device
{
public:
@ -394,6 +488,7 @@ public:
m_maincpu(*this, "maincpu"),
m_ram(*this, "maincpu:ram"),
m_flashbank(*this, "flashbank"),
m_in2(*this, "IN2"),
m_out1(*this, "OUT1"),
m_out2(*this, "OUT2"),
m_cd(*this, "CD"),
@ -404,7 +499,8 @@ public:
m_encoder(*this, "ENCODER"),
m_gunmania_id(*this, "gunmania_id"),
m_duart(*this, "mb89371"),
m_lamps(*this, "lamp%u", 0U)
m_lamps(*this, "lamp%u", 0U),
m_sys573_jvs_host(*this, "sys573_jvs_host")
{ }
void drmn9m(machine_config &config);
@ -422,6 +518,7 @@ public:
void ddrsbm(machine_config &config);
void ddr3mp(machine_config &config);
void dsftkd(machine_config &config);
void dsfdct(machine_config &config);
void dsfdcta(machine_config &config);
void mamboagga(machine_config &config);
void gunmania(machine_config &config);
@ -433,7 +530,9 @@ public:
void animechmp(machine_config &config);
void salarymc(machine_config &config);
void gbbchmp(machine_config &config);
void ddr2mc2(machine_config &config);
void ddr2ml(machine_config &config);
void ddrbocd(machine_config &config);
void konami573(machine_config &config);
void drmn2m(machine_config &config);
void gtrfrk3m(machine_config &config);
@ -448,6 +547,7 @@ public:
void konami573x(machine_config &config);
void ddrusa(machine_config &config);
void dsem(machine_config &config);
void dsem2(machine_config &config);
void dmx(machine_config &config);
void drmn(machine_config &config);
void k573d(machine_config &config);
@ -507,6 +607,8 @@ public:
DECLARE_WRITE_LINE_MEMBER( h8_clk_w );
DECLARE_READ_LINE_MEMBER( jvs_rx_r );
double m_pad_position[ 6 ];
optional_ioport m_pads;
@ -516,6 +618,12 @@ protected:
virtual void driver_start() override;
private:
bool jvs_is_valid_packet();
void jvs_input_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t jvs_input_r(offs_t offset, uint16_t mem_mask = ~0);
uint16_t port_in2_jvs_r(offs_t offset, uint16_t mem_mask = ~0);
uint16_t control_r(offs_t offset, uint16_t mem_mask = ~0);
void control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
@ -564,7 +672,6 @@ private:
required_ioport m_analog2;
required_ioport m_analog3;
inline void ATTR_PRINTF( 3,4 ) verboselog( int n_level, const char *s_fmt, ... );
void update_disc();
void gx700pwbf_output( int offset, uint8_t data );
void gx700pwfbf_init( void ( ksys573_state::*output_callback_func )( ATTR_UNUSED offs_t offset, ATTR_UNUSED uint8_t data ) );
@ -620,9 +727,15 @@ private:
int m_tank_shutter_position;
int m_cable_holder_release;
int m_jvs_input_idx_r, m_jvs_input_idx_w;
int m_jvs_output_idx_w, m_jvs_output_len_w;
uint8_t m_jvs_input_buffer[512];
uint8_t m_jvs_output_buffer[512];
required_device<psxcpu_device> m_maincpu;
required_device<ram_device> m_ram;
required_device<address_map_bank_device> m_flashbank;
required_ioport m_in2;
required_ioport m_out1;
required_ioport m_out2;
required_ioport m_cd;
@ -634,27 +747,16 @@ private:
optional_device<ds2401_device> m_gunmania_id;
optional_device<mb89371_device> m_duart;
output_finder<2> m_lamps;
};
void ATTR_PRINTF( 3,4 ) ksys573_state::verboselog( int n_level, const char *s_fmt, ... )
{
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
char buf[ 32768 ];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
logerror( "%s: %s", machine().describe_context(), buf );
}
}
required_device<sys573_jvs_host> m_sys573_jvs_host;
};
void ksys573_state::konami573_map(address_map &map)
{
map(0x1f000000, 0x1f3fffff).m(m_flashbank, FUNC(address_map_bank_device::amap16));
map(0x1f400000, 0x1f400003).portr("IN0").portw("OUT0");
map(0x1f400004, 0x1f400007).portr("IN1");
map(0x1f400008, 0x1f40000b).portr("IN2");
map(0x1f400008, 0x1f40000b).r(FUNC(ksys573_state::port_in2_jvs_r));
map(0x1f40000c, 0x1f40000f).portr("IN3");
map(0x1f480000, 0x1f48000f).rw(m_ata, FUNC(ata_interface_device::cs0_r), FUNC(ata_interface_device::cs0_w));
map(0x1f500000, 0x1f500001).rw(FUNC(ksys573_state::control_r), FUNC(ksys573_state::control_w)); // Konami can't make a game without a "control" register.
@ -662,6 +764,7 @@ void ksys573_state::konami573_map(address_map &map)
map(0x1f5c0000, 0x1f5c0003).nopw(); // watchdog?
map(0x1f600000, 0x1f600003).portw("LAMPS");
map(0x1f620000, 0x1f623fff).rw("m48t58", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask32(0x00ff00ff);
map(0x1f680000, 0x1f680001).rw(FUNC(ksys573_state::jvs_input_r), FUNC(ksys573_state::jvs_input_w));
map(0x1f6a0000, 0x1f6a0001).rw(FUNC(ksys573_state::security_r), FUNC(ksys573_state::security_w));
}
@ -710,9 +813,104 @@ void ksys573_state::gbbchmp_map(address_map& map)
map(0x1f640000, 0x1f640007).rw(m_duart, FUNC(mb89371_device::read), FUNC(mb89371_device::write)).umask32(0x00ff00ff);
}
bool ksys573_state::jvs_is_valid_packet()
{
if (m_jvs_input_idx_w < 5) {
// A valid packet will have at the very least
// - sync (0xe0)
// - node number (non-zero)
// - size
// - at least 1 byte in the request message
// - checksum
return false;
}
if (m_jvs_input_buffer[0] != 0xe0 || m_jvs_input_buffer[1] == 0x00) {
return false;
}
int command_size = m_jvs_input_buffer[2] + 3;
if (m_jvs_input_idx_w < command_size) {
return false;
}
uint8_t checksum = 0;
for (int i = 1; i < command_size - 1; i++) {
checksum += m_jvs_input_buffer[i];
}
return checksum == m_jvs_input_buffer[command_size - 1];
}
void ksys573_state::jvs_input_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
m_jvs_input_buffer[m_jvs_input_idx_w++] = data & 0xff;
m_jvs_input_buffer[m_jvs_input_idx_w++] = data >> 8;
if (m_jvs_input_buffer[0] != 0xe0) {
m_jvs_input_idx_w = 0;
}
if (jvs_is_valid_packet()) {
LOGJVS("jvs_input_w( %08x, %08x, %02x %02x )\n", offset, mem_mask, data & 0xff, data >> 8 );
for (int i = 0; i < m_jvs_input_idx_w; i++)
LOGJVS("%02x ", m_jvs_input_buffer[i]);
LOGJVS("\n");
int command_size = m_jvs_input_buffer[2] + 3;
m_sys573_jvs_host->send_packet(m_jvs_input_buffer + 1, command_size - 2); // jvshost doesn't actually check the checksum, so don't send it
m_jvs_input_idx_w = 0;
m_jvs_input_idx_r = 0;
m_jvs_input_buffer[0] = 0;
}
}
uint16_t ksys573_state::jvs_input_r(offs_t offset, uint16_t mem_mask)
{
uint16_t data = m_jvs_input_buffer[m_jvs_input_idx_r++];
data |= m_jvs_input_buffer[m_jvs_input_idx_r++] << 8;
return data;
}
uint16_t ksys573_state::port_in2_jvs_r(offs_t offset, uint16_t mem_mask)
{
if (offset == 0) {
// 0x1f400008-0x1f400009 are for inputs
return m_in2->read();
}
if (m_jvs_output_len_w <= 0) {
return 0;
}
uint16_t data = m_jvs_output_buffer[m_jvs_output_idx_w] | (m_jvs_output_buffer[m_jvs_output_idx_w+1] << 8);
m_jvs_output_idx_w += 2;
if (m_jvs_output_idx_w >= m_jvs_output_len_w) {
m_jvs_output_idx_w = 0;
m_jvs_output_len_w = 0;
}
LOGJVS("m_jvs_output_r %08x %08x | %02x %02x | %02x\n", offset, mem_mask, data & 0xff, data >> 8, m_jvs_output_idx_w);
return data;
}
READ_LINE_MEMBER( ksys573_state::jvs_rx_r )
{
if (m_jvs_output_len_w <= 0) {
m_jvs_output_len_w = m_sys573_jvs_host->received_packet(m_jvs_output_buffer);
}
return m_jvs_output_len_w > 0;
}
uint16_t ksys573_state::control_r(offs_t offset, uint16_t mem_mask)
{
verboselog( 2, "control_r( %08x, %08x ) %08x\n", offset, mem_mask, m_control );
LOGCONTROL( "control_r( %08x, %08x ) %08x\n", offset, mem_mask, m_control );
return m_control;
}
@ -721,7 +919,7 @@ void ksys573_state::control_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA( &m_control );
verboselog( 2, "control_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
LOGCONTROL( "control_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
m_out2->write( data, mem_mask );
@ -765,7 +963,7 @@ void ksys573_state::atapi_reset_w(uint16_t data)
void ksys573_state::cdrom_dma_read( uint32_t *ram, uint32_t n_address, int32_t n_size )
{
verboselog( 2, "cdrom_dma_read( %08x, %08x )\n", n_address, n_size );
LOGCDROM( "cdrom_dma_read( %08x, %08x )\n", n_address, n_size );
// osd_printf_debug( "DMA read: address %08x size %08x\n", n_address, n_size );
}
@ -773,7 +971,7 @@ void ksys573_state::cdrom_dma_write( uint32_t *ram, uint32_t n_address, int32_t
{
m_p_n_psxram = ram;
verboselog( 2, "cdrom_dma_write( %08x, %08x )\n", n_address, n_size );
LOGCDROM( "cdrom_dma_write( %08x, %08x )\n", n_address, n_size );
// osd_printf_debug( "DMA write: address %08x size %08x\n", n_address, n_size );
m_atapi_xferbase = n_address;
@ -786,7 +984,7 @@ void ksys573_state::security_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA( &m_n_security_control );
verboselog( 2, "security_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
LOGSECURITY( "security_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
m_out1->write( data, mem_mask );
}
@ -794,7 +992,7 @@ void ksys573_state::security_w(offs_t offset, uint16_t data, uint16_t mem_mask)
uint16_t ksys573_state::security_r(offs_t offset, uint16_t mem_mask)
{
uint16_t data = m_n_security_control;
verboselog( 2, "security_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
LOGSECURITY( "security_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
return data;
}
@ -834,10 +1032,6 @@ void ksys573_state::driver_start()
m_available_cdroms[ 0 ] = cdrom_open(machine().rom_load().get_disk_handle(":cdrom0"));
m_available_cdroms[ 1 ] = cdrom_open(machine().rom_load().get_disk_handle(":cdrom1"));
m_n_security_control = 0;
m_control = 0;
m_h8_index = 0;
save_item( NAME( m_n_security_control ) );
save_item( NAME( m_control ) );
}
@ -846,52 +1040,22 @@ void ksys573_state::machine_reset()
{
update_disc();
m_n_security_control = 0;
m_control = 0;
m_h8_index = 0;
m_h8_clk = 0;
m_jvs_input_idx_r = m_jvs_input_idx_w = 0;
m_jvs_output_idx_w = m_jvs_output_len_w = 0;
std::fill_n(m_jvs_input_buffer, sizeof(m_jvs_input_buffer), 0);
std::fill_n(m_jvs_output_buffer, sizeof(m_jvs_output_buffer), 0);
}
WRITE_LINE_MEMBER(ksys573_state::sys573_vblank)
{
update_disc();
/// TODO: emulate the memory controller board
if( strcmp( machine().system().name, "ddr2ml" ) == 0 )
{
/* patch out security-plate error */
uint32_t *p_n_psxram = (uint32_t *) m_ram->pointer();
/* install cd */
/* 801e1540: jal $801e1f7c */
if( p_n_psxram[ 0x1e1540 / 4 ] == 0x0c0787df )
{
/* 801e1540: j $801e1560 */
p_n_psxram[ 0x1e1540 / 4 ] = 0x08078558;
}
/* flash */
/* 8001f850: jal $80031fd8 */
if( p_n_psxram[ 0x1f850 / 4 ] == 0x0c00c7f6 )
{
/* 8001f850: j $8001f888 */
p_n_psxram[ 0x1f850 / 4 ] = 0x08007e22;
}
}
else if( strcmp( machine().system().name, "ddr2mla" ) == 0 )
{
/* patch out security-plate error */
uint32_t *p_n_psxram = (uint32_t *) m_ram->pointer();
/* 8001f850: jal $8003221c */
if( p_n_psxram[ 0x1f850 / 4 ] == 0x0c00c887 )
{
/* 8001f850: j $8001f888 */
p_n_psxram[ 0x1f850 / 4 ] = 0x08007e22;
}
}
}
// H8 check at startup (JVS related)
@ -952,11 +1116,11 @@ uint16_t ksys573_state::ge765pwbba_r(offs_t offset, uint16_t mem_mask)
return m_upd4701->read_y(offset & 1);
default:
verboselog( 0, "ge765pwbba_r: unhandled offset %08x %08x\n", offset, mem_mask );
LOGIOBOARD( "ge765pwbba_r: unhandled offset %08x %08x\n", offset, mem_mask );
break;
}
verboselog( 2, "ge765pwbba_r( %08x, %08x )\n", offset, mem_mask );
LOGIOBOARD( "ge765pwbba_r( %08x, %08x )\n", offset, mem_mask );
return 0;
}
@ -981,11 +1145,11 @@ void ksys573_state::ge765pwbba_w(offs_t offset, uint16_t data, uint16_t mem_mask
break;
default:
verboselog( 0, "ge765pwbba_w: unhandled offset %08x %08x %08x\n", offset, mem_mask, data );
LOGIOBOARD( "ge765pwbba_w: unhandled offset %08x %08x %08x\n", offset, mem_mask, data );
break;
}
verboselog( 2, "ge765pwbba_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
LOGIOBOARD( "ge765pwbba_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
}
/*
@ -1022,7 +1186,7 @@ uint16_t ksys573_state::gx700pwbf_io_r(offs_t offset, uint16_t mem_mask)
break;
}
verboselog( 2, "gx700pwbf_io_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
LOGIOBOARD( "gx700pwbf_io_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
return data;
}
@ -1048,7 +1212,7 @@ void ksys573_state::gx700pwbf_output( int offset, uint8_t data )
void ksys573_state::gx700pwbf_io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
verboselog( 2, "gx700pwbf_io_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
LOGIOBOARD( "gx700pwbf_io_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
switch( offset )
{
@ -1076,7 +1240,7 @@ void ksys573_state::gx700pwbf_io_w(offs_t offset, uint16_t data, uint16_t mem_ma
void ksys573_state::gx700pwfbf_init( void ( ksys573_state::*output_callback_func )( ATTR_UNUSED offs_t offset, ATTR_UNUSED uint8_t data ) )
{
memset( m_gx700pwbf_output_data, 0, sizeof( m_gx700pwbf_output_data ) );
std::fill_n( m_gx700pwbf_output_data, sizeof( m_gx700pwbf_output_data ), 0);
m_gx700pwfbf_output_callback = output_callback_func;
@ -1153,7 +1317,7 @@ void ksys573_state::gn845pwbb_clk_w( int offset, int data )
}
}
verboselog( 2, "stage: %dp data clk=%d state=%d d0=%d shift=%08x bit=%d stage_mask=%08x\n", offset + 1, clk,
LOGIOBOARD( "stage: %dp data clk=%d state=%d d0=%d shift=%08x bit=%d stage_mask=%08x\n", offset + 1, clk,
m_stage_state[ offset ].state, m_stage_state[ offset ].DO, m_stage_state[ offset ].shift, m_stage_state[ offset ].bit, m_stage_mask );
}
@ -1606,7 +1770,7 @@ WRITE_LINE_MEMBER( ksys573_state::animechmp_lamp_clock )
{
if( ( m_serial_lamp_shift & ~0xfff ) != 0 )
{
verboselog( 0, "unknown bits in serial_lamp_shift %08x\n", m_serial_lamp_shift & ~0xfff );
LOG( "unknown bits in serial_lamp_shift %08x\n", m_serial_lamp_shift & ~0xfff );
}
output().set_value( "player 1 red", ( m_serial_lamp_shift >> 11 ) & 1 );
@ -1670,7 +1834,7 @@ WRITE_LINE_MEMBER( ksys573_state::salarymc_lamp_clock )
{
if( ( m_serial_lamp_shift & ~0xe38 ) != 0 )
{
verboselog( 0, "unknown bits in serial_lamp_shift %08x\n", m_serial_lamp_shift & ~0xe38 );
LOG( "unknown bits in serial_lamp_shift %08x\n", m_serial_lamp_shift & ~0xe38 );
}
output().set_value( "player 1 red", ( m_serial_lamp_shift >> 11 ) & 1 );
@ -1871,7 +2035,7 @@ double konami573_cassette_xi_device::punchmania_inputs_callback(uint8_t input)
int pads = state->m_pads->read();
for( int i = 0; i < 6; i++ )
{
if( ( pads & ( 1 << i ) ) != 0 )
if( BIT( pads, i ) )
{
pad_position[ i ] = 5;
}
@ -2127,7 +2291,7 @@ void ksys573_state::gunmania_w(offs_t offset, uint16_t data, uint16_t mem_mask)
break;
}
verboselog( 2, "gunmania_w %08x %08x %08x\n", offset, mem_mask, data );
LOGIOBOARD( "gunmania_w %08x %08x %08x\n", offset, mem_mask, data );
}
READ_LINE_MEMBER( ksys573_state::gunmania_tank_shutter_sensor )
@ -2165,7 +2329,7 @@ uint16_t ksys573_state::gunmania_r(offs_t offset, uint16_t mem_mask)
break;
}
verboselog( 2, "gunmania_r %08x %08x %08x\n", offset, mem_mask, data );
LOGIOBOARD( "gunmania_r %08x %08x %08x\n", offset, mem_mask, data );
return data;
}
@ -2250,6 +2414,8 @@ void ksys573_state::konami573(machine_config &config)
adc0834_device &adc(ADC0834(config, "adc0834"));
adc.set_input_callback(FUNC(ksys573_state::analogue_inputs_callback));
SYS573_JVS_HOST(config, m_sys573_jvs_host, 0);
}
// Variants with additional digital sound board
@ -2354,11 +2520,26 @@ void ksys573_state::ddr(machine_config &config)
cassx(config);
}
void ksys573_state::ddr2mc2(machine_config &config)
{
k573a(config);
cassx(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::ddr2ml(machine_config &config)
{
k573a(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0);
pccard1_16mb(config);
cassx(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::ddrbocd(machine_config &config)
{
k573a(config);
pccard1_16mb(config);
cassx(config);
}
@ -2370,6 +2551,8 @@ void ksys573_state::ddr3m(machine_config &config)
pccard2_32mb(config);
cassyyi(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::ddr3mp(machine_config &config)
@ -2379,6 +2562,8 @@ void ksys573_state::ddr3mp(machine_config &config)
pccard2_32mb(config);
cassxzi(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::ddrusa(machine_config &config)
@ -2396,10 +2581,21 @@ void ksys573_state::ddr5m(machine_config &config)
pccard2_32mb(config);
casszi(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
// Dancing Stage
void ksys573_state::dsfdct(machine_config &config)
{
k573d(config);
subdevice<k573dio_device>("k573dio")->output_callback().set(FUNC(ksys573_state::ddr_output_callback));
pccard2_32mb(config);
cassyyi(config);
}
void ksys573_state::dsfdcta(machine_config &config)
{
k573a(config);
@ -2429,6 +2625,15 @@ void ksys573_state::dsem(machine_config &config)
cassxi(config);
}
void ksys573_state::dsem2(machine_config &config)
{
k573d(config);
subdevice<k573dio_device>("k573dio")->output_callback().set(FUNC(ksys573_state::ddr_output_callback));
pccard2_32mb(config);
casszi(config);
}
// Dance Dance Revolution Solo
void ksys573_state::ddrsolo(machine_config &config)
@ -2463,6 +2668,8 @@ void ksys573_state::ddr4ms(machine_config &config)
pccard2_32mb(config);
cassxzi(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
// DrumMania
@ -2524,6 +2731,9 @@ void ksys573_state::gtrfrk2m(machine_config &config)
k573a(config);
cassyi(config);
pccard1_32mb(config); // HACK: The installation tries to check and erase 32mb but only flashes 16mb.
// For Guitar Freaks 2nd Mix Link Ver 1 (memory cards) and Link Ver 2 (memory cards + controllers)
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::gtrfrk3m(machine_config &config)
@ -2531,6 +2741,8 @@ void ksys573_state::gtrfrk3m(machine_config &config)
k573d(config);
cassxzi(config);
pccard1_16mb(config);
KONAMI_573_MEMORY_CARD_READER(config, "k573mcr", 0, m_sys573_jvs_host);
}
void ksys573_state::gtrfrk5m(machine_config &config)
@ -2693,7 +2905,6 @@ void ksys573_state::mamboagga(machine_config &config)
KONAMI_573_NETWORK_PCB_UNIT(config, "k573npu", 0);
}
static INPUT_PORTS_START( konami573 )
PORT_START( "IN0" )
PORT_BIT( 0xffffffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
@ -2734,9 +2945,9 @@ static INPUT_PORTS_START( konami573 )
PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER( "adc0834", adc083x_device, do_read )
// PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER( "cassette", konami573_cassette_slot_device, read_line_secflash_sda )
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* skip hang at startup */
PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) /* skip hang at startup */
PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER( "sys573_jvs_host", sys573_jvs_host, jvs_sense_r )
PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, ksys573_state, jvs_rx_r )
PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // JVS-related
// PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_UNKNOWN )
// PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x01000000, IP_ACTIVE_LOW, IPT_COIN1 )
@ -2763,7 +2974,6 @@ static INPUT_PORTS_START( konami573 )
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER( "cassette", konami573_cassette_slot_device, write_line_zs01_sda )
PORT_START( "IN2" )
PORT_BIT( 0xffff0000, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER( 1 )
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER( 1 )
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER( 1 )
@ -5329,9 +5539,9 @@ GAME( 1999, fbaitmca, fbaitmc, fbaitbc, fbaitmc, ksys573_state, empty_ini
GAME( 1999, ddr2m, sys573, ddr, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix (GN895 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddr2ml, ddr2m, ddr2ml, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix - Link Ver (GE885 VER. JAB)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddr2mla, ddr2m, ddr2ml, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix - Link Ver (GE885 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddrbocd, ddr2m, ddr2ml, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution Best of Cool Dancers (GE892 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddrbocd, ddr2m, ddrbocd, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution Best of Cool Dancers (GE892 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddr2mc, ddr2m, ddr, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix with beatmaniaIIDX CLUB VERSiON (GE896 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddr2mc2, ddr2m, ddr, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix with beatmaniaIIDX substream CLUB VERSiON 2 (GE984 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, ddr2mc2, ddr2m, ddr2mc2, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dance Dance Revolution 2nd Mix with beatmaniaIIDX substream CLUB VERSiON 2 (GE984 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, gtrfrk2m, sys573, gtrfrk2m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 2nd Mix Ver 1.01 (GQ883 VER. JAD)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, dsftkd, sys573, dsftkd, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dancing Stage featuring TRUE KiSS DESTiNATiON (G*884 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, cr589fw, sys573, konami573, konami573, ksys573_state, empty_init, ROT0, "Konami", "CD-ROM Drive Updater 2.0 (700B04)", MACHINE_IMPERFECT_SOUND )
@ -5345,7 +5555,7 @@ GAME( 1999, ddrs2k, sys573, ddrs2k, ddrsolo, ksys573_state, empty_ini
GAME( 1999, ddrs2kj, ddrs2k, ddrs2k, ddrsolo, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Solo 2000 (GC905 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.2 */
GAME( 1999, hypbbc2p, sys573, hypbbc2p, hypbbc2p, ksys573_state, init_hyperbbc, ROT0, "Konami", "Hyper Bishi Bashi Champ - 2 Player (GX908 1999/08/24 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, hypbbc2pk, hypbbc2p, hypbbc2p, hypbbc2p, ksys573_state, init_hyperbbc, ROT0, "Konami", "Hyper Bishi Bashi Champ - 2 Player (GX908 1999/08/24 VER. KAA)", MACHINE_IMPERFECT_SOUND )
GAME( 1999, dsfdct, sys573, ddr3m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dancing Stage featuring Dreams Come True (GC910 VER. JCA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING )
GAME( 1999, dsfdct, sys573, dsfdct, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dancing Stage featuring Dreams Come True (GC910 VER. JCA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING )
GAME( 1999, dsfdcta, dsfdct, dsfdcta, ddr, ksys573_state, init_ddr, ROT0, "Konami", "Dancing Stage featuring Dreams Come True (GC910 VER. JAA)", MACHINE_IMPERFECT_SOUND )
GAME( 2000, pcnfrk2m, sys573, drmn2m, drmn, ksys573_state, empty_init, ROT0, "Konami", "Percussion Freaks 2nd Mix (GE912 VER. KAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.5 */
GAME( 1999, drmn2m, pcnfrk2m, drmn2m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 2nd Mix (GE912 VER. JAB)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.5 */
@ -5396,12 +5606,12 @@ GAME( 2001, gtrfrk7m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_ini
GAME( 2001, ddrmax, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max - Dance Dance Revolution 6th Mix (G*B19 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */
GAME( 2002, ddrmax2, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max 2 - Dance Dance Revolution 7th Mix (G*B20 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, mrtlbeat, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Martial Beat (G*B47 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */
GAME( 2002, gbbchmp, sys573, gbbchmp, hyperbbc, ksys573_state, init_serlamp, ROT0, "Konami", "Great Bishi Bashi Champ (GBA48 VER. JAB)", MACHINE_IMPERFECT_SOUND )
GAME( 2002, gbbchmp, sys573, gbbchmp, hyperbbc, ksys573_state, init_serlamp, ROT0, "Konami", "Great Bishi Bashi Champ (GBA48 VER. JAB)", MACHINE_IMPERFECT_SOUND )
GAME( 2002, drmn7m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 7th Mix power-up ver. (G*C07 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, drmn7ma, drmn7m, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 7th Mix (G*C07 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, gtrfrk8m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 8th Mix power-up ver. (G*C08 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, gtrfrk8ma, gtrfrk8m, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 8th Mix (G*C08 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, dsem2, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dancing Stage Euro Mix 2 (G*C23 VER. EAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, dsem2, sys573, dsem2, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dancing Stage Euro Mix 2 (G*C23 VER. EAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2002, ddrextrm, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Extreme (G*C36 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2003, drmn8m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 8th Mix (G*C07 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */
GAME( 2003, gtrfrk9m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 9th Mix (G*C39 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */

View File

@ -1,24 +1,485 @@
// license:BSD-3-Clause
// copyright-holders:smf
// copyright-holders:smf, windyfairy
/*
* Konami 573 Memory Card Reader
*
*/
Main PCB Layout
---------------
GE885-PWB(A)A
(C)1999 KONAMI CO. LTD.
|---------------------------------------|
| PQ30RV11 |
| |----------| |-------| CN61 |
| DIP8 | | | XCS05 | |
| | TMPR | | /10 | |
| | 3904AF | |-------| CN62 |
| | | |
| CN65 |----------| |
| 8.25 MHz CN67 |
| EP4M16 |
| DRAM4M |
| |
| --------|
| USB-A CN64 |
| |
| ADM485JR |
| USB-B CN63 |
|-------------------------------|
Notes:
DIP8 - 8-position DIP switch
CN61 - BS8PSHF1AA 8 pin connector, connects to memory card harness
CN62 - BS8PSHF1AA 8 pin connector
CN63 - 6P-SHVQ labeled "0", GE885-JB security dongle is connected here
CN64 - 6P-SHVQ labeled "1"
CN65 - B4PS-VH, 4 pin power connector
CN67 - BS15PSHF1AA, 15-pin connector, unpopulated
USB-A - USB-A connector
USB-B - USB-B connector, connects to USB on System 573 motherboard
ADM485JR - Analog Devices ADM485 low power EIA RS-485 transceiver
TMPR3904AF - Toshiba TMPR3904AF RISC Microprocessor
XCS05/10 - XILINX XCS10XL VQ100AKP9909 A2026631A
DRAM4M - Silicon Magic 66 MHz C9742 SM81C256K16CJ-35, 256K x 16 EDO DRAM
EP4M16 - ROM labeled "855-A01"
*/
#include "emu.h"
#include "k573mcr.h"
/*
GE885-PWB(A)A ( contains Toshiba tmpr3904af, ram, rom, tranceiver and glue ).
*/
k573mcr_device::k573mcr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, KONAMI_573_MEMORY_CARD_READER, tag, owner, clock)
jvs_device(mconfig, KONAMI_573_MEMORY_CARD_READER, tag, owner, clock),
m_controllers(*this, "controllers"),
m_meta(*this, "META")
{
m_ram = std::make_unique<uint8_t[]>(RAM_SIZE);
}
void k573mcr_device::device_start()
{
jvs_device::device_start();
save_pointer(NAME(m_ram), RAM_SIZE);
save_item(NAME(m_is_memcard_initialized));
save_item(NAME(m_status));
save_item(NAME(m_psx_clock));
save_item(NAME(m_psx_rx_data));
save_item(NAME(m_psx_rx_bit));
}
void k573mcr_device::device_reset()
{
jvs_device::device_reset();
std::fill_n(m_ram.get(), RAM_SIZE, 0);
m_is_memcard_initialized = false;
m_status = 0;
m_psx_clock = false;
m_psx_rx_data = 0;
m_psx_rx_bit = 0;
}
void k573mcr_device::device_add_mconfig(machine_config &config)
{
// The actual controllers are only used in Guitar Freaks and it was
// meant to be used with the home version PS1 guitar controller.
// The PS1 guitar controller isn't emulated in MAME and it doesn't
// make much sense to have it enabled by default. You can still select
// a controller through the slots menu.
// The memory card ports are still usable even without a controller
// enabled which is the main reason for using the PSX controller ports.
PSXCONTROLLERPORTS(config, m_controllers, 0);
m_controllers->rxd().set(FUNC(k573mcr_device::write_rxd));
PSX_CONTROLLER_PORT(config, "port1", psx_controllers, nullptr);
PSX_CONTROLLER_PORT(config, "port2", psx_controllers, nullptr);
}
const char *k573mcr_device::device_id()
{
return "KONAMI CO.,LTD.;White I/O;Ver1.0;White I/O PCB";
}
uint8_t k573mcr_device::command_format_version()
{
return 0x11;
}
uint8_t k573mcr_device::jvs_standard_version()
{
return 0x20;
}
uint8_t k573mcr_device::comm_method_version()
{
return 0x10;
}
WRITE_LINE_MEMBER(k573mcr_device::write_rxd)
{
if (m_psx_clock) {
if (m_psx_rx_bit == 0) {
m_psx_rx_data = 0;
}
m_psx_rx_data |= state << m_psx_rx_bit;
m_psx_rx_bit = (m_psx_rx_bit + 1) % 8;
}
}
void k573mcr_device::controller_set_port(uint32_t port_no)
{
m_controllers->write_dtr(!!port_no);
m_controllers->write_dtr(!port_no);
}
uint8_t k573mcr_device::controller_port_send_byte(uint8_t data)
{
for (int i = 0; i < 8; i++) {
m_controllers->write_sck(m_psx_clock);
m_psx_clock = !m_psx_clock;
m_controllers->write_txd(BIT(data, i));
m_controllers->write_sck(m_psx_clock);
m_psx_clock = !m_psx_clock;
}
return m_psx_rx_data;
}
bool k573mcr_device::pad_read(uint32_t port_no, uint8_t *output)
{
controller_set_port(port_no);
controller_port_send_byte(0x01);
uint8_t a = controller_port_send_byte('B');
uint8_t b = controller_port_send_byte(0);
*output++ = controller_port_send_byte(0);
*output++ = controller_port_send_byte(0);
return a == 0x41 && b == 0x5a;
}
bool k573mcr_device::memcard_read(uint32_t port_no, uint16_t block_addr, uint8_t *output)
{
controller_set_port(port_no);
controller_port_send_byte(0x81);
if (controller_port_send_byte('R') == 0xff) { // state_command, Request read
return false;
}
controller_port_send_byte(0); // state_command -> state_cmdack
controller_port_send_byte(0); // state_cmdack -> state_wait
controller_port_send_byte(block_addr >> 8); // state_wait -> state_addr_hi
controller_port_send_byte(block_addr & 0xff); // state_addr_hi -> state_addr_lo
if (controller_port_send_byte(0) != 0x5c) { // state_addr_lo -> state_read
// If the command wasn't correct then it transitions to state_illegal at this point
return false;
}
controller_port_send_byte(0); // Skip 0x5d
controller_port_send_byte(0); // Skip addr hi
controller_port_send_byte(0); // Skip addr lo
for (int i = 0; i < MEMCARD_BLOCK_SIZE; i++) {
auto c = controller_port_send_byte(0);
if (output != nullptr) {
*output++ = c;
}
}
controller_port_send_byte(0);
return controller_port_send_byte(0) == 'G';
}
bool k573mcr_device::memcard_write(uint32_t port_no, uint16_t block_addr, uint8_t *input)
{
controller_set_port(port_no);
controller_port_send_byte(0x81);
if (controller_port_send_byte('W') == 0xff) { // state_command, Request write
return false;
}
controller_port_send_byte(0); // state_command -> state_cmdack
controller_port_send_byte(0); // state_cmdack -> state_wait
controller_port_send_byte(block_addr >> 8); // state_wait -> state_addr_hi
controller_port_send_byte(block_addr & 0xff); // state_addr_hi -> state_addr_lo
uint8_t checksum = (block_addr >> 8) ^ (block_addr & 0xff);
for (int i = 0; i < MEMCARD_BLOCK_SIZE; i++) {
controller_port_send_byte(input[i]); // state_read
checksum ^= input[i];
}
controller_port_send_byte(checksum);
controller_port_send_byte(0);
controller_port_send_byte(0);
return controller_port_send_byte(0) == 'G';
}
int k573mcr_device::handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer)
{
// Notes:
// 80678::E0:01:06:70:02:01:C0:00:3A: <- Command from game (E0:01:...)
// 80681::E0:00:03:01:01:05: <- Response from memory card reader device (E0:00:...)
//
// The returned value of this function should be 0 (invalid parameters), -1 (unknown command), or the number of bytes in the message.
// The number of bytes to return is covered by the xx section:
// 80678::E0:01:yy:xx:xx:xx:xx:xx:3A:
// This should correspond to yy - 1, but you don't actually get access to yy in the message handler so you must calculate it yourself.
//
// recv_buffer will correspond to this part when returning data:
// 80681::E0:00:03:01:rr:05:
// In some special cases there is an empty respond but that is not supported in MAME currently so a single byte is returned instead.
switch(send_buffer[0]) {
case 0xf0:
// The bootloader for System 573 games checks for the master calendar which initializes the JVS device.
// After the bootloader, the actual game's code tries to initialize the JVS device again and (seemingly)
// expects it to be in a fresh state. Since it was already initialized in the bootloader, it will throw
// the error message "JVS SUBS RESET ERROR".
// There might be something else that happens on real hardware between when it loads the bootloader
// and when it starts the actual game's code that resets the JVS device, but I do not have hands on
// access to test such a thing.
// Reset immediately to hack around that error.
device_reset();
break;
case 0x14:
// Function list returns nothing on
// 75502::E0:01:02:14:17:
// 75503::E0:00:04:01:01:00:06:
*recv_buffer++ = 0x01;
*recv_buffer++ = 0x00;
return 1;
case 0x70:
{
int ram_addr = (send_buffer[2] << 16) | (send_buffer[3] << 8) | send_buffer[4];
int target_len = send_buffer[5];
if (send_buffer[1] == 0) {
// Buffer read
// 39595::E0:01:07:70:00:02:00:00:80:FA:
// 39596::E0:00:83:01:01:4D:43:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
// :00:00:00:00:00:00:
*recv_buffer++ = 0x01;
if (target_len > 0 && ram_addr + target_len < RAM_SIZE) {
memcpy(recv_buffer, &m_ram[ram_addr], target_len);
recv_buffer += target_len;
}
return 6;
} else if (send_buffer[1] == 1) {
// Buffer write
// 77565::E0:01:87:70:01:02:04:00:80:24:A5:04:70:30:30:7A
// :24:87:C6:85:10:00:64:05:58:02:44:45:CA:8C:FD:A2
// :00:04:A3:00:04:8C:A6:00:FF:08:8C:00:82:00:20:00
// :E8:00:F4:00:DD:F8:C0:24:EF:85:FC:21:20:20:04:5B
// :14:40:51:73:77:
// 77583::E0:00:01:
if (target_len > 0) {
memcpy(&m_ram[ram_addr], send_buffer + 6, target_len);
}
*recv_buffer++ = 0x01;
return 6 + target_len;
} else if (send_buffer[1] == 2) {
// Set execution address
// 80678::E0:01:06:70:02:01:C0:00:3A:
// 80681::E0:00:03:01:01:05:
*recv_buffer++ = 0x01;
return 5;
}
return -1;
}
case 0x71:
{
// Status request
// 81681::E0:01:02:71:74:
// 81682::E0:00:05:01:01:00:00:07:
*recv_buffer++ = 0x01;
*recv_buffer++ = m_status >> 8;
*recv_buffer++ = m_status & 0xff;
return 1;
}
case 0x72:
{
// Security plate
uint8_t cmd = send_buffer[1] & ~1;
int sec_slot = send_buffer[1] & 1;
if (cmd == 0x00) {
// Packet: e0 01 03 72 00 76 slot 0 (CN63)
// Packet: e0 01 03 72 01 77 slot 1 (CN64)
*recv_buffer++ = 0x01;
return 2;
} else if (cmd == 0x10) {
// Set password (presumably to unlock/read security dongle)
// Packet: e0 01 0b 72 10 a4 60 f0 5d ea c4 5d ec d6
*recv_buffer++ = 0x01;
return 10;
} else if (cmd == 0x20) {
// Get dongle data? (slot 0: GE885-JB, slot 1: ?)
// Packet: e0 01 0a 72 20 00 00 02 00 00 00 08 a7
// It seems that as long as the checksum matches, the game will accept it as valid
int ram_addr = (send_buffer[4] << 16) | (send_buffer[5] << 8) | send_buffer[6];
m_ram[ram_addr] = 'J';
m_ram[ram_addr + 1] = sec_slot ? 'A' : 'B'; // GF uses GE929-JA, but the games will accept anything
m_ram[ram_addr + 2] = 0x00;
m_ram[ram_addr + 3] = 0x00;
m_ram[ram_addr + 4] = ~(m_ram[ram_addr] + m_ram[ram_addr + 1]); // Checksum byte
*recv_buffer++ = 0x01;
return 9;
} else if (cmd == 0x40) {
// Get some kind of registration info from dongle?
// Game code calls it "config register"
// Packet: e0 01 06 72 40 02 00 00 bb
int ram_addr = (send_buffer[2] << 16) | (send_buffer[3] << 8) | send_buffer[4];
m_ram[ram_addr] = 0xFF;
m_ram[ram_addr + 1] = 0xFF;
m_ram[ram_addr + 2] = 0xAC;
m_ram[ram_addr + 3] = 0x09;
m_ram[ram_addr + 4] = 0x00;
*recv_buffer++ = 0x01;
return 5;
}
return -1;
}
case 0x73:
{
// Execute previously set address (0x70 0x02)
// 81674::E0:01:02:73:76:
// 81675::E0:00:03:01:01:05:
*recv_buffer++ = 0x01;
return 1;
}
case 0x76:
{
// Memory card
if (send_buffer[1] == 0x74) {
// Read from card
// Packet (port 2): e0 01 0a 76 74 80 00 02 00 00 00 01 78
int memcard_port = send_buffer[2] >> 7;
int memcard_addr = ((send_buffer[2] << 8) | send_buffer[3]) & 0x7fff;
int ram_addr = (send_buffer[4] << 16) | (send_buffer[5] << 8) | send_buffer[6];
int block_count = (send_buffer[7] << 8) | send_buffer[8];
bool is_ejected = BIT(m_meta->read(), memcard_port); // Forcefully ejected using hotkey
if (!is_ejected && memcard_read(memcard_port, 0, nullptr)) {
// Check if card is inserted
m_status = MEMCARD_AVAILABLE;
} else {
m_status = MEMCARD_UNAVAILABLE;
}
if (m_status == MEMCARD_AVAILABLE) {
for (int i = 0; i < block_count; i++) {
m_status |= MEMCARD_READING;
if (memcard_read(memcard_port, memcard_addr + i, &m_ram[ram_addr + (i * MEMCARD_BLOCK_SIZE)])) {
m_status = MEMCARD_AVAILABLE;
} else {
m_status = MEMCARD_ERROR;
break;
}
}
}
*recv_buffer++ = 0x01;
*recv_buffer++ = 0x01;
return 9;
} else if (send_buffer[1] == 0x75) {
// Write to card
// Packet: e0 01 0a 76 75 02 00 00 00 3f 00 01 38
int ram_addr = (send_buffer[2] << 16) | (send_buffer[3] << 8) | send_buffer[4];
int memcard_port = send_buffer[5] >> 7;
int memcard_addr = ((send_buffer[5] << 8) | send_buffer[6]) & 0x7fff;
int block_count = (send_buffer[7] << 8) | send_buffer[8];
bool is_ejected = BIT(m_meta->read(), memcard_port); // Forcefully ejected using hotkey
if (!is_ejected && memcard_read(memcard_port, 0, nullptr)) {
// Check if card is inserted
m_status = MEMCARD_AVAILABLE;
} else {
m_status = MEMCARD_UNAVAILABLE;
}
if (m_status == MEMCARD_AVAILABLE && m_is_memcard_initialized) {
for (int i = 0; i < block_count; i++) {
m_status |= MEMCARD_WRITING;
if (memcard_write(memcard_port, memcard_addr + i, &m_ram[ram_addr + (i * MEMCARD_BLOCK_SIZE)])) {
m_status = MEMCARD_AVAILABLE;
} else {
m_status = MEMCARD_ERROR;
break;
}
}
}
*recv_buffer++ = 0x01;
*recv_buffer++ = 0x01;
// The game will write a block of 0xffs to block 3f immediately after inserting a memory card for the first time.
// I believe it's some kind of initialization, and based on the game's code, the 0xff buffer is prepared when the firmware is being sent.
// Based on someone else's research with real hardware, the 0xff block doesn't actually get written to the memory card.
m_is_memcard_initialized = true;
return 9;
}
return -1;
}
case 0x77:
{
// Controller ports
// Packet: e0 01 02 77 7a
//
// Only used by Guitar Freaks.
// This was introduced in Guitar Freaks 2nd Mix Link Kit 2, which allowed players to bring their own PS1 guitar controllers to the arcade
// and plug it into the machine to use as a controller instead of the normal machine's guitar controllers.
*recv_buffer++ = 0x01;
pad_read(0, recv_buffer);
pad_read(1, recv_buffer + 2);
recv_buffer += 4;
return 1;
}
}
// Command not recognized, pass it off to the base message handler
return jvs_device::handle_message(send_buffer, send_size, recv_buffer);
}
ROM_START( k573mcr )
@ -31,4 +492,16 @@ const tiny_rom_entry *k573mcr_device::device_rom_region() const
return ROM_NAME( k573mcr );
}
INPUT_PORTS_START( k573mcr_meta_controls )
PORT_START("META")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SERVICE1) PORT_TOGGLE PORT_NAME("Insert/Eject Memory Card 1")
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SERVICE2) PORT_TOGGLE PORT_NAME("Insert/Eject Memory Card 2")
INPUT_PORTS_END
ioport_constructor k573mcr_device::device_input_ports() const
{
return INPUT_PORTS_NAME(k573mcr_meta_controls);
}
DEFINE_DEVICE_TYPE(KONAMI_573_MEMORY_CARD_READER, k573mcr_device, "k573mcr", "Konami 573 Memory Card Reader")

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:smf
// copyright-holders:smf, windyfairy
/*
* Konami 573 Memory Card Reader
*
@ -9,19 +9,73 @@
#pragma once
#include "bus/psx/ctlrport.h"
#include "machine/jvsdev.h"
#include "machine/timer.h"
class k573mcr_device : public jvs_device
{
public:
template <typename T>
k573mcr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&jvs_host_tag)
: k573mcr_device(mconfig, tag, owner, clock)
{
host.set_tag(std::forward<T>(jvs_host_tag));
}
k573mcr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ioport_constructor device_input_ports() const override;
DECLARE_WRITE_LINE_MEMBER(write_rxd);
protected:
template <uint8_t First> void set_port_tags() { }
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
// JVS device overrides
virtual const char *device_id() override;
virtual uint8_t command_format_version() override;
virtual uint8_t jvs_standard_version() override;
virtual uint8_t comm_method_version() override;
virtual int handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer) override;
private:
enum {
MEMCARD_UNINITIALIZED = 0x0000, // Default value, also used after writing?
MEMCARD_ERROR = 0x0002,
MEMCARD_UNAVAILABLE = 0x0008, // Card is not inserted
MEMCARD_READING = 0x0200, // Read request is executing
MEMCARD_WRITING = 0x0400, // Write request is executing
MEMCARD_AVAILABLE = 0x8000 // Can be combined with MEMCARD_READING and MEMCARD_WRITING for busy state
};
enum {
RAM_SIZE = 0x400000,
MEMCARD_BLOCK_SIZE = 128
};
void controller_set_port(uint32_t port_no);
uint8_t controller_port_send_byte(uint8_t data);
bool pad_read(uint32_t port_no, uint8_t *output);
bool memcard_read(uint32_t port_no, uint16_t block_addr, uint8_t *output);
bool memcard_write(uint32_t port_no, uint16_t block_addr, uint8_t *input);
std::unique_ptr<uint8_t[]> m_ram;
uint16_t m_status;
bool m_is_memcard_initialized;
uint8_t m_psx_rx_data, m_psx_rx_bit;
bool m_psx_clock;
required_device<psxcontrollerports_device> m_controllers;
required_ioport m_meta;
};
DECLARE_DEVICE_TYPE(KONAMI_573_MEMORY_CARD_READER, k573mcr_device)
class k573mcr_device : public device_t
{
public:
k573mcr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void device_start() override;
virtual const tiny_rom_entry *device_rom_region() const override;
};
#endif // MAME_MACHINE_K573_MCR_H