vd.cpp: Both games working

This commit is contained in:
Robbbert 2021-11-11 21:17:32 +11:00
parent 11745ec4a5
commit 93d416d08e
3 changed files with 206 additions and 149 deletions

View File

@ -24,7 +24,6 @@ ToDo:
- Schematic shows sound rom banking, but no machine has those roms, so not coded.
- xforce: sound rom is missing
- spcteam: Bad display - can't tell if keys are doing anything.
- spcteam: randomly, lots of unmapped reads by the audiocpu from 0x20D8,9.
***********************************************************************************/

View File

@ -2,15 +2,23 @@
// copyright-holders:Robbbert
/**************************************************************************************
PINBALL
Video Dens S.A., Madrid
PINBALL
Video Dens S.A., Madrid
PinMAME used as reference. The Break '86 manual scan available on the net includes
a mostly illegible schematic.
PinMAME used as reference. The Break '86 manual scan available on the net includes
a mostly illegible schematic.
Nothing in this driver is confirmed except where noted.
Machines by this manufacturer: Ator, Break, Papillion.
Ator runs on different hardware (peyper.cpp).
Ator runs on different hardware (peyper.cpp).
Status:
- Games are playable
- You need to hold X when starting a game
ToDo:
- Papillion: ball number not showing
- Status display is in different digits per game
- Mechanical sounds
***************************************************************************************/
@ -25,6 +33,8 @@
#include "vd.lh"
namespace {
class vd_state : public genpin_class
{
public:
@ -32,46 +42,52 @@ public:
: genpin_class(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_digits(*this, "digit%u", 0U)
, m_io_outputs(*this, "out%u", 0U)
{ }
void vd(machine_config &config);
void init_0() { m_game = 0; }
void init_1() { m_game = 1; }
private:
uint8_t ack_r();
void col_w(uint8_t data);
void disp_w(offs_t offset, uint8_t data);
void lamp_w(uint8_t data) { };
void sol_w(uint8_t data) { };
u8 ack_r();
u8 x0_r();
void col_w(u8 data);
void disp_w(offs_t offset, u8 data);
void lamp_w(offs_t, u8);
void sol_w(u8 data);
TIMER_DEVICE_CALLBACK_MEMBER(irq);
void vd_io(address_map &map);
void vd_map(address_map &map);
void io_map(address_map &map);
void mem_map(address_map &map);
uint8_t m_t_c;
uint8_t segment[5];
bool m_ready = 0;
u8 m_t_c = 0;
u8 m_game = 0;
u8 m_segment[5]{};
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void machine_start() override { m_digits.resolve(); }
required_device<cpu_device> m_maincpu;
output_finder<60> m_digits;
output_finder<48> m_digits;
output_finder<80> m_io_outputs; // 16 solenoids + 64 lamps
};
uint8_t vd_state::ack_r()
u8 vd_state::ack_r()
{
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); // guess
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
return 0; // this value is not used
}
void vd_state::vd_map(address_map &map)
void vd_state::mem_map(address_map &map)
{
map(0x0000, 0x5fff).rom();
map(0x6000, 0x62ff).ram();
map(0x6700, 0x67ff).ram();
map(0x6000, 0x67ff).ram().share("nvram");
}
void vd_state::vd_io(address_map &map)
void vd_state::io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x00).portr("X0");
map(0x00, 0x00).r(FUNC(vd_state::x0_r));
map(0x01, 0x01).portr("X1");
map(0x02, 0x02).portr("X2");
map(0x03, 0x03).portr("X3");
@ -109,7 +125,7 @@ static INPUT_PORTS_START( break86 )
PORT_START("DSW2") // "Micro Swicher Nº 2"
PORT_DIPNAME(0x03, 0x03, "Scoring") PORT_DIPLOCATION("SW2:8,7") // "Tanteo"
PORT_DIPSETTING(0x03, "800k / 1.4M / 2.0M / 2.6M") // = "Bola Extra," "1ª Partida," "2ª Partida," "High Score"
PORT_DIPSETTING(0x03, "800k / 1.4M / 2.0M / 2.6M") // = "Bola Extra," "1 Partida," "2 Partida," "High Score"
PORT_DIPSETTING(0x02, "1.0M / 1.6M / 2.2M / 2.8M")
PORT_DIPSETTING(0x01, "1.2M / 1.8M / 2.4M / 3.0M")
PORT_DIPSETTING(0x00, "1.4M / 2.0M / 2.6M / 3.2M")
@ -135,16 +151,64 @@ static INPUT_PORTS_START( break86 )
PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_UNUSED) // SW3 not populated
PORT_START("X0")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_START1)
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_COIN1)
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_COIN2)
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_TILT)
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_X) PORT_NAME("Outhole")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_A) PORT_NAME("INP02")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("INP03")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("INP04")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_D) PORT_NAME("INP05")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("INP06")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_F) PORT_NAME("INP07")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("X1")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_START1) // start
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_G) PORT_NAME("INP12")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_H) PORT_NAME("INP13")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) PORT_NAME("INP14")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_J) PORT_NAME("INP15")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_K) PORT_NAME("INP16")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("INP17")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("X2")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M) PORT_NAME("INP21")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_N) PORT_NAME("INP22")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_O) PORT_NAME("INP23")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_P) PORT_NAME("INP24")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Q) PORT_NAME("INP25")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("INP26")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_S) PORT_NAME("INP27")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("X3")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_COIN1) // coin
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("INP32")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) PORT_NAME("INP33")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_V) PORT_NAME("INP34")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("INP35")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Y) PORT_NAME("INP36")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Z) PORT_NAME("INP37")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("X4")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_9) PORT_NAME("Tilt")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_COMMA) PORT_NAME("INP42")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_STOP) PORT_NAME("INP43")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_SLASH) PORT_NAME("INP44")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_COLON) PORT_NAME("INP45") // start break
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_QUOTE) PORT_NAME("INP46") // start pap
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("INP47")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("X5")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_OPENBRACE) PORT_NAME("INP51")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_NAME("INP52")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_BACKSLASH) PORT_NAME("INP53")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_MINUS) PORT_NAME("INP54")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("INP55")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("INP56")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("INP57")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
INPUT_PORTS_END
static INPUT_PORTS_START( papillon )
@ -153,57 +217,112 @@ INPUT_PORTS_END
TIMER_DEVICE_CALLBACK_MEMBER( vd_state::irq )
{
if (m_t_c > 40)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, HOLD_LINE);
if (m_t_c > 4)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
else
m_t_c++;
}
void vd_state::disp_w(offs_t offset, uint8_t data)
// machine won't boot without a ball in the outhole,
// so this does it for you.
u8 vd_state::x0_r()
{
segment[offset] = data;
#if 0 // probably not how this works
if (!offset)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
#endif
return ioport("X0")->read() | (m_ready ? 0 : 1);
}
void vd_state::col_w(uint8_t data)
void vd_state::lamp_w(offs_t offset, u8 data)
{
if (data != 0x3f)
for (u8 i = 0; i < 8; i++)
m_io_outputs[16+offset*8+i] = BIT(data, i);
}
void vd_state::sol_w(u8 data)
{
for (u8 i = 0; i < 16; i++)
m_io_outputs[i] = (data == i) ? 1 : 0;
// Outhole for each game
if (((data == 0x0a) && (m_game == 1)) || ((data == 0x0b) && (m_game == 0)))
{
data &= 7;
m_digits[data + 11] = segment[0];
m_digits[data + 21] = segment[1];
m_digits[data + 31] = segment[2];
m_digits[data + 41] = segment[3];
m_digits[data + 51] = segment[4];
m_samples->start(0, 5);
m_ready = 1;
}
}
void vd_state::disp_w(offs_t offset, u8 data)
{
m_segment[offset] = bitswap<8>(data, 0, 1, 2, 3, 4, 5, 6, 7);
}
// The digits are standard 7-segment, except that there's no DP but instead a comma at the front.
void vd_state::col_w(u8 data)
{
if (data & 8)
return;
data &= 7;
if (!data) // machine writes to this digit but it doesn't physically exist
return;
// apply or remove comma in the previous digit
for (u8 i = 0; i < 5; i++)
{
u8 t = (m_digits[data+10*i-1] & 0x7f) | (m_segment[i] & 0x80);
m_digits[data+10*i-1] = t;
}
// now do the current digits
// if the comma was there before, keep it on to stop flicker
for (u8 i = 0; i < 5; i++)
{
u8 t = m_digits[data+10*i] & 0x80;
m_digits[data+10*i] = (m_segment[i] & 0x7f) | t;
}
}
void vd_state::machine_start()
{
genpin_class::machine_start();
m_digits.resolve();
m_io_outputs.resolve();
save_item(NAME(m_segment));
save_item(NAME(m_t_c));
save_item(NAME(m_game));
save_item(NAME(m_ready));
}
void vd_state::machine_reset()
{
genpin_class::machine_reset();
for (u8 i = 0; i < m_io_outputs.size(); i++)
m_io_outputs[i] = 0;
m_t_c = 0;
m_ready = 0;
}
void vd_state::vd(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, 4000000);
m_maincpu->set_addrmap(AS_PROGRAM, &vd_state::vd_map);
m_maincpu->set_addrmap(AS_IO, &vd_state::vd_io);
TIMER(config, "irq").configure_periodic(FUNC(vd_state::irq), attotime::from_hz(484));
m_maincpu->set_addrmap(AS_PROGRAM, &vd_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &vd_state::io_map);
TIMER(config, "irq").configure_periodic(FUNC(vd_state::irq), attotime::from_hz(300));
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
/* Sound */
genpin_audio(config);
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
ay8910_device &ay1(AY8910(config, "ay1", 2000000)); //?
ay1.add_route(ALL_OUTPUTS, "lspeaker", 0.33/3);
ay1.add_route(ALL_OUTPUTS, "lspeaker", 0.5);
ay1.port_a_read_callback().set_ioport("DSW2");
ay1.port_b_read_callback().set_ioport("DSW1");
ay8910_device &ay2(AY8910(config, "ay2", 2000000)); //?
ay2.add_route(ALL_OUTPUTS, "rspeaker", 0.33/3);
ay2.add_route(ALL_OUTPUTS, "rspeaker", 0.5);
ay2.port_b_read_callback().set_ioport("DSW3");
/* Video */
@ -234,6 +353,7 @@ ROM_START(papillon)
ROM_LOAD("u6.dat", 0x4000, 0x2000, CRC(6b2867b3) SHA1(720fe8a65b447e839b0eb9ea21e0b3cb0e50cf7a))
ROM_END
} // Anonymous namespace
GAME(1986, break86, 0, vd, break86, vd_state, empty_init, ROT0, "Video Dens", "Break '86", MACHINE_IS_SKELETON_MECHANICAL)
GAME(1986, papillon, 0, vd, papillon, vd_state, empty_init, ROT0, "Video Dens", "Papillon", MACHINE_IS_SKELETON_MECHANICAL)
GAME(1986, break86, 0, vd, break86, vd_state, init_0, ROT0, "Video Dens", "Break '86", MACHINE_IS_SKELETON_MECHANICAL)
GAME(1986, papillon, 0, vd, papillon, vd_state, init_1, ROT0, "Video Dens", "Papillon", MACHINE_IS_SKELETON_MECHANICAL)

View File

@ -12,120 +12,58 @@ copyright-holders:Robbbert
</led7seg>
</element>
<element name="P0"><text string="Ball / Match"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P1"><text string="Credits"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P0"><text string="Status"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P3"><text string="Player 1"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P4"><text string="Player 2"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P5"><text string="Player 3"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<element name="P6"><text string="Player 4"><color red="1.0" green="1.0" blue="1.0" /></text></element>
<group name="score">
<repeat count="7">
<param name="n" start="~s~" increment="1" />
<param name="x" start="0" increment="44" />
<element name="digit~n~" ref="digit">
<bounds x="~x~" y="0" width="34" height="39" />
</element>
</repeat>
</group>
<view name="Default Layout">
<bounds left="0" top="20" right="274" bottom="394" />
<bounds left="0" top="20" right="318" bottom="394" />
<!-- LEDs -->
<!-- Player 1 Score -->
<element name="digit11" ref="digit">
<bounds left="10" top="45" right="44" bottom="84" />
</element>
<element name="digit12" ref="digit">
<bounds left="54" top="45" right="88" bottom="84" />
</element>
<element name="digit13" ref="digit">
<bounds left="98" top="45" right="132" bottom="84" />
</element>
<element name="digit14" ref="digit">
<bounds left="142" top="45" right="176" bottom="84" />
</element>
<element name="digit15" ref="digit">
<bounds left="186" top="45" right="220" bottom="84" />
</element>
<element name="digit16" ref="digit">
<bounds left="230" top="45" right="264" bottom="84" />
</element>
<param name="s" value="1" />
<group ref="score">
<bounds left="10" top="45" right="308" bottom="84" />
</group>
<!-- Player 2 Score -->
<element name="digit21" ref="digit">
<bounds left="10" top="105" right="44" bottom="144" />
</element>
<element name="digit22" ref="digit">
<bounds left="54" top="105" right="88" bottom="144" />
</element>
<element name="digit23" ref="digit">
<bounds left="98" top="105" right="132" bottom="144" />
</element>
<element name="digit24" ref="digit">
<bounds left="142" top="105" right="176" bottom="144" />
</element>
<element name="digit25" ref="digit">
<bounds left="186" top="105" right="220" bottom="144" />
</element>
<element name="digit26" ref="digit">
<bounds left="230" top="105" right="264" bottom="144" />
</element>
<param name="s" value="11" />
<group ref="score">
<bounds left="10" top="105" right="308" bottom="144" />
</group>
<!-- Player 3 Score -->
<element name="digit31" ref="digit">
<bounds left="10" top="165" right="44" bottom="204" />
</element>
<element name="digit32" ref="digit">
<bounds left="54" top="165" right="88" bottom="204" />
</element>
<element name="digit33" ref="digit">
<bounds left="98" top="165" right="132" bottom="204" />
</element>
<element name="digit34" ref="digit">
<bounds left="142" top="165" right="176" bottom="204" />
</element>
<element name="digit35" ref="digit">
<bounds left="186" top="165" right="220" bottom="204" />
</element>
<element name="digit36" ref="digit">
<bounds left="230" top="165" right="264" bottom="204" />
</element>
<param name="s" value="21" />
<group ref="score">
<bounds left="10" top="165" right="308" bottom="204" />
</group>
<!-- Player 4 Score -->
<element name="digit41" ref="digit">
<bounds left="10" top="225" right="44" bottom="264" />
</element>
<element name="digit42" ref="digit">
<bounds left="54" top="225" right="88" bottom="264" />
</element>
<element name="digit43" ref="digit">
<bounds left="98" top="225" right="132" bottom="264" />
</element>
<element name="digit44" ref="digit">
<bounds left="142" top="225" right="176" bottom="264" />
</element>
<element name="digit45" ref="digit">
<bounds left="186" top="225" right="220" bottom="264" />
</element>
<element name="digit46" ref="digit">
<bounds left="230" top="225" right="264" bottom="264" />
</element>
<param name="s" value="31" />
<group ref="score">
<bounds left="10" top="225" right="308" bottom="264" />
</group>
<!-- Credits and Balls -->
<element name="digit51" ref="digit">
<bounds left="10" top="345" right="44" bottom="384" />
</element>
<element name="digit52" ref="digit">
<bounds left="54" top="345" right="88" bottom="384" />
</element>
<element name="digit53" ref="digit">
<bounds left="98" top="345" right="132" bottom="384" />
</element>
<element name="digit54" ref="digit">
<bounds left="142" top="345" right="176" bottom="384" />
</element>
<element name="digit55" ref="digit">
<bounds left="186" top="345" right="220" bottom="384" />
</element>
<element name="digit56" ref="digit">
<bounds left="230" top="345" right="264" bottom="384" />
</element>
<element ref="P0"><bounds left="200" right="258" top="330" bottom="342" /></element>
<element ref="P1"><bounds left="30" right="88" top="330" bottom="342" /></element>
<param name="s" value="40" />
<group ref="score">
<bounds left="10" top="345" right="308" bottom="384" />
</group>
<element ref="P0"><bounds left="100" right="180" top="330" bottom="342" /></element>
<element name="text3" ref="P3"><bounds left="100" right="180" top="30" bottom="42" /></element>
<element name="text2" ref="P4"><bounds left="100" right="180" top="90" bottom="102" /></element>
<element name="text1" ref="P5"><bounds left="100" right="180" top="150" bottom="162" /></element>