-bus/sms_ctrl: Added raphnet DIY SMS/Mark III paddle.

-cpu/avr8: Added minimal ADC support (in particular, ADC interrupts are
 not implemented).

-sega/megadriv.cpp: Further broke up base Mega Drive class.
* Created a light-weight base class with just the core functionality,
  used for "Genie" hardware (Puckman Pockimon).
* Moved built-in controller emulation to a derived class so it isn't
  lurking underneath the consoles with pluggable controllers.
* Moved the Sun Mixing Mega Drive bootlegs to their own source file -
  they're substantially different, not using the I/O blocks for input.

-sega/sms.cpp: Untangled SG-1000 Mark III slightly.
This commit is contained in:
Vas Crabb 2022-12-13 08:00:03 +11:00
parent 3e8cb6894c
commit 85fd7f8c45
24 changed files with 1268 additions and 623 deletions

View File

@ -3545,6 +3545,8 @@ if (BUSES["SMS_CTRL"]~=null) then
files {
MAME_DIR .. "src/devices/bus/sms_ctrl/controllers.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/controllers.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/diypaddle.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/diypaddle.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/joypad.cpp",

View File

@ -9,6 +9,7 @@
#include "emu.h"
#include "controllers.h"
#include "diypaddle.h"
#include "graphic.h"
#include "joypad.h"
#include "lphaser.h"
@ -22,6 +23,7 @@
#include "sportsjp.h"
char const *const SMS_CTRL_OPTION_DIY_PADDLE = "diypaddle";
char const *const SMS_CTRL_OPTION_GRAPHIC = "graphic";
char const *const SMS_CTRL_OPTION_LPHASER = "lphaser";
char const *const SMS_CTRL_OPTION_MD_6BUTTON = "md6button";
@ -38,6 +40,7 @@ char const *const SMS_CTRL_OPTION_SPORTS_JP = "sportsjp";
void sms_control_port_devices(device_slot_interface &device)
{
device.option_add(SMS_CTRL_OPTION_DIY_PADDLE, SMS_DIY_PADDLE);
device.option_add(SMS_CTRL_OPTION_GRAPHIC, SMS_GRAPHIC);
device.option_add(SMS_CTRL_OPTION_LPHASER, SMS_LIGHT_PHASER);
device.option_add(SMS_CTRL_OPTION_MD_6BUTTON, SMS_MD6BUTTON);

View File

@ -11,6 +11,7 @@
#pragma once
extern char const *const SMS_CTRL_OPTION_DIY_PADDLE;
extern char const *const SMS_CTRL_OPTION_GRAPHIC;
extern char const *const SMS_CTRL_OPTION_LPHASER;
extern char const *const SMS_CTRL_OPTION_MD_6BUTTON;

View File

@ -0,0 +1,227 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Raphaël Assenat's DIY SMS/Mark III Paddle Controller
English description:
https://www.raphnet.net/electronique/sms_paddle/index_en.php
French description:
https://www.raphnet.net/electronique/sms_paddle/index.php
Firmware source:
https://github.com/raphnet/sms_paddle
TODO:
* Add ATmega8 variant - need CPU core.
**********************************************************************/
#include "emu.h"
#include "diypaddle.h"
#include "cpu/avr8/avr8.h"
namespace {
ROM_START( sms_diy_paddle )
ROM_REGION(0x4000, "u1", ROMREGION_ERASEFF)
ROM_LOAD( "sms_paddle.bin", 0x0000, 0x0138, CRC(97c7d334) SHA1(dd9e20f2447c43dbe29a49bb3a4fd8049775acd3) )
ROM_REGION(0x200, "eeprom", ROMREGION_ERASEFF)
ROM_END
INPUT_PORTS_START( sms_diy_paddle )
PORT_START("BUTTON")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_START("PADDLE")
PORT_BIT( 0x3ff, 0x200, IPT_PADDLE) PORT_MINMAX(0, 1023) PORT_REVERSE PORT_SENSITIVITY(160) PORT_KEYDELTA(20) PORT_CENTERDELTA(0)
PORT_START("MODE")
PORT_CONFNAME( 0x01, 0x00, "Mode" )
PORT_CONFSETTING( 0x00, "HPD-200" )
PORT_CONFSETTING( 0x01, "Export paddle" )
INPUT_PORTS_END
class sms_diy_paddle_device : public device_t, public device_sms_control_interface
{
public:
sms_diy_paddle_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual u8 in_r() override;
virtual void out_w(u8 data, u8 mem_mask) override;
protected:
virtual tiny_rom_entry const *device_rom_region() const override { return ROM_NAME(sms_diy_paddle); }
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_diy_paddle); }
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
private:
void program_map(address_map &map);
void data_map(address_map &map);
u8 portb_in();
u8 portc_in();
u8 portd_in();
void portb_out(u8 data);
void portc_out(u8 data);
TIMER_CALLBACK_MEMBER(set_lines);
TIMER_CALLBACK_MEMBER(set_portd);
required_device<avr8_device> m_mcu;
required_ioport m_button;
required_ioport m_paddle;
required_ioport m_mode;
u8 m_lines;
u8 m_portb;
u8 m_portc;
u8 m_portd;
};
sms_diy_paddle_device::sms_diy_paddle_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_DIY_PADDLE, tag, owner, clock),
device_sms_control_interface(mconfig, *this),
m_mcu(*this, "u1"),
m_button(*this, "BUTTON"),
m_paddle(*this, "PADDLE"),
m_mode(*this, "MODE"),
m_lines(0x2f),
m_portb(0xff),
m_portc(0xff),
m_portd(0xff)
{
}
u8 sms_diy_paddle_device::in_r()
{
if (!machine().side_effects_disabled())
machine().scheduler().add_quantum(attotime::from_usec(5), attotime::from_usec(100));
// button connected to TL directly
return m_lines | (BIT(m_button->read(), 0) << 4);
}
void sms_diy_paddle_device::out_w(u8 data, u8 mem_mask)
{
// TH connected to PD2
machine().scheduler().synchronize(
timer_expired_delegate(FUNC(sms_diy_paddle_device::set_portd), this),
0xfb | (BIT(data, 6) << 2));
machine().scheduler().add_quantum(attotime::from_usec(1), attotime::from_usec(20));
}
void sms_diy_paddle_device::device_add_mconfig(machine_config &config)
{
ATMEGA168(config, m_mcu, 8'000'000); // internally-generated clock
m_mcu->set_addrmap(AS_PROGRAM, &sms_diy_paddle_device::program_map);
m_mcu->set_addrmap(AS_DATA, &sms_diy_paddle_device::data_map);
m_mcu->set_eeprom_tag("eeprom");
m_mcu->set_low_fuses(0xe2);
m_mcu->set_high_fuses(0xdd);
m_mcu->set_extended_fuses(0xf9);
m_mcu->gpio_in<AVR8_IO_PORTB>().set(FUNC(sms_diy_paddle_device::portb_in));
m_mcu->gpio_in<AVR8_IO_PORTC>().set(FUNC(sms_diy_paddle_device::portc_in));
m_mcu->gpio_in<AVR8_IO_PORTD>().set(FUNC(sms_diy_paddle_device::portd_in));
m_mcu->gpio_out<AVR8_IO_PORTB>().set(FUNC(sms_diy_paddle_device::portb_out));
m_mcu->gpio_out<AVR8_IO_PORTC>().set(FUNC(sms_diy_paddle_device::portc_out));
m_mcu->adc_in<AVR8_ADC_ADC0>().set_ioport("PADDLE");
}
void sms_diy_paddle_device::device_start()
{
m_lines = 0x2f;
m_portb = 0xff;
m_portc = 0xff;
m_portd = 0xff;
save_item(NAME(m_lines));
save_item(NAME(m_portb));
save_item(NAME(m_portc));
save_item(NAME(m_portd));
}
void sms_diy_paddle_device::program_map(address_map &map)
{
map(0x0000, 0x3fff).rom();
}
void sms_diy_paddle_device::data_map(address_map &map)
{
map(0x0100, 0x04ff).ram();
}
u8 sms_diy_paddle_device::portb_in()
{
// PB0 looped back to PB1 via mode switch
if (BIT(m_mode->read(), 0))
return 0xfc | bitswap<2>(m_portb, 0, 0);
else
return 0xfe | BIT(m_portb, 0);
}
u8 sms_diy_paddle_device::portc_in()
{
return (m_portc & 0x3e) | 0xc0 | ((m_paddle->read() > 0x1ff) ? 0x01 : 0x00);
}
u8 sms_diy_paddle_device::portd_in()
{
return m_portd;
}
void sms_diy_paddle_device::portb_out(u8 data)
{
m_portb = data;
}
void sms_diy_paddle_device::portc_out(u8 data)
{
// PC1 -> TR, PC2 -> Up, PC3 -> Down, PC4 -> Left, PC5 -> Right
if (data != m_portc)
{
m_portc = data;
machine().scheduler().synchronize(
timer_expired_delegate(FUNC(sms_diy_paddle_device::set_lines), this),
(BIT(data, 1) << 5) | BIT(data, 2, 4));
machine().scheduler().add_quantum(attotime::from_usec(1), attotime::from_usec(20));
}
}
TIMER_CALLBACK_MEMBER(sms_diy_paddle_device::set_lines)
{
m_lines = param & 0x2f;
}
TIMER_CALLBACK_MEMBER(sms_diy_paddle_device::set_portd)
{
m_portd = param & 0xff;
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(SMS_DIY_PADDLE, device_sms_control_interface, sms_diy_paddle_device, "sms_diypaddle", "raphnet DIY SMS/Mark III Paddle Controller")

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Raphaël Assenat's DIY SMS/Mark III Paddle Controller
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_DIYPADDLE_H
#define MAME_BUS_SMS_CTRL_DIYPADDLE_H
#pragma once
#include "smsctrl.h"
DECLARE_DEVICE_TYPE(SMS_DIY_PADDLE, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_DIYPADDLE_H

View File

@ -94,8 +94,10 @@
| LOG_OSC | LOG_PINCHG | LOG_EXTMEM | LOG_ADC | LOG_DIGINPUT | LOG_ASYNC | LOG_TWI | LOG_UART)
#define VERBOSE (0)
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
//**************************************************************************
// ENUMS AND MACROS
//**************************************************************************
@ -587,6 +589,37 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' };
#define AVR8_EECR_EEPE ((AVR8_EECR & AVR8_EECR_EEPE_MASK) >> 1)
#define AVR8_EECR_EERE ((AVR8_EECR & AVR8_EECR_EERE_MASK) >> 0)
//---------------------------------------------------------------
#define AVR8_ADMUX (m_r[AVR8_REGIDX_ADMUX])
#define AVR8_ADMUX_REFS_MASK 0xc0
#define AVR8_ADMUX_ADLAR_MASK 0x20
#define AVR8_ADMUX_MUX_MASK 0x0f
#define AVR8_ADMUX_REFS ((AVR8_ADMUX & AVR8_ADMUX_REFS_MASK) >> 6)
#define AVR8_ADMUX_ADLAR ((AVR8_ADMUX & AVR8_ADMUX_ADLAR_MASK) >> 5)
#define AVR8_ADMUX_MUX ((AVR8_ADMUX & AVR8_ADMUX_MUX_MASK) >> 0)
#define AVR8_ADCSRB (m_r[AVR8_REGIDX_ADCSRB])
#define AVR8_ADCSRB_ACME_MASK 0x40
#define AVR8_ADCSRB_ADTS_MASK 0x07
#define AVR8_ADCSRB_ACME ((AVR8_ADCSRB & AVR8_ADCSRB_ACME_MASK) >> 6)
#define AVR8_ADCSRB_ADTS ((AVR8_ADCSRB & AVR8_ADCSRB_ADTS_MASK) >> 0)
#define AVR8_ADCSRA (m_r[AVR8_REGIDX_ADCSRA])
#define AVR8_ADCSRA_ADEN_MASK 0x80
#define AVR8_ADCSRA_ADSC_MASK 0x40
#define AVR8_ADCSRA_ADATE_MASK 0x20
#define AVR8_ADCSRA_ADIF_MASK 0x10
#define AVR8_ADCSRA_ADIE_MASK 0x08
#define AVR8_ADCSRA_ADPS_MASK 0x07
#define AVR8_ADCSRA_ADEN ((AVR8_ADCSRA & AVR8_ADCSRA_ADEN_MASK) >> 7)
#define AVR8_ADCSRA_ADSC ((AVR8_ADCSRA & AVR8_ADCSRA_ADSC_MASK) >> 6)
#define AVR8_ADCSRA_ADATE ((AVR8_ADCSRA & AVR8_ADCSRA_ADATE_MASK) >> 5)
#define AVR8_ADCSRA_ADIF ((AVR8_ADCSRA & AVR8_ADCSRA_ADIF_MASK) >> 4)
#define AVR8_ADCSRA_ADIE ((AVR8_ADCSRA & AVR8_ADCSRA_ADIE_MASK) >> 3)
#define AVR8_ADCSRA_ADPS ((AVR8_ADCSRA & AVR8_ADCSRA_ADPS_MASK) >> 0)
//**************************************************************************
// DEVICE INTERFACE
//**************************************************************************
@ -719,6 +752,8 @@ avr8_device::avr8_device(const machine_config &mconfig, const char *tag, device_
, m_num_timers(num_timers)
, m_gpio_out_cb(*this)
, m_gpio_in_cb(*this)
, m_adc_in_cb(*this)
, m_adc_timer(nullptr)
, m_spi_active(false)
, m_spi_prescale(0)
, m_spi_prescale_count(0)
@ -817,6 +852,9 @@ void avr8_device::device_start()
m_gpio_out_cb.resolve_all_safe();
m_gpio_in_cb.resolve_all_safe(0);
m_adc_in_cb.resolve_all_safe(0);
m_adc_timer = timer_alloc(FUNC(avr8_device::adc_conversion_complete), this);
// register our state for the debugger
state_add(STATE_GENPC, "GENPC", m_shifted_pc).noshow();
state_add(STATE_GENPCBASE, "CURPC", m_shifted_pc).noshow();
@ -878,6 +916,13 @@ void avr8_device::device_start()
save_item(NAME(m_ocr1));
save_item(NAME(m_timer1_count));
// ADC
save_item(NAME(m_adc_sample));
save_item(NAME(m_adc_result));
save_item(NAME(m_adc_data));
save_item(NAME(m_adc_first));
save_item(NAME(m_adc_hold));
// SPI
save_item(NAME(m_spi_active));
save_item(NAME(m_spi_prescale));
@ -960,6 +1005,12 @@ void avr8_device::device_reset()
m_r[i] = 0;
}
m_adc_sample = 0;
m_adc_result = 0;
m_adc_data = 0;
m_adc_first = true;
m_adc_hold = false;
m_spi_active = false;
m_spi_prescale = 0;
m_spi_prescale_count = 0;
@ -2234,6 +2285,103 @@ void avr8_device::changed_tccr5b(uint8_t data)
/************************************************************************************************/
/****************/
/* ADC Handling */
/****************/
void avr8_device::adc_start_conversion()
{
// set capture in progress flag
AVR8_ADCSRA |= AVR8_ADCSRA_ADSC_MASK;
// get a sample - the sample-and-hold circuit will hold this for the duration of the conversion
if (AVR8_ADMUX_MUX < 0x8)
{
m_adc_sample = m_adc_in_cb[AVR8_ADMUX_MUX]();
}
else if (AVR8_ADMUX_MUX == 0xe)
{
// 1.1V (Vbg)
// FIXME: the value this acquires depends on what the reference source is set to
logerror("%s: Using unimplemented 1.1V reference voltage as ADC input\n", machine().describe_context());
m_adc_sample = 0x3ff;
}
else if (AVR8_ADMUX_MUX == 0x0f)
{
// 0V (GND)
m_adc_sample = 0;
}
else
{
logerror("%s: Using reserved ADC input 0x%X\n", machine().describe_context(), AVR8_ADMUX_MUX);
m_adc_sample = 0;
}
// wait for conversion to complete
int const scale = 1 << std::max(AVR8_ADCSRA_ADPS, 1);
m_adc_timer->adjust(attotime::from_ticks((m_adc_first ? 25 : 13) * scale, clock()));
}
TIMER_CALLBACK_MEMBER(avr8_device::adc_conversion_complete)
{
// set conversion result
m_adc_result = m_adc_sample;
if (!m_adc_hold)
m_adc_data = m_adc_result;
// clear conversion in progress flag, set conversion interrupt flag
AVR8_ADCSRA &= ~AVR8_ADCSRA_ADSC_MASK;
AVR8_ADCSRA |= AVR8_ADCSRA_ADIF_MASK;
// trigger another conversion if appropriate
if (AVR8_ADCSRA_ADATE && (AVR8_ADCSRB_ADTS == 0))
adc_start_conversion();
}
void avr8_device::change_adcsra(uint8_t data)
{
// set auto trigger enable, interrupt enable, and prescaler directly
AVR8_ADCSRA = (AVR8_ADCSRA & ~(AVR8_ADCSRA_ADATE_MASK | AVR8_ADCSRA_ADIE_MASK | AVR8_ADCSRA_ADPS_MASK)) | (data & (AVR8_ADCSRA_ADATE_MASK | AVR8_ADCSRA_ADIE_MASK | AVR8_ADCSRA_ADPS_MASK));
// check enable bit
if (!(data & AVR8_ADCSRA_ADEN_MASK))
{
// disable ADC, terminate any conversion in progress
AVR8_ADCSRA &= ~(AVR8_ADCSRA_ADEN_MASK | AVR8_ADCSRA_ADSC_MASK);
m_adc_timer->reset();
}
else
{
// first conversion after initial enable takes longer
if (!AVR8_ADCSRA_ADEN)
{
m_adc_first = true;
AVR8_ADCSRA |= AVR8_ADCSRA_ADEN_MASK;
}
// trigger conversion if necessary
if (!AVR8_ADCSRA_ADSC && (data & AVR8_ADCSRA_ADSC_MASK))
adc_start_conversion();
}
// writing with ADIF set clears the interrupt flag manually
if (data & AVR8_ADCSRA_ADIF_MASK)
AVR8_ADCSRA &= ~AVR8_ADCSRA_ADIF_MASK;
if (AVR8_ADCSRA_ADIE)
logerror("%s: Unimplemented ADC interrupt enabled\n");
}
void avr8_device::change_adcsrb(uint8_t data)
{
AVR8_ADCSRB = data & (AVR8_ADCSRB_ACME_MASK | AVR8_ADCSRB_ADTS_MASK);
if (AVR8_ADCSRB_ADTS != 0x00)
logerror("%s: Unimplemented ADC auto trigger source %X selected\n", machine().describe_context(), AVR8_ADCSRB_ADTS);
}
/************************************************************************************************/
/****************/
/* SPI Handling */
/****************/
@ -2690,23 +2838,26 @@ void avr8_device::regs_w(offs_t offset, uint8_t data)
break;
case AVR8_REGIDX_ADCL:
LOGMASKED(LOG_ADC, "%s: (not yet implemented) ADCL = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_ADC, "%s: ADCL = %02x\n", machine().describe_context(), data);
break;
case AVR8_REGIDX_ADCH:
LOGMASKED(LOG_ADC, "%s: (not yet implemented) ADCH = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_ADC, "%s: ADCH = %02x\n", machine().describe_context(), data);
break;
case AVR8_REGIDX_ADCSRA:
LOGMASKED(LOG_ADC, "%s: (not yet implemented) ADCSRA = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_ADC, "%s: ADCSRA = %02x\n", machine().describe_context(), data);
change_adcsra(data);
break;
case AVR8_REGIDX_ADCSRB:
LOGMASKED(LOG_ADC, "%s: (not yet implemented) ADCSRB = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_ADC, "%s: ADCSRB = %02x\n", machine().describe_context(), data);
change_adcsrb(data);
break;
case AVR8_REGIDX_ADMUX:
LOGMASKED(LOG_ADC, "%s: (not yet implemented) ADMUX = %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_ADC, "%s: ADMUX = %02x\n", machine().describe_context(), data);
AVR8_ADMUX = data & (AVR8_ADMUX_REFS_MASK | AVR8_ADMUX_ADLAR_MASK | AVR8_ADMUX_MUX_MASK);
break;
case AVR8_REGIDX_DIDR0:
@ -3147,6 +3298,28 @@ uint8_t avr8_device::regs_r(offs_t offset)
case AVR8_REGIDX_UCSR0A:
return m_r[offset];
case AVR8_REGIDX_ADCL:
if (!machine().side_effects_disabled())
m_adc_hold = true;
if (AVR8_ADMUX_ADLAR)
return (m_adc_data & 0x03) << 6;
else
return uint8_t(m_adc_data);
case AVR8_REGIDX_ADCH:
{
uint8_t const result = AVR8_ADMUX_ADLAR ? BIT(m_adc_data, 2, 8) : BIT(m_adc_data, 8, 2);
if (!machine().side_effects_disabled())
{
m_adc_data = m_adc_result;
m_adc_hold = false;
}
return result;
}
case AVR8_REGIDX_ADCSRA:
case AVR8_REGIDX_ADCSRB:
case AVR8_REGIDX_ADMUX:
return m_r[offset];
default:
LOGMASKED(LOG_UNKNOWN, "%s: Unknown Register Read: %03X\n", machine().describe_context(), offset);
return 0;

View File

@ -15,8 +15,6 @@
// TYPE DEFINITIONS
//**************************************************************************
class avr8_device;
// ======================> avr8_device
// Used by core CPU interface
@ -44,6 +42,9 @@ public:
template<uint8_t Port> auto gpio_out() { return m_gpio_out_cb[Port].bind(); }
template<uint8_t Port> auto gpio_in() { return m_gpio_in_cb[Port].bind(); }
// ADC
template<uint8_t Pin> auto adc_in() { return m_adc_in_cb[Pin].bind(); }
protected:
avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t address_mask, address_map_constructor internal_map, int32_t num_timers);
@ -115,6 +116,19 @@ protected:
devcb_write8::array<11> m_gpio_out_cb;
devcb_read8::array<11> m_gpio_in_cb;
// ADC
devcb_read16::array<8> m_adc_in_cb;
emu_timer *m_adc_timer;
uint16_t m_adc_sample;
uint16_t m_adc_result;
uint16_t m_adc_data;
bool m_adc_first;
bool m_adc_hold;
void adc_start_conversion();
TIMER_CALLBACK_MEMBER(adc_conversion_complete);
void change_adcsra(uint8_t data);
void change_adcsrb(uint8_t data);
// SPI
bool m_spi_active;
uint8_t m_spi_prescale;
@ -822,7 +836,8 @@ enum : uint16_t
//0x1FF: Reserved
};
enum : uint8_t {
enum : uint8_t
{
AVR8_IO_PORTA = 0,
AVR8_IO_PORTB,
AVR8_IO_PORTC,
@ -836,6 +851,18 @@ enum : uint8_t {
AVR8_IO_PORTL
};
enum : uint8_t
{
AVR8_ADC_ADC0 = 0,
AVR8_ADC_ADC1,
AVR8_ADC_ADC2,
AVR8_ADC_ADC3,
AVR8_ADC_ADC4,
AVR8_ADC_ADC5,
AVR8_ADC_ADC6,
AVR8_ADC_ADC7
};
enum : uint8_t
{
AVR8_REG_A = 0,

View File

@ -23331,12 +23331,10 @@ barek3mb // MegaDrive-based hack
bk3ssrmb // MegaDrive-based hack
jparkmb // MegaDrive-based hack
mk3mdb // MegaDrive-based hack
sbubsm // (c) 1996 Sun Mixing
sonic2mb // MegaDrive-based hack
sonic3mb // MegaDrive-based hack
srmdb // MegaDrive-based hack
ssf2mdb // MegaDrive-based hack
topshoot // (c) 1995 Sun Mixing
twinktmb // MegaDrive-based hack
@source:sega/megadriv_rad.cpp
@ -23354,6 +23352,10 @@ msi_sf2
dgunl3227
ra145
@source:sega/megadriv_sunmix.cpp
sbubsm // (c) 1996 Sun Mixing
topshoot // (c) 1995 Sun Mixing
@source:sega/megadriv_sunplus_hybrid.cpp
reactmd

View File

@ -38,8 +38,6 @@ help with figuring out the encryption on the coin-op parts of the program.
#include "emu.h"
#include "megadriv.h"
#include "megadriv_acbl.h"
#include "cpu/m68000/m68000.h"

View File

@ -98,7 +98,7 @@ void md_base_state::megadriv_68k_YM2612_write(offs_t offset, uint8_t data, uint8
}
// this is used by 6 button pads and gets installed in machine_start for drivers requiring it
TIMER_CALLBACK_MEMBER(md_base_state::ioport_timeout)
TIMER_CALLBACK_MEMBER(md_ctrl_state::ioport_timeout)
{
m_ioport_phase[param] = 0;
}
@ -175,7 +175,7 @@ INPUT_PORTS_END
template <unsigned N>
uint8_t md_base_state::ioport_in_3button()
uint8_t md_ctrl_state::ioport_in_3button()
{
ioport_value const pad = m_io_pad[N]->read();
if (m_ioport_th[N])
@ -185,7 +185,7 @@ uint8_t md_base_state::ioport_in_3button()
}
template <unsigned N>
uint8_t md_base_state::ioport_in_6button()
uint8_t md_ctrl_state::ioport_in_6button()
{
ioport_value const pad = m_io_pad[N]->read();
switch (m_ioport_phase[N])
@ -211,13 +211,13 @@ uint8_t md_base_state::ioport_in_6button()
}
template <unsigned N>
void md_base_state::ioport_out_3button(uint8_t data, uint8_t mem_mask)
void md_ctrl_state::ioport_out_3button(uint8_t data, uint8_t mem_mask)
{
m_ioport_th[N] = BIT(data, 6);
}
template <unsigned N>
void md_base_state::ioport_out_6button(uint8_t data, uint8_t mem_mask)
void md_ctrl_state::ioport_out_6button(uint8_t data, uint8_t mem_mask)
{
uint8_t const th = BIT(data, 6);
if (!th)
@ -232,15 +232,6 @@ void md_base_state::ioport_out_6button(uint8_t data, uint8_t mem_mask)
m_ioport_th[N] = th;
}
template uint8_t md_base_state::ioport_in_3button<0>();
template uint8_t md_base_state::ioport_in_3button<1>();
template uint8_t md_base_state::ioport_in_6button<0>();
template uint8_t md_base_state::ioport_in_6button<1>();
template void md_base_state::ioport_out_3button<0>(uint8_t, uint8_t);
template void md_base_state::ioport_out_3button<1>(uint8_t, uint8_t);
template void md_base_state::ioport_out_6button<0>(uint8_t, uint8_t);
template void md_base_state::ioport_out_6button<1>(uint8_t, uint8_t);
uint16_t md_base_state::m68k_version_read()
{
@ -648,9 +639,9 @@ void md_base_state::megadriv_z80_io_map(address_map &map)
map(0x00, 0xff).noprw();
}
uint32_t md_base_state::screen_update_megadriv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
uint32_t md_core_state::screen_update_megadriv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
/* Copy our screen buffer here */
// Copy our screen buffer here
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint32_t *const desty = &bitmap.pix(y, 0);
@ -674,16 +665,21 @@ uint32_t md_base_state::screen_update_megadriv(screen_device &screen, bitmap_rgb
/*****************************************************************************************/
void md_core_state::machine_reset()
{
if (!m_vdp->m_use_alt_timing)
{
m_vdp->m_megadriv_scanline_timer = m_scan_timer;
m_vdp->m_megadriv_scanline_timer->adjust(attotime::zero);
}
m_vdp->device_reset_old();
}
void md_base_state::machine_start()
{
m_ioport_idle[0] = timer_alloc(FUNC(md_base_state::ioport_timeout), this);
m_ioport_idle[1] = timer_alloc(FUNC(md_base_state::ioport_timeout), this);
std::fill(std::begin(m_ioport_th), std::end(m_ioport_th), 1);
std::fill(std::begin(m_ioport_phase), std::end(m_ioport_phase), 0);
save_item(NAME(m_ioport_th));
save_item(NAME(m_ioport_phase));
md_core_state::machine_start();
if (m_z80snd)
m_genz80.z80_run_timer = timer_alloc(FUNC(md_base_state::megadriv_z80_run_state), this);
@ -691,7 +687,9 @@ void md_base_state::machine_start()
void md_base_state::machine_reset()
{
/* default state of z80 = reset, with bus */
md_core_state::machine_reset();
// default state of z80 = reset, with bus
osd_printf_debug("Resetting Megadrive / Genesis\n");
if (m_z80snd)
@ -703,18 +701,26 @@ void md_base_state::machine_reset()
m_genz80.z80_run_timer->adjust(attotime::zero);
}
if (!m_vdp->m_use_alt_timing)
{
m_vdp->m_megadriv_scanline_timer = m_scan_timer;
m_vdp->m_megadriv_scanline_timer->adjust(attotime::zero);
}
if (m_megadrive_ram)
memset(m_megadrive_ram, 0x00, 0x10000);
m_vdp->device_reset_old();
}
void md_ctrl_state::machine_start()
{
md_base_state::machine_start();
m_ioport_idle[0] = timer_alloc(FUNC(md_ctrl_state::ioport_timeout), this);
m_ioport_idle[1] = timer_alloc(FUNC(md_ctrl_state::ioport_timeout), this);
std::fill(std::begin(m_ioport_th), std::end(m_ioport_th), 1);
std::fill(std::begin(m_ioport_phase), std::end(m_ioport_phase), 0);
save_item(NAME(m_ioport_th));
save_item(NAME(m_ioport_phase));
}
void md_base_state::megadriv_stop_scanline_timer()
{
if (!m_vdp->m_use_alt_timing)
@ -741,7 +747,7 @@ WRITE_LINE_MEMBER(md_base_state::vdp_sndirqline_callback_genesis_z80)
}
// this comes from the vdp, and is connected to 68k irq level 6 (main vbl interrupt)
WRITE_LINE_MEMBER(md_base_state::vdp_lv6irqline_callback_genesis_68k)
WRITE_LINE_MEMBER(md_core_state::vdp_lv6irqline_callback_genesis_68k)
{
if (state == ASSERT_LINE)
m_maincpu->set_input_line(6, HOLD_LINE);
@ -750,7 +756,7 @@ WRITE_LINE_MEMBER(md_base_state::vdp_lv6irqline_callback_genesis_68k)
}
// this comes from the vdp, and is connected to 68k irq level 4 (raster interrupt)
WRITE_LINE_MEMBER(md_base_state::vdp_lv4irqline_callback_genesis_68k)
WRITE_LINE_MEMBER(md_core_state::vdp_lv4irqline_callback_genesis_68k)
{
if (state == ASSERT_LINE)
m_maincpu->set_input_line(4, HOLD_LINE);
@ -759,7 +765,7 @@ WRITE_LINE_MEMBER(md_base_state::vdp_lv4irqline_callback_genesis_68k)
}
/* Callback when the 68k takes an IRQ */
IRQ_CALLBACK_MEMBER(md_base_state::genesis_int_callback)
IRQ_CALLBACK_MEMBER(md_core_state::genesis_int_callback)
{
if (irqline==4)
{
@ -775,11 +781,64 @@ IRQ_CALLBACK_MEMBER(md_base_state::genesis_int_callback)
}
void md_base_state::megadriv_timers(machine_config &config)
void md_core_state::megadriv_timers(machine_config &config)
{
TIMER(config, m_scan_timer).configure_generic(m_vdp, FUNC(sega315_5313_device::megadriv_scanline_timer_callback));
}
void md_core_state::md_core_ntsc(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_NTSC / 7); // 7.67 MHz
m_maincpu->set_irq_acknowledge_callback(FUNC(md_core_state::genesis_int_callback));
// IRQs are handled via the timers
megadriv_timers(config);
SEGA315_5313(config, m_vdp, MASTER_CLOCK_NTSC, m_maincpu);
m_vdp->set_is_pal(false);
m_vdp->lv6_irq().set(FUNC(md_core_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_core_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->set_screen("megadriv");
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(double(MASTER_CLOCK_NTSC) / 10.0 / 262.0 / 342.0); // same as SMS?
// m_screen->set_refresh_hz(double(MASTER_CLOCK_NTSC) / 8.0 / 262.0 / 427.0); // or 427 Htotal?
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); // Vblank handled manually.
m_screen->set_size(64*8, 620);
m_screen->set_visarea(0, 32*8-1, 0, 28*8-1);
m_screen->set_screen_update(FUNC(md_core_state::screen_update_megadriv)); /* Copies a bitmap */
m_screen->screen_vblank().set(FUNC(md_core_state::screen_vblank_megadriv)); /* Used to Sync the timing */
YM2612(config, m_ymsnd, MASTER_CLOCK_NTSC/7); // 7.67 MHz
}
void md_core_state::md_core_pal(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_PAL / 7); // 7.67 MHz
m_maincpu->set_irq_acknowledge_callback(FUNC(md_core_state::genesis_int_callback));
// IRQs are handled via the timers
megadriv_timers(config);
SEGA315_5313(config, m_vdp, MASTER_CLOCK_PAL, m_maincpu);
m_vdp->set_is_pal(true);
m_vdp->lv6_irq().set(FUNC(md_core_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_core_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->set_screen("megadriv");
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(double(MASTER_CLOCK_PAL) / 10.0 / 313.0 / 342.0); // same as SMS?
// m_screen->set_refresh_hz(double(MASTER_CLOCK_PAL) / 8.0 / 313.0 / 423.0); // or 423 Htotal?
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); // Vblank handled manually.
m_screen->set_size(64*8, 620);
m_screen->set_visarea(0, 32*8-1, 0, 28*8-1);
m_screen->set_screen_update(FUNC(md_core_state::screen_update_megadriv)); /* Copies a bitmap */
m_screen->screen_vblank().set(FUNC(md_core_state::screen_vblank_megadriv)); /* Used to Sync the timing */
YM2612(config, m_ymsnd, MASTER_CLOCK_PAL / 7); // 7.67 MHz
}
void md_base_state::megadriv_ioports(machine_config &config)
{
// TODO: this latches video counters as well as setting interrupt level 2
@ -787,13 +846,9 @@ void md_base_state::megadriv_ioports(machine_config &config)
hl.output_handler().set_inputline(m_maincpu, 2);
MEGADRIVE_IO_PORT(config, m_ioports[0], 0);
m_ioports[0]->set_in_handler(FUNC(md_base_state::ioport_in_3button<0>));
m_ioports[0]->set_out_handler(FUNC(md_base_state::ioport_out_3button<0>));
m_ioports[0]->hl_handler().set("hl", FUNC(input_merger_device::in_w<0>));
MEGADRIVE_IO_PORT(config, m_ioports[1], 0);
m_ioports[1]->set_in_handler(FUNC(md_base_state::ioport_in_3button<1>));
m_ioports[1]->set_out_handler(FUNC(md_base_state::ioport_out_3button<1>));
m_ioports[1]->hl_handler().set("hl", FUNC(input_merger_device::in_w<1>));
MEGADRIVE_IO_PORT(config, m_ioports[2], 0);
@ -801,47 +856,53 @@ void md_base_state::megadriv_ioports(machine_config &config)
}
void md_ctrl_state::ctrl1_3button(machine_config &config)
{
m_ioports[0]->set_in_handler(FUNC(md_ctrl_state::ioport_in_3button<0>));
m_ioports[0]->set_out_handler(FUNC(md_ctrl_state::ioport_out_3button<0>));
}
void md_ctrl_state::ctrl2_3button(machine_config &config)
{
m_ioports[1]->set_in_handler(FUNC(md_ctrl_state::ioport_in_3button<1>));
m_ioports[1]->set_out_handler(FUNC(md_ctrl_state::ioport_out_3button<1>));
}
void md_ctrl_state::ctrl1_6button(machine_config &config)
{
m_ioports[0]->set_in_handler(FUNC(md_ctrl_state::ioport_in_6button<0>));
m_ioports[0]->set_out_handler(FUNC(md_ctrl_state::ioport_out_6button<0>));
}
void md_ctrl_state::ctrl2_6button(machine_config &config)
{
m_ioports[1]->set_in_handler(FUNC(md_ctrl_state::ioport_in_6button<1>));
m_ioports[1]->set_out_handler(FUNC(md_ctrl_state::ioport_out_6button<1>));
}
void md_base_state::md_ntsc(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_NTSC / 7); /* 7.67 MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &md_base_state::megadriv_68k_map);
m_maincpu->set_irq_acknowledge_callback(FUNC(md_base_state::genesis_int_callback));
md_core_ntsc(config);
/* IRQs are handled via the timers */
m_maincpu->set_addrmap(AS_PROGRAM, &md_base_state::megadriv_68k_map);
Z80(config, m_z80snd, MASTER_CLOCK_NTSC / 15); /* 3.58 MHz */
m_z80snd->set_addrmap(AS_PROGRAM, &md_base_state::megadriv_z80_map);
m_z80snd->set_addrmap(AS_IO, &md_base_state::megadriv_z80_io_map);
/* IRQ handled via the timers */
megadriv_timers(config);
/* I/O port controllers */
megadriv_ioports(config);
SEGA315_5313(config, m_vdp, MASTER_CLOCK_NTSC, m_maincpu);
m_vdp->set_is_pal(false);
m_vdp->snd_irq().set(FUNC(md_base_state::vdp_sndirqline_callback_genesis_z80));
m_vdp->lv6_irq().set(FUNC(md_base_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_base_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->set_screen("megadriv");
m_vdp->add_route(ALL_OUTPUTS, "lspeaker", 0.50);
m_vdp->add_route(ALL_OUTPUTS, "rspeaker", 0.50);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(double(MASTER_CLOCK_NTSC) / 10.0 / 262.0 / 342.0); // same as SMS?
// m_screen->set_refresh_hz(double(MASTER_CLOCK_NTSC) / 8.0 / 262.0 / 427.0); // or 427 Htotal?
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); // Vblank handled manually.
m_screen->set_size(64*8, 620);
m_screen->set_visarea(0, 32*8-1, 0, 28*8-1);
m_screen->set_screen_update(FUNC(md_base_state::screen_update_megadriv)); /* Copies a bitmap */
m_screen->screen_vblank().set(FUNC(md_base_state::screen_vblank_megadriv)); /* Used to Sync the timing */
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
YM2612(config, m_ymsnd, MASTER_CLOCK_NTSC/7); /* 7.67 MHz */
m_ymsnd->add_route(0, "lspeaker", 0.50);
m_ymsnd->add_route(1, "rspeaker", 0.50);
}
@ -860,44 +921,26 @@ void md_base_state::md2_ntsc(machine_config &config)
void md_base_state::md_pal(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_PAL / 7); /* 7.67 MHz */
md_core_pal(config);
m_maincpu->set_addrmap(AS_PROGRAM, &md_base_state::megadriv_68k_map);
m_maincpu->set_irq_acknowledge_callback(FUNC(md_base_state::genesis_int_callback));
/* IRQs are handled via the timers */
Z80(config, m_z80snd, MASTER_CLOCK_PAL / 15); /* 3.58 MHz */
m_z80snd->set_addrmap(AS_PROGRAM, &md_base_state::megadriv_z80_map);
m_z80snd->set_addrmap(AS_IO, &md_base_state::megadriv_z80_io_map);
/* IRQ handled via the timers */
megadriv_timers(config);
/* I/O port controllers */
megadriv_ioports(config);
SEGA315_5313(config, m_vdp, MASTER_CLOCK_PAL, m_maincpu);
m_vdp->set_is_pal(true);
m_vdp->snd_irq().set(FUNC(md_base_state::vdp_sndirqline_callback_genesis_z80));
m_vdp->lv6_irq().set(FUNC(md_base_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_base_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->set_screen("megadriv");
m_vdp->add_route(ALL_OUTPUTS, "lspeaker", 0.50);
m_vdp->add_route(ALL_OUTPUTS, "rspeaker", 0.50);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(double(MASTER_CLOCK_PAL) / 10.0 / 313.0 / 342.0); // same as SMS?
// m_screen->set_refresh_hz(double(MASTER_CLOCK_PAL) / 8.0 / 313.0 / 423.0); // or 423 Htotal?
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); // Vblank handled manually.
m_screen->set_size(64*8, 620);
m_screen->set_visarea(0, 32*8-1, 0, 28*8-1);
m_screen->set_screen_update(FUNC(md_base_state::screen_update_megadriv)); /* Copies a bitmap */
m_screen->screen_vblank().set(FUNC(md_base_state::screen_vblank_megadriv)); /* Used to Sync the timing */
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
YM2612(config, m_ymsnd, MASTER_CLOCK_PAL / 7); /* 7.67 MHz */
m_ymsnd->add_route(0, "lspeaker", 0.50);
m_ymsnd->add_route(1, "rspeaker", 0.50);
}
@ -913,7 +956,7 @@ void md_base_state::md2_pal(machine_config &config)
}
void md_base_state::megadriv_tas_callback(offs_t offset, uint8_t data)
void md_core_state::megadriv_tas_callback(offs_t offset, uint8_t data)
{
// writeback not allowed
}
@ -938,7 +981,7 @@ void md_base_state::init_megadriv()
{
megadriv_init_common();
// todo: move this to the device interface?
// TODO: move this to the device interface?
m_vdp->set_use_cram(1);
m_vdp->set_vdp_pal(false);
m_vdp->set_framerate(60);
@ -951,7 +994,7 @@ void md_base_state::init_megadrij()
{
megadriv_init_common();
// todo: move this to the device interface?
// TODO: move this to the device interface?
m_vdp->set_use_cram(1);
m_vdp->set_vdp_pal(false);
m_vdp->set_framerate(60);
@ -973,7 +1016,7 @@ void md_base_state::init_megadrie()
m_version_hi_nibble = 0xe0; // Export PAL no-SCD
}
WRITE_LINE_MEMBER(md_base_state::screen_vblank_megadriv)
WRITE_LINE_MEMBER(md_core_state::screen_vblank_megadriv)
{
if (m_io_reset.read_safe(0) & 0x01)
m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);

View File

@ -1,7 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
#ifndef MAME_SHARED_MEGADRIV_H
#define MAME_SHARED_MEGADRIV_H
#ifndef MAME_SEGA_MEGADRIV_H
#define MAME_SEGA_MEGADRIV_H
#pragma once
@ -23,33 +23,60 @@ INPUT_PORTS_EXTERN( md_common );
INPUT_PORTS_EXTERN( megadriv );
class md_base_state : public driver_device
class md_core_state : public driver_device
{
protected:
md_core_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this,"maincpu"),
m_scan_timer(*this, "md_scan_timer"),
m_vdp(*this,"gen_vdp"),
m_screen(*this,"megadriv"),
m_ymsnd(*this,"ymsnd"),
m_io_reset(*this, "RESET")
{
}
virtual void machine_reset() override;
void md_core_ntsc(machine_config &config);
void md_core_pal(machine_config &config);
void megadriv_tas_callback(offs_t offset, uint8_t data);
uint32_t screen_update_megadriv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_megadriv);
required_device<m68000_base_device> m_maincpu;
required_device<timer_device> m_scan_timer;
required_device<sega315_5313_device> m_vdp;
optional_device<screen_device> m_screen;
optional_device<ym_generic_device> m_ymsnd;
optional_ioport m_io_reset;
private:
IRQ_CALLBACK_MEMBER(genesis_int_callback);
WRITE_LINE_MEMBER(vdp_lv6irqline_callback_genesis_68k);
WRITE_LINE_MEMBER(vdp_lv4irqline_callback_genesis_68k);
void megadriv_timers(machine_config &config);
};
class md_base_state : public md_core_state
{
public:
md_base_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this,"maincpu"),
md_core_state(mconfig, type, tag),
m_z80snd(*this,"genesis_snd_z80"),
m_ymsnd(*this,"ymsnd"),
m_scan_timer(*this, "md_scan_timer"),
m_vdp(*this,"gen_vdp"),
m_megadrive_ram(*this,"megadrive_ram"),
m_screen(*this,"megadriv"),
m_io_reset(*this, "RESET"),
m_ioports(*this, "ioport%u", 1U),
m_io_pad(*this, "PAD%u", 1U),
m_io_extra(*this, "EXTRA%u", 1U)
m_ioports(*this, "ioport%u", 1U)
{ }
required_device<m68000_base_device> m_maincpu;
optional_device<cpu_device> m_z80snd;
optional_device<ym_generic_device> m_ymsnd;
optional_device<timer_device> m_scan_timer;
required_device<sega315_5313_device> m_vdp;
optional_shared_ptr<uint16_t> m_megadrive_ram;
optional_device<screen_device> m_screen;
optional_ioport m_io_reset;
struct genesis_z80_vars
{
@ -69,7 +96,7 @@ public:
uint8_t megadriv_68k_YM2612_read(offs_t offset, uint8_t mem_mask = ~0);
void megadriv_68k_YM2612_write(offs_t offset, uint8_t data, uint8_t mem_mask = ~0);
IRQ_CALLBACK_MEMBER(genesis_int_callback);
void megadriv_init_common();
void megadriv_z80_bank_w(uint16_t data);
@ -88,16 +115,9 @@ public:
TIMER_CALLBACK_MEMBER(megadriv_z80_run_state);
WRITE_LINE_MEMBER(vdp_sndirqline_callback_genesis_z80);
WRITE_LINE_MEMBER(vdp_lv6irqline_callback_genesis_68k);
WRITE_LINE_MEMBER(vdp_lv4irqline_callback_genesis_68k);
void megadriv_stop_scanline_timer();
uint32_t screen_update_megadriv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_megadriv);
void megadriv_tas_callback(offs_t offset, uint8_t data);
void md_ntsc(machine_config &config);
void md2_ntsc(machine_config &config);
void md_pal(machine_config &config);
@ -113,12 +133,6 @@ protected:
void megadriv_z80_io_map(address_map &map);
void megadriv_z80_map(address_map &map);
template <unsigned N> uint8_t ioport_in_3button();
template <unsigned N> uint8_t ioport_in_6button();
template <unsigned N> void ioport_out_3button(uint8_t data, uint8_t mem_mask);
template <unsigned N> void ioport_out_6button(uint8_t data, uint8_t mem_mask);
required_device_array<megadrive_io_port_device, 3> m_ioports;
private:
@ -134,10 +148,35 @@ private:
template <unsigned N> void m68k_ioport_txdata_write(uint16_t data);
template <unsigned N> void m68k_ioport_s_ctrl_write(uint16_t data);
TIMER_CALLBACK_MEMBER(ioport_timeout);
void megadriv_timers(machine_config &config);
void megadriv_ioports(machine_config &config);
};
class md_ctrl_state : public md_base_state
{
protected:
md_ctrl_state(const machine_config &mconfig, device_type type, const char *tag) :
md_base_state(mconfig, type, tag),
m_io_pad(*this, "PAD%u", 1U),
m_io_extra(*this, "EXTRA%u", 1U)
{
}
void ctrl1_3button(machine_config &config);
void ctrl2_3button(machine_config &config);
void ctrl1_6button(machine_config &config);
void ctrl2_6button(machine_config &config);
virtual void machine_start() override;
private:
template <unsigned N> uint8_t ioport_in_3button();
template <unsigned N> uint8_t ioport_in_6button();
template <unsigned N> void ioport_out_3button(uint8_t data, uint8_t mem_mask);
template <unsigned N> void ioport_out_6button(uint8_t data, uint8_t mem_mask);
TIMER_CALLBACK_MEMBER(ioport_timeout);
optional_ioport_array<2> m_io_pad;
optional_ioport_array<2> m_io_extra;
@ -148,4 +187,4 @@ private:
uint8_t m_ioport_phase[2];
};
#endif // MAME_SHARED_MEGADRIV_H
#endif // MAME_SEGA_MEGADRIV_H

View File

@ -15,7 +15,6 @@
* Sonic The Hedgehog 3
* Super Street Fighter II - The New Challengers
* Sunset Riders
* Top Shooter
* Twinkle Tale
@ -145,118 +144,6 @@ Sunset Riders info
- title raster effect is broken (bug in Mega Drive code, happens with normal set too)
****************************************************************************
Top Shooter PCB info
====================
Sun Mixing board, looks like a hacked up Genesis clone.
Original driver by David Haywood
Inputs by Mariusz Wojcieszek
Top Shooter - (c)1995 - older board, look more like an actual hacked cart system, has an MCU
TOP SHOOTER - Sun Mixing Co. Ltd. 1995
To me it seems like an original cartridge-based arcade board
hacked to use an external ROM board and a standard JAMMA
connector, but of course, I can be wrong.
UPPER BOARD
_________________________________________________________
| ___________ ___________ _____ __ |
| 74LS245P |U14 Empty | |U12 ROM1 | |IC1| |B| |
| 74LS245P |__________| |__________| |___| |
| 74LS245P ___________ ___________ _____________ |
__| |U13 Empty | |U11 ROM2 | | AT89C51 | |
|_ J |__________| |__________| |____________| |_
|_ A ______________________ _____ |_ J
|_ M | U10 MC68000P10 | |OSC| |_ P
|_ M | Motorola | |_ 2
|_ A |______________________| 74HC00P |_
|_ 74LS245P ______________________ ________ |
|_ | U9 Empty | |HM6116L |
|_ | | |_______| |_ J
|_ |______________________| |_ P
|_ 74LS245P TD62oo3AP 74LS373P |_ 3
|_ __________ |
|_ 74LS245P |GALv20V8B| |
|_ ______ |
|_ _____ |DIPS| |_ P
| |U24 | |_ 1
| 74LS245P |
| TD62oo3AP |
| |
|_ 97 ____________ _____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_| |_|_|_|_|
IC1 = Surface scratched out, don't know what it is
U24 = Surface scratched out, seems like a PROM
DIPs = Fixed as: 00001000
ROMs = Toshiba TC574000AD
JP2, JP3 and P1 connects both boards, also another
on-board connector is used, see notes for the 68K socket
for the lower board.
LOWER BOARD
_________________________________________________________
| ____ ____ |
| ___ | I| | I| |
| |I| | C| | C| |
| |C| | 3| | 2| |
| |1| |__| |__| |
| |3| |__
| _ _________________________ __|
| |_| ||||||||||||||||||||||||| __|
| IC14 ---------- SLOT --------- __|
| ______________________ __|
| | | __|
| ___ | 68K (to upper board) | _______ __|
| |I| |______________________| |SE-94| __|
| |C| |JDDB | _|
| |1| _______ |_____| |
| |2| |SE-93| IC4 |
| |JDDA | |
| |_____| ___________ |_
| IC8 |Z8400A PS| |
| |_________| |
| ______ _________ _________ |
| | OSC| | IC11 | | IC7 | |
| _____________ |_______| |_______| |
| RST | | CN5 CN6 |
|___________| |______________________________|
IC3 = IC2 = Winbond W24257V
IC7 = 6264LD 9440
IC11 = SE-95 JDDC
IC12 = Sony CXA1634P
IC13 = Sony CXA1145P
IC14 = GL358 N16
RST is a reset button.
OSC = 53.693175 MHz
CN5 and CN6 are 9-pin connectors... serial ports?
There are two wires soldered directly to two connectors
of the slot, going to the upper board (via P1).
The whole upper board is plugged using the 68000 socket,
there is no 68K on the lower board.
There is an edge connector, but it isn't JAMMA.
"HK-986 (KINYO)" is written on the PCB, near the slot.
****************************************************************************/
#include "emu.h"
@ -274,30 +161,6 @@ void md_boot_state::md_bootleg_map(address_map &map)
map(0x200000, 0x2023ff).ram(); // Tested
}
void md_boot_state::topshoot_68k_map(address_map &map)
{
md_bootleg_map(map);
// these are shared RAM, MCU puts the inputs here
map(0x200042, 0x200043).portr("IN0");
map(0x200044, 0x200045).portr("IN1");
map(0x200046, 0x200047).portr("IN2");
map(0x200048, 0x200049).portr("IN3");
map(0x200050, 0x200051).r(FUNC(md_boot_state::topshoot_200051_r));
}
void md_boot_state::sbubsm_68k_map(address_map &map)
{
topshoot_68k_map(map);
// these are shared RAM, MCU puts the inputs here
map(0x20007e, 0x20007f).portr("IN4");
// needed to boot, somme kind of hardware ident?
map(0x400000, 0x400001).r(FUNC(md_boot_state::sbubsm_400000_r));
map(0x400002, 0x400003).r(FUNC(md_boot_state::sbubsm_400002_r));
}
void md_boot_6button_state::ssf2mdb_68k_map(address_map &map)
{
megadriv_68k_map(map);
@ -312,6 +175,9 @@ void md_boot_state::megadrvb(machine_config &config)
{
md_ntsc(config);
ctrl1_3button(config);
ctrl2_3button(config);
m_ioports[2]->set_in_handler(NAME([this] () { return m_io_exp.read_safe(0x3f); }));
}
@ -322,20 +188,6 @@ void md_boot_state::md_bootleg(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &md_boot_state::md_bootleg_map);
}
void md_boot_state::topshoot(machine_config &config)
{
megadrvb(config);
m_maincpu->set_addrmap(AS_PROGRAM, &md_boot_state::topshoot_68k_map);
}
void md_boot_state::sbubsm(machine_config &config)
{
megadrvb(config);
m_maincpu->set_addrmap(AS_PROGRAM, &md_boot_state::sbubsm_68k_map);
}
/*************************************
*
@ -450,23 +302,6 @@ uint16_t md_boot_state::dsw_r(offs_t offset)
return ioport(dswname[offset])->read();
}
uint16_t md_boot_state::topshoot_200051_r()
{
return -0x5b;
}
uint16_t md_boot_state::sbubsm_400000_r()
{
logerror("%s: sbubsm_400000_r\n", machine().describe_context().c_str());
return 0x5500;
}
uint16_t md_boot_state::sbubsm_400002_r()
{
logerror("%s: sbubsm_400002_r\n", machine().describe_context().c_str());
return 0x0f00;
}
/*************************************
*
@ -784,94 +619,6 @@ INPUT_PORTS_START( srmdb )
PORT_DIPSETTING( 0x00, "6" )
INPUT_PORTS_END
static INPUT_PORTS_START( topshoot ) // Top Shooter Input Ports
PORT_START("PAD1")
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PAD2")
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN0")
PORT_BIT( 0x4f, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Bet") PORT_IMPULSE(1)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Start") PORT_IMPULSE(1)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Fire") PORT_IMPULSE(1)
PORT_START("IN1")
PORT_BIT( 0xe7, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_SERVICE_NO_TOGGLE( 0x08, IP_ACTIVE_LOW )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Test mode down") PORT_IMPULSE(1)
PORT_START("IN2")
PORT_BIT( 0xfd, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(1)
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(1)
PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNKNOWN )
INPUT_PORTS_END
static INPUT_PORTS_START( sbubsm )
PORT_START("PAD1")
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PAD2")
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
// the bit ordering in the ports is strange here because this is being read through shared RAM, the MCU presumably reads the real inputs then scrambles them in RAM for the 68k to sort out
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START1 )
PORT_START("IN1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(1)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN4")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
// no service mode here?
INPUT_PORTS_END
INPUT_PORTS_START( barekch ) // TODO: identify dips. PCB has 3 x 8-dip banks, but probably most unused
PORT_INCLUDE( md_common )
@ -1110,11 +857,8 @@ void md_boot_6button_state::megadrvb_6b(machine_config &config)
{
megadrvb(config);
m_ioports[0]->set_in_handler(FUNC(md_boot_6button_state::ioport_in_6button<0>));
m_ioports[0]->set_out_handler(FUNC(md_boot_6button_state::ioport_out_6button<0>));
m_ioports[1]->set_in_handler(FUNC(md_boot_6button_state::ioport_in_6button<1>));
m_ioports[1]->set_out_handler(FUNC(md_boot_6button_state::ioport_out_6button<1>));
ctrl1_6button(config);
ctrl2_6button(config);
}
void md_boot_6button_state::ssf2mdb(machine_config &config)
@ -1406,25 +1150,6 @@ ROM_START( srmdb )
ROM_LOAD16_BYTE( "u4", 0x040000, 0x020000, CRC(fc2aed41) SHA1(27eb3957f5ed26ee5276523b1df46fa7eb298e1f) )
ROM_END
ROM_START( topshoot ) // Top Shooter (c)1995 Sun Mixing
ROM_REGION( 0x200000, "maincpu", 0 )
ROM_LOAD16_BYTE( "tc574000ad_u11_2.bin", 0x000000, 0x080000, CRC(b235c4d9) SHA1(fbb308a5f6e769f3277824cb6a3b50c308969ac2) )
ROM_LOAD16_BYTE( "tc574000ad_u12_1.bin", 0x000001, 0x080000, CRC(e826f6ad) SHA1(23ec8bb608f954d3b915f061e7076c0c63b8259e) )
// Not hooked up yet
ROM_REGION( 0x1000, "mcu", 0 )
ROM_LOAD( "89c51.bin", 0x0000, 0x1000, CRC(595475c8) SHA1(8313819ba06cc92b54f88c1ca9f34be8d1ec94d0) )
ROM_END
ROM_START( sbubsm )
ROM_REGION( 0x200000, "maincpu", 0 )
ROM_LOAD16_BYTE( "u11.bin", 0x000000, 0x080000, CRC(4f9337ea) SHA1(b245eb615f80afd25e29b2efdddb7f61c1deff6b) )
ROM_LOAD16_BYTE( "u12.bin", 0x000001, 0x080000, CRC(f5374835) SHA1(3a97910f5f7327ec7ad6425dfdfa72c86196ed33) )
ROM_REGION( 0x1000, "mcu", 0 ) // could be the same as topshoot (same PCB)
ROM_LOAD( "89c51.bin", 0x0000, 0x1000, NO_DUMP )
ROM_END
ROM_START( sonic2mb )
ROM_REGION( 0x400000, "maincpu", 0 ) // 68000 Code
ROM_LOAD16_BYTE( "m1", 0x000001, 0x080000, CRC(7b40aa24) SHA1(247882cd1f412366d61aeb4d85bbeefd5f108e1d) )
@ -1523,8 +1248,6 @@ GAME( 1993, aladmdb, 0, megadrvb, aladmdb, md_boot_state, init_ala
GAME( 1996, mk3mdb, 0, megadrvb_6b, mk3mdb, md_boot_6button_state, init_mk3mdb, ROT0, "bootleg / Midway", "Mortal Kombat 3 (bootleg of Mega Drive version)", 0 )
GAME( 1994, ssf2mdb, 0, ssf2mdb, ssf2mdb, md_boot_6button_state, init_megadrij, ROT0, "bootleg / Capcom", "Super Street Fighter II - The New Challengers (bootleg of Japanese Mega Drive version)", 0 )
GAME( 1993, srmdb, 0, megadrvb, srmdb, md_boot_state, init_srmdb, ROT0, "bootleg / Konami", "Sunset Riders (bootleg of Mega Drive version)", 0 )
GAME( 1995, topshoot, 0, topshoot, topshoot, md_boot_state, init_megadriv, ROT0, "Sun Mixing", "Top Shooter", 0 )
GAME( 1996, sbubsm, 0, sbubsm, sbubsm, md_boot_state, init_megadriv, ROT0, "Sun Mixing", "Super Bubble Bobble (Sun Mixing, Mega Drive clone hardware)", 0 )
GAME( 1993, sonic2mb, 0, md_bootleg, sonic2mb, md_boot_state, init_sonic2mb, ROT0, "bootleg / Sega", "Sonic The Hedgehog 2 (bootleg of Mega Drive version)", 0 ) // Flying wires going through the empty PIC space aren't completely understood
GAME( 1993, sonic3mb, 0, md_bootleg, sonic3mb, md_sonic3bl_state, init_sonic3mb, ROT0, "bootleg / Sega", "Sonic The Hedgehog 3 (bootleg of Mega Drive version)", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING ) // undumped PIC
GAME( 1994, barek2mb, 0, md_bootleg, barek2, md_boot_state, init_barek2, ROT0, "bootleg / Sega", "Bare Knuckle II (bootleg of Mega Drive version)", MACHINE_UNEMULATED_PROTECTION | MACHINE_NOT_WORKING ) // Needs PIC hook up

View File

@ -6,18 +6,16 @@
#include "megadriv.h"
class md_boot_state : public md_base_state
class md_boot_state : public md_ctrl_state
{
public:
md_boot_state(const machine_config &mconfig, device_type type, const char *tag) :
md_base_state(mconfig, type, tag),
md_ctrl_state(mconfig, type, tag),
m_io_exp(*this, "EXP")
{ }
void megadrvb(machine_config &config);
void md_bootleg(machine_config &config);
void topshoot(machine_config &config);
void sbubsm(machine_config &config);
void init_aladmdb();
void init_srmdb();
@ -39,12 +37,6 @@ private:
uint16_t barek2mb_r();
uint16_t jparkmb_r();
uint16_t twinktmb_r();
uint16_t topshoot_200051_r();
uint16_t sbubsm_400000_r();
uint16_t sbubsm_400002_r();
void topshoot_68k_map(address_map &map);
void sbubsm_68k_map(address_map &map);
optional_ioport m_io_exp;

View File

@ -20,7 +20,99 @@
*/
#include "emu.h"
#include "megadriv_rad.h"
#include "megadriv.h"
namespace {
class megadriv_radica_state_base : public md_ctrl_state
{
public:
megadriv_radica_state_base(const machine_config &mconfig, device_type type, const char *tag) :
md_ctrl_state(mconfig, type, tag),
m_bank(0),
m_romsize(0x400000),
m_rom(*this, "maincpu")
{ }
protected:
uint16_t read(offs_t offset);
uint16_t read_a13(offs_t offset);
void megadriv_radica_map(address_map &map);
void radica_base_map(address_map &map);
int m_bank;
int m_romsize;
private:
required_region_ptr<uint16_t> m_rom;
};
class megadriv_radica_state : public megadriv_radica_state_base
{
public:
megadriv_radica_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_radica_state_base(mconfig, type, tag)
{ }
void megadriv_radica_3button_ntsc(machine_config &config);
void megadriv_radica_3button_pal(machine_config &config);
void megadriv_radica_6button_ntsc(machine_config &config);
void megadriv_radica_6button_pal(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
};
class megadriv_dgunl_state : public megadriv_radica_state
{
public:
megadriv_dgunl_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_radica_state(mconfig, type, tag)
{ }
void megadriv_dgunl_ntsc(machine_config &config);
void init_dgunl3227();
protected:
virtual void machine_start() override;
uint16_t m_a1630a = 0;
private:
uint16_t read_a16300(offs_t offset, uint16_t mem_mask);
uint16_t read_a16302(offs_t offset, uint16_t mem_mask);
virtual void write_a1630a(offs_t offset, uint16_t data, uint16_t mem_mask);
void megadriv_dgunl_map(address_map &map);
};
class megadriv_ra145_state : public megadriv_dgunl_state
{
public:
megadriv_ra145_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_dgunl_state(mconfig, type, tag)
{ }
void megadriv_ra145_ntsc(machine_config &config);
void init_ra145();
protected:
virtual void machine_reset() override;
private:
virtual void write_a1630a(offs_t offset, uint16_t data, uint16_t mem_mask) override;
};
void megadriv_radica_state_base::radica_base_map(address_map &map)
@ -368,13 +460,13 @@ void megadriv_dgunl_state::machine_start()
void megadriv_ra145_state::machine_reset()
{
m_bank = 4;
md_base_state::machine_reset();
megadriv_radica_state_base::machine_reset();
}
void megadriv_radica_state::machine_reset()
{
m_bank = 0;
md_base_state::machine_reset();
megadriv_radica_state_base::machine_reset();
}
@ -382,42 +474,45 @@ void megadriv_radica_state::megadriv_radica_3button_ntsc(machine_config &config)
{
md_ntsc(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_radica_state_base::megadriv_radica_map);
ctrl1_3button(config);
ctrl2_3button(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_radica_state::megadriv_radica_map);
}
void megadriv_radica_state::megadriv_radica_3button_pal(machine_config &config)
{
md_pal(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_radica_state_base::megadriv_radica_map);
ctrl1_3button(config);
ctrl2_3button(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_radica_state::megadriv_radica_map);
}
void megadriv_radica_state::megadriv_radica_6button_pal(machine_config &config)
{
megadriv_radica_3button_pal(config);
m_ioports[0]->set_in_handler(FUNC(megadriv_radica_state::ioport_in_6button<0>));
m_ioports[0]->set_out_handler(FUNC(megadriv_radica_state::ioport_out_6button<0>));
m_ioports[1]->set_in_handler(FUNC(megadriv_radica_state::ioport_in_6button<1>));
m_ioports[1]->set_out_handler(FUNC(megadriv_radica_state::ioport_out_6button<1>));
ctrl1_6button(config);
ctrl2_6button(config);
}
void megadriv_radica_state::megadriv_radica_6button_ntsc(machine_config &config)
{
megadriv_radica_3button_ntsc(config);
m_ioports[0]->set_in_handler(FUNC(megadriv_radica_state::ioport_in_6button<0>));
m_ioports[0]->set_out_handler(FUNC(megadriv_radica_state::ioport_out_6button<0>));
m_ioports[1]->set_in_handler(FUNC(megadriv_radica_state::ioport_in_6button<1>));
m_ioports[1]->set_out_handler(FUNC(megadriv_radica_state::ioport_out_6button<1>));
ctrl1_6button(config);
ctrl2_6button(config);
}
void megadriv_dgunl_state::megadriv_dgunl_ntsc(machine_config &config)
{
md_ntsc(config);
ctrl1_3button(config);
ctrl2_3button(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_dgunl_state::megadriv_dgunl_map);
}
@ -425,11 +520,8 @@ void megadriv_ra145_state::megadriv_ra145_ntsc(machine_config &config)
{
megadriv_dgunl_ntsc(config);
m_ioports[0]->set_in_handler(FUNC(megadriv_ra145_state::ioport_in_6button<0>));
m_ioports[0]->set_out_handler(FUNC(megadriv_ra145_state::ioport_out_6button<0>));
m_ioports[1]->set_in_handler(FUNC(megadriv_ra145_state::ioport_in_6button<1>));
m_ioports[1]->set_out_handler(FUNC(megadriv_ra145_state::ioport_out_6button<1>));
ctrl1_6button(config);
ctrl2_6button(config);
}
@ -612,6 +704,9 @@ void megadriv_ra145_state::init_ra145()
init_megadriv();
}
} // anonymous namespace
// US versions show 'Genesis' on the menu, show a www.radicagames.com splash screen, and use NTSC versions of the ROMs, sometimes region locked
// EU versions show 'Mega Drive' on the menu, show a www.radicagames.com splash screen, and use PAL versions of the ROMs, sometimes region locked
// UK versions show "Mega Drive' on the menu, show a www.radicauk.com splash screen, and use PAL versions of the ROMs, sometimes region locked
@ -657,4 +752,3 @@ CONS( 2018, msi_sf2, 0, 0, megadriv_radica_6button_ntsc, msi_6button,
CONS( 2018, dgunl3227, 0, 0, megadriv_dgunl_ntsc, dgunl_1player, megadriv_dgunl_state, init_dgunl3227, "dreamGEAR", "My Arcade Pac-Man Pocket Player (DGUNL-3227)", 0 )
CONS( 2018, ra145, 0, 0, megadriv_ra145_ntsc, msi_6button, megadriv_ra145_state, init_ra145, "<unknown>", "Retro Arcade 16 Bits Classic Edition Mini TV Game Console - 145 Classic Games - TV Arcade Plug and Play (Mega Drive bootlegs)", MACHINE_NOT_WORKING )

View File

@ -1,100 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
#ifndef MAME_INCLUDES_MEGADRIV_RAD_H
#define MAME_INCLUDES_MEGADRIV_RAD_H
#pragma once
#include "megadriv.h"
class megadriv_radica_state_base : public md_base_state
{
public:
megadriv_radica_state_base(const machine_config &mconfig, device_type type, const char *tag) :
md_base_state(mconfig, type, tag),
m_bank(0),
m_romsize(0x400000),
m_rom(*this, "maincpu")
{ }
uint16_t read(offs_t offset);
uint16_t read_a13(offs_t offset);
void megadriv_radica_map(address_map &map);
protected:
void radica_base_map(address_map &map);
int m_bank;
int m_romsize;
private:
required_region_ptr<uint16_t> m_rom;
};
class megadriv_radica_state : public megadriv_radica_state_base
{
public:
megadriv_radica_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_radica_state_base(mconfig, type, tag)
{ }
void megadriv_radica_3button_ntsc(machine_config &config);
void megadriv_radica_3button_pal(machine_config &config);
void megadriv_radica_6button_ntsc(machine_config &config);
void megadriv_radica_6button_pal(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
};
class megadriv_dgunl_state : public megadriv_radica_state
{
public:
megadriv_dgunl_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_radica_state(mconfig, type, tag)
{ }
void megadriv_dgunl_ntsc(machine_config &config);
void init_dgunl3227();
protected:
virtual void machine_start() override;
uint16_t m_a1630a = 0;
private:
uint16_t read_a16300(offs_t offset, uint16_t mem_mask);
uint16_t read_a16302(offs_t offset, uint16_t mem_mask);
virtual void write_a1630a(offs_t offset, uint16_t data, uint16_t mem_mask);
void megadriv_dgunl_map(address_map &map);
};
class megadriv_ra145_state : public megadriv_dgunl_state
{
public:
megadriv_ra145_state(const machine_config& mconfig, device_type type, const char* tag) :
megadriv_dgunl_state(mconfig, type, tag)
{ }
void megadriv_ra145_ntsc(machine_config &config);
void init_ra145();
protected:
virtual void machine_reset() override;
private:
virtual void write_a1630a(offs_t offset, uint16_t data, uint16_t mem_mask) override;
};
#endif // MAME_INCLUDES_MEGADRIV_RAD_H

View File

@ -0,0 +1,340 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************
Sega Mega Drive/Genesis-based bootlegs
Games supported:
* Top Shooter
Top Shooter PCB info
====================
Sun Mixing board, looks like a hacked up Genesis clone.
Original driver by David Haywood
Inputs by Mariusz Wojcieszek
Top Shooter - (c)1995 - older board, look more like an actual hacked cart system, has an MCU
TOP SHOOTER - Sun Mixing Co. Ltd. 1995
To me it seems like an original cartridge-based arcade board
hacked to use an external ROM board and a standard JAMMA
connector, but of course, I can be wrong.
UPPER BOARD
_________________________________________________________
| ___________ ___________ _____ __ |
| 74LS245P |U14 Empty | |U12 ROM1 | |IC1| |B| |
| 74LS245P |__________| |__________| |___| |
| 74LS245P ___________ ___________ _____________ |
__| |U13 Empty | |U11 ROM2 | | AT89C51 | |
|_ J |__________| |__________| |____________| |_
|_ A ______________________ _____ |_ J
|_ M | U10 MC68000P10 | |OSC| |_ P
|_ M | Motorola | |_ 2
|_ A |______________________| 74HC00P |_
|_ 74LS245P ______________________ ________ |
|_ | U9 Empty | |HM6116L |
|_ | | |_______| |_ J
|_ |______________________| |_ P
|_ 74LS245P TD62oo3AP 74LS373P |_ 3
|_ __________ |
|_ 74LS245P |GALv20V8B| |
|_ ______ |
|_ _____ |DIPS| |_ P
| |U24 | |_ 1
| 74LS245P |
| TD62oo3AP |
| |
|_ 97 ____________ _____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_| |_|_|_|_|
IC1 = Surface scratched out, don't know what it is
U24 = Surface scratched out, seems like a PROM
DIPs = Fixed as: 00001000
ROMs = Toshiba TC574000AD
JP2, JP3 and P1 connects both boards, also another
on-board connector is used, see notes for the 68K socket
for the lower board.
LOWER BOARD
_________________________________________________________
| ____ ____ |
| ___ | I| | I| |
| |I| | C| | C| |
| |C| | 3| | 2| |
| |1| |__| |__| |
| |3| |__
| _ _________________________ __|
| |_| ||||||||||||||||||||||||| __|
| IC14 ---------- SLOT --------- __|
| ______________________ __|
| | | __|
| ___ | 68K (to upper board) | _______ __|
| |I| |______________________| |SE-94| __|
| |C| |JDDB | _|
| |1| _______ |_____| |
| |2| |SE-93| IC4 |
| |JDDA | |
| |_____| ___________ |_
| IC8 |Z8400A PS| |
| |_________| |
| ______ _________ _________ |
| | OSC| | IC11 | | IC7 | |
| _____________ |_______| |_______| |
| RST | | CN5 CN6 |
|___________| |______________________________|
IC3 = IC2 = Winbond W24257V
IC7 = 6264LD 9440
IC11 = SE-95 JDDC
IC12 = Sony CXA1634P
IC13 = Sony CXA1145P
IC14 = GL358 N16
RST is a reset button.
OSC = 53.693175 MHz
CN5 and CN6 are 9-pin connectors... serial ports?
There are two wires soldered directly to two connectors
of the slot, going to the upper board (via P1).
The whole upper board is plugged using the 68000 socket,
there is no 68K on the lower board.
There is an edge connector, but it isn't JAMMA.
"HK-986 (KINYO)" is written on the PCB, near the slot.
****************************************************************************/
#include "emu.h"
#include "megadriv.h"
namespace {
class md_sunmixing_state : public md_base_state
{
public:
md_sunmixing_state(machine_config const &mconfig, device_type type, char const *tag) :
md_base_state(mconfig, type, tag)
{
}
void topshoot(machine_config &config);
void sbubsm(machine_config &config);
private:
void topshoot_68k_map(address_map &map);
void sbubsm_68k_map(address_map &map);
uint16_t topshoot_200051_r();
uint16_t sbubsm_400000_r();
uint16_t sbubsm_400002_r();
};
/*************************************
*
* Machine Configuration
*
*************************************/
void md_sunmixing_state::topshoot(machine_config &config)
{
md_ntsc(config);
m_maincpu->set_addrmap(AS_PROGRAM, &md_sunmixing_state::topshoot_68k_map);
}
void md_sunmixing_state::sbubsm(machine_config &config)
{
md_ntsc(config);
m_maincpu->set_addrmap(AS_PROGRAM, &md_sunmixing_state::sbubsm_68k_map);
}
void md_sunmixing_state::topshoot_68k_map(address_map &map)
{
megadriv_68k_base_map(map);
map(0x000000, 0x1fffff).rom(); // Cartridge Program ROM
map(0x200000, 0x2023ff).ram(); // Tested
// these are shared RAM, MCU puts the inputs here
map(0x200042, 0x200043).portr("IN0");
map(0x200044, 0x200045).portr("IN1");
map(0x200046, 0x200047).portr("IN2");
map(0x200048, 0x200049).portr("IN3");
map(0x200050, 0x200051).r(FUNC(md_sunmixing_state::topshoot_200051_r));
}
void md_sunmixing_state::sbubsm_68k_map(address_map &map)
{
topshoot_68k_map(map);
// these are shared RAM, MCU puts the inputs here
map(0x20007e, 0x20007f).portr("IN4");
// needed to boot, somme kind of hardware ident?
map(0x400000, 0x400001).r(FUNC(md_sunmixing_state::sbubsm_400000_r));
map(0x400002, 0x400003).r(FUNC(md_sunmixing_state::sbubsm_400002_r));
}
/*************************************
*
* Games memory handlers
*
*************************************/
uint16_t md_sunmixing_state::topshoot_200051_r()
{
return -0x5b;
}
uint16_t md_sunmixing_state::sbubsm_400000_r()
{
logerror("%s: sbubsm_400000_r\n", machine().describe_context().c_str());
return 0x5500;
}
uint16_t md_sunmixing_state::sbubsm_400002_r()
{
logerror("%s: sbubsm_400002_r\n", machine().describe_context().c_str());
return 0x0f00;
}
/*************************************
*
* Game-specific port definitions
*
*************************************/
static INPUT_PORTS_START( topshoot ) // Top Shooter Input Ports
PORT_START("IN0")
PORT_BIT( 0x4f, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Bet") PORT_IMPULSE(1)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Start") PORT_IMPULSE(1)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Fire") PORT_IMPULSE(1)
PORT_START("IN1")
PORT_BIT( 0xe7, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_SERVICE_NO_TOGGLE( 0x08, IP_ACTIVE_LOW )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Test mode down") PORT_IMPULSE(1)
PORT_START("IN2")
PORT_BIT( 0xfd, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(1)
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(1)
PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNKNOWN )
INPUT_PORTS_END
static INPUT_PORTS_START( sbubsm )
// the bit ordering in the ports is strange here because this is being read through shared RAM, the MCU presumably reads the real inputs then scrambles them in RAM for the 68k to sort out
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START1 )
PORT_START("IN1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(1)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN4")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
// no service mode here?
INPUT_PORTS_END
/*************************************
*
* ROM definitions
*
*************************************/
ROM_START( topshoot ) // Top Shooter (c)1995 Sun Mixing
ROM_REGION( 0x200000, "maincpu", 0 )
ROM_LOAD16_BYTE( "tc574000ad_u11_2.bin", 0x000000, 0x080000, CRC(b235c4d9) SHA1(fbb308a5f6e769f3277824cb6a3b50c308969ac2) )
ROM_LOAD16_BYTE( "tc574000ad_u12_1.bin", 0x000001, 0x080000, CRC(e826f6ad) SHA1(23ec8bb608f954d3b915f061e7076c0c63b8259e) )
// Not hooked up yet
ROM_REGION( 0x1000, "mcu", 0 )
ROM_LOAD( "89c51.bin", 0x0000, 0x1000, CRC(595475c8) SHA1(8313819ba06cc92b54f88c1ca9f34be8d1ec94d0) )
ROM_END
ROM_START( sbubsm )
ROM_REGION( 0x200000, "maincpu", 0 )
ROM_LOAD16_BYTE( "u11.bin", 0x000000, 0x080000, CRC(4f9337ea) SHA1(b245eb615f80afd25e29b2efdddb7f61c1deff6b) )
ROM_LOAD16_BYTE( "u12.bin", 0x000001, 0x080000, CRC(f5374835) SHA1(3a97910f5f7327ec7ad6425dfdfa72c86196ed33) )
ROM_REGION( 0x1000, "mcu", 0 ) // could be the same as topshoot (same PCB)
ROM_LOAD( "89c51.bin", 0x0000, 0x1000, NO_DUMP )
ROM_END
} // anonymous namespace
/*************************************
*
* Game drivers
*
*************************************/
GAME( 1995, topshoot, 0, topshoot, topshoot, md_sunmixing_state, init_megadriv, ROT0, "Sun Mixing", "Top Shooter", 0 )
GAME( 1996, sbubsm, 0, sbubsm, sbubsm, md_sunmixing_state, init_megadriv, ROT0, "Sun Mixing", "Super Bubble Bobble (Sun Mixing, Mega Drive clone hardware)", 0 )

View File

@ -16,12 +16,14 @@
#include "emu.h"
#include "megadriv.h"
class megadriv_sunplus_state : public md_base_state
namespace {
class megadriv_sunplus_state : public md_ctrl_state
{
public:
megadriv_sunplus_state(const machine_config &mconfig, device_type type, const char *tag) :
// Mega Drive part
md_base_state(mconfig, type, tag),
md_ctrl_state(mconfig, type, tag),
m_md_is_running(true),
m_bank(0),
m_rom(*this, "maincpu")
@ -30,7 +32,6 @@ public:
// Mega Drive part
uint16_t read(offs_t offset);
void megadriv_sunplus_pal(machine_config &config);
void megadriv_sunplus_map(address_map &map);
void init_reactmd();
@ -44,9 +45,11 @@ private:
// Mega Drive part
int m_bank;
required_region_ptr<uint16_t> m_rom;
uint32_t screen_update_hybrid(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_hybrid);
void megadriv_sunplus_map(address_map &map);
};
@ -87,7 +90,7 @@ INPUT_PORTS_END
void megadriv_sunplus_state::machine_start()
{
logerror("megadriv_sunplus_state::machine_start\n");
md_base_state::machine_start();
md_ctrl_state::machine_start();
m_vdp->stop_timers();
save_item(NAME(m_bank));
@ -96,7 +99,7 @@ void megadriv_sunplus_state::machine_start()
void megadriv_sunplus_state::machine_reset()
{
logerror("megadriv_sunplus_state::machine_reset\n");
md_base_state::machine_reset();
md_ctrl_state::machine_reset();
}
uint32_t megadriv_sunplus_state::screen_update_hybrid(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
@ -115,7 +118,7 @@ WRITE_LINE_MEMBER(megadriv_sunplus_state::screen_vblank_hybrid)
if (m_md_is_running)
{
/* Used to Sync the timing */
md_base_state::screen_vblank_megadriv(state);
md_ctrl_state::screen_vblank_megadriv(state);
}
}
@ -123,10 +126,14 @@ WRITE_LINE_MEMBER(megadriv_sunplus_state::screen_vblank_hybrid)
void megadriv_sunplus_state::megadriv_sunplus_pal(machine_config &config)
{
md_pal(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_sunplus_state::megadriv_sunplus_map);
m_screen->set_screen_update(FUNC(megadriv_sunplus_state::screen_update_hybrid));
m_screen->screen_vblank().set(FUNC(megadriv_sunplus_state::screen_vblank_hybrid));
ctrl1_3button(config);
ctrl2_3button(config);
}
@ -156,6 +163,8 @@ ROM_START( reactmd )
ROM_IGNORE(0x4000000) // the 2nd half of the ROM can't be accessed by the PCB (address line tied low) (contains garbage? data)
ROM_END
} // anonymous namespace
// Two systems in one unit - Genesis on a Chip and SunPlus, only the SunPlus part is currently emulated. Genesis on a chip is a very poor implementation with many issues on real hardware.
// This should actually boot to a menu on the MD side, with the SunPlus only being enabled if selected from that menu. MD side menu runs in some enhanced / custom MD mode though.

View File

@ -17,12 +17,12 @@
namespace {
class megadriv_vt0203_state : public md_base_state
class megadriv_vt0203_state : public md_ctrl_state
{
public:
megadriv_vt0203_state(const machine_config &mconfig, device_type type, const char *tag) :
// Mega Drive part
md_base_state(mconfig, type, tag),
md_ctrl_state(mconfig, type, tag),
m_md_is_running(true),
m_bank(0),
m_rom(*this, "maincpu")
@ -31,7 +31,6 @@ public:
// Mega Drive part
uint16_t read(offs_t offset);
void megadriv_vt0203_pal(machine_config &config);
void megadriv_vt0203_map(address_map &map);
protected:
virtual void machine_start() override;
@ -43,9 +42,11 @@ private:
// Mega Drive part
int m_bank;
required_region_ptr<uint16_t> m_rom;
uint32_t screen_update_hybrid(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_hybrid);
void megadriv_vt0203_map(address_map &map);
};
@ -92,7 +93,7 @@ INPUT_PORTS_END
void megadriv_vt0203_state::machine_start()
{
logerror("megadriv_vt0203_state::machine_start\n");
md_base_state::machine_start();
md_ctrl_state::machine_start();
m_vdp->stop_timers();
save_item(NAME(m_bank));
@ -101,7 +102,7 @@ void megadriv_vt0203_state::machine_start()
void megadriv_vt0203_state::machine_reset()
{
logerror("megadriv_vt0203_state::machine_reset\n");
md_base_state::machine_reset();
md_ctrl_state::machine_reset();
}
uint32_t megadriv_vt0203_state::screen_update_hybrid(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
@ -120,7 +121,7 @@ WRITE_LINE_MEMBER(megadriv_vt0203_state::screen_vblank_hybrid)
if (m_md_is_running)
{
/* Used to Sync the timing */
md_base_state::screen_vblank_megadriv(state);
md_ctrl_state::screen_vblank_megadriv(state);
}
}
@ -128,11 +129,15 @@ WRITE_LINE_MEMBER(megadriv_vt0203_state::screen_vblank_hybrid)
void megadriv_vt0203_state::megadriv_vt0203_pal(machine_config &config)
{
md_pal(config);
m_maincpu->set_addrmap(AS_PROGRAM, &megadriv_vt0203_state::megadriv_vt0203_map);
m_screen->set_screen_update(FUNC(megadriv_vt0203_state::screen_update_hybrid));
m_screen->screen_vblank().set(FUNC(megadriv_vt0203_state::screen_vblank_hybrid));
ctrl1_3button(config);
ctrl2_3button(config);
// TODO: add the VT part, this might require refactoring of the VT stuff as the SoC currently contains the screen
// but instead we'll need to use a shared screen that is reconfigured depending on which part is enabled
}

View File

@ -36,17 +36,20 @@ this reason.
#include "cpu/z80/z80.h"
#include "machine/cxd1095.h"
namespace {
#define MASTER_CLOCK 53693100
#define MP_ROM 1
#define MP_GAME 0
class mplay_state : public md_base_state
class mplay_state : public md_ctrl_state
{
public:
mplay_state(const machine_config &mconfig, device_type type, const char *tag) :
md_base_state(mconfig, type, tag),
md_ctrl_state(mconfig, type, tag),
m_ic3_ram(*this, "ic3_ram"),
m_vdp1(*this, "vdp1"),
m_bioscpu(*this, "mtbios")
@ -429,6 +432,7 @@ void mplay_state::bios_gamesel_w(uint8_t data)
void mplay_state::mp_io_exp_out(uint8_t data, uint8_t mem_mask)
{
// TODO: TH (bit 6) is configured as an output and seems to be used for something, too
m_io_exp_data = (data & 0x07) | (m_io_exp_data & 0xf8);
}
@ -650,7 +654,7 @@ void mplay_state::machine_reset()
m_bios_mode = MP_ROM;
m_bios_bank_addr = 0;
m_readpos = 1;
md_base_state::machine_reset();
md_ctrl_state::machine_reset();
}
void mplay_state::megaplay(machine_config &config)
@ -658,6 +662,10 @@ void mplay_state::megaplay(machine_config &config)
// basic machine hardware
md_ntsc(config);
// integrated 3-button controllers
ctrl1_3button(config);
ctrl2_3button(config);
// for now ...
m_ioports[2]->set_in_handler(FUNC(mplay_state::mp_io_exp_in));
m_ioports[2]->set_out_handler(FUNC(mplay_state::mp_io_exp_out));
@ -971,6 +979,9 @@ void mplay_state::init_megaplay()
m_maincpu->space(AS_PROGRAM).install_write_handler(0xa02000, 0xa03fff, write16s_delegate(*this, FUNC(mplay_state::extra_ram_w)));
}
} // anonymous namespace
/*
Sega Mega Play Cartridges
-------------------------

View File

@ -93,11 +93,11 @@ Sonic Hedgehog 2 171-6215A 837-6963-62 610-0239-62 MPR
namespace {
class mtech_state : public md_base_state
class mtech_state : public md_ctrl_state
{
public:
mtech_state(const machine_config &mconfig, device_type type, const char *tag) :
md_base_state(mconfig, type, tag),
md_ctrl_state(mconfig, type, tag),
m_vdp1(*this, "vdp1"),
m_cart1(*this, "mt_slot1"),
m_cart2(*this, "mt_slot2"),
@ -652,7 +652,7 @@ WRITE_LINE_MEMBER(mtech_state::screen_vblank_main)
void mtech_state::machine_start()
{
md_base_state::machine_start();
md_ctrl_state::machine_start();
m_alarm_sound.resolve();
m_flash_screen.resolve();
@ -661,7 +661,7 @@ void mtech_state::machine_start()
void mtech_state::machine_reset()
{
m_mt_bank_addr = 0;
md_base_state::machine_reset();
md_ctrl_state::machine_reset();
for (int i = 0; i < 8; i++)
m_cart_reg[i] = nullptr;
@ -697,10 +697,14 @@ uint32_t mtech_state::screen_update_menu(screen_device &screen, bitmap_rgb32 &bi
void mtech_state::megatech(machine_config &config)
{
/* basic machine hardware */
// basic machine hardware
md_ntsc(config);
/* Megatech has an extra SMS based bios *and* an additional screen */
// integrated 3-button controllers
ctrl1_3button(config);
ctrl2_3button(config);
// Megatech has an extra SMS-based BIOS *and* an additional screen
Z80(config, m_bioscpu, MASTER_CLOCK / 15); /* ?? */
m_bioscpu->set_addrmap(AS_PROGRAM, &mtech_state::megatech_bios_map);
m_bioscpu->set_addrmap(AS_IO, &mtech_state::megatech_bios_portmap);

View File

@ -52,13 +52,18 @@ Notes:
#include "sound/sn76496.h"
#include "sound/ymopn.h"
#include "speaker.h"
namespace {
class puckpkmn_state : public md_base_state
class puckpkmn_state : public md_core_state
{
public:
using md_base_state::md_base_state;
puckpkmn_state(const machine_config &mconfig, device_type type, const char *tag) :
md_core_state(mconfig, type, tag)
{
}
void puckpkmn(machine_config &config) ATTR_COLD;
void puckpkmna(machine_config &config) ATTR_COLD;
@ -266,7 +271,7 @@ void puckpkmn_state::puckpkmn_base_map(address_map &map)
map(0x700016, 0x700017).portr("DSW1");
map(0x700018, 0x700019).portr("DSW2");
map(0x700023, 0x700023).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write));
map(0xa04000, 0xa04003).rw(FUNC(puckpkmn_state::megadriv_68k_YM2612_read), FUNC(puckpkmn_state::megadriv_68k_YM2612_write));
map(0xa04000, 0xa04003).rw(m_ymsnd, FUNC(ym_generic_device::read), FUNC(ym_generic_device::write));
map(0xc00000, 0xc0001f).rw(m_vdp, FUNC(sega315_5313_device::vdp_r), FUNC(sega315_5313_device::vdp_w));
map(0xe00000, 0xe0ffff).ram().mirror(0x1f0000);
@ -390,11 +395,19 @@ uint16_t jzth_state::bl_710000_r()
void puckpkmn_state::puckpkmn(machine_config &config)
{
md_ntsc(config);
md_core_ntsc(config);
m_maincpu->set_addrmap(AS_PROGRAM, &puckpkmn_state::puckpkmn_map);
config.device_remove("genesis_snd_z80");
m_vdp->add_route(ALL_OUTPUTS, "lspeaker", 0.50);
m_vdp->add_route(ALL_OUTPUTS, "rspeaker", 0.50);
// sound hardware
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
m_ymsnd->add_route(0, "lspeaker", 0.50);
m_ymsnd->add_route(1, "rspeaker", 0.50);
okim6295_device &oki(OKIM6295(config, "oki", XTAL(4'000'000) / 4, okim6295_device::PIN7_HIGH));
oki.add_route(ALL_OUTPUTS, "lspeaker", 0.25);
@ -513,7 +526,13 @@ void puckpkmn_state::init_puckpkmn()
for (size_t i = 0; i < len; i++)
rom[i] = bitswap<8>(rom[i], 1, 4, 2, 0, 7, 5, 3, 6);
init_megadriv();
m_maincpu->set_tas_write_callback(*this, FUNC(puckpkmn_state::megadriv_tas_callback));
// TODO: move this to the device interface?
m_vdp->set_use_cram(1);
m_vdp->set_vdp_pal(false);
m_vdp->set_framerate(60);
m_vdp->set_total_scanlines(262);
}
ROM_START( puckpkmn ) /* Puckman Pockimon (c)2000 Genie */

View File

@ -297,20 +297,22 @@ void smssdisp_state::sms_store_mem(address_map &map)
}
// I/O ports $3E and $3F do not exist on Mark III
void sms_state::sg1000m3_io(address_map &map)
void sg1000m3_state::sg1000m3_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0x40, 0x7f).r(FUNC(sms_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w));
map(0x40, 0x7f).r(FUNC(sg1000m3_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w));
map(0x80, 0x80).mirror(0x3e).rw(m_vdp, FUNC(sega315_5124_device::data_read), FUNC(sega315_5124_device::data_write));
map(0x81, 0x81).mirror(0x3e).rw(m_vdp, FUNC(sega315_5124_device::control_read), FUNC(sega315_5124_device::control_write));
map(0xc0, 0xc7).mirror(0x38).rw(FUNC(sms_state::sg1000m3_peripheral_r), FUNC(sms_state::sg1000m3_peripheral_w));
map(0xc0, 0xc7).mirror(0x38).rw(FUNC(sg1000m3_state::sg1000m3_peripheral_r), FUNC(sg1000m3_state::sg1000m3_peripheral_w));
}
void sms_state::sms_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0x00, 0x00).mirror(0x3e).w(FUNC(sms_state::sms_mem_control_w));
map(0x01, 0x01).mirror(0x3e).w(FUNC(sms_state::sms_io_control_w));
map(0x40, 0x7f).r(FUNC(sms_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w));
@ -345,6 +347,7 @@ void sms_state::smsj_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0x3e, 0x3e).w(FUNC(sms_state::sms_mem_control_w));
map(0x3f, 0x3f).w(FUNC(sms_state::sms_io_control_w));
map(0x40, 0x7f).r(FUNC(sms_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w));
@ -366,6 +369,7 @@ void gamegear_state::gg_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0x00, 0x00).r(FUNC(gamegear_state::gg_input_port_00_r));
map(0x01, 0x05).rw(FUNC(gamegear_state::gg_sio_r), FUNC(gamegear_state::gg_sio_w));
map(0x06, 0x06).w(FUNC(gamegear_state::gg_psg_stereo_w));
@ -484,7 +488,7 @@ static INPUT_PORTS_START( gg )
PORT_START("START")
PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("Start") /* Game Gear START */
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("Start")
PORT_START("PERSISTENCE")
PORT_CONFNAME( 0x01, 0x01, "LCD Persistence Hack" )
@ -920,11 +924,11 @@ void sms1_state::smsj(machine_config &config)
m_is_smsj = true;
}
void sms1_state::sg1000m3(machine_config &config)
void sg1000m3_state::sg1000m3(machine_config &config)
{
sms1_ntsc(config);
m_maincpu->set_addrmap(AS_IO, &sms1_state::sg1000m3_io);
m_maincpu->set_addrmap(AS_IO, &sg1000m3_state::sg1000m3_io);
// Remove and reinsert all media slots, as done with the sms1_kr config,
// and also replace the expansion slot with the SG-1000 version.
@ -933,7 +937,7 @@ void sms1_state::sg1000m3(machine_config &config)
config.device_remove("smsexp");
SG1000MK3_CART_SLOT(config, "slot", sg1000mk3_cart, nullptr);
SMS_CARD_SLOT(config, "mycard", sms_cart, nullptr);
SG1000_EXPANSION_SLOT(config, "sgexp", sg1000_expansion_devices, nullptr, false);
SG1000_EXPANSION_SLOT(config, m_sgexpslot, sg1000_expansion_devices, nullptr, false);
SOFTWARE_LIST(config, "cart_list2").set_original("sg1000");
@ -1241,7 +1245,7 @@ ROM_END
***************************************************************************/
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
CONS( 1985, sg1000m3, sms, 0, sg1000m3, sg1000m3, sms1_state, empty_init, "Sega", "Mark III", MACHINE_SUPPORTS_SAVE )
CONS( 1985, sg1000m3, sms, 0, sg1000m3, sg1000m3, sg1000m3_state, empty_init, "Sega", "Mark III", MACHINE_SUPPORTS_SAVE )
CONS( 1986, sms1, sms, 0, sms1_ntsc, sms1, sms1_state, empty_init, "Sega", "Master System I", MACHINE_SUPPORTS_SAVE )
CONS( 1986, sms1pal, sms, 0, sms1_pal, sms1, sms1_state, empty_init, "Sega", "Master System I (PAL)" , MACHINE_SUPPORTS_SAVE )
CONS( 1986, smssdisp, sms, 0, sms_sdisp, smssdisp, smssdisp_state, empty_init, "Sega", "Master System Store Display Unit", MACHINE_SUPPORTS_SAVE )

View File

@ -59,8 +59,7 @@ public:
m_has_pwr_led(false),
m_slot(*this, "slot"),
m_cardslot(*this, "mycard"),
m_smsexpslot(*this, "smsexp"),
m_sgexpslot(*this, "sgexp")
m_smsexpslot(*this, "smsexp")
{ }
void sms_base(machine_config &config);
@ -94,8 +93,6 @@ protected:
uint8_t sms_count_r(offs_t offset);
uint8_t sms_input_port_dc_r();
uint8_t sms_input_port_dd_r();
uint8_t sg1000m3_peripheral_r(offs_t offset);
void sg1000m3_peripheral_w(offs_t offset, uint8_t data);
uint8_t smsj_audio_control_r();
void smsj_audio_control_w(uint8_t data);
void smsj_ym2413_register_port_w(uint8_t data);
@ -105,7 +102,6 @@ protected:
DECLARE_WRITE_LINE_MEMBER(sms_ctrl1_th_input);
DECLARE_WRITE_LINE_MEMBER(sms_ctrl2_th_input);
void sg1000m3_io(address_map &map);
void sms_io(address_map &map);
void sms_mem(address_map &map);
void smsj_io(address_map &map);
@ -143,7 +139,7 @@ protected:
std::unique_ptr<uint8_t[]> m_mainram;
uint8_t *m_BIOS;
// for gamegear LCD persistence hack
// for Game Gear LCD persistence hack
bitmap_rgb32 m_prev_bitmap;
bool m_prev_bitmap_copied;
@ -192,9 +188,9 @@ protected:
optional_device<sega8_cart_slot_device> m_slot;
optional_device<sega8_card_slot_device> m_cardslot;
optional_device<sms_expansion_slot_device> m_smsexpslot;
optional_device<sg1000_expansion_slot_device> m_sgexpslot;
};
class sms1_state : public sms_state
{
public:
@ -212,7 +208,6 @@ public:
void sms1_br(machine_config &config);
void sms1_kr(machine_config &config);
void smsj(machine_config &config);
void sg1000m3(machine_config &config);
protected:
virtual void video_start() override;
@ -241,6 +236,7 @@ private:
uint8_t m_frame_sscope_state;
};
class smssdisp_state : public sms1_state
{
public:
@ -278,6 +274,30 @@ private:
uint8_t m_store_cart_selection_data;
};
class sg1000m3_state : public sms1_state
{
public:
sg1000m3_state(const machine_config &mconfig, device_type type, const char *tag) :
sms1_state(mconfig, type, tag),
m_sgexpslot(*this, "sgexp")
{ }
void sg1000m3(machine_config &config);
protected:
virtual void machine_reset() override;
private:
uint8_t sg1000m3_peripheral_r(offs_t offset);
void sg1000m3_peripheral_w(offs_t offset, uint8_t data);
void sg1000m3_io(address_map &map);
required_device<sg1000_expansion_slot_device> m_sgexpslot;
};
class gamegear_state : public sms_state
{
public:
@ -312,9 +332,10 @@ private:
// for gamegear SMS mode scaling
bitmap_rgb32 m_gg_sms_mode_bitmap;
// line_buffer will be used to hold 4 lines of line data as a kind of cache for
// vertical scaling in the gamegear sms compatibility mode.
std::unique_ptr<int[]> m_line_buffer;
// vertical scaling in the Game Gear SMS compatibility mode.
std::unique_ptr<int []> m_line_buffer;
uint8_t m_gg_sio[5]{};
int m_gg_paused = 0;

View File

@ -290,12 +290,6 @@ WRITE_LINE_MEMBER(sms_state::rapid_n_csync_callback)
uint8_t sms_state::sms_input_port_dc_r()
{
if (m_is_mark_iii)
{
sms_get_inputs();
return m_port_dc_reg;
}
if (m_is_gamegear)
{
// If SMS mode is disabled, just return the data read from the
@ -337,12 +331,6 @@ uint8_t sms_state::sms_input_port_dc_r()
uint8_t sms_state::sms_input_port_dd_r()
{
if (m_is_mark_iii)
{
sms_get_inputs();
return m_port_dd_reg;
}
if (m_is_gamegear)
{
if (!(m_cartslot->exists() && m_cartslot->get_sms_mode()))
@ -763,9 +751,9 @@ void sms_state::sms_mem_control_w(uint8_t data)
}
uint8_t sms_state::sg1000m3_peripheral_r(offs_t offset)
uint8_t sg1000m3_state::sg1000m3_peripheral_r(offs_t offset)
{
bool joy_ports_disabled = m_sgexpslot->is_readable(offset);
bool const joy_ports_disabled = m_sgexpslot->is_readable(offset);
if (joy_ports_disabled)
{
@ -773,22 +761,21 @@ uint8_t sms_state::sg1000m3_peripheral_r(offs_t offset)
}
else
{
sms_get_inputs();
if (offset & 0x01)
return sms_input_port_dd_r();
return m_port_dd_reg;
else
return sms_input_port_dc_r();
return m_port_dc_reg;
}
}
void sms_state::sg1000m3_peripheral_w(offs_t offset, uint8_t data)
void sg1000m3_state::sg1000m3_peripheral_w(offs_t offset, uint8_t data)
{
bool joy_ports_disabled = m_sgexpslot->is_writeable(offset);
bool const joy_ports_disabled = m_sgexpslot->is_writeable(offset);
if (joy_ports_disabled)
{
m_sgexpslot->write(offset, data);
}
}
@ -1053,7 +1040,7 @@ void sms_state::machine_start()
void smssdisp_state::machine_start()
{
sms_state::machine_start();
sms1_state::machine_start();
save_item(NAME(m_store_control));
save_item(NAME(m_store_cart_selection_data));
@ -1092,13 +1079,7 @@ void sms_state::machine_reset()
m_led_pwr = 1;
}
if (m_is_mark_iii)
{
// pin 7 is tied to ground on the Mark III
m_port_ctrl1->out_w(0x3f, 0x40);
m_port_ctrl2->out_w(0x3f, 0x40);
}
else
if (!m_is_mark_iii)
{
m_io_ctrl_reg = 0xff;
m_ctrl1_th_latch = 0;
@ -1115,7 +1096,16 @@ void smssdisp_state::machine_reset()
m_store_cart_selection_data = 0;
store_select_cart(m_store_cart_selection_data);
sms_state::machine_reset();
sms1_state::machine_reset();
}
void sg1000m3_state::machine_reset()
{
sms1_state::machine_reset();
// controller port pin 7 is tied to ground on the Mark III
m_port_ctrl1->out_w(0x3f, 0x40);
m_port_ctrl2->out_w(0x3f, 0x40);
}
void gamegear_state::machine_reset()