/***************************************************************************
Pong (c) 1972 Atari
driver by Couriersud
Notes:
TODO:
============================================================================
***************************************************************************/
#include "emu.h"
#include "machine/rescap.h"
#include "machine/netlist.h"
#include "machine/net_lib.h"
#include "sound/dac.h"
#include "astring.h"
/*
* H count width to 512
* Reset at 1C6 = 454
* V count width to 512, counts on HReset
* Reset at 105 = 261
* Clock = 7.159 MHz
* ==> 15.768 Khz Horz Freq
* ==> 60.41 Refresh
* HBlank 0 to 79
* HSync 32 to 63
* VBlank 0 to 15
* VSync 4 to 7
* Video = (HVID & VVID ) & (NET & PAD1 & PAD2)
* Net at 256H alternating at 4V
*
*
* http://www.youtube.com/watch?v=pDrRnJOCKZc
*/
#define MASTER_CLOCK 7159000
#define V_TOTAL (0x105+1)
#define H_TOTAL (0x1C6+1) // 454
#define HBSTART (H_TOTAL)
#define HBEND (80)
#define VBSTART (V_TOTAL)
#define VBEND (16)
#define HRES_MULT (1)
enum input_changed_enum
{
IC_PADDLE1,
IC_PADDLE2,
IC_COIN,
IC_SWITCH,
IC_VR1,
IC_VR2
};
static NETLIST_START(pong_schematics)
NETDEV_TTL_CONST(high, 1)
NETDEV_TTL_CONST(low, 0)
NETDEV_CLOCK(clk)
NETDEV_PARAM(clk.FREQ, 7159000.0)
NETDEV_LOGIC_INPUT(SRST)
NETDEV_ANALOG_INPUT(P1)
NETDEV_ANALOG_INPUT(P2)
TTL_7404_INVERT(hitQ, hit)
TTL_7400_NAND(hit, hit1Q, hit2Q)
TTL_7402_NOR(attractQ, StopG, runQ)
TTL_7404_INVERT(attract, attractQ)
TTL_7420_NAND(ic_h6a, hvidQ, hvidQ, hvidQ, hvidQ)
NET_ALIAS(hvid, ic_h6a.Q)
TTL_7400_NAND(ic_e6c, hvid, hblank)
NET_ALIAS(MissQ, ic_e6c.Q)
TTL_7404_INVERT(ic_d1e, MissQ)
TTL_7400_NAND(ic_e1a, ic_d1e.Q, attractQ)
NET_ALIAS(Missed, ic_e1a.Q)
// runQ is basically the output of a RS flipflop
// This is realized with discrete components in the real thing
NETDEV_RSFF(runQ_ff, SRST, StopG)
NET_ALIAS(runQ, runQ_ff.QQ)
TTL_7400_NAND(rstspeed, SRSTQ, MissQ)
TTL_7400_NAND(StopG, StopG1Q, StopG2Q)
NET_ALIAS(L, ic_h3b.Q)
NET_ALIAS(R, ic_h3b.QQ)
TTL_7400_NAND(hit1Q, pad1, ic_g1b.Q)
TTL_7400_NAND(hit2Q, pad2, ic_g1b.Q)
TTL_7404_INVERT(SRSTQ, SRST)
TTL_7400_NAND(ic_g3c, 128H, ic_h3a.QQ)
TTL_7427_NOR(ic_g2c, ic_g3c.Q, 256H, vpad1Q)
NET_ALIAS(pad1, ic_g2c.Q)
TTL_7427_NOR(ic_g2a, ic_g3c.Q, 256HQ, vpad2Q)
NET_ALIAS(pad2, ic_g2a.Q)
// horizontal counter
TTL_7493(ic_f8, clk, ic_f8.QA, ic_e7b.QQ, ic_e7b.QQ) // f8, f9, f6b
TTL_7493(ic_f9, ic_f8.QD, ic_f9.QA, ic_e7b.QQ, ic_e7b.QQ) // f8, f9, f6b
TTL_74107(ic_f6b, ic_f9.QD, high, high, ic_e7b.Q)
TTL_7430_NAND(ic_f7, ic_f8.QB, ic_f8.QC, ic_f9.QC, ic_f9.QD, ic_f6b.Q, high, high, high)
TTL_7474(ic_e7b, clk, ic_f7, high, high)
NET_ALIAS(hreset, ic_e7b.QQ)
NET_ALIAS(hresetQ, ic_e7b.Q)
NET_ALIAS( 4H, ic_f8.QC)
NET_ALIAS( 8H, ic_f8.QD)
NET_ALIAS( 16H, ic_f9.QA)
NET_ALIAS( 32H, ic_f9.QB)
NET_ALIAS( 64H, ic_f9.QC)
NET_ALIAS(128H, ic_f9.QD)
NET_ALIAS(256H, ic_f6b.Q)
NET_ALIAS(256HQ, ic_f6b.QQ)
// vertical counter
TTL_7493(ic_e8, hreset, ic_e8.QA, ic_e7a.QQ, ic_e7a.QQ) // e8, e9, d9b
TTL_7493(ic_e9, ic_e8.QD,ic_e9.QA, ic_e7a.QQ, ic_e7a.QQ) // e8, e9, d9b
TTL_74107(ic_d9b, ic_e9.QD, high, high, ic_e7a.Q)
TTL_7474(ic_e7a, hreset, e7a_data, high, high)
TTL_7410_NAND(e7a_data, ic_e8.QA, ic_e8.QC, ic_d9b.Q)
NET_ALIAS(vreset, ic_e7a.QQ)
NET_ALIAS( 4V, ic_e8.QC)
NET_ALIAS( 8V, ic_e8.QD)
NET_ALIAS( 16V, ic_e9.QA)
NET_ALIAS( 32V, ic_e9.QB)
NET_ALIAS( 64V, ic_e9.QC)
NET_ALIAS(128V, ic_e9.QD)
NET_ALIAS(256V, ic_d9b.Q)
NET_ALIAS(256VQ, ic_d9b.QQ)
// hblank flip flop
TTL_7400_NAND(ic_g5b, 16H, 64H)
// the time critical one
TTL_7400_NAND(ic_h5c, ic_h5b.Q, hresetQ)
TTL_7400_NAND(ic_h5b, ic_h5c.Q, ic_g5b.Q)
NET_ALIAS(hblank, ic_h5c.Q)
NET_ALIAS(hblankQ, ic_h5b.Q)
TTL_7400_NAND(hsyncQ, hblank, 32H)
// vblank flip flop
TTL_7402_NOR(ic_f5c, ic_f5d.Q, vreset)
TTL_7402_NOR(ic_f5d, ic_f5c.Q, 16V)
NET_ALIAS(vblank, ic_f5d.Q)
NET_ALIAS(vblankQ, ic_f5c.Q)
TTL_7400_NAND(ic_h5a, 8V, 8V)
TTL_7410_NAND(ic_g5a, vblank, 4V, ic_h5a.Q)
NET_ALIAS(vsyncQ, ic_g5a.Q)
// move logic
TTL_7400_NAND(ic_e1d, hit_sound, ic_e1c.Q)
TTL_7400_NAND(ic_e1c, ic_f1.QC, ic_f1.QD)
TTL_7493(ic_f1, ic_e1d.Q, ic_f1.QA, rstspeed, rstspeed)
TTL_7402_NOR(ic_g1d, ic_f1.QC, ic_f1.QD)
TTL_7400_NAND(ic_h1a, ic_g1d.Q, ic_g1d.Q)
TTL_7400_NAND(ic_h1d, ic_e1c.Q, ic_h1a.Q)
TTL_7400_NAND(ic_h1c, ic_h1d.Q, vreset)
TTL_7400_NAND(ic_h1b, ic_h1a.Q, vreset)
TTL_7402_NOR(ic_g1c, 256HQ, vreset)
TTL_74107(ic_h2a, ic_g1c.Q, ic_h2b.Q, low, ic_h1b.Q)
TTL_74107(ic_h2b, ic_g1c.Q, high, move, ic_h1c.Q)
TTL_7400_NAND(ic_h4a, ic_h2b.Q, ic_h2a.Q)
NET_ALIAS(move, ic_h4a.Q)
TTL_7400_NAND(ic_c1d, SC, attract)
TTL_7404_INVERT(ic_d1a, ic_c1d.Q)
TTL_7474(ic_h3b, ic_d1a.Q, ic_h3b.QQ, hit1Q, hit2Q)
TTL_7400_NAND(ic_h4d, ic_h3b.Q, move)
TTL_7400_NAND(ic_h4b, ic_h3b.QQ, move)
TTL_7400_NAND(ic_h4c, ic_h4d.Q, ic_h4b.Q)
NET_ALIAS(Aa, ic_h4c.Q)
NET_ALIAS(Ba, ic_h4b.Q)
// hvid circuit
TTL_7400_NAND(hball_resetQ, Serve, attractQ)
TTL_9316(ic_g7, clk, high, hblankQ, hball_resetQ, ic_g5c.Q, Aa, Ba, low, high)
TTL_9316(ic_h7, clk, ic_g7.RC, high, hball_resetQ, ic_g5c.Q, low, low, low, high)
TTL_74107(ic_g6b, ic_h7.RC, high, high, hball_resetQ)
TTL_7410_NAND(ic_g5c, ic_g6b.Q, ic_h7.RC, ic_g7.RC)
TTL_7420_NAND(ic_h6b, ic_g6b.Q, ic_h7.RC, ic_g7.QC, ic_g7.QD)
NET_ALIAS(hvidQ, ic_h6b.Q)
// vvid circuit
TTL_9316(ic_b3, hsyncQ, high, vblankQ, high, ic_b2b.Q, a6, b6, c6, d6)
TTL_9316(ic_a3, hsyncQ, ic_b3.RC, high, high, ic_b2b.Q, low, low, low, low)
TTL_7400_NAND(ic_b2b, ic_a3.RC, ic_b3.RC)
TTL_7410_NAND(ic_e2b, ic_a3.RC, ic_b3.QC, ic_b3.QD)
NET_ALIAS(vvidQ, ic_e2b.Q)
TTL_7404_INVERT(vvid, vvidQ) // D2D
NET_ALIAS(vpos256, ic_a3.RC)
NET_ALIAS(vpos32, ic_a3.QB)
NET_ALIAS(vpos16, ic_a3.QA)
// vball ctrl circuit
TTL_7450_ANDORINVERT(ic_a6a, b1, 256HQ, b2, 256H)
TTL_7450_ANDORINVERT(ic_a6b, c1, 256HQ, c2, 256H)
TTL_7450_ANDORINVERT(ic_b6b, d1, 256HQ, d2, 256H)
TTL_7474(ic_a5b, hit, ic_a6a, attractQ, high)
TTL_7474(ic_a5a, hit, ic_a6b, attractQ, high)
TTL_7474(ic_b5a, hit, ic_b6b, attractQ, high)
TTL_74107(ic_h2x, vblank, vvid, vvid, hitQ) // two marked at position h2a ==> this h2x
TTL_7486_XOR(ic_a4c, ic_a5b.Q, ic_h2x.Q)
TTL_7486_XOR(ic_a4b, ic_a5a.Q, ic_h2x.Q)
TTL_7450_ANDORINVERT(ic_b6a, ic_b5a.Q, ic_h2x.Q, ic_b5a.QQ, ic_h2x.QQ)
TTL_7404_INVERT(ic_c4a, ic_b6a)
TTL_7483(ic_b4, ic_a4c, ic_a4b, ic_b6a, low, ic_c4a, high, high, low, low)
NET_ALIAS(a6, ic_b4.SA)
NET_ALIAS(b6, ic_b4.SB)
NET_ALIAS(c6, ic_b4.SC)
NET_ALIAS(d6, ic_b4.SD)
// serve monoflop
TTL_7404_INVERT(f4_trig, rstspeed)
NE555N_MSTABLE(ic_f4_serve, f4_trig, NC)
NETDEV_PARAM(ic_f4_serve.R, RES_K(330))
NETDEV_PARAM(ic_f4_serve.C, CAP_U(4.7))
TTL_7427_NOR(ic_e5a, ic_f4_serve.Q, StopG, runQ)
TTL_7474(ic_b5b_serve, pad1, ic_e5a, ic_e5a, high)
NET_ALIAS(Serve, ic_b5b_serve.QQ)
NET_ALIAS(ServeQ, ic_b5b_serve.Q)
// score logic
TTL_7474(ic_h3a, 4H, 128H, high, attractQ)
// sound logic
TTL_7474(ic_c2a, vpos256, high, hitQ, high)
TTL_74107(ic_f3_topbot, vblank, vvid, vvidQ, ServeQ)
NE555N_MSTABLE(ic_g4_sc, MissQ, NC)
NET_ALIAS(SC, ic_g4_sc.Q) // monoflop with NE555 determines score sound
NETDEV_PARAM(ic_g4_sc.R, RES_K(220))
NETDEV_PARAM(ic_g4_sc.C, CAP_U(1))
NET_ALIAS(hit_sound_en, ic_c2a.QQ)
TTL_7400_NAND(hit_sound, hit_sound_en, vpos16)
TTL_7400_NAND(score_sound, SC, vpos32)
TTL_7400_NAND(topbothitsound, ic_f3_topbot.Q, vpos32)
TTL_7410_NAND(ic_c4b, topbothitsound, hit_sound, score_sound)
TTL_7400_NAND(ic_c1b, ic_c4b.Q, attractQ)
NET_ALIAS(sound, ic_c1b.Q)
// paddle1 logic 1
NE555N_MSTABLE(ic_b9, 256VQ, P1)
NETDEV_PARAM(ic_b9.R, RES_K(90))
NETDEV_PARAM(ic_b9.C, CAP_U(.1))
NETDEV_PARAM(ic_b9.VL, 0.7)
TTL_7404_INVERT(ic_c9b, ic_b9.Q)
TTL_7400_NAND(ic_b7b, ic_a7b.Q, hsyncQ)
TTL_7493(ic_b8, ic_b7b.Q, ic_b8.QA, ic_b9.Q, ic_b9.Q)
TTL_7400_NAND(ic_b7a, ic_c9b.Q, ic_a7b.Q)
TTL_7420_NAND(ic_a7b, ic_b8.QA, ic_b8.QB, ic_b8.QC, ic_b8.QD)
NET_ALIAS(vpad1Q, ic_b7a.Q)
NET_ALIAS(b1, ic_b8.QB)
NET_ALIAS(c1, ic_b8.QC)
NET_ALIAS(d1, ic_b8.QD)
// paddle1 logic 2
NE555N_MSTABLE(ic_a9, 256VQ, P2)
NETDEV_PARAM(ic_a9.R, RES_K(90))
NETDEV_PARAM(ic_a9.C, CAP_U(.1))
NETDEV_PARAM(ic_a9.VL, 0.7)
TTL_7404_INVERT(ic_c9a, ic_a9.Q)
TTL_7400_NAND(ic_b7c, ic_a7a.Q, hsyncQ)
TTL_7493(ic_a8, ic_b7c.Q, ic_a8.QA, ic_a9.Q, ic_a9.Q)
TTL_7400_NAND(ic_b7d, ic_c9a.Q, ic_a7a.Q)
TTL_7420_NAND(ic_a7a, ic_a8.QA, ic_a8.QB, ic_a8.QC, ic_a8.QD)
NET_ALIAS(vpad2Q, ic_b7d.Q)
NET_ALIAS(b2, ic_a8.QB)
NET_ALIAS(c2, ic_a8.QC)
NET_ALIAS(d2, ic_a8.QD)
// C5-EN Logic
TTL_7404_INVERT(ic_e3a, 128H)
TTL_7427_NOR( ic_e3b, 256H, 64H, ic_e3a.Q)
TTL_7410_NAND(ic_e2c, 256H, 64H, ic_e3a.Q)
TTL_7404_INVERT(ic_e3c, ic_e2c.Q)
TTL_7402_NOR(ic_d2c, ic_e3c.Q, ic_e3b.Q)
TTL_7404_INVERT(ic_g1a, 32V)
TTL_7425_NOR(ic_f2a, ic_g1a.Q, 64V, 128V, ic_d2c.Q)
NET_ALIAS(c5-en, ic_f2a.Q)
// Score logic ...
TTL_7402_NOR(ic_f5b, L, Missed)
TTL_7490(ic_c7, ic_f5b, SRST, SRST, low, low)
TTL_74107(ic_c8a, ic_c7.QD, high, high, SRSTQ)
NETDEV_SWITCH2(sw1a, high, ic_c7.QC)
NETDEV_PARAM(sw1a.POS, 0)
TTL_7410_NAND(ic_d8a, ic_c7.QA, sw1a.Q, ic_c8a.Q) // would be nand2 for 11 instead of 15 points, need a switch dev!
NET_ALIAS(StopG1Q, ic_d8a.Q)
NET_ALIAS(score1_1, ic_c7.QA)
NET_ALIAS(score1_2, ic_c7.QB)
NET_ALIAS(score1_4, ic_c7.QC)
NET_ALIAS(score1_8, ic_c7.QD)
NET_ALIAS(score1_10, ic_c8a.Q)
NET_ALIAS(score1_10Q, ic_c8a.QQ)
TTL_7402_NOR(ic_f5a, R, Missed)
TTL_7490(ic_d7, ic_f5a, SRST, SRST, low, low)
TTL_74107(ic_c8b, ic_d7.QD, high, high, SRSTQ)
NETDEV_SWITCH2(sw1b, high, ic_d7.QC)
NETDEV_PARAM(sw1b.POS, 0)
TTL_7410_NAND(ic_d8b, ic_d7.QA, sw1b.Q, ic_c8b.Q) // would be nand2 for 11 instead of 15 points, need a switch dev!
NET_ALIAS(StopG2Q, ic_d8b.Q)
NET_ALIAS(score2_1, ic_d7.QA)
NET_ALIAS(score2_2, ic_d7.QB)
NET_ALIAS(score2_4, ic_d7.QC)
NET_ALIAS(score2_8, ic_d7.QD)
NET_ALIAS(score2_10, ic_c8b.Q)
NET_ALIAS(score2_10Q, ic_c8b.QQ)
// Score display
TTL_74153(ic_d6a, score1_10Q, score1_4, score2_10Q, score2_4, 32H, 64H, low)
TTL_74153(ic_d6b, score1_10Q, score1_8, score2_10Q, score2_8, 32H, 64H, low)
TTL_74153(ic_c6a, high, score1_1, high, score2_1, 32H, 64H, low)
TTL_74153(ic_c6b, score1_10Q, score1_2, score2_10Q, score2_2, 32H, 64H, low)
TTL_7448(ic_c5, ic_c6a.AY, ic_c6b.AY, ic_d6a.AY, ic_d6b.AY, high, c5-en, high)
TTL_7404_INVERT(ic_e4b, 16H)
TTL_7427_NOR(ic_e5c, ic_e4b.Q, 8H, 4H)
NET_ALIAS(scoreFE, ic_e5c.Q)
TTL_7400_NAND(ic_c3d, 4H, 8H)
TTL_7402_NOR(ic_d2b, ic_e4b.Q, ic_c3d.Q)
NET_ALIAS(scoreBC, ic_d2b.Q)
TTL_7427_NOR(ic_e5b, ic_e4b.Q, 8V, 4V)
NET_ALIAS(scoreA, ic_e5b.Q)
TTL_7410_NAND(ic_e2a, 16H, 8V, 4V)
TTL_7404_INVERT(ic_e4a, ic_e2a.Q)
NET_ALIAS(scoreGD, ic_e4a.Q)
TTL_7404_INVERT(ic_e4c, 16V)
TTL_7410_NAND(ic_d4a, ic_e4c.Q, ic_c5.f, scoreFE)
TTL_7410_NAND(ic_d5c, 16V, ic_c5.e, scoreFE)
TTL_7410_NAND(ic_c4c, ic_e4c.Q, ic_c5.b, scoreBC)
TTL_7410_NAND(ic_d5a, 16V, ic_c5.c, scoreBC)
TTL_7410_NAND(ic_d4c, ic_e4c.Q, ic_c5.a, scoreA)
TTL_7410_NAND(ic_d4b, ic_e4c.Q, ic_c5.g, scoreGD)
TTL_7410_NAND(ic_d5b, 16V, ic_c5.d, scoreGD)
TTL_7430_NAND(ic_d3, ic_d4a, ic_d5c, ic_c4c, ic_d5a, ic_d4c, ic_d4b, ic_d5b, high)
NET_ALIAS(score, ic_d3.Q) //FIXME
// net
TTL_74107(ic_f3b, clk, 256H, 256HQ, high)
TTL_7400_NAND(ic_g3b, ic_f3b.QQ, 256H)
TTL_7427_NOR(ic_g2b, ic_g3b.Q, vblank, 4V)
NET_ALIAS(net, ic_g2b.Q)
// video
TTL_7402_NOR(ic_g1b, hvidQ, vvidQ)
TTL_7425_NOR(ic_f2b, ic_g1b.Q, pad1, pad2, net)
TTL_7404_INVERT(ic_e4e, ic_f2b.Q)
NET_ALIAS(video, ic_e4e.Q)
TTL_7486_XOR(ic_a4d, hsyncQ, vsyncQ)
TTL_7404_INVERT(ic_e4f, ic_a4d.Q)
NETDEV_MIXER3(videomix, video, score, ic_e4f.Q)
NETDEV_PARAM(videomix.R1, RES_K(1))
NETDEV_PARAM(videomix.R2, RES_K(1.2))
NETDEV_PARAM(videomix.R3, RES_K(22))
NETLIST_END
static NETLIST_START(pong)
//NETLIST_INCLUDE(pong_schematics)
NETLIST_MEMREGION("maincpu")
NETDEV_CALLBACK(sound_cb, sound)
NETDEV_CALLBACK(video_cb, videomix)
NETLIST_END
static NETLIST_START(pong_fast)
NETLIST_INCLUDE(pong_schematics)
/* the signal above is delayed on pong due to counter at gate delays.
* This is approximated by the following circuit ...
*/
//NET_REMOVE_DEV(ic_h5b)
//NETDEV_DELAY_RISE(ic_g5b_D, clk, ic_g5b.Q)
//TTL_7400_NAND(ic_h5b, ic_h5c.Q, ic_g5b_D.Q)
NETDEV_CALLBACK(sound_cb, sound)
NETDEV_CALLBACK(video_cb, videomix)
NETLIST_END
class pong_state : public driver_device
{
public:
pong_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_dac(*this, "dac"), /* just to have a sound device */
m_srst(*this, "maincpu", "SRST"),
m_p_V0(*this, "maincpu", "P1"),
m_p_V1(*this, "maincpu", "P2"),
m_sw1a(*this, "maincpu", "sw1a.POS"),
m_sw1b(*this, "maincpu", "sw1b.POS"),
m_p_R0(*this, "maincpu", "ic_a9.R"),
m_p_R1(*this, "maincpu", "ic_b9.R")
{
}
// devices
required_device<netlist_mame_device> m_maincpu;
required_device<dac_device> m_dac; /* just to have a sound device */
// sub devices
netlist_mame_device::required_output<logic_output_t> m_srst;
netlist_mame_device::required_output<analog_output_t> m_p_V0;
netlist_mame_device::required_output<analog_output_t> m_p_V1;
netlist_mame_device::required_param m_sw1a;
netlist_mame_device::required_param m_sw1b;
netlist_mame_device::required_param m_p_R0;
netlist_mame_device::required_param m_p_R1;
UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_INPUT_CHANGED_MEMBER(input_changed);
void sound_cb(double newval)
{
//printf("snd %f\n", newval);
//dac_w(m_dac, 0, newval*64);
m_dac->write_unsigned8(64*newval);
}
void video_cb(double newval)
{
//printf("%f\n", newval);
if (newval != m_vid)
{
update_vid();
m_vid = newval;
}
}
protected:
// driver_device overrides
virtual void machine_start();
virtual void machine_reset();
virtual void video_start();
private:
void update_vid()
{
const netlist_time clock_period = netlist_time::from_hz(NETLIST_CLOCK);
const netlist_time hsync_min_time = netlist_time::from_us(4);
const netlist_time vsync_min_time = netlist_time::from_us(50); /* usec */
const int vsync_min_pulses = 4;
UINT64 clocks = m_maincpu->total_cycles(); // m_maincpu->attotime_to_cycles(m_maincpu->local_time());
int pw = NETLIST_CLOCK / ((UINT64)MASTER_CLOCK) / HRES_MULT;
netlist_time time = clock_period * (clocks - m_last_clock);
//UINT64 clocks = m_maincpu->netlist().time().as_raw() >> 10; // m_maincpu->attotime_to_cycles(m_maincpu->local_time());
//int pw = (NETLIST_INTERNAL_CLOCK / ((UINT64)MASTER_CLOCK) / HRES_MULT) >> 8;
if (m_last_y < m_bitmap->height())
{
int colv = (int) (m_vid / 3.5 * 255.0);
rgb_t col = MAKE_RGB(colv, colv, colv);
int pixels = (clocks - m_line_clock) / pw;
while (pixels >= m_bitmap->width())
{
for (int i = m_last_x ; i < m_bitmap->width() - 1; i++)
m_bitmap->pix(m_last_y, i) = col;
pixels -= m_bitmap->width();
m_last_x = 0;
}
for (int i = m_last_x ; i < pixels; i++)
m_bitmap->pix(m_last_y, i) = col;
m_last_x = pixels;
}
if (m_vid <= 0.34)
{
if (time >= vsync_min_time)
{
m_vsync_cnt++;
if (m_vsync_cnt >= vsync_min_pulses)
{
m_vsync_cnt = 0;
m_last_y = 0;
attoseconds_t new_refresh = DOUBLE_TO_ATTOSECONDS((double) (clocks - m_vsync_clock) / (double) NETLIST_CLOCK);
if (new_refresh != m_refresh)
{
m_refresh = new_refresh;
rectangle visarea(0, H_TOTAL * HRES_MULT - 1, 0, V_TOTAL-1);
this->mconfig().first_screen()->configure(H_TOTAL * HRES_MULT, V_TOTAL, visarea, m_refresh);
m_vsync_clock = clocks;
}
}
m_last_y++;
m_last_x = 0;
}
else if (time >= hsync_min_time)
{
m_last_x = 0; // hsync
m_last_y++;
m_line_clock = clocks;
}
}
m_last_clock = clocks;
}
double m_vid;
int m_last_x;
int m_last_y;
UINT64 m_last_clock;
UINT64 m_line_clock;
UINT64 m_vsync_clock;
attoseconds_t m_refresh;
int m_vsync_cnt;
bitmap_rgb32 *m_bitmap;
};
void pong_state::machine_start()
{
m_bitmap = auto_bitmap_rgb32_alloc(machine(),H_TOTAL * HRES_MULT,V_TOTAL);
m_maincpu->setup().register_callback("sound_cb", net_output_delegate(&pong_state::sound_cb, "pong_state::sound_cb", this));
m_maincpu->setup().register_callback("video_cb", net_output_delegate(&pong_state::video_cb, "pong_state::video_cb", this));
}
void pong_state::machine_reset()
{
}
void pong_state::video_start()
{
//FIXME: createtemporary bitmap
}
UINT32 pong_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect )
{
copybitmap(bitmap, *m_bitmap, 0, 0, 0, 0, cliprect);
//m_bitmap->fill(MAKE_RGB(0,0,0));
return 0;
}
INPUT_CHANGED_MEMBER(pong_state::input_changed)
{
static const double NE555_R = RES_K(5);
static const double PRE_R = RES_R(470);
double pad;
int numpad = (FPTR) (param);
switch (numpad)
{
case IC_PADDLE1:
case IC_PADDLE2:
{
// http://ion.chem.usu.edu/~sbialkow/Classes/564/Thevenin/Thevenin.html
double fac = (double) newval / (double) 256;
double R1 = fac * RES_K(10);
double R3 = (1.0 - fac) * RES_K(10);
double vA = 5.0 * R3 / (R3 + R1);
double vB = 5.0 * 2 * NE555_R / (2 * NE555_R + NE555_R);
double Req = RES_2_PARALLEL(R1, R3) + RES_2_PARALLEL(NE555_R, 2.0 * NE555_R);
double pad = vA + (vB - vA)*PRE_R / (Req + PRE_R);
switch (numpad)
{
case IC_PADDLE1: m_p_V0->setToPS(pad, NLTIME_FROM_NS(0)); break;
case IC_PADDLE2: m_p_V1->setToPS(pad, NLTIME_FROM_NS(0)); break;
}
break;
}
case IC_SWITCH:
m_sw1a->setTo(newval ? 1 : 0);
m_sw1b->setTo(newval ? 1 : 0);
break;
case IC_COIN:
m_srst->setToPS(newval & 1, NLTIME_FROM_US(500));
break;
case IC_VR1:
case IC_VR2:
pad = (double) newval / (double) 100 * RES_K(50) + RES_K(56);
switch (numpad)
{
case IC_VR1: m_p_R0->setTo(pad); break;
case IC_VR2: m_p_R1->setTo(pad); break;
}
break;
}
}
static INPUT_PORTS_START( pong )
PORT_START( "PADDLE0" ) /* fake input port for player 1 paddle */
PORT_BIT( 0xff, 0x00, IPT_PADDLE ) PORT_SENSITIVITY(2) PORT_KEYDELTA(100) PORT_CENTERDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed,IC_PADDLE1)
PORT_START( "PADDLE1" ) /* fake input port for player 2 paddle */
PORT_BIT( 0xff, 0x00, IPT_PADDLE ) PORT_SENSITIVITY(2) PORT_KEYDELTA(100) PORT_CENTERDELTA(0) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_PADDLE2)
PORT_START("IN0") /* fake as well */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_COIN)
PORT_DIPNAME( 0x06, 0x00, "Game Won" ) PORT_DIPLOCATION("SW1A:1,SW1B:1") PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_SWITCH)
PORT_DIPSETTING( 0x00, "11" )
PORT_DIPSETTING( 0x06, "15" )
PORT_START("VR1")
PORT_ADJUSTER( 63, "VR1 - 50k, Paddle 1 adjustment" ) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_VR1)
PORT_START("VR2")
PORT_ADJUSTER( 63, "VR2 - 50k, Paddle 2 adjustment" ) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_VR2)
//PORT_START("GATESPEED")
//PORT_ADJUSTER( 100, "Logic Gate Delay" ) PORT_MINMAX(10, 200) PORT_CHANGED_MEMBER(DEVICE_SELF, pong_state, input_changed, IC_GATEDELAY)
INPUT_PORTS_END
static MACHINE_CONFIG_START( pong, pong_state )
/* basic machine hardware */
MCFG_NETLIST_ADD("maincpu", pong)
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK * HRES_MULT, H_TOTAL * HRES_MULT, HBEND * HRES_MULT, HBSTART * HRES_MULT, V_TOTAL, VBEND, VBSTART)
MCFG_SCREEN_UPDATE_DRIVER(pong_state, screen_update)
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("dac", DAC, 48000)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( pongf, pong )
/* basic machine hardware */
//MCFG_NETLIST_REPLACE("maincpu", MASTER_CLOCK, pong_fast, 100)
MCFG_NETLIST_REPLACE("maincpu", pong_fast)
MACHINE_CONFIG_END
/***************************************************************************
Game driver(s)
***************************************************************************/
ROM_START( pong ) /* dummy to satisfy game entry*/
ROM_REGION( 0x10000, "maincpu", 0 ) /* enough for netlist */
ROM_LOAD( "pong.netlist", 0x000000, 0x0029e4, CRC(e9c409a1) SHA1(1dc99437f49261c3cb3f46153c6258043bc720a0) )
ROM_END
ROM_START( pongf ) /* dummy to satisfy game entry*/
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 )
ROM_END
GAME( 1972, pong, 0, pong, pong, driver_device, 0, ROT0, "Atari", "Pong (Rev E)", 0 )
GAME( 1972, pongf, 0, pongf, pong, driver_device, 0, ROT0, "Atari", "Pong (Rev E), no subcycles", 0 )