Document that inlining not automatically helps performance. Template

specialized implementations outperform the inlined code. (nw)
This commit is contained in:
couriersud 2016-06-05 22:55:58 +02:00
parent 498a560ec7
commit 7a302cebb3
10 changed files with 453 additions and 110 deletions

View File

@ -6,6 +6,7 @@
*/
#include "nld_74279.h"
#include "nld_truthtable.h"
namespace netlist
{
@ -53,8 +54,8 @@ namespace netlist
NETLIB_SUB(74279A) m_4;
};
nld_74279A::truthtable_t nld_74279A::m_ttbl;
nld_74279B::truthtable_t nld_74279B::m_ttbl;
nld_74279A::truthtable_t nld_74279A::m_ttbl(3,1,0);
nld_74279B::truthtable_t nld_74279B::m_ttbl(4,1,0);
const char *nld_74279A::m_desc[] = {
"S,R,_Q|Q",

View File

@ -36,18 +36,7 @@
#ifndef NLD_74279_H_
#define NLD_74279_H_
#include "nld_truthtable.h"
#define TTL_74279_DIP(name) \
NET_REGISTER_DEV(TTL_74279_DIP, name)
namespace netlist
{
namespace devices
{
} //namespace devices
} // namespace netlist
#endif /* NLD_74279_H_ */

View File

@ -6,6 +6,7 @@
*/
#include "nld_7448.h"
#include "nld_truthtable.h"
namespace netlist
{

View File

@ -25,7 +25,6 @@
#define NLD_7448_H_
#include "nl_base.h"
#include "nld_truthtable.h"
#define TTL_7448(name, cA0, cA1, cA2, cA3, cLTQ, cBIQ, cRBIQ) \
NET_REGISTER_DEV(TTL_7448, name) \

View File

@ -107,7 +107,7 @@ namespace netlist
};
#if (1 && USE_TRUTHTABLE)
nld_9312::truthtable_t nld_9312::m_ttbl;
nld_9312::truthtable_t nld_9312::m_ttbl(12,2,0);
/* FIXME: Data changes are propagating faster than changing selects A,B,C
* Please refer to data sheet.

View File

@ -13,6 +13,25 @@ namespace netlist
namespace devices
{
template<unsigned m_NI, unsigned m_NO, int has_state>
class netlist_factory_truthtable_t : public netlist_base_factory_truthtable_t
{
P_PREVENT_COPYING(netlist_factory_truthtable_t)
public:
netlist_factory_truthtable_t(const pstring &name, const pstring &classname,
const pstring &def_param)
: netlist_base_factory_truthtable_t(name, classname, def_param)
, m_ttbl(m_NI, m_NO, has_state){ }
plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override
{
typedef nld_truthtable_t<m_NI, m_NO, has_state> tt_type;
return plib::owned_ptr<device_t>::Create<tt_type>(anetlist, name, m_family, &m_ttbl, m_desc);
}
private:
typename nld_truthtable_t<m_NI, m_NO, has_state>::truthtable_t m_ttbl;
};
unsigned truthtable_desc_t::count_bits(UINT32 v)
{
unsigned ret = 0;

View File

@ -11,6 +11,7 @@
#define NLD_TRUTHTABLE_H_
#include <new>
#include <cstdint>
#include "nl_base.h"
#include "nl_factory.h"
@ -51,6 +52,66 @@ namespace netlist
namespace devices
{
class dyn_bitset
{
dyn_bitset(const std::size_t size)
: m_size(size)
, m_data_size((m_data_bits - 1 + size) / m_data_bits)
{
m_d = new data_type[m_data_size];
for (std::size_t i=0; i<m_data_size; i++)
m_d[i] = 0;
}
~dyn_bitset()
{
delete [] m_d;
}
void set()
{
for (std::size_t i=0; i<m_data_size; i++)
m_d[i] = ~0;
}
void set(std::size_t pos)
{
const std::size_t bytepos = (pos >> m_data_shift);
const std::size_t bitpos = (pos & m_data_mask);
m_d[bytepos] |= (1 << bitpos);
}
void reset()
{
for (std::size_t i=0; i<m_data_size; i++)
m_d[i] = 0;
}
void reset(std::size_t pos)
{
const std::size_t bytepos = (pos >> m_data_shift);
const std::size_t bitpos = (pos & m_data_mask);
m_d[bytepos] &= ~(1 << bitpos);
}
bool operator[] (size_t pos) const
{
const std::size_t bytepos = (pos >> m_data_shift);
const std::size_t bitpos = (pos & m_data_mask);
return (m_d[bytepos] >> bitpos) & 1;
}
private:
typedef std::uint64_t data_type;
static constexpr std::size_t m_data_bits = sizeof(data_type) * 8;
static constexpr std::size_t m_data_shift = 6;
static constexpr std::size_t m_data_mask = (1<< m_data_shift) - 1;
std::size_t m_size;
std::size_t m_data_size;
data_type *m_d;
};
#if 0
static inline UINT32 remove_first_bit(UINT32 v)
{
@ -64,7 +125,7 @@ static inline UINT32 remove_first_bit(UINT32 v)
struct truthtable_desc_t
{
truthtable_desc_t(int NO, int NI, int has_state, bool *initialized,
UINT32 *outs, UINT8 *timing, netlist_time *timing_nt)
UINT16 *outs, UINT8 *timing, netlist_time *timing_nt)
: m_NO(NO), m_NI(NI), /*m_has_state(has_state),*/ m_initialized(initialized),
m_outs(outs), m_timing(timing), m_timing_nt(timing_nt),
m_num_bits(m_NI + has_state * (m_NI + m_NO)),
@ -86,7 +147,7 @@ private:
unsigned m_NI;
//int m_has_state;
bool *m_initialized;
UINT32 *m_outs;
UINT16 *m_outs;
UINT8 *m_timing;
netlist_time *m_timing_nt;
@ -97,23 +158,25 @@ private:
};
template<unsigned m_NI, unsigned m_NO, int has_state>
#if 1
template<unsigned m_NI, unsigned m_NO, int m_has_state>
NETLIB_OBJECT(truthtable_t)
{
private:
family_setter_t m_fam;
public:
static const int m_num_bits = m_NI + has_state * (m_NI + m_NO);
static const int m_num_bits = m_NI + m_has_state * (m_NI + m_NO);
static const int m_size = (1 << (m_num_bits));
struct truthtable_t
{
truthtable_t()
truthtable_t(size_t NI, size_t NO, bool has_state)
: m_initialized(false)
, m_desc(m_NO, m_NI, has_state, &m_initialized, m_outs, m_timing, m_timing_nt) {}
, m_desc(NO, NI, has_state, &m_initialized, m_outs, m_timing, m_timing_nt) {}
bool m_initialized;
UINT32 m_outs[m_size];
UINT16 m_outs[m_size];
//UINT32 m_outs[m_size];
UINT8 m_timing[m_size * m_NO];
netlist_time m_timing_nt[16];
truthtable_desc_t m_desc;
@ -230,7 +293,7 @@ public:
void inc_active() override
{
nl_assert(netlist().use_deactivate());
if (has_state == 0)
if (m_has_state == 0)
if (++m_active == 1)
{
process<false>();
@ -246,7 +309,7 @@ public:
* can decide for each individual gate whether it is benefitial to
* ignore deactivation.
*/
if (m_NI > 1 && has_state == 0)
if (m_NI > 1 && m_has_state == 0)
if (--m_active == 0)
{
for (std::size_t i = 0; i< m_NI; i++)
@ -270,12 +333,22 @@ private:
netlist_time mt = netlist_time::zero();
UINT32 state = 0;
if (m_NI > 1 && !has_state)
for (std::size_t i = 0; i < m_NI; i++)
if (m_NI > 1 && !m_has_state)
{
if (!doOUT)
{
if (!doOUT || (m_ign & (1<<i)))
for (std::size_t i = 0; i < m_NI; i++)
m_I[i].activate();
}
else
{
auto ign(m_ign);
for (std::size_t i = 0; ign != 0; ign >>= 1, i++)
if ((ign & 1))
m_I[i].activate();
}
}
if (!doOUT)
for (std::size_t i = 0; i < m_NI; i++)
@ -287,14 +360,18 @@ private:
for (std::size_t i = 0; i < m_NI; i++)
state |= (INPLOGIC(m_I[i]) << i);
const UINT32 nstate = state | (has_state ? (m_last_state << m_NI) : 0);
UINT32 nstate = state;
if (m_has_state)
nstate |= (m_last_state << m_NI);
const UINT32 outstate = m_ttp->m_outs[nstate];
const UINT32 out = outstate & ((1 << m_NO) - 1);
m_ign = outstate >> m_NO;
if (has_state)
m_last_state = (state << m_NO) | out;
const UINT32 timebase = nstate * m_NO;
if (doOUT)
{
for (std::size_t i = 0; i < m_NO; i++)
@ -304,10 +381,14 @@ private:
for (std::size_t i = 0; i < m_NO; i++)
m_Q[i].net().set_Q_time((out >> i) & 1, mt + m_ttp->m_timing_nt[m_ttp->m_timing[timebase + i]]);
if (m_NI > 1 && !has_state)
if (m_has_state)
m_last_state = (state << m_NO) | out;
if (m_NI > 1 && !m_has_state)
{
for (std::size_t i = 0; i < m_NI; i++)
if (m_ign & (1 << i))
auto ign(m_ign);
for (std::size_t i = 0; ign != 0; ign >>= 1, i++)
if (ign & 1)
m_I[i].inactivate();
}
}
@ -320,6 +401,286 @@ private:
plib::pstring_vector_t m_desc;
};
#else
NETLIB_OBJECT(xtruthtable_t)
{
private:
family_setter_t m_fam;
public:
struct truthtable_t
{
truthtable_t(size_t NI, size_t NO, bool has_state)
: m_initialized(false)
, m_num_bits(NI + has_state * (NI + NO))
, m_size(1 << (m_num_bits))
{
m_timing = new UINT8[m_size * NO];
m_outs = new UINT16[m_size];
m_desc = new truthtable_desc_t(NO, NI, has_state, &m_initialized, m_outs, m_timing, m_timing_nt);
}
bool m_initialized;
UINT16 *m_outs;
//UINT32 m_outs[m_size];
UINT8 *m_timing;
netlist_time m_timing_nt[16];
truthtable_desc_t *m_desc;
int m_num_bits;
int m_size;
};
template <class C>
nld_xtruthtable_t(size_t NI, size_t NO, bool has_state, C &owner, const pstring &name, const logic_family_desc_t *fam,
truthtable_t *ttbl, const char *desc[])
: device_t(owner, name)
, m_fam(*this, fam)
, m_last_state(0)
, m_ign(0)
, m_active(1)
, m_ttp(ttbl)
, m_NI(NI)
, m_NO(NO)
, m_has_state(has_state)
{
m_is_truthtable = true;
while (*desc != nullptr && **desc != 0 )
{
m_desc.push_back(*desc);
desc++;
}
startxx();
}
template <class C>
nld_xtruthtable_t(size_t NI, size_t NO, bool has_state, C &owner, const pstring &name, const logic_family_desc_t *fam,
truthtable_t *ttbl, const plib::pstring_vector_t &desc)
: device_t(owner, name)
, m_fam(*this, fam)
, m_last_state(0)
, m_ign(0)
, m_active(1)
, m_ttp(ttbl)
, m_NI(NI)
, m_NO(NO)
, m_has_state(has_state)
{
m_is_truthtable = true;
m_desc = desc;
startxx();
}
void startxx()
{
pstring header = m_desc[0];
plib::pstring_vector_t io(header,"|");
// checks
nl_assert_always(io.size() == 2, "too many '|'");
plib::pstring_vector_t inout(io[0], ",");
nl_assert_always(inout.size() == m_ttp->m_num_bits, "bitcount wrong");
plib::pstring_vector_t out(io[1], ",");
nl_assert_always(out.size() == m_NO, "output count wrong");
for (std::size_t i=0; i < m_NI; i++)
{
//new (&m_I[i]) logic_input_t();
inout[i] = inout[i].trim();
m_I.emplace(i, *this, inout[i]);
}
for (std::size_t i=0; i < m_NO; i++)
{
//new (&m_Q[i]) logic_output_t();
out[i] = out[i].trim();
m_Q.emplace(i, *this, out[i]);
//enregister(out[i], m_Q[i]);
}
// Connect output "Q" to input "_Q" if this exists
// This enables timed state without having explicit state ....
UINT32 disabled_ignore = 0;
for (std::size_t i=0; i < m_NO; i++)
{
pstring tmp = "_" + out[i];
const int idx = inout.indexof(tmp);
if (idx>=0)
{
connect_late(m_Q[i], m_I[idx]);
// disable ignore for this inputs altogether.
// FIXME: This shouldn't be necessary
disabled_ignore |= (1<<idx);
}
}
m_ign = 0;
m_ttp->m_desc->setup(m_desc, disabled_ignore * 0);
#if 0
printf("%s\n", name().cstr());
for (int j=0; j < m_size; j++)
printf("%05x %04x %04x %04x\n", j, m_ttp->m_outs[j] & ((1 << m_NO)-1),
m_ttp->m_outs[j] >> m_NO, m_ttp->m_timing[j * m_NO + 0]);
for (int k=0; m_ttp->m_timing_nt[k] != netlist_time::zero(); k++)
printf("%d %f\n", k, m_ttp->m_timing_nt[k].as_double() * 1000000.0);
#endif
save(NLNAME(m_last_state));
save(NLNAME(m_ign));
save(NLNAME(m_active));
}
NETLIB_RESETI()
{
m_active = 0;
m_ign = 0;
for (std::size_t i = 0; i < m_NI; i++)
m_I[i].activate();
for (std::size_t i=0; i<m_NO;i++)
if (this->m_Q[i].net().num_cons()>0)
m_active++;
m_last_state = 0;
}
public:
void update() noexcept override final
{
process<true>();
}
public:
void inc_active() override
{
nl_assert(netlist().use_deactivate());
if (m_has_state == 0)
if (++m_active == 1)
{
process<false>();
}
}
void dec_active() override
{
nl_assert(netlist().use_deactivate());
/* FIXME:
* Based on current measurements there is no point to disable
* 1 input devices. This should actually be a parameter so that we
* can decide for each individual gate whether it is benefitial to
* ignore deactivation.
*/
if (m_NI > 1 && m_has_state == 0)
if (--m_active == 0)
{
for (std::size_t i = 0; i< m_NI; i++)
m_I[i].inactivate();
m_ign = (1<<m_NI)-1;
}
}
//logic_input_t m_I[m_NI];
//logic_output_t m_Q[m_NO];
plib::uninitialised_array_t<logic_input_t, 16> m_I;
plib::uninitialised_array_t<logic_output_t, 8> m_Q;
protected:
private:
template<bool doOUT>
inline void process()
{
netlist_time mt = netlist_time::zero();
UINT32 state = 0;
if (m_NI > 1 && !m_has_state)
{
if (!doOUT)
{
for (std::size_t i = 0; i < m_NI; i++)
m_I[i].activate();
}
else
{
auto ign(m_ign);
for (std::size_t i = 0; ign != 0; ign >>= 1, i++)
if ((ign & 1))
m_I[i].activate();
}
}
if (!doOUT)
for (std::size_t i = 0; i < m_NI; i++)
{
state |= (INPLOGIC(m_I[i]) << i);
mt = std::max(this->m_I[i].net().time(), mt);
}
else
for (std::size_t i = 0; i < m_NI; i++)
state |= (INPLOGIC(m_I[i]) << i);
UINT32 nstate = state;
if (m_has_state)
nstate |= (m_last_state << m_NI);
const UINT32 outstate = m_ttp->m_outs[nstate];
const UINT32 out = outstate & ((1 << m_NO) - 1);
m_ign = outstate >> m_NO;
const UINT32 timebase = nstate * m_NO;
if (doOUT)
{
for (std::size_t i = 0; i < m_NO; i++)
OUTLOGIC(m_Q[i], (out >> i) & 1, m_ttp->m_timing_nt[m_ttp->m_timing[timebase + i]]);
}
else
for (std::size_t i = 0; i < m_NO; i++)
m_Q[i].net().set_Q_time((out >> i) & 1, mt + m_ttp->m_timing_nt[m_ttp->m_timing[timebase + i]]);
if (m_has_state)
m_last_state = (state << m_NO) | out;
if (m_NI > 1 && !m_has_state)
{
auto ign(m_ign);
for (std::size_t i = 0; ign != 0; ign >>= 1, i++)
if (ign & 1)
m_I[i].inactivate();
}
}
UINT32 m_last_state;
UINT32 m_ign;
INT32 m_active;
truthtable_t *m_ttp;
size_t m_NI;
size_t m_NO;
bool m_has_state;
plib::pstring_vector_t m_desc;
};
template<unsigned NI, unsigned NO, int has_state>
NETLIB_OBJECT_DERIVED(truthtable_t, xtruthtable_t)
{
public:
template <class C>
nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam,
truthtable_t *ttbl, const char *desc[])
: nld_xtruthtable_t(NI, NO, has_state, owner, name, fam, ttbl, desc)
{
}
template <class C>
nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam,
truthtable_t *ttbl, const plib::pstring_vector_t &desc)
: nld_xtruthtable_t(NI, NO, has_state, owner, name, fam, ttbl, desc)
{
}
};
#endif
class netlist_base_factory_truthtable_t : public base_factory_t
{
P_PREVENT_COPYING(netlist_base_factory_truthtable_t)
@ -337,25 +698,6 @@ public:
const logic_family_desc_t *m_family;
};
template<unsigned m_NI, unsigned m_NO, int has_state>
class netlist_factory_truthtable_t : public netlist_base_factory_truthtable_t
{
P_PREVENT_COPYING(netlist_factory_truthtable_t)
public:
netlist_factory_truthtable_t(const pstring &name, const pstring &classname,
const pstring &def_param)
: netlist_base_factory_truthtable_t(name, classname, def_param) { }
plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override
{
typedef nld_truthtable_t<m_NI, m_NO, has_state> tt_type;
return plib::owned_ptr<device_t>::Create<tt_type>(anetlist, name, m_family, &m_ttbl, m_desc);
}
private:
typename nld_truthtable_t<m_NI, m_NO, has_state>::truthtable_t m_ttbl;
};
plib::owned_ptr<netlist_base_factory_truthtable_t> nl_tt_factory_create(const unsigned ni, const unsigned no,
const unsigned has_state,
const pstring &name, const pstring &classname,

View File

@ -12,6 +12,7 @@
#include "nl_base.h"
#include "devices/nlid_system.h"
#include "devices/nld_truthtable.h"
#include "nl_util.h"
namespace netlist
@ -430,6 +431,7 @@ core_device_t::core_device_t(netlist_t &owner, const pstring &name)
, stat_call_count(0)
#endif
{
m_is_truthtable = false;
if (logic_family() == nullptr)
set_logic_family(family_TTL());
}
@ -443,6 +445,7 @@ core_device_t::core_device_t(core_device_t &owner, const pstring &name)
, stat_call_count(0)
#endif
{
m_is_truthtable = false;
set_logic_family(owner.logic_family());
if (logic_family() == nullptr)
set_logic_family(family_TTL());
@ -675,7 +678,15 @@ void net_t::update_devs()
{
inc_stat(p.device().stat_call_count);
if ((p.state() & mask) != 0)
p.device().update_dev();
{
//if (0 && p.device().m_is_truthtable)
{
/* inlining doesn't help, this kills performance */
//reinterpret_cast<devices::nld_xtruthtable_t &>(p.device()).update();
}
//else
p.device().update_dev();
}
}
}

View File

@ -888,6 +888,7 @@ namespace netlist
INT32 stat_call_count;
#endif
bool m_is_truthtable;
protected:
virtual void update() NOEXCEPT { }

View File

@ -12,30 +12,10 @@
#define FAST_CLOCK (1)
#ifndef __PLIB_PREPROCESSOR__
#if 0
#define TTL_7400A_NAND(_name, _A, _B) TTL_7400_NAND(_name, _A, _B)
#else
#define TTL_7400A_NAND(_name, _A, _B) \
NET_REGISTER_DEV(TTL_7400A_NAND, _name) \
NET_CONNECT(_name, A, _A) \
NET_CONNECT(_name, B, _B)
#endif
#endif
NETLIST_START(lib)
TRUTHTABLE_START(TTL_7400A_NAND, 2, 1, 0, "A,B")
TT_HEAD(" A , B | Q ")
TT_LINE(" 0 , X | 1 |22")
TT_LINE(" X , 0 | 1 |22")
TT_LINE(" 1 , 1 | 0 |15")
TRUTHTABLE_END()
NETLIST_END()
NETLIST_START(pong_fast)
LOCAL_SOURCE(lib)
INCLUDE(lib)
SOLVER(Solver, 48000)
PARAM(Solver.PARALLEL, 0) // Don't do parallel solvers
PARAM(Solver.ACCURACY, 1e-4) // works and is sufficient
@ -144,7 +124,7 @@ NETLIST_START(pong_fast)
/* hit logic */
TTL_7404_INVERT(hitQ, hit)
TTL_7400A_NAND(hit, hit1Q, hit2Q)
TTL_7400_NAND(hit, hit1Q, hit2Q)
TTL_7402_NOR(attractQ, StopG, runQ)
TTL_7404_INVERT(attract, attractQ)
@ -152,22 +132,22 @@ NETLIST_START(pong_fast)
TTL_7420_NAND(ic_h6a, hvidQ, hvidQ, hvidQ, hvidQ)
ALIAS(hvid, ic_h6a.Q)
TTL_7400A_NAND(ic_e6c, hvid, hblank)
TTL_7400_NAND(ic_e6c, hvid, hblank)
ALIAS(MissQ, ic_e6c.Q)
TTL_7404_INVERT(ic_d1e, MissQ)
TTL_7400A_NAND(ic_e1a, ic_d1e.Q, attractQ)
TTL_7400_NAND(ic_e1a, ic_d1e.Q, attractQ)
ALIAS(Missed, ic_e1a.Q)
TTL_7400A_NAND(rstspeed, SRSTQ, MissQ)
TTL_7400A_NAND(StopG, StopG1Q, StopG2Q)
TTL_7400_NAND(rstspeed, SRSTQ, MissQ)
TTL_7400_NAND(StopG, StopG1Q, StopG2Q)
ALIAS(L, ic_h3b.Q)
ALIAS(R, ic_h3b.QQ)
TTL_7400A_NAND(hit1Q, pad1, ic_g1b.Q)
TTL_7400A_NAND(hit2Q, pad2, ic_g1b.Q)
TTL_7400_NAND(hit1Q, pad1, ic_g1b.Q)
TTL_7400_NAND(hit2Q, pad2, ic_g1b.Q)
TTL_7400A_NAND(ic_g3c, 128H, ic_h3a.QQ)
TTL_7400_NAND(ic_g3c, 128H, ic_h3a.QQ)
TTL_7427_NOR(ic_g2c, ic_g3c.Q, 256H, vpad1Q)
ALIAS(pad1, ic_g2c.Q)
TTL_7427_NOR(ic_g2a, ic_g3c.Q, 256HQ, vpad2Q)
@ -217,15 +197,15 @@ NETLIST_START(pong_fast)
// hblank flip flop
// ----------------------------------------------------------------------------------------
TTL_7400A_NAND(ic_g5b, 16H, 64H)
TTL_7400_NAND(ic_g5b, 16H, 64H)
// the time critical one
TTL_7400A_NAND(ic_h5c, ic_h5b.Q, hresetQ)
TTL_7400A_NAND(ic_h5b, ic_h5c.Q, ic_g5b.Q)
TTL_7400_NAND(ic_h5c, ic_h5b.Q, hresetQ)
TTL_7400_NAND(ic_h5b, ic_h5c.Q, ic_g5b.Q)
ALIAS(hblank, ic_h5c.Q)
ALIAS(hblankQ, ic_h5b.Q)
TTL_7400A_NAND(hsyncQ, hblank, 32H)
TTL_7400_NAND(hsyncQ, hblank, 32H)
// ----------------------------------------------------------------------------------------
// vblank flip flop
@ -236,7 +216,7 @@ NETLIST_START(pong_fast)
ALIAS(vblank, ic_f5d.Q)
ALIAS(vblankQ, ic_f5c.Q)
TTL_7400A_NAND(ic_h5a, 8V, 8V)
TTL_7400_NAND(ic_h5a, 8V, 8V)
TTL_7410_NAND(ic_g5a, vblank, 4V, ic_h5a.Q)
ALIAS(vsyncQ, ic_g5a.Q)
@ -244,31 +224,31 @@ NETLIST_START(pong_fast)
// move logic
// ----------------------------------------------------------------------------------------
TTL_7400A_NAND(ic_e1d, hit_sound, ic_e1c.Q)
TTL_7400A_NAND(ic_e1c, ic_f1.QC, ic_f1.QD)
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_7400A_NAND(ic_h1a, ic_g1d.Q, ic_g1d.Q)
TTL_7400A_NAND(ic_h1d, ic_e1c.Q, ic_h1a.Q)
TTL_7400_NAND(ic_h1a, ic_g1d.Q, ic_g1d.Q)
TTL_7400_NAND(ic_h1d, ic_e1c.Q, ic_h1a.Q)
TTL_7400A_NAND(ic_h1c, ic_h1d.Q, vreset)
TTL_7400A_NAND(ic_h1b, ic_h1a.Q, vreset)
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_7400A_NAND(ic_h4a, ic_h2b.Q, ic_h2a.Q)
TTL_7400_NAND(ic_h4a, ic_h2b.Q, ic_h2a.Q)
ALIAS(move, ic_h4a.Q)
TTL_7400A_NAND(ic_c1d, SC, attract)
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_7400A_NAND(ic_h4d, ic_h3b.Q, move)
TTL_7400A_NAND(ic_h4b, ic_h3b.QQ, move)
TTL_7400A_NAND(ic_h4c, ic_h4d.Q, ic_h4b.Q)
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)
ALIAS(Aa, ic_h4c.Q)
ALIAS(Ba, ic_h4b.Q)
@ -276,7 +256,7 @@ NETLIST_START(pong_fast)
// hvid circuit
// ----------------------------------------------------------------------------------------
TTL_7400A_NAND(hball_resetQ, Serve, attractQ)
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)
@ -291,7 +271,7 @@ NETLIST_START(pong_fast)
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_7400A_NAND(ic_b2b, ic_a3.RC, ic_b3.RC)
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)
ALIAS(vvidQ, ic_e2b.Q)
TTL_7404_INVERT(vvid, vvidQ) // D2D
@ -383,12 +363,12 @@ NETLIST_START(pong_fast)
NET_C(GND, ic_g4_C.2)
ALIAS(hit_sound_en, ic_c2a.QQ)
TTL_7400A_NAND(hit_sound, hit_sound_en, vpos16)
TTL_7400A_NAND(score_sound, SC, vpos32)
TTL_7400A_NAND(topbothitsound, ic_f3_topbot.Q, vpos32)
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_7400A_NAND(ic_c1b, ic_c4b.Q, attractQ)
TTL_7400_NAND(ic_c1b, ic_c4b.Q, attractQ)
ALIAS(sound, ic_c1b.Q)
@ -422,9 +402,9 @@ NETLIST_START(pong_fast)
NET_C(GND, ic_b9_C.2)
TTL_7404_INVERT(ic_c9b, ic_b9.OUT)
TTL_7400A_NAND(ic_b7b, ic_a7b.Q, hsyncQ)
TTL_7400_NAND(ic_b7b, ic_a7b.Q, hsyncQ)
TTL_7493(ic_b8, ic_b7b.Q, ic_b8.QA, ic_b9.OUT, ic_b9.OUT)
TTL_7400A_NAND(ic_b7a, ic_c9b.Q, ic_a7b.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)
ALIAS(vpad1Q, ic_b7a.Q)
@ -462,9 +442,9 @@ NETLIST_START(pong_fast)
NET_C(GND, ic_a9_C.2)
TTL_7404_INVERT(ic_c9a, ic_a9.OUT)
TTL_7400A_NAND(ic_b7c, ic_a7a.Q, hsyncQ)
TTL_7400_NAND(ic_b7c, ic_a7a.Q, hsyncQ)
TTL_7493(ic_a8, ic_b7c.Q, ic_a8.QA, ic_a9.OUT, ic_a9.OUT)
TTL_7400A_NAND(ic_b7d, ic_c9a.Q, ic_a7a.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)
ALIAS(vpad2Q, ic_b7d.Q)
@ -544,8 +524,8 @@ NETLIST_START(pong_fast)
TTL_7427_NOR(ic_e5c, ic_e4b.Q, 8H, 4H)
ALIAS(scoreFE, ic_e5c.Q)
TTL_7400A_NAND(ic_c3d, 8H, 4H)
//TTL_7400A_NAND(ic_c3d, 4H, 8H)
TTL_7400_NAND(ic_c3d, 8H, 4H)
//TTL_7400_NAND(ic_c3d, 4H, 8H)
TTL_7402_NOR(ic_d2b, ic_e4b.Q, ic_c3d.Q)
ALIAS(scoreBC, ic_d2b.Q)
@ -571,7 +551,7 @@ NETLIST_START(pong_fast)
// net
TTL_74107(ic_f3b, clk, 256H, 256HQ, high)
TTL_7400A_NAND(ic_g3b, ic_f3b.QQ, 256H)
TTL_7400_NAND(ic_g3b, ic_f3b.QQ, 256H)
TTL_7427_NOR(ic_g2b, ic_g3b.Q, vblank, 4V)
ALIAS(net, ic_g2b.Q)