-tankbatt: Added netlist audio. [Ryan Holtz]

This commit is contained in:
Ryan Holtz 2020-08-02 20:53:32 +02:00
parent 88bfa9826d
commit 48be14bade
6 changed files with 282 additions and 116 deletions

View File

@ -2975,6 +2975,8 @@ files {
MAME_DIR .. "src/mame/includes/skykid.h",
MAME_DIR .. "src/mame/video/skykid.cpp",
MAME_DIR .. "src/mame/drivers/sweetland.cpp",
MAME_DIR .. "src/mame/audio/nl_tankbatt.h",
MAME_DIR .. "src/mame/audio/nl_tankbatt.cpp",
MAME_DIR .. "src/mame/drivers/tankbatt.cpp",
MAME_DIR .. "src/mame/includes/tankbatt.h",
MAME_DIR .. "src/mame/video/tankbatt.cpp",

View File

@ -595,7 +595,7 @@
// ---------------------------------------------------------------------
// Source: src/lib/netlist/devices/nld_4006.cpp
// ---------------------------------------------------------------------
// usage : CD4006(name, pCLOCK, pD1, pD2, pD3, pD4, pD1P4, pD1P4S, pD2P4, pD2P5, pD3P4, pD4P4, pD3P5)
// usage : CD4006(name, pCLOCK, pD1, pD2, pD3, pD4, pD1P4, pD1P4S, pD2P4, pD2P5, pD3P4, pD4P4, pD4P5)
// auto connect: VCC, GND
#define CD4006(...) \
NET_REGISTER_DEVEXT(CD4006, __VA_ARGS__)

View File

@ -0,0 +1,165 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
//
// Netlist for Tank Battalion
//
// Derived from the schematics in the manual.
//
// Known problems/issues:
//
// * None.
//
#include "netlist/devices/net_lib.h"
#include "nl_tankbatt.h"
//
// Main netlist
//
NETLIST_START(tankbatt)
SOLVER(Solver, 48000)
ANALOG_INPUT(V5, 5)
ALIAS(VCC, V5)
CLOCK(2V, 4000) // 18.432MHz / (3 * 384 * 2)
CLOCK(4V, 2000) // 18.432MHz / (3 * 384 * 4)
TTL_INPUT(S1, 0) // active high
TTL_INPUT(S2, 0) // active high
TTL_INPUT(OFF, 1) // active high
TTL_INPUT(ENGINE_HI, 0) // active high
TTL_INPUT(SHOOT, 0) // active high
TTL_INPUT(HIT, 0) // active high
RES(R31, 470)
RES(R32, 470)
RES(R35, RES_K(4.7))
RES(R36, RES_K(4.7))
RES(R37, RES_K(6.8))
RES(R38, RES_K(10))
//RES(R41, RES_K(22))
RES(R42, RES_K(22))
RES(R43, RES_K(22))
RES(R44, RES_K(33))
RES(R45, RES_K(47))
RES(R46, RES_K(4.7)) // Possible schematic or scan-quality error: Schematic says 47K
RES(R47, RES_K(4.7))
RES(R48, RES_K(4.7))
RES(R49, RES_K(4.7)) // Possible schematic or scan-quality error: Schematic says 47K
RES(R50, RES_K(150))
RES(R51, RES_K(150))
RES(R52, RES_K(220))
RES(R53, RES_K(470))
RES(R54, RES_K(470))
RES(R56_1, RES_K(1))
RES(R56_2, RES_K(1))
RES(R57, RES_K(10))
RES(R58, RES_K(1))
RES(R59, RES_K(1))
RES(R60, RES_K(1))
RES(R61, RES_K(1))
CAP(C10, CAP_U(2.2))
CAP(C11, CAP_U(2.2))
CAP(C12, CAP_U(2.2))
CAP(C13, CAP_U(2.2))
CAP(C14, CAP_U(0.1))
CAP(C15, CAP_U(0.01))
CAP(C16, CAP_U(0.01))
CAP(C17, CAP_U(0.01))
CAP(C18, CAP_U(0.01))
CAP(C42, CAP_U(0.1))
DIODE(D8, "D") // Generic diodes, types not listed on schematic
DIODE(D9, "D")
DIODE(D10, "D")
DIODE(D11, "D")
CD4006(_6F)
CD4066_DIP(_6L)
LM324_DIP(_6J)
TTL_7486_DIP(_6K)
TTL_7492_DIP(_5K)
NET_C(VCC, _5K.5, _6F.VDD, _6J.4, _6K.7, _6L.14, S1.VCC, S2.VCC, OFF.VCC, ENGINE_HI.VCC, SHOOT.VCC, HIT.VCC, 2V.VCC, 4V.VCC)
NET_C(GND, _5K.10, _6F.VSS, _6J.11, _6K.14, _6L.7, S1.GND, S2.GND, OFF.GND, ENGINE_HI.GND, SHOOT.GND, HIT.GND, 2V.GND, 4V.GND)
// Noise generation (presumably)
NET_C(_6F.CLOCK, 2V)
NET_C(_6F.D1P4, _6F.D3)
NET_C(_6F.D3P4, _6F.D4, _6L.12, _6L.6)
NET_C(_6F.D1, _6F.D2P5, _6K.A.A)
NET_C(_6F.D4P4, _6K.A.B)
NET_C(_6K.A.Q, R38.1)
NET_C(_6F.D2, R38.2, D9.K)
NET_C(_6F.D4P5, D8.A, R53.1)
NET_C(D8.K, R53.2, C42.1, _6J.2)
NET_C(_6J.1, C42.2, D9.A)
NET_C(_6J.3, C12.1, R43.1, R44.1, _6J.12, _6J.10)
NET_C(C12.2, GND)
NET_C(R43.2, GND)
NET_C(R44.2, V5)
// S1
NET_C(S1.Q, _6L.5)
NET_C(4V, _6L.4)
NET_C(_6L.3, R35.1)
// S2
NET_C(S2.Q, _6L.13)
NET_C(2V, _6L.1)
NET_C(_6L.2, R36.1)
// Hit
NET_C(HIT.Q, R31.1)
NET_C(R31.2, D10.A)
NET_C(D10.K, C10.1, _6L.8)
NET_C(C10.2, GND)
NET_C(_6L.9, R50.1)
NET_C(R50.2, R42.1, C15.1, C16.1)
NET_C(R42.2, GND)
NET_C(C16.2, R54.1, _6J.9)
NET_C(C15.2, R54.2, _6J.8, R56_1.1)
// Shoot
NET_C(SHOOT.Q, R32.1)
NET_C(R32.2, D11.A)
NET_C(D11.K, C11.1, _6L.11)
NET_C(C11.2, GND)
NET_C(_6L.10, R45.1)
NET_C(R45.2, R37.1, C17.1, C18.1)
NET_C(R37.2, GND)
NET_C(C18.2, R51.1, _6J.13)
NET_C(C17.2, R51.2, _6J.14, R56_2.1)
// Engine Rumble
NET_C(ENGINE_HI.Q, _6K.B.A)
NET_C(_6K.B.B, _6K.C.Q)
NET_C(_6K.B.Q, R52.1, _5K.1)
NET_C(R52.2, R46.1, _6J.6, C14.1)
NET_C(C14.2, GND)
NET_C(_6J.5, R47.1, R48.1, R49.1)
NET_C(R47.2, V5)
NET_C(R48.2, GND)
NET_C(R49.2, R57.1, _6J.7, R46.2, _6K.C.A)
NET_C(R57.2, GND)
NET_C(_6K.C.B, VCC)
NET_C(_5K.7, VCC)
NET_C(_5K.6, OFF.Q)
NET_C(_5K.11, R60.1, _6K.D.A)
NET_C(_5K.8, R58.1, _6K.D.B)
NET_C(_6K.D.Q, _5K.14)
NET_C(_5K.12, R61.1)
NET_C(R58.2, R60.2, R61.2, C13.1, R59.1)
NET_C(C13.2, GND)
// Mixing
//NET_C(R56_1.2, R56_2.2)
//NET_C(R35.2, R36.2)
//NET_C(R56_2.2, R59.2)
NET_C(R35.2, R36.2, R56_1.2, R56_2.2, R59.2)
//NET_C(R41.2, GND)
NETLIST_END()

View File

@ -0,0 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef MAME_AUDIO_NL_TANKBATT_H
#define MAME_AUDIO_NL_TANKBATT_H
#pragma once
NETLIST_EXTERNAL(tankbatt)
#endif // MAME_AUDIO_NL_TANKBATT_H

View File

@ -6,49 +6,71 @@ Tank Battalion memory map (verified)
driver by Brad Oliver
$0000-$000f : bullet ram, first entry is player's bullet
$0010-$01ff : zero page & stack
$0200-$07ff : RAM
$0800-$0bff : videoram
$0c00-$0c1f : I/O
Memory Map:
$0000-$03ff : Work RAM 0
$0400-$07ff : Work RAM 1
$0800-$0bff : VRAM
$0c00-$0fff : I/O
$2000-$3fff : ROM
Read:
$0c00-$0c03 : p1 joystick
$0c04
$0c07 : stop at grid self-test if bit 7 is low
$0c0f : stop at first self-test if bit 7 is low
A 4-bit BCD value is created from the following four bits:
Bit 0: A3
Bit 1: A4
Bit 2: Read
Bit 3: !(A10 & A11)
$0c18 : Cabinet, 0 = table, 1 = upright
$0c19-$0c1a : Coinage, 00 = free play, 01 = 2 coin 1 credit, 10 = 1 coin 2 credits, 11 = 1 coin 1 credit
$0c1b-$0c1c : Bonus, 00 = 10000, 01 = 15000, 10 = 20000, 11 = none
$0c1d : Tanks, 0 = 3, 1 = 2
$0c1e-$0c1f : ??
For writes, the following upper ranges are decoded:
xxxx 11xx xxx0 0xxx: OUT0
xxxx 11xx xxx0 1xxx: OUT1
xxxx 11xx xxx1 0xxx: INTACK
xxxx 11xx xxx1 1xxx: Watchdog
Write:
$0c00-$0c01 : p1/p2 start leds
$0c02 : ?? written to at end of IRQ, either 0 or 1 - coin counter?
$0c03 : ?? written to during IRQ if grid test is on
$0c08 : ?? written to during IRQ if grid test is on
$0c09 : Sound - coin ding
$0c0a : Sound enable (active low) ?? game only ??
$0c0b : Sound - background noise, 0 - low rumble, 1 - high rumble
$0c0c : Sound - player fire
$0c0d : Sound - explosion
$0c0f : NMI enable (active high) ?? demo only ??
For reads, the following upper ranges are decoded:
xxxx 11xx xxx0 0xxx: IN0
xxxx 11xx xxx0 1xxx: IN1
xxxx 11xx xxx1 0xxx: -
xxxx 11xx xxx1 1xxx: DIP switches
$0c10 : IRQ ack (written at the end of the irq routine)
$0c18 : Watchdog
OUT0:
000: Edge Pin F P1 LED (schematic states Unused)
001: Edge Pin 6 P2 LED (schematic states Unused)
010: Edge Pin H Coin Counter (schematic states Unused)
011: Edge Pin 7 Coin Lockout (schematic states Coin Counter)
1xx: Unused
$2000-$3fff : ROM (A14, A15 not decoded)
OUT1:
000: S1 (Square Wave 1, connected to 2V)
001: S2 (Square Wave 2, connected to 4V)
010: Sound off (1), on (0)
011: Rumble hi (1), rumble low (0)
100: Shoot sound effect
101: Hit sound effect
110: Unused
111: NMI Enable
IN0:
000: Edge Pin Y Joystick Up
001: Edge Pin M Joystick Left
010: Edge Pin 14 Joystick Down
011: Edge Pin 11 Joystick Right
100: Edge Pin N Shoot
101: Edge Pin J Coin 1
110: Edge Pin 8 Coin 2
111: Edge Pin 9 Service Switch
IN1:
000: Edge Pin 21 Joystick Up (Cocktail)
001: Edge Pin P Joystick Left (Cocktail)
010: Edge Pin V Joystick Down (Cocktail)
011: Edge Pin 13 Joystick Right (Cocktail)
100: Edge Pin 12 Shoot (Cocktail)
101: Edge Pin L P1 Start
110: Edge Pin 10 P2 Start
111: Edge Pin K Test DIP Switch
TODO:
. Needs proper discrete emulation
. Resistor values on the color prom need to be corrected
Known issues:
. The 'moving' tank rumble noise seems to keep playing a second too long
. Sample support is all a crapshoot. I have no idea how it really works
***************************************************************************/
#include "emu.h"
@ -58,7 +80,6 @@ Known issues:
#include "machine/74259.h"
#include "machine/input_merger.h"
#include "machine/watchdog.h"
#include "sound/samples.h"
#include "screen.h"
#include "speaker.h"
@ -70,62 +91,17 @@ void tankbatt_state::machine_start()
uint8_t tankbatt_state::in0_r(offs_t offset)
{
int val;
val = ioport("P1")->read();
return ((val << (7 - offset)) & 0x80);
return BIT(m_player_input[0]->read(), offset) << 7;
}
uint8_t tankbatt_state::in1_r(offs_t offset)
{
int val;
val = ioport("P2")->read();
return ((val << (7 - offset)) & 0x80);
return BIT(m_player_input[1]->read(), offset) << 7;
}
uint8_t tankbatt_state::dsw_r(offs_t offset)
{
int val;
val = ioport("DSW")->read();
return ((val << (7 - offset)) & 0x80);
}
WRITE_LINE_MEMBER(tankbatt_state::sound_off_w)
{
m_sound_enable = !state;
// turn off the engine noise
if (state) m_samples->stop(2);
}
WRITE_LINE_MEMBER(tankbatt_state::sh_expl_w)
{
if (state) // rising edge
{
m_samples->start(1, 3);
}
}
WRITE_LINE_MEMBER(tankbatt_state::sh_engine_w)
{
if (m_sound_enable)
{
if (state)
m_samples->start(2, 2, true);
else
m_samples->start(2, 1, true);
}
else m_samples->stop(2);
}
WRITE_LINE_MEMBER(tankbatt_state::sh_fire_w)
{
if (state) // rising edge
{
m_samples->start(0, 0);
}
return BIT(m_dips->read(), offset) << 7;
}
void tankbatt_state::intack_w(uint8_t data)
@ -172,7 +148,7 @@ static INPUT_PORTS_START( tankbatt )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_TILT )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE )
PORT_START("P2") /* IN1 */
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY PORT_COCKTAIL
@ -237,17 +213,6 @@ GFXDECODE_END
static const char *const tankbatt_sample_names[] =
{
"*tankbatt",
"fire",
"engine1",
"engine2",
"explode1",
nullptr /* end of array */
};
void tankbatt_state::tankbatt(machine_config &config)
{
/* basic machine hardware */
@ -268,12 +233,12 @@ void tankbatt_state::tankbatt(machine_config &config)
// Q4 through Q7 are not connected
cd4099_device &outlatch1(CD4099(config, "outlatch1")); // 4099 at 4H or 259 at 4J
outlatch1.q_out_cb<0>().set_nop(); // TODO: S1 tone
outlatch1.q_out_cb<1>().set_nop(); // TODO: S2 tone
outlatch1.q_out_cb<2>().set(FUNC(tankbatt_state::sound_off_w));
outlatch1.q_out_cb<3>().set(FUNC(tankbatt_state::sh_engine_w));
outlatch1.q_out_cb<4>().set(FUNC(tankbatt_state::sh_fire_w));
outlatch1.q_out_cb<5>().set(FUNC(tankbatt_state::sh_expl_w)); // bit 7 also set by ASL instruction
outlatch1.q_out_cb<0>().set(m_sound_s1, FUNC(netlist_mame_logic_input_device::write_line));
outlatch1.q_out_cb<1>().set(m_sound_s2, FUNC(netlist_mame_logic_input_device::write_line));
outlatch1.q_out_cb<2>().set(m_sound_off, FUNC(netlist_mame_logic_input_device::write_line));
outlatch1.q_out_cb<3>().set(m_sound_engine_hi, FUNC(netlist_mame_logic_input_device::write_line));
outlatch1.q_out_cb<4>().set(m_sound_shoot, FUNC(netlist_mame_logic_input_device::write_line));
outlatch1.q_out_cb<5>().set(m_sound_hit, FUNC(netlist_mame_logic_input_device::write_line));
// Q6 is not connected
outlatch1.q_out_cb<7>().set("nmigate", FUNC(input_merger_device::in_w<1>));
@ -290,10 +255,18 @@ void tankbatt_state::tankbatt(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SAMPLES(config, m_samples);
m_samples->set_channels(3);
m_samples->set_samples_names(tankbatt_sample_names);
m_samples->add_route(ALL_OUTPUTS, "mono", 0.25);
NETLIST_SOUND(config, "sound_nl", 48000)
.set_source(NETLIST_NAME(tankbatt))
.add_route(ALL_OUTPUTS, "mono", 1.0);
NETLIST_LOGIC_INPUT(config, "sound_nl:s1", "S1.IN", 0);
NETLIST_LOGIC_INPUT(config, "sound_nl:s2", "S2.IN", 0);
NETLIST_LOGIC_INPUT(config, "sound_nl:off", "OFF.IN", 0);
NETLIST_LOGIC_INPUT(config, "sound_nl:engine_hi", "ENGINE_HI.IN", 0);
NETLIST_LOGIC_INPUT(config, "sound_nl:shoot", "SHOOT.IN", 0);
NETLIST_LOGIC_INPUT(config, "sound_nl:hit", "HIT.IN", 0);
NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "R35.2").set_mult_offset(10000.0, 0.0);
}

View File

@ -6,7 +6,11 @@
#pragma once
#include "machine/timer.h"
#include "sound/samples.h"
#include "machine/netlist.h"
#include "netlist/nl_setup.h"
#include "audio/nl_tankbatt.h"
#include "emupal.h"
#include "tilemap.h"
@ -16,37 +20,49 @@ public:
tankbatt_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_samples(*this, "samples"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_bulletsram(*this, "bulletsram"),
m_videoram(*this, "videoram")
m_videoram(*this, "videoram"),
m_player_input(*this, "P%u", 1U),
m_dips(*this, "DSW"),
m_sound_s1(*this, "sound_nl:s1"),
m_sound_s2(*this, "sound_nl:s2"),
m_sound_off(*this, "sound_nl:off"),
m_sound_engine_hi(*this, "sound_nl:engine_hi"),
m_sound_shoot(*this, "sound_nl:shoot"),
m_sound_hit(*this, "sound_nl:hit")
{ }
void tankbatt(machine_config &config);
private:
required_device<cpu_device> m_maincpu;
required_device<samples_device> m_samples;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_bulletsram;
required_shared_ptr<uint8_t> m_videoram;
required_ioport_array<2> m_player_input;
required_ioport m_dips;
required_device<netlist_mame_logic_input_device> m_sound_s1;
required_device<netlist_mame_logic_input_device> m_sound_s2;
required_device<netlist_mame_logic_input_device> m_sound_off;
required_device<netlist_mame_logic_input_device> m_sound_engine_hi;
required_device<netlist_mame_logic_input_device> m_sound_shoot;
required_device<netlist_mame_logic_input_device> m_sound_hit;
int m_sound_enable;
tilemap_t *m_bg_tilemap;
uint8_t in0_r(offs_t offset);
uint8_t in1_r(offs_t offset);
uint8_t dsw_r(offs_t offset);
DECLARE_WRITE_LINE_MEMBER(sound_off_w);
DECLARE_WRITE_LINE_MEMBER(sh_expl_w);
DECLARE_WRITE_LINE_MEMBER(sh_engine_w);
DECLARE_WRITE_LINE_MEMBER(sh_fire_w);
void intack_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(coincounter_w);
DECLARE_WRITE_LINE_MEMBER(coinlockout_w);
void coincounter_w(int state);
void coinlockout_w(int state);
void videoram_w(offs_t offset, uint8_t data);
TIMER_DEVICE_CALLBACK_MEMBER(scanline_interrupt);