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
This commit is contained in:
janniz 2019-10-31 12:11:45 +01:00 committed by Vas Crabb
parent ba273549dd
commit f31b19f9c9
7 changed files with 884 additions and 12 deletions

View File

@ -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;
}

View File

@ -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);
}

44
src/mame/audio/8080bw.h Normal file
View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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;
}