Updated netlist implementation:

- Now supports any resolution fitting reasonably into a UINT64
- Execution now uses a list sorted by execution time
- Implementation now supports analog and digital inputs / outputs
  - First step in a move to "terminals" being both input / output
- Improved object model

Pong:
- Rewrote video code, now emulates a monitor by analyzing the analog
  video signal and identifying vsync and hysnc pulses.
- Removed all hacks.

Overall performance increase of about 10% over the previous "pongf" implementation.
This commit is contained in:
Couriersud 2012-08-20 19:17:31 +00:00
parent 4a73f8bcfb
commit 5280005bfa
5 changed files with 2045 additions and 1134 deletions

File diff suppressed because it is too large Load Diff

View File

@ -54,12 +54,14 @@
// Special chips
// ----------------------------------------------------------------------------------------
#define NETDEV_CONST(_name, _v) \
NET_REGISTER_DEV(netdev_const, _name) \
NETDEV_PARAM(_name.CONST, _v) \
#define NETDEV_CLOCK(_name) \
NET_REGISTER_DEV(netdev_clock, _name) \
#define NETDEV_INPUT(_name) \
NET_REGISTER_DEV(netdev_input, _name) \
#define NETDEV_LOGIC_INPUT(_name) \
NET_REGISTER_DEV(netdev_logic_input, _name) \
#define NETDEV_ANALOG_INPUT(_name) \
NET_REGISTER_DEV(netdev_analog_input, _name) \
#define NETDEV_CALLBACK(_name, _IN) \
NET_REGISTER_DEV(netdev_callback, _name) \
@ -92,7 +94,7 @@
#define TTL_7402_NOR(_name, _I1, _I2) \
NET_REGISTER_DEV(nic7402, _name) \
NET_CONNECT(_name, I1, _I1) \
NET_CONNECT(_name, I1, _I1) \
NET_CONNECT(_name, I2, _I2) \
#define TTL_7404_INVERT(_name, _I1) \
@ -145,7 +147,7 @@
#define TTL_7486_XOR(_name, _I1, _I2) \
NET_REGISTER_DEV(nic7486, _name) \
NET_CONNECT(_name, I1, _I1) \
NET_CONNECT(_name, I1, _I1) \
NET_CONNECT(_name, I2, _I2) \
#define TTL_7448(_name, _A0, _A1, _A2, _A3, _LTQ, _BIQ, _RBIQ) \
@ -185,9 +187,10 @@
NET_CONNECT(_name, R91, _R91) \
NET_CONNECT(_name, R92, _R92) \
#define TTL_7493(_name, _CLK, _R1, _R2) \
#define TTL_7493(_name, _CLKA, _CLKB, _R1, _R2) \
NET_REGISTER_DEV(nic7493, _name) \
NET_CONNECT(_name, CLK, _CLK) \
NET_CONNECT(_name, CLKA, _CLKA) \
NET_CONNECT(_name, CLKB, _CLKB) \
NET_CONNECT(_name, R1, _R1) \
NET_CONNECT(_name, R2, _R2) \
@ -198,7 +201,7 @@
NET_CONNECT(_name, K, _K) \
NET_CONNECT(_name, CLRQ, _CLRQ) \
#define TTL_74107(_name, _CLK, _J, _K, _CLRQ) \
#define TTL_74107(_name, _CLK, _J, _K, _CLRQ) \
TTL_74107A(_name, _CLK, _J, _K, _CLRQ)
#define TTL_74153(_name, _A1, _A2, _A3, _A4, _A, _B, _GA) \
@ -224,46 +227,50 @@
NET_CONNECT(_name, D, _D) \
#define NE555N_MSTABLE(_name, _TRIG) \
#define NE555N_MSTABLE(_name, _TRIG, _CV) \
NET_REGISTER_DEV(nicNE555N_MSTABLE, _name) \
NET_CONNECT(_name, TRIG, _TRIG) \
NET_CONNECT(_name, CV, _CV) \
#define NETDEV_MIXER3(_name, _I1, _I2, _I3) \
NET_REGISTER_DEV(nicMixer8, _name) \
NET_CONNECT(_name, I1, _I1) \
NET_CONNECT(_name, I2, _I2) \
NET_CONNECT(_name, I3, _I3) \
// ----------------------------------------------------------------------------------------
// Special support devices ...
// ----------------------------------------------------------------------------------------
NETLIB_DEVICE_WITH_PARAMS(netdev_const,
net_output_t m_Q;
net_param_t m_const;
NETLIB_DEVICE(netdev_logic_input,
ttl_output_t m_Q;
);
NETLIB_DEVICE(netdev_input,
net_output_t m_Q;
NETLIB_DEVICE(netdev_analog_input,
analog_output_t m_Q;
);
// ----------------------------------------------------------------------------------------
// Special devices ...
// ----------------------------------------------------------------------------------------
/* This class is an artificial delay circuit delaying a signal until the next low to high transition
* this is needed by pong to model delays in the hblank circuit
*/
NETLIB_DEVICE(netdev_delay_lh,
net_input_t m_clk;
net_input_t m_D;
NETLIB_DEVICE_WITH_PARAMS(netdev_clock,
ttl_input_t m_feedback;
ttl_output_t m_Q;
net_sig_t m_lastclk;
net_output_t m_Q;
net_param_t m_freq;
netlist_time m_inc;
);
NETLIB_DEVICE_WITH_PARAMS(nicMultiSwitch,
net_input_t m_I[8];
analog_input_t m_I[8];
net_output_t m_Q;
net_output_t m_low;
analog_output_t m_Q;
analog_output_t m_low;
net_param_t m_POS;
@ -271,11 +278,22 @@ NETLIB_DEVICE_WITH_PARAMS(nicMultiSwitch,
);
NETLIB_DEVICE(nicRSFF,
net_input_t m_S;
net_input_t m_R;
ttl_input_t m_S;
ttl_input_t m_R;
net_output_t m_Q;
net_output_t m_QQ;
ttl_output_t m_Q;
ttl_output_t m_QQ;
);
NETLIB_DEVICE_WITH_PARAMS(nicMixer8,
analog_input_t m_I[8];
analog_output_t m_Q;
analog_output_t m_low;
net_param_t m_R[8];
double m_w[8];
);
// ----------------------------------------------------------------------------------------
@ -284,186 +302,252 @@ NETLIB_DEVICE(nicRSFF,
NETLIB_DEVICE_WITH_PARAMS(nicNE555N_MSTABLE,
ATTR_HOT void timer_cb(INT32 timer_id);
//ATTR_HOT void timer_cb(INT32 timer_id);
net_input_t m_trigger;
analog_input_t m_trigger;
analog_input_t m_CV;
analog_input_t m_THRESHOLD; /* internal */
UINT8 m_last;
UINT8 m_fired;
double m_time;
bool m_last;
net_output_t m_Q;
analog_output_t m_Q;
analog_output_t m_THRESHOLD_OUT; /* internal */
netlist_base_timer_t *m_timer;
//netlist_base_timer_t *m_timer;
net_param_t m_R;
net_param_t m_C;
net_param_t m_VS;
net_param_t m_VL;
net_param_t m_VT;
);
NETLIB_SIGNAL(nic7400, 2)
NETLIB_SIGNAL(nic7402, 2)
NETLIB_SIGNAL(nic7404, 1)
NETLIB_SIGNAL(nic7410, 3)
NETLIB_SIGNAL(nic7420, 4)
NETLIB_SIGNAL(nic7425, 4)
NETLIB_SIGNAL(nic7427, 3)
NETLIB_SIGNAL(nic7430, 8)
NETLIB_SIGNAL(nic7450, 4)
NETLIB_SIGNAL(nic7400, 2, 0)
NETLIB_SIGNAL(nic7402, 2, 1)
NETLIB_SIGNAL(nic7410, 3, 0)
NETLIB_SIGNAL(nic7420, 4, 0)
NETLIB_SIGNAL(nic7425, 4, 1)
NETLIB_SIGNAL(nic7427, 3, 1)
NETLIB_SIGNAL(nic7430, 8, 0)
NETLIB_DEVICE(nic7404,
ttl_input_t m_I;
ttl_output_t m_Q;
);
NETLIB_DEVICE(nic7450,
ttl_input_t m_I0;
ttl_input_t m_I1;
ttl_input_t m_I2;
ttl_input_t m_I3;
ttl_output_t m_Q;
);
#if 0
NETLIB_DEVICE(nic7474,
net_input_t m_clk;
net_input_t m_D;
net_input_t m_clrQ;
net_input_t m_preQ;
ttl_input_t m_clk;
ttl_input_t m_D;
ttl_input_t m_clrQ;
ttl_input_t m_preQ;
net_sig_t m_lastclk;
net_output_t m_Q;
net_output_t m_QQ;
ttl_output_t m_Q;
ttl_output_t m_QQ;
);
NETLIB_SIGNAL(nic7486, 2)
#else
NETLIB_SUBDEVICE(nic7474sub,
ttl_input_t m_clk;
UINT8 m_nextD;
ttl_output_t m_Q;
ttl_output_t m_QQ;
);
NETLIB_DEVICE(nic7474,
nic7474sub sub;
ttl_input_t m_D;
ttl_input_t m_clrQ;
ttl_input_t m_preQ;
);
#endif
NETLIB_DEVICE(nic7486,
ttl_input_t m_I0;
ttl_input_t m_I1;
ttl_output_t m_Q;
);
/* 74107 does latch data during high !
* For modelling purposes, we assume 74107 and 74107A are the same
*/
NETLIB_SUBDEVICE(nic74107Asub,
ttl_input_t m_clk;
UINT8 m_Q1;
UINT8 m_Q2;
UINT8 m_F;
ttl_output_t m_Q;
ttl_output_t m_QQ;
);
NETLIB_DEVICE(nic74107A,
net_input_t m_clk;
net_input_t m_J;
net_input_t m_K;
net_input_t m_clrQ;
nic74107Asub sub;
net_sig_t m_lastclk;
ttl_input_t m_J;
ttl_input_t m_K;
ttl_input_t m_clrQ;
net_output_t m_Q;
net_output_t m_QQ;
);
class nic74107 : public nic74107A
{
public:
nic74107(netlist_setup_t *parent, const char *name)
: nic74107A(parent, name) {}
nic74107()
: nic74107A() {}
};
NETLIB_SUBDEVICE(nic7493ff,
ttl_input_t m_I;
ttl_output_t m_Q;
UINT8 m_active;
);
#if 1
NETLIB_DEVICE(nic7493,
ttl_input_t m_R1;
ttl_input_t m_R2;
nic7493ff A;
nic7493ff B;
nic7493ff C;
nic7493ff D;
);
#else
NETLIB_DEVICE(nic7493,
ATTR_HOT void update_outputs();
net_input_t m_R1;
net_input_t m_R2;
net_input_t m_clk;
ttl_input_t m_clk;
ttl_input_t m_R1;
ttl_input_t m_R2;
ttl_output_t m_QA;
ttl_output_t m_QB;
ttl_output_t m_QC;
ttl_output_t m_QD;
UINT8 m_lastclk;
UINT8 m_cnt;
net_output_t m_QA;
net_output_t m_QB;
net_output_t m_QC;
net_output_t m_QD;
);
#endif
NETLIB_DEVICE(nic7490,
ATTR_HOT void update_outputs();
net_input_t m_R1;
net_input_t m_R2;
net_input_t m_R91;
net_input_t m_R92;
net_input_t m_clk;
ttl_input_t m_R1;
ttl_input_t m_R2;
ttl_input_t m_R91;
ttl_input_t m_R92;
ttl_input_t m_clk;
net_sig_t m_lastclk;
UINT8 m_cnt;
net_output_t m_QA;
net_output_t m_QB;
net_output_t m_QC;
net_output_t m_QD;
ttl_output_t m_QA;
ttl_output_t m_QB;
ttl_output_t m_QC;
ttl_output_t m_QD;
);
/* ripple-carry counter on low-high clock transition */
NETLIB_DEVICE(nic9316,
NETLIB_SUBDEVICE(nic9316sub,
ATTR_HOT void update_outputs_all();
ATTR_HOT void update_outputs();
net_input_t m_clk;
net_input_t m_ENP;
net_input_t m_ENT;
net_input_t m_CLRQ;
net_input_t m_LOADQ;
net_input_t m_A;
net_input_t m_B;
net_input_t m_C;
net_input_t m_D;
ttl_input_t m_clk;
ttl_input_t m_LOADQ;
ttl_input_t m_ENT;
ttl_input_t m_A;
ttl_input_t m_B;
ttl_input_t m_C;
ttl_input_t m_D;
UINT8 m_lastclk;
UINT8 m_cnt;
net_output_t m_QA;
net_output_t m_QB;
net_output_t m_QC;
net_output_t m_QD;
net_output_t m_RC;
ttl_output_t m_QA;
ttl_output_t m_QB;
ttl_output_t m_QC;
ttl_output_t m_QD;
ttl_output_t m_RC;
);
NETLIB_DEVICE(nic9316,
nic9316sub sub;
ttl_input_t m_ENP;
ttl_input_t m_CLRQ;
);
NETLIB_DEVICE(nic7483,
net_input_t m_CI;
net_input_t m_A1;
net_input_t m_A2;
net_input_t m_A3;
net_input_t m_A4;
net_input_t m_B1;
net_input_t m_B2;
net_input_t m_B3;
net_input_t m_B4;
net_input_t m_clk;
ttl_input_t m_CI;
ttl_input_t m_A1;
ttl_input_t m_A2;
ttl_input_t m_A3;
ttl_input_t m_A4;
ttl_input_t m_B1;
ttl_input_t m_B2;
ttl_input_t m_B3;
ttl_input_t m_B4;
ttl_input_t m_clk;
UINT8 m_lastr;
net_output_t m_SA;
net_output_t m_SB;
net_output_t m_SC;
net_output_t m_SD;
net_output_t m_CO;
ttl_output_t m_SA;
ttl_output_t m_SB;
ttl_output_t m_SC;
ttl_output_t m_SD;
ttl_output_t m_CO;
);
/* one half of a nic74153 */
NETLIB_DEVICE(nic74153,
net_input_t m_I[4];
net_input_t m_A;
net_input_t m_B;
net_input_t m_GA;
ttl_input_t m_I[4];
ttl_input_t m_A;
ttl_input_t m_B;
ttl_input_t m_GA;
net_output_t m_AY;
ttl_output_t m_AY;
);
NETLIB_DEVICE(nic7448,
static const UINT8 tab7448[16][7];
net_input_t m_A0;
net_input_t m_A1;
net_input_t m_A2;
net_input_t m_A3;
net_input_t m_LTQ;
net_input_t m_RBIQ;
net_input_t m_BIQ;
ttl_input_t m_A0;
ttl_input_t m_A1;
ttl_input_t m_A2;
ttl_input_t m_A3;
ttl_input_t m_LTQ;
ttl_input_t m_RBIQ;
ttl_input_t m_BIQ;
UINT8 m_state;
net_output_t m_a;
net_output_t m_b;
net_output_t m_c;
net_output_t m_d;
net_output_t m_e;
net_output_t m_f;
net_output_t m_g;
ttl_output_t m_a;
ttl_output_t m_b;
ttl_output_t m_c;
ttl_output_t m_d;
ttl_output_t m_e;
ttl_output_t m_f;
ttl_output_t m_g;
);

View File

@ -42,10 +42,10 @@
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
****************************************************************************/
#include "netlist.h"
#include "net_lib.h"
//============================================================
// DEBUGGING
@ -54,11 +54,6 @@
#define VERBOSE (0)
#define KEEP_STATISTICS (0)
#if KEEP_STATISTICS && USE_DELEGATES
#error "Statistics only work without delegates!"
#endif
#if (VERBOSE)
#define VERBOSE_OUT(x) printf x
@ -71,9 +66,9 @@
//============================================================
#if KEEP_STATISTICS
#define add_to_stat(v,x) do { atomic_add32((v), (x)); } while (0)
#define add_to_stat(v,x) do { v += (x); } while (0)
#define inc_stat(v) add_to_stat(v, 1)
#define begin_timing(v) do { (v) -= get_profile_ticks(); } while (0)
#define begin_timing(v) do { (v) -= get_profile_ticks(); } while (0)
#define end_timing(v) do { (v) += get_profile_ticks(); } while (0)
#else
#define add_to_stat(v,x) do { } while (0)
@ -82,6 +77,9 @@
#define end_timing(v) do { } while (0)
#endif
const netlist_time netlist_time::zero = netlist_time::from_raw(0);
// ----------------------------------------------------------------------------------------
// A netlist parser
// ----------------------------------------------------------------------------------------
@ -103,86 +101,96 @@ public:
n = getname('(');
VERBOSE_OUT(("Parser: Device: %s\n", n));
if (strcmp(n,"NET_ALIAS") == 0)
{
char *alias;
char *out;
m_p++;
skipws();
alias = getname(',');
m_p++;
skipws();
out = getname(')');
m_p++;
VERBOSE_OUT(("Parser: Alias: %s %s\n", alias, out));
m_setup.register_alias(alias, out);
}
net_alias();
else if (strcmp(n,"NETDEV_PARAM") == 0)
{
char *param;
double val;
m_p++;
skipws();
param = getname(',');
m_p++;
skipws();
val = eval_param();
m_p++;
VERBOSE_OUT(("Parser: Param: %s %f\n", param, val));
m_setup.find_param(param)->setTo(val);
}
else if (strcmp(n,"NETDEV_CONST") == 0)
{
char *devname;
net_dev_t *dev;
char paramfq[30];
double val;
m_p++;
skipws();
devname = getname(',');
dev = net_create_device_by_name(n, &m_setup, devname);
m_setup.register_dev(dev);
m_p++;
skipws();
val = eval_param();
m_p++;
strcpy(paramfq, devname);
strcat(paramfq, ".CONST");
VERBOSE_OUT(("Parser: Const: %s %f\n", devname, val));
m_setup.find_param(paramfq)->setTo(val);
}
netdev_param();
else if ((strcmp(n,"NETDEV_TTL_CONST") == 0) || (strcmp(n,"NETDEV_ANALOG_CONST") == 0))
netdev_const(n);
else
{
char *devname;
net_dev_t *dev;
int cnt;
m_p++;
skipws();
devname = getname2(',', ')');
dev = net_create_device_by_name(n, &m_setup, devname);
m_setup.register_dev(dev);
skipws();
VERBOSE_OUT(("Parser: IC: %s\n", n));
cnt = 0;
while (*m_p != ')')
{
m_p++;
skipws();
n = getname2(',', ')');
VERBOSE_OUT(("Parser: ID: %s %s\n", n, dev->m_inputs.item(cnt)));
m_setup.register_link(dev->m_inputs.item(cnt), n);
skipws();
cnt++;
//return 0;
}
if (cnt != dev->m_inputs.count() && !dev->variable_input_count())
fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname, dev->m_inputs.count(), cnt);
m_p++;
}
netdev_device(n);
}
}
void net_alias()
{
char *alias;
char *out;
skipws();
alias = getname(',');
skipws();
out = getname(')');
VERBOSE_OUT(("Parser: Alias: %s %s\n", alias, out));
m_setup.register_alias(alias, out);
}
void netdev_param()
{
char *param;
double val;
skipws();
param = getname(',');
skipws();
val = eval_param();
VERBOSE_OUT(("Parser: Param: %s %f\n", param, val));
m_setup.find_param(param).initial(val);
check_char(')');
}
void netdev_const(const char *dev_name)
{
char *devname;
net_device_t *dev;
char paramfq[30];
double val;
skipws();
devname = getname(',');
dev = net_create_device_by_name(dev_name, &m_setup, devname);
m_setup.register_dev(dev);
skipws();
val = eval_param();
check_char(')');
strcpy(paramfq, devname);
strcat(paramfq, ".CONST");
VERBOSE_OUT(("Parser: Const: %s %f\n", devname, val));
m_setup.find_param(paramfq).setTo(val);
}
void netdev_device(const char *dev_type)
{
char *devname;
net_device_t *dev;
int cnt;
skipws();
devname = getname2(',', ')');
dev = net_create_device_by_name(dev_type, &m_setup, devname);
m_setup.register_dev(dev);
skipws();
VERBOSE_OUT(("Parser: IC: %s\n", n));
cnt = 0;
while (*m_p != ')')
{
m_p++;
skipws();
char *output_name = getname2(',', ')');
VERBOSE_OUT(("Parser: ID: %s %s\n", output_name, dev->m_inputs.item(cnt)));
m_setup.register_link(dev->m_inputs.item(cnt), output_name);
skipws();
cnt++;
}
if (cnt != dev->m_inputs.count() && !dev->variable_input_count())
fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname, dev->m_inputs.count(), cnt);
check_char(')');
}
private:
char *cdup(const char *s)
{
return core_strdup(s);
}
void skipeol()
{
while (*m_p)
@ -190,6 +198,8 @@ private:
if (*m_p == 10)
{
m_p++;
if (*m_p && *m_p == 13)
m_p++;
return;
}
m_p++;
@ -226,7 +236,8 @@ private:
while (*m_p != sep)
*p1++ = *m_p++;
*p1 = 0;
return core_strdup(buf);
m_p++;
return cdup(buf);
}
char *getname2(char sep1, char sep2)
@ -237,7 +248,18 @@ private:
while ((*m_p != sep1) && (*m_p != sep2))
*p1++ = *m_p++;
*p1 = 0;
return core_strdup(buf);
return cdup(buf);
}
void check_char(char ctocheck)
{
skipws();
if (*m_p == ctocheck)
{
m_p++;
return;
}
fatalerror("Parser: expected '%c' found '%c'", ctocheck, *m_p);
}
double eval_param()
@ -255,7 +277,7 @@ private:
f = i;
ret = strtod(s+strlen(macs[f]), &e);
if ((f>0) && (*e != ')'))
exit(0);
fatalerror("Parser: Error with parameter ...");
if (f>0)
e++;
m_p = e;
@ -268,83 +290,142 @@ private:
};
// ----------------------------------------------------------------------------------------
// netdev_a_to_d
// ----------------------------------------------------------------------------------------
class netdev_a_to_d_proxy : public net_device_t
{
public:
netdev_a_to_d_proxy(net_input_t &in_proxied) : net_device_t()
{
assert_always(in_proxied.object_type(SIGNAL_MASK) == SIGNAL_DIGITAL, "Digital signal expected");
m_I.m_high_thresh_V = in_proxied.m_high_thresh_V;
m_I.m_low_thresh_V = in_proxied.m_low_thresh_V;
}
ATTR_HOT void update()
{
if (m_I.Q_Analog() > m_I.m_high_thresh_V)
m_Q.setToPS(1, NLTIME_FROM_NS(1));
else if (m_I.Q_Analog() < m_I.m_low_thresh_V)
m_Q.setToPS(0, NLTIME_FROM_NS(1));
}
ATTR_COLD void start()
{
m_I.init(this);
m_Q.set_netdev(this);
m_Q.initial(1);
}
analog_input_t m_I;
ttl_output_t m_Q;
};
// ----------------------------------------------------------------------------------------
// netdev_const
// ----------------------------------------------------------------------------------------
NETLIB_START(netdev_ttl_const)
{
register_output("Q", m_Q);
register_param("CONST", m_const, 0.0);
}
NETLIB_UPDATE(netdev_ttl_const)
{
}
NETLIB_UPDATE_PARAM(netdev_ttl_const)
{
m_Q.setToPS(m_const.ValueInt(), NLTIME_IMMEDIATE);
}
NETLIB_START(netdev_analog_const)
{
register_output("Q", m_Q);
register_param("CONST", m_const, 0.0);
}
NETLIB_UPDATE(netdev_analog_const)
{
}
NETLIB_UPDATE_PARAM(netdev_analog_const)
{
m_Q.initial(m_const.Value());
}
// ----------------------------------------------------------------------------------------
// netlist_base_t
// ----------------------------------------------------------------------------------------
netlist_base_t::netlist_base_t(bool sub_cycle_exact)
netlist_base_t::netlist_base_t()
//m_output_list(ttl_list_t<output_t *>(2048)),
: m_current(0), m_divisor(32), m_sub_cycle_exact(sub_cycle_exact), m_gatedelay(100), m_clockfreq(1000000)
//: m_divisor(32), m_gatedelay(100), m_clockfreq(1000000)
: m_div(1024)
{
m_netlist_mask = NET_LIST_MASK;
reset_lists();
}
netlist_base_t::~netlist_base_t()
{
}
void netlist_base_t::set_clock_freq(int clockfreq)
void netlist_base_t::set_clock_freq(UINT64 clockfreq)
{
m_clockfreq = clockfreq;
m_divisor = U64(100000000000) / m_clockfreq / m_gatedelay;
VERBOSE_OUT(("Divisor %d\n", m_divisor));
m_div = netlist_time::from_hz(clockfreq).as_raw();
VERBOSE_OUT(("Setting clock %lld and divisor %d\n", clockfreq, m_div));
}
void netlist_base_t::set_gatedelay(int gatedelay)
ATTR_HOT ATTR_ALIGN void netlist_base_t::process_list(INT32 &atime)
{
m_gatedelay = gatedelay;
m_divisor = U64(100000000000) / m_clockfreq / m_gatedelay;
VERBOSE_OUT(("Divisor %d\n", m_divisor));
}
ATTR_HOT inline void netlist_base_t::process_list(void)
{
net_list_t<net_output_t *, 512> &list = m_output_list[m_sub_cycle_exact ? m_current : 0];
#if 0
net_output_t * RESTRICT * RESTRICT first;
net_output_t * RESTRICT * RESTRICT last;
first = list.first();
last = list.last();
while (first <= last)
while ( (atime > 0) && (m_queue.is_not_empty()))
{
net_output_t * RESTRICT * RESTRICT out = first;
while (out <= last)
{
(*out)->update_out();
(*out)->update_devs();
out++;
}
first = last + 1;
last = list.last();
}
#else
net_output_t * RESTRICT * RESTRICT out;
queue_t::entry_t e = m_queue.pop();
netlist_time delta = e.time() - m_time_ps + netlist_time::from_raw(m_rem);
out = list.first();
while (out <= list.last())
atime -= divu_64x32_rem(delta.as_raw(), m_div, &m_rem);
m_time_ps = e.time();
e.object()->update_devs();
add_to_stat(m_perf_out_processed, 1);
add_to_stat(m_perf_list_len, m_end);
}
if (atime > 0)
{
(*out)->update_out();
(*out)->update_devs();
out++;
m_time_ps += netlist_time::from_raw(atime * m_div);
atime = 0;
}
#endif
reset_list();
if (m_sub_cycle_exact)
m_current = (m_current + 1) & m_netlist_mask;
if (KEEP_STATISTICS)
printf("%f\n", (double) m_perf_list_len / (double) m_perf_out_processed);
}
// ----------------------------------------------------------------------------------------
// Default netlist elements ...
// ----------------------------------------------------------------------------------------
static NETLIST_START(base)
NETDEV_TTL_CONST(ttlhigh, 1)
NETDEV_TTL_CONST(ttllow, 0)
NETDEV_ANALOG_CONST(NC, NETLIST_HIGHIMP_V)
NETLIST_END
// ----------------------------------------------------------------------------------------
// netlist_setup_t
// ----------------------------------------------------------------------------------------
netlist_setup_t::netlist_setup_t(netlist_base_t &netlist)
//m_output_list(ttl_list_t<output_t *>(2048)),
: m_netlist(netlist)
{
NETLIST_NAME(base)(*this);
}
netlist_setup_t::~netlist_setup_t()
@ -352,7 +433,7 @@ netlist_setup_t::~netlist_setup_t()
}
net_dev_t *netlist_setup_t::register_dev(net_dev_t *dev)
net_device_t *netlist_setup_t::register_dev(net_device_t *dev)
{
if (!(m_devices.add(dev->name(), dev, false)==TMERR_NONE))
fatalerror("Error adding %s to device list\n", dev->name());
@ -378,7 +459,7 @@ static void remove_start_with(T &hm, astring &sw)
void netlist_setup_t::remove_dev(const char *name)
{
net_dev_t *dev = m_devices.find(name);
net_device_t *dev = m_devices.find(name);
astring temp = name;
if (dev == NULL)
fatalerror("Device %s does not exist\n", name);
@ -413,11 +494,10 @@ void netlist_setup_t::register_output(const char *name, net_output_t *out)
fatalerror("Error adding output %s to output list\n", name);
}
void netlist_setup_t::register_input(const char *name, net_input_t *inp, net_input_type type)
void netlist_setup_t::register_input(const char *name, net_input_t *inp)
{
net_input_setup_t *setup_inp = new net_input_setup_t(inp, type);
VERBOSE_OUT(("input %s\n", name));
if (!(m_inputs.add(name, setup_inp, false) == TMERR_NONE))
if (!(m_inputs.add(name, inp, false) == TMERR_NONE))
fatalerror("Error adding input %s to input list\n", name);
}
@ -431,7 +511,7 @@ void netlist_setup_t::register_link(const char *sin, const char *sout)
void netlist_setup_t::register_param(const char *sname, net_param_t *param)
{
astring temp = param->ttl_dev()->name();
astring temp = param->netdev().name();
temp.cat(".");
temp.cat(sname);
if (!(m_params.add(temp, param, false)==TMERR_NONE))
@ -454,7 +534,7 @@ net_output_t *netlist_setup_t::find_output_exact(const char *outname_in)
return ret;
}
net_output_t *netlist_setup_t::find_output(const char *outname_in)
net_output_t &netlist_setup_t::find_output(const char *outname_in)
{
const char *outname = resolve_alias(outname_in);
net_output_t *ret;
@ -471,10 +551,10 @@ net_output_t *netlist_setup_t::find_output(const char *outname_in)
if (ret == NULL)
fatalerror("output %s(%s) not found!", outname_in, outname);
VERBOSE_OUT(("Found input %s\n", outname));
return ret;
return *ret;
}
net_param_t *netlist_setup_t::find_param(const char *param_in)
net_param_t &netlist_setup_t::find_param(const char *param_in)
{
const char *outname = resolve_alias(param_in);
net_param_t *ret;
@ -483,7 +563,7 @@ net_param_t *netlist_setup_t::find_param(const char *param_in)
if (ret == NULL)
fatalerror("parameter %s(%s) not found!", param_in, outname);
VERBOSE_OUT(("Found parameter %s\n", outname));
return ret;
return *ret;
}
void netlist_setup_t::resolve_inputs(void)
@ -493,39 +573,47 @@ void netlist_setup_t::resolve_inputs(void)
{
const astring *sout = entry->object();
astring sin = entry->tag();
net_input_setup_t *in = m_inputs.find(sin);
int p = sin.find(".");
const char *devname = sin.substr(0, p);
net_dev_t *dev = m_devices.find(devname);
net_output_t *out = find_output(sout->cstr() );
net_input_t *in = m_inputs.find(sin);
(*in->inp()).o = GETINPPTR(*out);
//in->inp()->v = out->Q_ptr();
if (in->type() == NET_INP_TYPE_ACTIVE)
out->register_con(dev);
net_output_t &out = find_output(sout->cstr());
if (out.object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_ANALOG
&& in->object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_DIGITAL)
{
// fatalerror("connecting analog output %s with %s\n", out.netdev()->name(), in->netdev()->name());
// fatalerror("connecting analog output %s with %s\n", out.netdev()->name(), in->netdev()->name());
netdev_a_to_d_proxy *proxy = new netdev_a_to_d_proxy(*in);
proxy->init(this, "abc");
proxy->start();
in->set_output(proxy->GETINPPTR(proxy->m_Q));
//Next check would not work with dynamic activation
//if (in->state() != net_input_t::INP_STATE_PASSIVE)
proxy->m_Q.register_con(*in);
proxy->m_I.set_output(&out);
//if (proxy->m_I.state() != net_input_t::INP_STATE_PASSIVE)
out.register_con(proxy->m_I);
}
else
{
in->set_output(out.netdev()->GETINPPTR(out));
//Next check would not work with dynamic activation
//if (in->state() != net_input_t::INP_STATE_PASSIVE)
out.register_con(*in);
}
}
/* make sure params are set now .. */
for (tagmap_param_t::entry_t *entry = m_params.first(); entry != NULL; entry = m_params.next(entry))
{
entry->object()->netdev().update_param();
}
step_all_devices();
//reset_list();
//process_list();
}
void netlist_setup_t::step_all_devices()
{
m_netlist.reset_list();
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
/* make sure all outputs are triggered once */
for (tagmap_output_t::entry_t *entry = m_outputs.first(); entry != NULL; entry = m_outputs.next(entry))
{
net_dev_t &dev = *entry->object();
dev.update_param();
dev.update();
for (tagmap_output_t::entry_t *entry = m_outputs.first(); entry != NULL; entry = m_outputs.next(entry))
{
net_output_t &out = *entry->object();
out.update_out();
}
m_netlist.reset_lists();
net_output_t *out = entry->object();
out->update_devs_force();
INT32 time = 1000;
m_netlist.process_list(time);
}
}
@ -547,119 +635,238 @@ void netlist_setup_t::print_stats()
}
// ----------------------------------------------------------------------------------------
// net_core_device_t
// ----------------------------------------------------------------------------------------
net_core_device_t::net_core_device_t()
: net_object_t(DEVICE)
{
}
net_core_device_t::~net_core_device_t()
{
}
ATTR_COLD void net_core_device_t::init_core(netlist_base_t *anetlist, const char *name)
{
m_netlist = anetlist;
m_name = name;
#if USE_DELEGATES_A
h = net_update_delegate(&net_core_device_t::update, "update", this);
#endif
}
ATTR_COLD void net_core_device_t::register_subdevice(net_core_device_t &subdev)
{
m_subdevs.add(&subdev);
subdev.init_core(m_netlist, this->name());
//subdev.start();
}
// ----------------------------------------------------------------------------------------
// net_dev_t
// ----------------------------------------------------------------------------------------
net_dev_t::~net_dev_t()
net_device_t::net_device_t()
: net_core_device_t(), m_variable_input_count(false)
{
}
ATTR_HOT void net_dev_t::update_timed()
net_device_t::~net_device_t()
{
inc_stat(&stat_count);
begin_timing(total_time);
update();
end_timing(total_time);
}
void net_dev_t::register_output(const char *name, net_output_t *port)
ATTR_COLD void net_device_t::init(netlist_setup_t *setup, const char *name)
{
astring temp = this->name();
m_setup = setup;
init_core(&setup->netlist(), name);
}
void net_device_t::register_output(const net_core_device_t &dev, const char *name, net_output_t &port)
{
astring temp = dev.name();
temp.cat(".");
temp.cat(name);
port->set_ttl_dev(this);
m_setup->register_output(temp, port);
port.set_netdev(&dev);
m_setup->register_output(temp, &port);
}
void net_dev_t::register_input(const char *name, net_input_t *inp, net_input_type type)
void net_device_t::register_output(const char *name, net_output_t &port)
{
astring temp = this->name();
register_output(*this, name, port);
}
void net_device_t::register_input(net_core_device_t &dev, const char *name, net_input_t &inp, int type)
{
astring temp = dev.name();
temp.cat(".");
temp.cat(name);
inp.init(&dev, type);
m_inputs.add(core_strdup(temp.cstr()));
m_setup->register_input(temp, inp, type);
m_setup->register_input(temp, &inp);
}
void net_dev_t::register_param(const char *name, net_param_t *param, double initialVal)
void net_device_t::register_input(const char *name, net_input_t &inp, int type)
{
param->set_ttl_dev(this);
param->initial(initialVal);
m_setup->register_param(name, param);
register_input(*this, name, inp, type);
}
void net_device_t::register_link_internal(net_core_device_t &dev, net_input_t &in, net_output_t &out)
{
in.set_output(GETINPPTR(out));
in.init(&dev);
//if (in.state() != net_input_t::INP_STATE_PASSIVE)
out.register_con(in);
}
void net_device_t::register_link_internal(net_input_t &in, net_output_t &out)
{
register_link_internal(*this, in, out);
}
void net_device_t::register_param(net_core_device_t &dev, const char *name, net_param_t &param, double initialVal)
{
param.set_netdev(dev);
param.initial(initialVal);
m_setup->register_param(name, &param);
}
void net_device_t::register_param(const char *name, net_param_t &param, double initialVal)
{
register_param(*this,name, param, initialVal);
}
// ----------------------------------------------------------------------------------------
// net_input_t
// ----------------------------------------------------------------------------------------
ATTR_COLD void net_input_t::init(net_core_device_t *dev, int astate)
{
m_netdev = dev;
m_state = astate;
#if USE_DELEGATES
h = net_update_delegate(&net_core_device_t::update, "update", dev);
#endif
}
// ----------------------------------------------------------------------------------------
// net_output_t
// ----------------------------------------------------------------------------------------
net_output_t::net_output_t()
net_output_t::net_output_t(int atype)
: net_object_t(atype)
{
#if USE_DELEGATES
//m_cons = global_alloc_array_clear(net_update_delegate, 32);
#else
// m_cons = global_alloc_array_clear(net_dev_t *, 32);
#endif
//m_Q = parent.alloc_sig();
//m_new_Q = parent.alloc_sig();
m_num_cons = 0;
m_last_Q = 1;
m_Q = 0;
m_new_Q = m_Q;
m_active = 0;
m_in_queue = 2;
}
ATTR_COLD void net_output_t::set_ttl_dev(net_dev_t *dev)
ATTR_COLD void net_output_t::set_netdev(const net_core_device_t *dev)
{
m_ttldev = dev;
m_netlist = &dev->setup()->netlist();
m_netdev = dev;
m_netlist = dev->netlist();
}
ATTR_COLD void net_output_t::register_con(net_dev_t *dev)
static inline void update_dev(const net_input_t *inp, const UINT32 mask)
{
assert(m_num_cons<32);
if ((inp->state() & mask) != 0)
{
begin_timing(inp->netdev()->total_time);
inc_stat(inp->netdev()->stat_count);
#if USE_DELEGATES
net_update_delegate aDelegate = net_update_delegate(&net_dev_t::update, "update", dev);
for (int i=0; i < m_num_cons; i++)
if (m_cons[i] == aDelegate)
return;
m_cons[m_num_cons++] = aDelegate;
inp->h();
#else
for (int i=0; i < m_num_cons; i++)
if (m_cons[i] == dev)
return;
m_cons[m_num_cons++] = dev;
inp->netdev()->update_device();
#endif
end_timing(inp->netdev()->total_time);
}
}
ATTR_HOT inline void net_output_t::update_devs()
{
#if USE_DELEGATES
net_update_delegate *s = m_cons;
net_update_delegate *e = s + m_num_cons;
const UINT32 masks[4] = { 1, 5, 3, 1 };
m_Q = m_new_Q;
m_Q_analog = m_new_Q_analog;
while (s<e)
//UINT32 mask = 1 | ((m_last_Q & (m_Q ^ 1)) << 1) | (((m_last_Q ^ 1) & m_Q) << 2);
const UINT32 mask = masks[ (m_last_Q << 1) | m_Q ];
switch (m_num_cons)
{
(*s++)();
case 2:
update_dev(m_cons[1], mask);
case 1:
update_dev(m_cons[0], mask);
break;
default:
{
for (int i=0; i < m_num_cons; i++)
update_dev(m_cons[i], mask);
}
case 0:
break;
}
#else
net_dev_t **s = m_cons;
net_dev_t **e = s + m_num_cons;
#if KEEP_STATISTICS
while (s<e)
(*s++)->update_timed();
m_in_queue = 2; /* mark as taken ... */
m_last_Q = m_Q;
}
ATTR_COLD void net_output_t::update_devs_force()
{
net_input_t **s = m_cons;
int i = m_num_cons;
m_Q = m_new_Q;
m_Q_analog = m_new_Q_analog;
while (i-- > 0)
{
if (((*s)->state() & net_input_t::INP_STATE_ACTIVE) != 0)
#if USE_DELEGATES
(*s)->h();
#else
while (s<e)
(*s++)->update();
(*s)->netdev()->update_device();
#endif
s++;
}
m_last_Q = m_Q;
}
ATTR_COLD void net_output_t::register_con(net_input_t &input)
{
int i;
if (m_num_cons >= ARRAY_LENGTH(m_cons))
fatalerror("Connections exceeded for %s\n", m_netdev->name());
/* keep similar devices together */
for (i = 0; i < m_num_cons; i++)
#if USE_DELEGATES
if (m_cons[i]->h == input.h)
break;
#else
if (m_cons[i]->netdev() == input.netdev())
break;
#endif
for (int j = m_num_cons; j > i; j--)
m_cons[j] = m_cons[j - 1];
m_cons[i] = &input;
m_num_cons++;
if (input.state() != net_input_t::INP_STATE_PASSIVE)
m_active++;
}
NETLIB_UPDATE(netdev_callback)
{
// FIXME: Remove after device cleanup
if (!m_callback.isnull())
m_callback(INPVAL(m_in));
m_callback(INPANALOG(m_in));
}
// ----------------------------------------------------------------------------------------
@ -674,17 +881,6 @@ netlist_mame_device::netlist_mame_device(const machine_config &mconfig, const ch
: device_t(mconfig, NETLIST, "netlist", tag, owner, clock),
device_execute_interface(mconfig, *this)
{
m_clock = clock;
}
void netlist_mame_device::static_set_subcycles(device_t &device, int subcycles)
{
netlist_mame_device &netlist = downcast<netlist_mame_device &>(device);
assert((subcycles & 1) == 0);
assert( subcycles > 0);
netlist.m_subcycles = subcycles;
}
void netlist_mame_device::static_set_constructor(device_t &device, void (*setup_func)(netlist_setup_t &))
@ -701,8 +897,8 @@ void netlist_mame_device::device_start()
{
//double dt = clocks_to_attotime(1).as_double();
m_netlist = global_alloc_clear(netlist_t(*this, m_subcycles > 2));
m_netlist->set_clock_freq(m_clock * m_subcycles);
m_netlist = global_alloc_clear(netlist_t(*this));
m_netlist->set_clock_freq(this->clock());
m_setup = global_alloc_clear(netlist_setup_t(*m_netlist));
@ -717,18 +913,12 @@ void netlist_mame_device::device_start()
m_setup->resolve_inputs();
//m_clockcnt = 0;
m_clock_input = m_setup->find_output("clk");
//save_item(NAME(m_clockcnt));
save_state();
/* TODO: we have to save the round robin queue as well */
// set our instruction counter
m_icountptr = &m_icount;
m_ss = SubCycles() / 2;
m_clk = 0;
}
void netlist_mame_device::device_reset()
@ -761,37 +951,25 @@ void netlist_mame_device::save_state()
UINT64 netlist_mame_device::execute_clocks_to_cycles(UINT64 clocks) const
{
return clocks * SubCycles();
return clocks;
}
UINT64 netlist_mame_device::execute_cycles_to_clocks(UINT64 cycles) const
{
return cycles / SubCycles();
return cycles;
}
ATTR_HOT void netlist_mame_device::execute_run()
{
//bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0);
osd_ticks_t a = -osd_ticks();
UINT8 ssdiv2 = (SubCycles() / 2);
//int p = m_icount;
do
{
// debugging
//m_ppc = m_pc; // copy PC to previous PC
//if (check_debugger)
// debugger_instruction_hook(this, 0); //m_pc);
if (--m_ss == 0)
{
m_ss = ssdiv2;
m_clk = !m_clk;
m_clock_input->setTo(m_clk);
}
m_netlist->process_list();
m_icount--;
} while (m_icount > 0);
a+=osd_ticks();
//printf("%ld %d %ld\n", (long) a, p, (long) (a * 1000 / p));
// debugging
//m_ppc = m_pc; // copy PC to previous PC
//if (check_debugger)
// debugger_instruction_hook(this, 0); //m_pc);
m_netlist->process_list(m_icount);
}

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ TODO:
* http://www.youtube.com/watch?v=pDrRnJOCKZc
*/
#define MASTER_CLOCK 7139000
#define MASTER_CLOCK 7159000
#define V_TOTAL (0x105+1)
#define H_TOTAL (0x1C6+1) // 454
@ -55,7 +55,7 @@ TODO:
#define VBSTART (V_TOTAL)
#define VBEND (16)
#define HRES_MULT (2)
#define HRES_MULT (1)
enum input_changed_enum
{
@ -64,15 +64,17 @@ enum input_changed_enum
IC_COIN,
IC_SWITCH,
IC_VR1,
IC_VR2,
IC_GATEDELAY
IC_VR2
};
static NETLIST_START(pong_schematics)
NETDEV_CONST(high, 1)
NETDEV_CONST(low, 0)
NETDEV_INPUT(clk)
NETDEV_INPUT(SRST)
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)
@ -111,9 +113,9 @@ static NETLIST_START(pong_schematics)
TTL_7427_NOR(ic_g2a, ic_g3c.Q, 256HQ, vpad2Q)
NET_ALIAS(pad2, ic_g2a.Q)
/* horizontal counter */
TTL_7493(ic_f8, clk, ic_e7b.QQ, ic_e7b.QQ) /* f8, f9, f6b */
TTL_7493(ic_f9, ic_f8.QD, ic_e7b.QQ, ic_e7b.QQ) /* f8, f9, f6b */
// 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)
@ -129,9 +131,9 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(256H, ic_f6b.Q)
NET_ALIAS(256HQ, ic_f6b.QQ)
/* vertical counter */
TTL_7493(ic_e8, hreset, ic_e7a.QQ, ic_e7a.QQ) /* e8, e9, d9b */
TTL_7493(ic_e9, ic_e8.QD, ic_e7a.QQ, ic_e7a.QQ) /* e8, e9, d9b */
// 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)
@ -147,11 +149,11 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(256VQ, ic_d9b.QQ)
/* hblank flip flop */
// hblank flip flop
TTL_7400_NAND(ic_g5b, 16H, 64H)
/* the time critical one */
// the time critical one
TTL_7400_NAND(ic_h5c, ic_h5b.Q, hresetQ)
TTL_7400_NAND(ic_h5b, ic_h5c.Q, ic_g5b.Q)
@ -159,7 +161,7 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(hblankQ, ic_h5b.Q)
TTL_7400_NAND(hsyncQ, hblank, 32H)
/* vblank flip flop */
// vblank flip flop
TTL_7402_NOR(ic_f5c, ic_f5d.Q, vreset)
TTL_7402_NOR(ic_f5d, ic_f5c.Q, 16V)
@ -170,11 +172,11 @@ static NETLIST_START(pong_schematics)
TTL_7410_NAND(ic_g5a, vblank, 4V, ic_h5a.Q)
NET_ALIAS(vsyncQ, ic_g5a.Q)
/* move logic */
// 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, rstspeed, rstspeed)
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)
@ -199,7 +201,7 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(Aa, ic_h4c.Q)
NET_ALIAS(Ba, ic_h4b.Q)
/* hvid circuit */
// hvid circuit
TTL_7400_NAND(hball_resetQ, Serve, attractQ)
@ -210,19 +212,19 @@ static NETLIST_START(pong_schematics)
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 */
// 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 */
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 */
// vball ctrl circuit
TTL_7450_ANDORINVERT(ic_a6a, b1, 256HQ, b2, 256H)
TTL_7450_ANDORINVERT(ic_a6b, c1, 256HQ, c2, 256H)
@ -231,7 +233,7 @@ static NETLIST_START(pong_schematics)
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_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)
@ -246,9 +248,9 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(c6, ic_b4.SC)
NET_ALIAS(d6, ic_b4.SD)
/* serve monoflop */
// serve monoflop
TTL_7404_INVERT(f4_trig, rstspeed)
NE555N_MSTABLE(ic_f4_serve, f4_trig)
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))
@ -258,15 +260,15 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(Serve, ic_b5b_serve.QQ)
NET_ALIAS(ServeQ, ic_b5b_serve.Q)
/* score logic */
// score logic
TTL_7474(ic_h3a, 4H, 128H, high, attractQ)
/* sound logic */
// 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)
NET_ALIAS(SC, ic_g4_sc.Q) /* monoflop with NE555 determines score sound */
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))
@ -280,15 +282,15 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(sound, ic_c1b.Q)
/* paddle1 logic 1 */
// paddle1 logic 1
NE555N_MSTABLE(ic_b9, 256VQ)
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_b9.Q, ic_b9.Q)
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)
@ -297,15 +299,15 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(c1, ic_b8.QC)
NET_ALIAS(d1, ic_b8.QD)
/* paddle1 logic 2 */
// paddle1 logic 2
NE555N_MSTABLE(ic_a9, 256VQ)
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_a9.Q, ic_a9.Q)
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)
@ -314,7 +316,7 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(c2, ic_a8.QC)
NET_ALIAS(d2, ic_a8.QD)
/* C5-EN Logic */
// C5-EN Logic
TTL_7404_INVERT(ic_e3a, 128H)
TTL_7427_NOR( ic_e3b, 256H, 64H, ic_e3a.Q)
@ -325,14 +327,14 @@ static NETLIST_START(pong_schematics)
TTL_7425_NOR(ic_f2a, ic_g1a.Q, 64V, 128V, ic_d2c.Q)
NET_ALIAS(c5-en, ic_f2a.Q)
/* Score logic ... */
// 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! */
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)
@ -347,7 +349,7 @@ static NETLIST_START(pong_schematics)
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! */
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)
@ -357,7 +359,7 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(score2_10, ic_c8b.Q)
NET_ALIAS(score2_10Q, ic_c8b.QQ)
/* Score display */
// 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)
@ -395,18 +397,26 @@ static NETLIST_START(pong_schematics)
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 */
// 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 */
// 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)
@ -414,8 +424,7 @@ static NETLIST_START(pong)
//NETLIST_INCLUDE(pong_schematics)
NETLIST_MEMREGION("maincpu")
NETDEV_CALLBACK(sound_cb, sound)
NETDEV_CALLBACK(video_cb, video)
NETDEV_CALLBACK(score_cb, score)
NETDEV_CALLBACK(video_cb, videomix)
NETLIST_END
@ -425,13 +434,12 @@ static NETLIST_START(pong_fast)
/* 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)
//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, video)
NETDEV_CALLBACK(score_cb, score)
NETDEV_CALLBACK(video_cb, videomix)
NETLIST_END
@ -443,10 +451,10 @@ public:
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_V0(*this, "maincpu", "ic_a9.VT"),
m_p_V1(*this, "maincpu", "ic_b9.VT"),
m_p_R0(*this, "maincpu", "ic_a9.R"),
m_p_R1(*this, "maincpu", "ic_b9.R")
{
@ -457,11 +465,11 @@ public:
required_device<dac_device> m_dac; /* just to have a sound device */
// sub devices
netlist_mame_device::required_output m_srst;
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_V0;
netlist_mame_device::required_param m_p_V1;
netlist_mame_device::required_param m_p_R0;
netlist_mame_device::required_param m_p_R1;
@ -469,21 +477,21 @@ public:
DECLARE_INPUT_CHANGED_MEMBER(input_changed);
void sound_cb(net_sig_t newval)
void sound_cb(double newval)
{
m_dac->write_unsigned8(128*(!newval));
//printf("snd %f\n", newval);
//dac_w(m_dac, 0, newval*64);
m_dac->write_unsigned8(64*newval);
}
void video_cb(net_sig_t newval)
void video_cb(double newval)
{
update_vid();
m_vid = (m_vid & 2) | (UINT8) newval;
}
void score_cb(net_sig_t newval)
{
update_vid();
m_vid = (m_vid & 1) | ((UINT8) newval<<1);
//printf("%f\n", newval);
if (newval != m_vid)
{
update_vid();
m_vid = newval;
}
}
protected:
@ -498,29 +506,75 @@ 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 new_x = clocks % ( m_maincpu->SubCycles() * H_TOTAL);
int new_y = (clocks / (m_maincpu->SubCycles() * H_TOTAL)) % V_TOTAL;
if (m_vid > 0)
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())
{
rgb_t col = MAKE_RGB(255,255,255);
if (new_y > m_last_y)
new_x = m_maincpu->SubCycles() * H_TOTAL-1;
int delta = (new_x - m_last_x);
if (delta < m_maincpu->SubCycles())
col = MAKE_RGB(255 * delta /( m_maincpu->SubCycles()),255 * delta /( m_maincpu->SubCycles()),255 * delta /( m_maincpu->SubCycles()));
for (int i = m_last_x / ( m_maincpu->SubCycles() / HRES_MULT); i < new_x / ( m_maincpu->SubCycles()/HRES_MULT); i++)
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;
}
m_last_x = new_x;
m_last_y = new_y;
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;
}
UINT8 m_vid;
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()
@ -530,13 +584,10 @@ void pong_state::machine_start()
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));
m_maincpu->setup().register_callback("score_cb", net_output_delegate(&pong_state::score_cb, "pong_state::score_cb", this));
}
void pong_state::machine_reset()
{
// m_sound_nmi_enabled = FALSE;
// m_nmi_enable = 0;
}
@ -549,7 +600,7 @@ void pong_state::video_start()
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));
//m_bitmap->fill(MAKE_RGB(0,0,0));
return 0;
}
@ -579,8 +630,8 @@ INPUT_CHANGED_MEMBER(pong_state::input_changed)
double pad = vA + (vB - vA)*PRE_R / (Req + PRE_R);
switch (numpad)
{
case IC_PADDLE1: m_p_V0->setTo(pad); break;
case IC_PADDLE2: m_p_V1->setTo(pad); break;
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;
}
@ -589,7 +640,7 @@ INPUT_CHANGED_MEMBER(pong_state::input_changed)
m_sw1b->setTo(newval ? 1 : 0);
break;
case IC_COIN:
m_srst->setTo(newval & 1);
m_srst->setToPS(newval & 1, NLTIME_FROM_US(500));
break;
case IC_VR1:
case IC_VR2:
@ -600,9 +651,6 @@ INPUT_CHANGED_MEMBER(pong_state::input_changed)
case IC_VR2: m_p_R1->setTo(pad); break;
}
break;
case IC_GATEDELAY:
m_maincpu->netlist().set_gatedelay(newval);
break;
}
@ -626,15 +674,15 @@ static INPUT_PORTS_START( pong )
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)
//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", MASTER_CLOCK, pong, 10)
MCFG_NETLIST_ADD("maincpu", pong)
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
@ -651,7 +699,8 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( pongf, pong )
/* basic machine hardware */
MCFG_NETLIST_REPLACE("maincpu", MASTER_CLOCK, pong_fast, 2)
//MCFG_NETLIST_REPLACE("maincpu", MASTER_CLOCK, pong_fast, 100)
MCFG_NETLIST_REPLACE("maincpu", pong_fast)
MACHINE_CONFIG_END
@ -663,7 +712,7 @@ MACHINE_CONFIG_END
ROM_START( pong ) /* dummy to satisfy game entry*/
ROM_REGION( 0x10000, "maincpu", 0 ) /* enough for netlist */
ROM_LOAD( "pong.netlist", 0x00000, 10306, CRC(bb92b267) SHA1(0dd6b3209ac1335a97cfe159502d24556f531007) )
ROM_LOAD( "pong.netlist", 0x000000, 0x0029e4, CRC(e9c409a1) SHA1(1dc99437f49261c3cb3f46153c6258043bc720a0) )
ROM_END
ROM_START( pongf ) /* dummy to satisfy game entry*/