summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author janniz <j2pguard-spam@yahoo.com>2019-10-31 12:11:45 +0100
committer Vas Crabb <cuavas@users.noreply.github.com>2019-10-31 22:11:45 +1100
commitf31b19f9c91a82d12f15959f03d0c7caf914c152 (patch)
tree78f7b2136c593403568eb784112d37b1094d12fe
parentba273549dd298adc55d786ea5d1d463874f24eda (diff)
Added two new unreleased Model Racing games (#5813)
* Fixed LOG_WAV_ENABLED_ONLY (m_enable has to be checked only if LOG_WAV_ENABLED_ONLY is set) Added log data to the right channel of the wave, accordingly to the definition declared in LOG_WAV_VALUE_R * Fixed an error with tag() returning a ':' and generating a filename not valid in Windows environment * Added Model Racing "Cane" * Added Model Racing "Orbite" * Replaced the char array with a std::string in sn76477_device::open_wav_file to override possible buffer overrun. Minor cosmetic change in a boolean expression in sn76477_device::sound_stream_update * Refactored "Cane" related code creating an audio device to encapsulate the audio system Refactored "Cane" and "Orbite" creating their own classes Other minor changes in indentation of the source code
-rw-r--r--src/devices/sound/sn76477.cpp38
-rw-r--r--src/mame/audio/8080bw.cpp280
-rw-r--r--src/mame/audio/8080bw.h44
-rw-r--r--src/mame/drivers/8080bw.cpp434
-rw-r--r--src/mame/includes/8080bw.h73
-rw-r--r--src/mame/mame.lst2
-rw-r--r--src/mame/video/8080bw.cpp25
7 files changed, 884 insertions, 12 deletions
diff --git a/src/devices/sound/sn76477.cpp b/src/devices/sound/sn76477.cpp
index c259b3cb0ed..d24ab6a1bb6 100644
--- a/src/devices/sound/sn76477.cpp
+++ b/src/devices/sound/sn76477.cpp
@@ -892,9 +892,11 @@ void sn76477_device::log_complete_state()
void sn76477_device::open_wav_file()
{
- char wav_file_name[30];
+ std::string s = tag();
+ std::replace(s.begin(), s.end(), ':', '_');
+
+ char const* wav_file_name = util::string_format(LOG_WAV_FILE_NAME, s).c_str();
- sprintf(wav_file_name, LOG_WAV_FILE_NAME, tag());
m_file = wav_open(wav_file_name, m_our_sample_rate, 2);
LOG(1, "SN76477: Logging output: %s\n", wav_file_name);
@@ -1996,7 +1998,7 @@ void sn76477_device::sound_stream_update(sound_stream &stream, stream_sample_t *
*/
*buffer++ = (((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1) * 32767;
- if (LOG_WAV && LOG_WAV_ENABLED_ONLY && !m_enable)
+ if (LOG_WAV && (!m_enable || !LOG_WAV_ENABLED_ONLY))
{
int16_t log_data_l;
int16_t log_data_r;
@@ -2005,30 +2007,48 @@ void sn76477_device::sound_stream_update(sound_stream &stream, stream_sample_t *
{
case 0:
log_data_l = LOG_WAV_GAIN_FACTOR * voltage_out;
- log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out;
break;
case 1:
log_data_l = LOG_WAV_GAIN_FACTOR * m_enable;
- log_data_r = LOG_WAV_GAIN_FACTOR * m_enable;
break;
case 2:
log_data_l = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
- log_data_r = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
break;
case 3:
log_data_l = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
- log_data_r = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
break;
case 4:
log_data_l = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
- log_data_r = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
break;
case 5:
log_data_l = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
- log_data_r = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
break;
case 6:
log_data_l = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage;
+ break;
+ }
+
+ switch (LOG_WAV_VALUE_R)
+ {
+ case 0:
+ log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out;
+ break;
+ case 1:
+ log_data_r = LOG_WAV_GAIN_FACTOR * m_enable;
+ break;
+ case 2:
+ log_data_r = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
+ break;
+ case 3:
+ log_data_r = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
+ break;
+ case 4:
+ log_data_r = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
+ break;
+ case 5:
+ log_data_r = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
+ break;
+ case 6:
log_data_r = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage;
break;
}
diff --git a/src/mame/audio/8080bw.cpp b/src/mame/audio/8080bw.cpp
index 27fcb7add51..08beb52cf52 100644
--- a/src/mame/audio/8080bw.cpp
+++ b/src/mame/audio/8080bw.cpp
@@ -24,6 +24,13 @@ MACHINE_START_MEMBER(_8080bw_state,extra_8080bw_sh)
save_item(NAME(m_port_3_last_extra));
}
+/*************************************
+ *
+ * Device type globals
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(CANE_AUDIO, cane_audio_device, "cane_audio", "Model Racing Cane Audio")
/*************************************
@@ -1397,3 +1404,276 @@ WRITE8_MEMBER( _8080bw_state::darthvdr_08_w )
m_port_1_last_extra = data;
}
+
+
+/*********************************************************/
+/* */
+/* Model Racing "Cane" (Slightly based on Claybuster hw) */
+/* */
+/*********************************************************/
+#define CANE_CLOCK (19968000.0)
+#define CANE_H64 CANE_CLOCK /2 /2 /4
+
+/* Nodes - Sound enable */
+#define CANE_SND_EN NODE_05
+
+/* Nodes - Adjusters */
+#define CANE_VR1 NODE_07 // Gain for 76477
+#define CANE_VR2 NODE_08 // VR attached to the output of the TOS
+#define CANE_VR3 NODE_09 // VR for SFX generated by the 555
+
+/* Nodes - sn76477 Sounds */
+#define CANE_EXP_STREAM NODE_03
+#define CANE_EXP_SND NODE_11
+
+/* Nodes - BGM */
+#define CANE_MUSIC_DATA NODE_06
+#define CANE_MUSIC_NOTE NODE_40
+#define CANE_MUSIC_NOTE_PF NODE_01
+#define CANE_MUSIC_SND NODE_12
+
+/* Nodes - 555 sfx */
+#define CANE_76477_PIN6 NODE_13
+#define CANE_555_CLAMPED NODE_14
+#define CANE_555_ONESHOT NODE_15
+#define CANE_555_EN NODE_16
+#define CANE_TMP_SND NODE_17
+#define CANE_SFX_SND NODE_18
+
+/* Node output */
+#define CANE_SOUND_OUT NODE_90
+
+static INPUT_PORTS_START( cane_audio )
+ PORT_START("VR1")
+ PORT_ADJUSTER( 80, "VR1 - SFX from 76477" )
+
+ PORT_START("VR2")
+ PORT_ADJUSTER( 90, "VR2 - TOS music" )
+
+ PORT_START("VR3")
+ PORT_ADJUSTER( 70, "VR3 - Shoot SFX from 555" )
+INPUT_PORTS_END
+
+cane_audio_device::cane_audio_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, CANE_AUDIO, tag, owner, clock),
+ m_cane_vco_timer(*this, "cane_vco_timer"),
+ m_sn(*this, "snsnd"),
+ m_discrete(*this, "discrete"),
+ m_cane_vco_rc_chargetime(INT_MAX)
+{
+}
+
+void cane_audio_device::device_add_mconfig(machine_config &config)
+{
+ // provare a commentare
+ m_cane_vco_rc_chargetime = INT_MAX;
+
+ TIMER(config, "cane_vco_timer").configure_periodic(FUNC(cane_vco_voltage_timer), attotime::from_hz(1000));
+
+ SPEAKER(config, "mono").front_center();
+
+ SN76477(config, m_sn);
+ // Amplitude res in the schematic is connected to a 470K potentiometer, so from the schematic is impossible to know the real res.
+ // This parameter drives the amp just before the audio output pin 13.
+ m_sn->set_amp_res(100+RES_K(20));
+ m_sn->set_noise_params(RES_K(39), RES_K(1), CAP_P(1000));
+ m_sn->set_decay_res(RES_M(1));
+ m_sn->set_attack_params(CAP_U(1.0), RES_K(47));
+ m_sn->set_feedback_res(RES_K(4.7));
+ m_sn->set_vco_params(0, CAP_P(3300), RES_K(100));
+ m_sn->set_pitch_voltage(5.0);
+ m_sn->set_slf_params(CAP_U(1.0), RES_K(33));
+ m_sn->set_oneshot_params(CAP_U(10), RES_K(100));
+ m_sn->set_vco_mode(0);
+ m_sn->set_mixer_params(0, 0, 0);
+ m_sn->set_envelope_params(1, 0);
+ m_sn->set_enable(0);
+ m_sn->add_route(0, "discrete", 1.0, 0);
+
+ DISCRETE(config, m_discrete, cane_discrete);
+ m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
+}
+
+ioport_constructor cane_audio_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(cane_audio);
+}
+
+void cane_audio_device::device_start()
+{
+}
+
+void cane_audio_device::cane_sh_port_1_w(u8 data)
+{
+ /*
+ bit 0 - SX0 - Sound enable on mixer
+ bit 1 - SX1 - SN76477 - Mixer select C - pin 27
+ bit 2 - SX2 - SN76477 - Mixer select A - pin 26
+ bit 3 - SX3 - SN76477 - Mixer select B - pin 25
+ bit 4 - SX4 - NE555 - Trigger (Step, high output level for 1.1*RC = 1.1*100K*0.47u = 51.7 ms)
+ */
+
+ m_discrete->write(CANE_SND_EN, data & 0x01); // BIT(data, 0) - bit 0 - SX0 - Sound enable on mixer
+ m_discrete->write(CANE_555_EN, data & 0x10); // BIT(data, 4) - bit 4 - SX4 - NE555 - Trigger
+
+ // 76477 enable bit is connected to the select line of the out port 3 (inverted).
+ m_sn->enable_w(1);
+ m_sn->set_mixer_params(BIT(data, 2), BIT(data, 3), BIT(data, 1));
+
+ m_cane_vco_timer->adjust(attotime::zero, m_cane_vco_timer->param(), attotime::from_hz(1000));
+ m_cane_vco_rc_chargetime = m_cane_vco_timer->start_time().as_double();
+
+ // Little hack...
+ // To be precise I should enable the 76477 every time the CPU reads or write to a port different from port 3
+ // and disable it every time the CPU read/write from/to port 3.
+ // Actually this can not be done easily so I decided to enable it preemptively here after every port 3 access
+ m_sn->enable_w(0);
+}
+
+void cane_audio_device::cane_music_w(u8 data)
+{
+ m_sn->enable_w(1);
+ m_discrete->write(CANE_MUSIC_DATA, data);
+}
+
+void cane_audio_device::cane_76477_en_w(u8 data)
+{
+ m_sn->enable_w(0);
+}
+
+void cane_audio_device::cane_76477_dis_w(u8 data)
+{
+ m_sn->enable_w(1);
+}
+
+/*******************************************************************************************************************************************************/
+/* Cane discrete implementation, slightly based on Claybuster hw. */
+/* This implementation doesn't pretend to be accurate thus trying to be at least functionally similar. */
+/* */
+/* Port 1 - SX4 CANE_VR3 Port 1 - SX0 */
+/* | | | */
+/* CANE_555_EN | | */
+/* | | | */
+/* +------------------+ | | */
+/* | CANE_555_ONESHOT | | | */
+/* +------------------+ | | */
+/* | | | */
+/* v v | */
+/* sn76477 pin 6 +------------------+ +---+ +--------------+ +---+ +--------------+ | */
+/* CLAMP(0, 5V) ->| CANE_555_CLAMPED |->| * |->| CANE_TMP_SND |->| * |->| CANE_SFX_SND | CANE_SND_EN */
+/* (DISCRETE_NOISE) +------------------+ +---+ +--------------+ +---+ +--------------+ | */
+/* | | */
+/* CANE_VR1 | | */
+/* | | | */
+/* v v v */
+/* sn76477 output +-----------------+ +---+ +--------------+ +---+ +----------------+ */
+/* DISCRETE_INPUTX_STREAM ->| CANE_EXP_STREAM |->| * |->| CANE_EXP_SND |->| + |->| CANE_SOUND_OUT |->OUT */
+/* +-----------------+ +---+ +--------------+ +---+ +----------------+ */
+/* ^ */
+/* | */
+/* CANE_MUSIC_DATA +--------------------+ +-----------+ +-----------------+ +---+ +----------------+ */
+/* Port 5 data---DISCRETE_INPUT_DATA ->| CANE_MUSIC_NOTE_PF |->| CR_FILTER |->| CANE_MUSIC_NOTE |->| * |->| CANE_MUSIC_SND | */
+/* DISCRETE_NOTE +--------------------+ +-----------+ +-----------------+ +---+ +----------------+ */
+/* RES_K(10) ^ */
+/* CAP_U(0.1) | */
+/* CANE_VR2 */
+/* */
+/* */
+/*******************************************************************************************************************************************************/
+DISCRETE_SOUND_START(cane_discrete)
+ /************************************************/
+ /* Input register mapping for cane */
+ /************************************************/
+ DISCRETE_INPUT_DATA (CANE_MUSIC_DATA)
+
+ DISCRETE_INPUT_LOGIC (CANE_555_EN)
+
+ // scale to 0-2.5V
+ DISCRETE_INPUTX_STREAM(CANE_EXP_STREAM, 0, 0.5, 0)
+
+ DISCRETE_INPUT_LOGIC (CANE_SND_EN)
+
+ /************************************************/
+ /* Volume adjusters. */
+ /* We will set them to adjust the realitive */
+ /* gains. */
+ /************************************************/
+ DISCRETE_ADJUSTMENT(CANE_VR1, 0, 0.33*6, DISC_LINADJ, "VR1") // Gain for 76477
+ DISCRETE_ADJUSTMENT(CANE_VR2, 0, 0.33*60000, DISC_LINADJ, "VR2") // VR attached to the output of the TOS
+ DISCRETE_ADJUSTMENT(CANE_VR3, 0, 0.33*60000, DISC_LINADJ, "VR3") // VR for SFX generated by the 555
+
+ /************************************************/
+ /* From 555 */
+ /************************************************/
+ /* TODO: find real noise freq and amplitude */
+ /* width was simulated with ltspice using Claybuster schematic as a source and it's value is about 51ms */
+ DISCRETE_NOISE(CANE_76477_PIN6,
+ 1, /* ENAB */
+ 1280, /* FREQ - Guessed */
+ 1, /* AMP */
+ 0) /* BIAS - fake AC is fine*/
+ DISCRETE_CLAMP(CANE_555_CLAMPED,
+ CANE_76477_PIN6, /* input node */
+ 0.0, /* minimum */
+ 5.0) /* maximum */
+ DISCRETE_ONESHOT(CANE_555_ONESHOT,
+ CANE_555_EN, /* trigger node */
+ 1, /* amplitude node or static value */
+ 0.05, /* width (in seconds) node or static value - 50 ms*/
+ DISC_ONESHOT_FEDGE | DISC_ONESHOT_RETRIG) /* type of oneshot static value */
+
+ DISCRETE_MULTIPLY(CANE_TMP_SND, CANE_555_CLAMPED, CANE_555_ONESHOT)
+ DISCRETE_MULTIPLY(CANE_SFX_SND, CANE_TMP_SND, CANE_VR3)
+
+/*****************************************************************************
+*
+* Music Generator (TOS)
+*
+* Values for this section of the sound hardware where derived from comments
+* in the source code and the analysis of TOS.ED sources.
+*
+* For further info look at the relevant comments reported into
+* drivers/8080bw.cpp
+*
+******************************************************************************/
+ DISCRETE_NOTE(CANE_MUSIC_NOTE_PF, 1, CANE_H64, CANE_MUSIC_DATA, 255, 1, DISC_CLK_IS_FREQ)
+ DISCRETE_CRFILTER(CANE_MUSIC_NOTE, CANE_MUSIC_NOTE_PF, RES_K(10), CAP_U(0.1)) // high pass filter
+ DISCRETE_MULTIPLY(CANE_MUSIC_SND, CANE_MUSIC_NOTE, CANE_VR2)
+
+/******************************************************************************
+*
+* From 76477 output
+*
+******************************************************************************/
+ DISCRETE_MULTIPLY(CANE_EXP_SND, CANE_EXP_STREAM, CANE_VR1)
+
+/******************************************************************************
+*
+* Final Mixing and Output
+*
+******************************************************************************/
+ DISCRETE_ADDER3(CANE_SOUND_OUT, CANE_SND_EN, CANE_SFX_SND, CANE_EXP_SND, CANE_MUSIC_SND)
+ DISCRETE_OUTPUT(CANE_SOUND_OUT, 1)
+
+//LOG
+/*
+ DISCRETE_WAVLOG1(CANE_EXP_STREAM, 1)
+ DISCRETE_WAVLOG1(CANE_EXP_SND, 1)
+ DISCRETE_WAVLOG1(CANE_TMP_SND, 1)
+ DISCRETE_WAVLOG1(CANE_SFX_SND, 1)
+ DISCRETE_WAVLOG1(CANE_MUSIC_NOTE, 1)
+ DISCRETE_WAVLOG1(CANE_MUSIC_SND, 1)
+ DISCRETE_WAVLOG1(CANE_SOUND_OUT, 1)
+*/
+DISCRETE_SOUND_END
+
+TIMER_DEVICE_CALLBACK_MEMBER(cane_audio_device::cane_vco_voltage_timer)
+{
+ double voltage;
+ voltage = 5 * (1 - exp(- (m_cane_vco_timer->fire_time().as_double() - m_cane_vco_rc_chargetime) / 47));
+
+ logerror("t = %d\n", m_cane_vco_timer->fire_time().as_double() - m_cane_vco_rc_chargetime);
+ logerror("vco_voltage = %d\n", voltage);
+
+ m_sn->vco_voltage_w(voltage);
+}
diff --git a/src/mame/audio/8080bw.h b/src/mame/audio/8080bw.h
new file mode 100644
index 00000000000..3bbe99c2ab4
--- /dev/null
+++ b/src/mame/audio/8080bw.h
@@ -0,0 +1,44 @@
+// license:BSD-3-Clause
+/***************************************************************************
+
+ 8080-based black and white sound hardware
+
+****************************************************************************/
+#ifndef MAME_AUDIO_8080BW_H
+#define MAME_AUDIO_8080BW_H
+
+#pragma once
+
+#include "machine/timer.h"
+#include "sound/discrete.h"
+#include "sound/samples.h"
+#include "sound/sn76477.h"
+
+class cane_audio_device : public device_t
+{
+public:
+ cane_audio_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
+
+ void cane_sh_port_1_w(u8 data);
+ void cane_music_w(u8 data);
+ void cane_76477_en_w(u8 data);
+ void cane_76477_dis_w(u8 data);
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+
+private:
+ TIMER_DEVICE_CALLBACK_MEMBER(cane_vco_voltage_timer);
+
+ required_device<timer_device> m_cane_vco_timer;
+ required_device<sn76477_device> m_sn;
+ required_device<discrete_sound_device> m_discrete;
+
+ double m_cane_vco_rc_chargetime;
+};
+
+DECLARE_DEVICE_TYPE(CANE_AUDIO, cane_audio_device)
+
+#endif // MAME_AUDIO_8080BW_H
diff --git a/src/mame/drivers/8080bw.cpp b/src/mame/drivers/8080bw.cpp
index 73d06ff1c8f..94271d0c5f7 100644
--- a/src/mame/drivers/8080bw.cpp
+++ b/src/mame/drivers/8080bw.cpp
@@ -3560,6 +3560,423 @@ void _8080bw_state::init_invmulti()
+/*******************************************************/
+/* */
+/* Cane (Model Racing) */
+/* */
+/*******************************************************/
+/***********************************************************************************************************************************
+ This game was never released by Model Racing to the public.
+
+ The assembler source files for this game where extracted from the original floppy disks used by the former Model Racing developer
+ Adolfo Melilli (adolfo@melilli.com).
+ Those disks where retrieved by Alessandro Bolgia (xadhoom76@gmail.com) and Lorenzo Fongaro (lorenzo.fongaro@virgilio.it) and
+ dumped by Piero Andreini (pieroandreini@gmail.com) using KryoFlux hardware and software.
+ Subsequently Jean Paul Piccato (j2pguard-spam@yahoo.com) mounted the images and compiled the source files, managed to set up a
+ romset and wrote a mame driver that aims to reproduce in the most faithful way the work of Melilli at Model Racing in late '70s.
+
+ The game driver is not based on hardware inspection and is solely derived from assumptions I've made looking at the assembler
+ code and comments written into the source files of the game. Several of those hypothesis came following the directions of
+ previous yet contemporary Model Racing works (Eg: Claybuster) and where confirmed by Melilli himself.
+
+ Being unreleased this games has not an official name, thus the name used in the source files was used instead.
+
+***********************************************************************************************************************************/
+void cane_state::machine_start()
+{
+ mw8080bw_state::machine_start();
+}
+
+void cane_state::cane_map(address_map &map)
+{
+ map(0x0000, 0x1fff).rom().nopw();
+ map(0x2000, 0x3fff).ram().share("main_ram");
+}
+
+void cane_state::cane_io_map(address_map &map)
+{
+/*********************************************************************************************************************************
+ -----------
+ I/O mapping
+ -----------
+ out:
+ $00 - Unknown - Not yet emulated
+ $01 - Hardware shift register - Shift count
+ $02 - Hardware shift register - Shift data
+ $03 - Audio sub-system - D0->sx0, D1->sx1, D2->sx2, D3->sx3, D4->sx4, D5-D7 unused
+ sx0 mute/unmute all
+ sx1,sx2,sx3 routed to 76477 mixer select
+ sx4 routed to 555 one-shot trigger
+ $04 - Reset watchdog timer
+ $05 - Audio TOS
+
+ in:
+ $01 - CPO / coin input port
+ $03 - Hardware shift register - Shift result
+
+=================================================================================================================
+------------
+-- OUT 0 --
+Source file: CANE1.ED - Referred only once in code, in the "rifle routine" (ROUTINE FUCILE)
+
+ > ;ROUTINE FUCILE
+ > CALL SPARO
+ > OUT 0
+
+------------
+-- OUT 1 --
+Source files: CANE2.ED, MIRINO.ED
+
+ Defined in CANE2.ED
+
+ > PRMTR EQU 1
+
+ and referred multiple times in CANE2.ED and MIRINO.ED. Eg:
+
+ > ;PER RISPETTARE POS ORIZZONT. UCCELLO
+ > LXI D,TPADEL
+ > XRA A
+ > OUT PRMTR
+
+------------
+-- OUT 2 --
+Source files: CANE1.ED, CANE2.ED, MIRINO.ED
+
+ Defined in CANE2.ED
+
+ > DATO EQU 2
+
+ and referred multiple times in CANE1.ED and MIRINO.ED. Eg:
+
+ > ZANZ: XRA A
+ > OUT DATO
+
+------------
+-- OUT 3 --
+Source file: CANE2.ED
+
+ The access to port 3 is mediated by the routines SETP3 and RESP3 defined in CANE2.ED
+ SETP3 -- Port 3 = Port 3 | A
+
+ > SETP3:
+ > ;SETTA I BITS CONTEN IN REG A NELLA PORTA 3
+
+ RESP3 -- Port 3 = Port 3 & A
+
+ > RESP3:
+ > ;IL CONTRARIO DI SETP3
+
+ and referred multiple times in CANE2.ED. Eg:
+
+ > ;SPENGO IL VOLO UCCELLI
+ > MVI A,0FEH
+ > CALL SETP3
+
+------------
+-- OUT 4 --
+Source file: CANE1.ED, CANE2.ED
+
+ Called directly in CANE1.ED
+
+ > INT8:
+ > OUT 4
+ > ;PER LAUTORESET
+
+ Also defined in CANE2.ED
+
+ > RESET EQU 4
+
+ and called multiple times in CANE1.ED and CANE2.ED. Eg:
+
+ > DELAY3: OUT RESET
+
+------------
+-- OUT 5 --
+Source file: CANE2.ED, TOS.ED
+
+TOS sound
+D0-D7 is pushed into a LS273 (Octal D-type Flip-Flop) and it's value is used to preload the starting value of
+two, cascaded, LS161 (Synchronous 4-Bit Counters).
+The counters drive a J-K Flip-Flop generating a square wave signal drived in frequency by the preloaded value.
+
+ > CANONE:
+ > ;AZZITTO IL TOS:
+ > MVI A,255 ; A = 255 ; TIMER spento
+ > OUT 5 ; OUT 5
+
+The musical note is defined in a library source file TOS.ED and referred later by the source files, eg. in CANE2.ED:
+ > CARICA: DB RE,FA,FA,FA,FA,PAU
+ > DB RE,FA,FA,FA,FA,PAU
+ > DB RE,FA,PAU,RE,FA,PAU
+ > DB RE,FA,FA,FA,FA,PAU
+ > DB FINALE
+ > TABSTR: NOP
+ > LULUP: DB DO,RE,MI,FA,SOL,LA,SI,DO2
+ > DB FINALE
+
+ > CIPCIP: DB 220,215,210,205,200,FINALE
+
+ The notes are defined in TOS.ed:
+ > ; SI PARTE DA UNA FREQUENZA DI CLOCK DI 1 MHZ CIRCA,QUESTA FREQUENZA DIVISA)
+ > ; PER UNA SERIE DI PARAMETRI ATTRAVERSO DEI DIVISORI PROGRAMMABILI FORNISCE
+ > ; ALL'USCITA DI QUESTI I DODICI SEMITONI DELLA SCALA CROMATICA
+
+ Name - Counter - Aprox. frequency
+ DO 16 - 1000/(255-16) = 4.18 KHz
+ DOD 30 - 1000/(255-30) = 4.44 KHz
+ RE 43 - 1000/(255-43) = 4.72 KHz
+ RED 55 - 1000/(255-55) = 5 KHz
+ MI 66 - 1000/(255-66) = 5.29 KHz
+ FA 77 - 1000/(255-77) = 5.62 KHz
+ FAD 87 - 1000/(255-87) = 5.95 KHz
+ SOL 96 - 1000/(255-96) = 6.29 KHz
+ SOLD 105 - 1000/(255-105) = 6.67 KHz
+ LA 114 - 1000/(255-114) = 7.09 KHz
+ LAD 122 - 1000/(255-122) = 7.52 KHz
+ SI 129 - 1000/(255-129) = 7.94 KHz
+
+ DO2 136 - 1000/(255-136) = 8.4 KHz
+ DOD2 143 - 1000/(255-143) = 8.93 KHz
+ RE2 149.5 - 1000/(255-150) = 9.52 KHz
+ RED2 155.5 - 1000/(255-156) = 10.1 KHz
+ MI2 161 - 1000/(255-161) = 10.64 KHz
+ FA2 166.5 - 1000/(255-167) = 11.36 KHz
+ FAD2 171.5 - 1000/(255-172) = 12.05 KHz
+ SOL2 176 - 1000/(255-176) = 12.66 KHz
+ SOLD2 180.5 - 1000/(255-181) = 13.51 KHz
+ LA2 185 - 1000/(255-185) = 14.29 KHz
+ LAD2 189 - 1000/(255-189) = 15.15 KHz
+ SI2 192.5 - 1000/(255-193) = 16.13 KHz
+
+ Pause code:
+ PAU EQU 255
+
+ End of note sequence:
+ FINALE EQU 254
+
+------------
+-- IN 1 --
+Source file: CANE2.ED
+
+ Defined in CANE2.ED
+ > PORTAM EQU 1 ;E' LA PORTA DI INPUT DI TUTTI I PULSANTI
+
+------------
+-- IN 3 --
+Source file: CANE1.ED, CANE2.ED
+ Defined in CANE2.ED
+
+ > PRONTO EQU 3
+
+ and referred in CANE1.ED
+
+ > OUT LOW DATO
+ > IN LOW PRONTO
+
+**********************************************************************************************************************************/
+ map(0x00, 0x00).w(FUNC(cane_state::cane_unknown_port0_w));
+
+ map(0x01, 0x01).portr("IN1").w(m_mb14241, FUNC(mb14241_device::shift_count_w));
+ map(0x02, 0x02).w(m_mb14241, FUNC(mb14241_device::shift_data_w));
+ map(0x03, 0x03).r(m_mb14241, FUNC(mb14241_device::shift_result_r)).w("soundboard", FUNC(cane_audio_device::cane_sh_port_1_w));
+
+ map(0x04, 0x04).w(m_watchdog, FUNC(watchdog_timer_device::reset_w));
+
+ map(0x05, 0x05).w("soundboard", FUNC(cane_audio_device::cane_music_w));
+}
+
+static INPUT_PORTS_START( cane )
+/* Source file: CANE2.ED, MIRINO.ED
+ Port definition:
+ > PORTAM EQU 1 ;E' LA PORTA DI INPUT DI TUTTI I PULSANTI
+
+ Bit values:
+ CANE2.ED
+ > DITO EQU 80H ;BIT DEL PULSANTE DI SPARO DEL FUCILE
+
+ MIRINO.ED
+ > UPPMIR EQU 20H ;BIT PER MIRINO IN ALTO
+ > LOWMIR EQU 40H ;BASSO
+ > RIGMIR EQU 8H ;DESTRA
+ > LEFMIR EQU 10H ;SINISTRA
+
+ Joystick reading routine:
+ MIRINO.ED
+ > ;ORA LEGGO LA PORTA DELLA CLOCHE
+ > IN LOW PORTAM
+ > MOV B,A
+ > ;A QUESTO PUNTO AGGIORNO LE COORDINATE X E Y A SECONDA DELLO STATO DEI BIT
+ > ;DELLA CLOCHE (ATTIVI BASSI)
+ > ANI LOWMIR
+ > CZ MIRLOW
+ > MOV A,B
+ > ANI UPPMIR
+ > CZ MIRUPP
+ > MOV A,B
+ > ANI LEFMIR
+ > CZ MIRLEF
+ > MOV A,B
+ > ANI RIGMIR
+ > CZ MIRRIG
+
+ Shot reading routine:
+ CANE2.ED
+ > ;QUI CI VADO SE NESSUNO PREME IL PULSANTE E STO ASPETTANDO UNO SPARO
+ > ;TEST GRILLETTO
+ > IN PORTAM
+ > ANI DITO
+
+ Coin reading routine;
+ CANE1.ED
+ > ;ACCREDITA
+ > SAR9A: IN 1
+ > ANI 4
+
+ Start game: (Verificare con debug $3C2)
+ CANE1.ED
+ > IN 1
+ > ANI 8
+ > JNZ FONTI
+
+*/
+
+PORT_START("IN1")
+// PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_NOTUSED )
+// PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_NOTUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_IMPULSE(2)
+INPUT_PORTS_END
+
+void cane_state::cane(machine_config &config)
+{
+ mw8080bw_root(config);
+
+ // Basic machine hardware
+ I8080(config.replace(), m_maincpu, 1996800); /* 19.968MHz / 10 */
+ m_maincpu->set_addrmap(AS_PROGRAM, &cane_state::cane_map);
+ m_maincpu->set_addrmap(AS_IO, &cane_state::cane_io_map);
+ m_maincpu->set_irq_acknowledge_callback(FUNC(cane_state::interrupt_vector));
+
+ WATCHDOG_TIMER(config, m_watchdog).set_vblank_count("screen", 255);
+
+ // add shifter
+ MB14241(config, m_mb14241);
+
+ // audio hardware
+ CANE_AUDIO(config, "soundboard");
+}
+
+void cane_state::cane_unknown_port0_w(u8 data)
+{
+ logerror("Unmapped io memory write to 00 = 00 %u\n", data);
+}
+
+/*******************************************************/
+/* */
+/* Model Racing "Orbite" */
+/* */
+/*******************************************************/
+/***********************************************************************************************************************************
+ This game was never completed and released by Model Racing to the public.
+ It's in a nearly incomplete form (eg: doesn't have any sound or score routine in the code) and it's barely playable.
+
+ The assembler source files for this game where extracted from the original floppy disks used by the former Model Racing developer
+ Adolfo Melilli (adolfo@melilli.com).
+ Those disks where retrieved by Alessandro Bolgia (xadhoom76@gmail.com) and Lorenzo Fongaro (lorenzo.fongaro@virgilio.it) and
+ dumped by Piero Andreini (pieroandreini@gmail.com) using KryoFlux hardware and software.
+ Subsequently Jean Paul Piccato (j2pguard-spam@yahoo.com) mounted the images and compiled the source files, managed to set up a
+ romset and wrote a mame driver that aims to reproduce in the most faithful way the work of Melilli at Model Racing in late '70s.
+
+ The game driver is not based on hardware inspection and is solely derived from assumptions I've made looking at the assembler
+ code and comments written into the source files of the game. Several of those hypothesis came following the directions of
+ previous yet contemporary Model Racing works (Eg: Claybuster) and where confirmed by Melilli himself.
+
+ Being unreleased this games has not an official name, thus the name used in the source files was used instead.
+
+***********************************************************************************************************************************/
+
+u8 orbite_state::orbite_scattered_colorram_r(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u8 mem_mask)
+{
+ return m_scattered_colorram[(offset & 0x1f) | ((offset & 0x1f80) >> 2)];
+}
+
+
+void orbite_state::orbite_scattered_colorram_w(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u8 data, ATTR_UNUSED u8 mem_mask)
+{
+ m_scattered_colorram[(offset & 0x1f) | ((offset & 0x1f80) >> 2)] = data;
+}
+
+
+void orbite_state::orbite_map(address_map &map)
+{
+// map(0x0000, 0x1fff).rom();
+ map(0x0000, 0x07ff).rom();
+ map(0x0800, 0x1fff).rom();
+ map(0x2000, 0x3fff).ram().share("main_ram");
+ map(0xc000, 0xdfff).rw(FUNC(orbite_state::orbite_scattered_colorram_r), FUNC(orbite_state::orbite_scattered_colorram_w));
+}
+
+
+void orbite_state::orbite_io_map(address_map &map)
+{
+ map(0x06, 0x06).w(m_watchdog, FUNC(watchdog_timer_device::reset_w));
+
+ // Ports verified on sources
+ map(0x08, 0x08).r(m_mb14241, FUNC(mb14241_device::shift_result_r));
+ map(0x20, 0x20).w(m_mb14241, FUNC(mb14241_device::shift_count_w));
+ map(0x40, 0x40).w(m_mb14241, FUNC(mb14241_device::shift_data_w));
+
+ map(0x66, 0x66).portr("IN0");
+ map(0x76, 0x76).portr("IN1");
+ map(0x7A, 0x7A).portr("IN2");
+}
+
+
+static INPUT_PORTS_START( orbite )
+ PORT_START("IN0")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_2WAY
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("IN1")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_2WAY
+
+ PORT_START("IN2") // port 2
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 )
+INPUT_PORTS_END
+
+
+void orbite_state::machine_start()
+{
+ m_scattered_colorram = std::make_unique<uint8_t []>(0x800);
+ save_pointer(&m_scattered_colorram[0], "m_scattered_colorram", 0x800);
+ mw8080bw_state::machine_start();
+}
+
+void orbite_state::orbite(machine_config &config)
+{
+ mw8080bw_root(config);
+
+ // basic machine hardware
+ I8080(config.replace(), m_maincpu, 1996800); /* 19.968MHz / 10 */
+ m_maincpu->set_addrmap(AS_PROGRAM, &orbite_state::orbite_map);
+ m_maincpu->set_addrmap(AS_IO, &orbite_state::orbite_io_map);
+ m_maincpu->set_irq_acknowledge_callback(FUNC(orbite_state::interrupt_vector));
+
+ WATCHDOG_TIMER(config, m_watchdog).set_vblank_count("screen", 255);
+
+ // add shifter
+ MB14241(config, m_mb14241);
+
+ // video hardware
+ m_screen->set_screen_update(FUNC(orbite_state::screen_update_orbite));
+
+ PALETTE(config, m_palette, palette_device::RGB_3BIT);
+}
+
/**************************************************************************************************************/
ROM_START( searthin )
@@ -5175,6 +5592,20 @@ ROM_START( attackfc )
ROM_LOAD( "39a.bin", 0x1c00, 0x0400, CRC(f538cf08) SHA1(4a375a41ab5d9f0d9f9a2ebef4c448038c139204) )
ROM_END
+ROM_START( cane )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "mrcane.71", 0x0000, 0x0800, CRC(47de691e) SHA1(8ed359774489ccf6023819b0d604b5a6d94b9f98) )
+ ROM_LOAD( "mrcane.70", 0x0800, 0x0800, CRC(3f3ee3b9) SHA1(ef45cf76697bbe037c680021ffa663856f2972d0) )
+ ROM_LOAD( "mrcane.69", 0x1000, 0x0800, CRC(d1fd883f) SHA1(30572ac7052d4898e458ad3130cc05f153427a64) )
+ ROM_LOAD( "mrcane.62", 0x1800, 0x0800, CRC(0d37cc00) SHA1(02f136b499cca35c70a6aaae475c516d91392e36) )
+ROM_END
+
+ROM_START( orbite )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "mrxx.71", 0x0000, 0x0800, CRC(78cf0c8a) SHA1(0bda9352c35e2ac175bd5ce6ee42e94247f5149a) )
+ ROM_LOAD( "mrxx.70", 0x0800, 0x0800, CRC(2914a5c4) SHA1(ac38c3a1c537ab22301bede0013db0d485012237) )
+ ROM_LOAD( "mrxx.69", 0x1000, 0x0800, CRC(46a8468b) SHA1(bf5dfed67fa4986994b8a74971e094bbff57c873) )
+ROM_END
// year rom parent machine inp class init monitor ...
@@ -5327,3 +5758,6 @@ GAME( 2002, invmultis3a, invmulti, invmulti, invmulti, _8080bw_state, init_in
GAME( 2002, invmultis2a, invmulti, invmulti, invmulti, _8080bw_state, init_invmulti, ROT270, "hack (Braze Technologies)", "Space Invaders Multigame (S0.82A)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 2002, invmultis1a, invmulti, invmulti, invmulti, _8080bw_state, init_invmulti, ROT270, "hack (Braze Technologies)", "Space Invaders Multigame (S0.81A)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 2002, invmultip, invmulti, invmulti, invmulti, _8080bw_state, init_invmulti, ROT270, "hack (Braze Technologies)", "Space Invaders Multigame (prototype)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+
+GAME(1979?, cane, 0, cane, cane, cane_state, empty_init, ROT0, "Model Racing", "Cane", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND)
+GAME(1979?, orbite, 0, orbite, orbite, orbite_state, empty_init, ROT270, "Model Racing", "Orbite", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW)
diff --git a/src/mame/includes/8080bw.h b/src/mame/includes/8080bw.h
index c2feda4b058..32693e39337 100644
--- a/src/mame/includes/8080bw.h
+++ b/src/mame/includes/8080bw.h
@@ -11,6 +11,7 @@
#pragma once
+#include "audio/8080bw.h"
#include "includes/mw8080bw.h"
#include "machine/eepromser.h"
@@ -89,7 +90,10 @@ public:
DECLARE_INPUT_CHANGED_MEMBER(claybust_gun_trigger);
DECLARE_READ_LINE_MEMBER(claybust_gun_on_r);
-private:
+protected:
+ void clear_extra_columns( bitmap_rgb32 &bitmap, int color );
+ inline void set_8_pixels( bitmap_rgb32 &bitmap, uint8_t y, uint8_t x, uint8_t data, int fore_color, int back_color );
+
/* devices/memory pointers */
optional_device<cpu_device> m_audiocpu;
optional_device<timer_device> m_schaser_effect_555_timer;
@@ -101,9 +105,11 @@ private:
optional_device<palette_device> m_palette;
optional_shared_ptr<uint8_t> m_colorram;
+private:
/* misc game specific */
optional_ioport m_gunx;
optional_ioport m_guny;
+
uint8_t m_color_map;
uint8_t m_screen_red;
uint8_t m_fleet_step;
@@ -226,8 +232,6 @@ private:
void schaser_reinit_555_time_remain();
inline void set_pixel( bitmap_rgb32 &bitmap, uint8_t y, uint8_t x, int color );
- inline void set_8_pixels( bitmap_rgb32 &bitmap, uint8_t y, uint8_t x, uint8_t data, int fore_color, int back_color );
- void clear_extra_columns( bitmap_rgb32 &bitmap, int color );
void invaders_samples_audio(machine_config &config);
@@ -281,4 +285,67 @@ DISCRETE_SOUND_EXTERN( indianbt_discrete );
DISCRETE_SOUND_EXTERN( polaris_discrete );
DISCRETE_SOUND_EXTERN( schaser_discrete );
+/*******************************************************/
+/* */
+/* Cane (Model Racing) */
+/* */
+/*******************************************************/
+class cane_state : public _8080bw_state
+{
+public:
+ cane_state(machine_config const &mconfig, device_type type, char const *tag) :
+ _8080bw_state(mconfig, type, tag),
+ m_soundboard(*this, "soundboard")
+ {
+ }
+
+ void cane(machine_config &config);
+ void cane_audio(machine_config &config);
+
+protected:
+ void cane_unknown_port0_w(u8 data);
+
+private:
+ virtual void machine_start() override;
+
+ void cane_io_map(address_map &map);
+ void cane_map(address_map &map);
+
+ required_device<cane_audio_device> m_soundboard;
+};
+
+DISCRETE_SOUND_EXTERN( cane_discrete );
+
+/*******************************************************/
+/* */
+/* Model Racing "Orbite" */
+/* */
+/*******************************************************/
+class orbite_state : public _8080bw_state
+{
+public:
+ orbite_state(machine_config const &mconfig, device_type type, char const *tag) :
+ _8080bw_state(mconfig, type, tag),
+ m_main_ram(*this, "main_ram")
+ {
+ }
+
+ void orbite(machine_config &config);
+
+protected:
+ required_shared_ptr<uint8_t> m_main_ram;
+ std::unique_ptr<uint8_t[]> m_scattered_colorram;
+
+ u8 orbite_scattered_colorram_r(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u8 mem_mask = 0xff);
+ void orbite_scattered_colorram_w(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED u8 data, ATTR_UNUSED u8 mem_mask = 0xff);
+
+private:
+ virtual void machine_start() override;
+
+ void orbite_io_map(address_map &map);
+ void orbite_map(address_map &map);
+
+ u32 screen_update_orbite(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+};
+
#endif // MAME_INCLUDES_8080BW_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 086f608b0c4..24f23098f4c 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -126,6 +126,7 @@ alieninvp2 // bootleg
astropal // (c) 19?? Sidam
attackfc // (c) 1979? E.G.S.
ballbomb // TN (c) 1980 Taito
+cane // Model Racing
claybust // (c) 1978 Model Racing
cosmicin // bootleg
cosmicm2 // Universal
@@ -186,6 +187,7 @@ lupin3a // LP (c) 1980 Taito
mlander // (c) 1980 Leisure Time Electronics
moonbase // Taito
moonbasea // Zeta - Nichibutsu
+orbite // Model Racing
ozmawars // Shin Nihon Kikaku (SNK)
ozmawars2 // Shin Nihon Kikaku (SNK)
ozmawarsmr // bootleg (Model Racing)
diff --git a/src/mame/video/8080bw.cpp b/src/mame/video/8080bw.cpp
index 2d84c4df351..f3df7201358 100644
--- a/src/mame/video/8080bw.cpp
+++ b/src/mame/video/8080bw.cpp
@@ -409,3 +409,28 @@ uint32_t _8080bw_state::screen_update_spacecom(screen_device &screen, bitmap_rgb
return 0;
}
+
+/*******************************************************/
+/* */
+/* Model Racing "Orbite" */
+/* */
+/*******************************************************/
+uint32_t orbite_state::screen_update_orbite(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ for (offs_t offs = 0; offs < m_main_ram.bytes(); offs++)
+ {
+ uint8_t back_color = 0;
+
+ uint8_t y = offs >> 5;
+ uint8_t x = offs << 3;
+
+ uint8_t data = m_main_ram[offs];
+ uint8_t fore_color = m_scattered_colorram[(offs & 0x1f) | ((offs & 0x1f80) >> 2)] & 0x07;
+
+ set_8_pixels(bitmap, y, x, data, fore_color, back_color);
+ }
+
+ clear_extra_columns(bitmap, 0);
+
+ return 0;
+}