diff --git a/src/lib/netlist/devices/nld_7448.cpp b/src/lib/netlist/devices/nld_7448.cpp index a4b358c3da5..9353c758bbc 100644 --- a/src/lib/netlist/devices/nld_7448.cpp +++ b/src/lib/netlist/devices/nld_7448.cpp @@ -12,7 +12,7 @@ namespace netlist { namespace devices { - #if (USE_TRUTHTABLE_7448 && USE_TRUTHTABLE) + #if (USE_TRUTHTABLE_7448) NETLIB_TRUTHTABLE(7448, 7, 7); @@ -78,9 +78,9 @@ namespace netlist #endif - #if (USE_TRUTHTABLE_7448 && USE_TRUTHTABLE) + #if (USE_TRUTHTABLE_7448) nld_7448::truthtable_t nld_7448::m_ttbl; - const pstring nld_7448::m_desc[] = { + std::vector nld_7448::m_desc = { " LTQ,BIQ,RBIQ, A , B , C , D | a, b, c, d, e, f, g", " 1, 1, 1, 0, 0, 0, 0 | 1, 1, 1, 1, 1, 1, 0|100,100,100,100,100,100,100", diff --git a/src/lib/netlist/devices/nld_7448.h b/src/lib/netlist/devices/nld_7448.h index 801b7fdb2f4..89528707bc1 100644 --- a/src/lib/netlist/devices/nld_7448.h +++ b/src/lib/netlist/devices/nld_7448.h @@ -26,14 +26,6 @@ #include "../nl_setup.h" -/* - * FIXME: Using truthtable is a lot slower than the explicit device - * in breakout. Performance drops by 20%. This can be fixed by - * setting param USE_DEACTIVATE for the device. - */ - -#define USE_TRUTHTABLE_7448 (0) - #ifndef NL_AUTO_DEVICES #define TTL_7448(name, cA0, cA1, cA2, cA3, cLTQ, cBIQ, cRBIQ) \ diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp index 55aa79b0457..96bf085ff1e 100755 --- a/src/lib/netlist/devices/nlid_truthtable.cpp +++ b/src/lib/netlist/devices/nlid_truthtable.cpp @@ -10,31 +10,101 @@ #include "../nl_setup.h" #include "../plib/palloc.h" +#include + namespace netlist { namespace devices { // ---------------------------------------------------------------------------------------- - // Truthtable description .... + // int compatible bitset .... // ---------------------------------------------------------------------------------------- + template + struct sbitset + { + typedef T type; + + sbitset() : m_bs(0) { } + sbitset(T v) : m_bs(v) { } + + sbitset &set() { *this = all_bits(); return *this; } + sbitset &set(const std::size_t bit) { m_bs |= (static_cast(1) << bit); return *this; } + sbitset &reset() { *this = no_bits(); return *this; } + sbitset &reset(const std::size_t bit) { m_bs &= ~(static_cast(1) << bit); return *this; } + + sbitset invert() const { return sbitset(~m_bs); } + std::size_t count() + { + std::size_t ret = 0; + for (T v = m_bs; v != 0; v = v >> 1) + { + ret += (v & 1); + } + return ret; + } + constexpr bool test(const std::size_t bit) const { return ((m_bs >> bit) & 1) == 1; } + + operator T&() { return m_bs; } + operator const T&() const { return m_bs; } + constexpr T as_uint() const { return m_bs; } + + constexpr bool all() const { return *this == all_bits(); } + + /* + * And all bits set with compressed bits from b + * + * Example: b = {b3,b2,b1,b0} + * v = {v7, 0, v5, 0, v3, v2, 0, 0} + * Returns {v7 & b3, 0, v5 & b2, 0, v3 & b1, v2 & b0, 0, 0} + */ + + sbitset expand_and(sbitset b) const + { + sbitset ret; + T v( m_bs); + + for (size_t i = 0; v != 0; v = v >> 1, ++i) + { + if (v & 1) + { + if (b.test(0)) + ret.set(i); + b = b >> 1; + } + } + return ret; + } + + static constexpr sbitset all_bits() { return sbitset(~static_cast(0)); } + static constexpr sbitset no_bits() { return sbitset(static_cast(0)); } + private: + T m_bs; + }; + // ---------------------------------------------------------------------------------------- + // Truthtable parsing .... + // ---------------------------------------------------------------------------------------- + + //static const uint_least64_t all_set = ~(static_cast(0)); + + using tt_bitset = sbitset; + struct packed_int { - template - packed_int(C *data) + packed_int(void *data, std::size_t bits) : m_data(data) - , m_size(sizeof(C)) + , m_size(bits) {} void set(const size_t pos, const uint_least64_t val) { switch (m_size) { - case 1: static_cast(m_data)[pos] = static_cast(val); break; - case 2: static_cast(m_data)[pos] = static_cast(val); break; - case 4: static_cast(m_data)[pos] = static_cast(val); break; - case 8: static_cast(m_data)[pos] = static_cast(val); break; + case 8: static_cast(m_data)[pos] = static_cast(val); break; + case 16: static_cast(m_data)[pos] = static_cast(val); break; + case 32: static_cast(m_data)[pos] = static_cast(val); break; + case 64: static_cast(m_data)[pos] = static_cast(val); break; default: { } } } @@ -43,37 +113,25 @@ namespace netlist { switch (m_size) { - case 1: return static_cast(m_data)[pos]; - case 2: return static_cast(m_data)[pos]; - case 4: return static_cast(m_data)[pos]; - case 8: return static_cast(m_data)[pos]; + case 8: return static_cast(m_data)[pos]; + case 16: return static_cast(m_data)[pos]; + case 32: return static_cast(m_data)[pos]; + case 64: return static_cast(m_data)[pos]; default: return 0; //should never happen } } - uint_least64_t adjust(uint_least64_t val) const - { - switch (m_size) - { - case 1: return static_cast(val); - case 2: return static_cast(val); - case 4: return static_cast(val); - case 8: return static_cast(val); - default: - return 0; //should never happen - } - } + uint_least64_t mask() const { return (static_cast(1) << m_size) - 1; } + private: void *m_data; size_t m_size; }; - static const uint_least64_t one64 = static_cast(1); - - struct truthtable_desc_t + struct truthtable_parser { - truthtable_desc_t(unsigned NO, unsigned NI, bool *initialized, + truthtable_parser(unsigned NO, unsigned NI, bool *initialized, packed_int outs, uint_least8_t *timing, netlist_time *timing_nt) : m_NO(NO), m_NI(NI), m_initialized(initialized), m_outs(outs), m_timing(timing), m_timing_nt(timing_nt), @@ -82,15 +140,13 @@ namespace netlist { } - void setup(const std::vector &desc, uint_least64_t disabled_ignore); + void parse(const std::vector &desc, uint_least64_t disabled_ignore); private: - void help(unsigned cur, std::vector list, - uint_least64_t state, uint_least64_t val, std::vector &timing_index); - static unsigned count_bits(uint_least64_t v); - static uint_least64_t set_bits(uint_least64_t v, uint_least64_t b); - uint_least64_t get_ignored_simple(uint_least64_t i); - uint_least64_t get_ignored_extended(uint_least64_t i); + void parseline(unsigned cur, std::vector list, + tt_bitset state, uint_least64_t val, std::vector &timing_index); + + tt_bitset calculate_ignored_inputs(tt_bitset i); unsigned m_NO; unsigned m_NI; @@ -106,30 +162,16 @@ namespace netlist }; - template - template - nld_truthtable_t::nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam, - truthtable_t *ttp, const pstring *desc) - : device_t(owner, name) - , m_fam(*this, fam) - , m_ign(*this, "m_ign", 0) - , m_active(*this, "m_active", 1) - , m_ttp(ttp) - { - while (*desc != "" ) - { - m_desc.push_back(*desc); - desc++; - } - init(); - } + // ---------------------------------------------------------------------------------------- + // Truthtable class .... + // ---------------------------------------------------------------------------------------- - template - void NETLIB_NAME(truthtable_t)::init() + template + void NETLIB_NAME(truthtable_t)::init(const std::vector &desc) { set_hint_deactivate(true); - pstring header = m_desc[0]; + pstring header = desc[0]; std::vector io(plib::psplit(header,"|")); // checks @@ -151,7 +193,7 @@ namespace netlist } // Connect output "Q" to input "_Q" if this exists // This enables timed state without having explicit state .... - uint_least64_t disabled_ignore = 0; + tt_bitset disabled_ignore = 0; for (std::size_t i=0; i < m_NO; i++) { pstring tmp = "_" + out[i]; @@ -159,19 +201,19 @@ namespace netlist if (idx != plib::container::npos) { connect(m_Q[i], m_I[idx]); - // disable ignore for this inputs altogether. + // disable ignore for theses inputs altogether. // FIXME: This shouldn't be necessary - disabled_ignore |= (one64 << idx); + disabled_ignore.set(idx); } } m_ign = 0; - truthtable_desc_t desc(m_NO, m_NI, &m_ttp->m_initialized, - packed_int(m_ttp->m_outs), + truthtable_parser desc_s(m_NO, m_NI, &m_ttp->m_initialized, + packed_int(m_ttp->m_outs, sizeof(m_ttp->m_outs[0]) * 8), m_ttp->m_timing, m_ttp->m_timing_nt); - desc.setup(m_desc, disabled_ignore * 0); + desc_s.parse(desc, disabled_ignore * 0); #if 0 printf("%s\n", name().c_str()); for (int j=0; j < m_size; j++) @@ -182,11 +224,6 @@ namespace netlist #endif } - // ---------------------------------------------------------------------------------------- - // Truthtable class .... - // ---------------------------------------------------------------------------------------- - - // ---------------------------------------------------------------------------------------- // Truthtable factory .... // ---------------------------------------------------------------------------------------- @@ -209,96 +246,71 @@ namespace netlist typename nld_truthtable_t::truthtable_t m_ttbl; }; - static const uint_least64_t all_set = ~(static_cast(0)); - -unsigned truthtable_desc_t::count_bits(uint_least64_t v) -{ - unsigned ret = 0; - for (; v != 0; v = v >> 1) + tt_bitset truthtable_parser::calculate_ignored_inputs(tt_bitset state) { - ret += (v & 1); - } - return ret; -} - -uint_least64_t truthtable_desc_t::set_bits(uint_least64_t v, uint_least64_t b) -{ - uint_least64_t ret = 0; - for (size_t i = 0; v != 0; v = v >> 1, ++i) - { - if (v & 1) + // Determine all inputs which may be ignored ... + tt_bitset ignore = 0; + for (std::size_t j=0; j> 1; + // if changing the input directly doesn't change outputs we can ignore + if (m_outs[state] == m_outs[tt_bitset(state).set(j)]) + ignore.set(j); } - } - return ret; -} -uint_least64_t truthtable_desc_t::get_ignored_simple(uint_least64_t i) -{ - uint_least64_t m_enable = 0; - for (uint_least64_t j=0; j t(bits); + + // loop over all combinations of bits set in ignore + for (uint_least64_t j=1; j < bits; j++) { - m_enable |= (i ^ j); - } - } - return m_enable ^ (m_size - 1); -} + tt_bitset tign = ignore.expand_and(j); + t[j] = false; + tt_bitset bitsk = tt_bitset().set(tign.count()); -uint_least64_t truthtable_desc_t::get_ignored_extended(uint_least64_t state) -{ - // Determine all inputs which may be ignored ... - uint_least64_t ignore = 0; - for (std::size_t j=0; j t(bits); + // now loop over all combinations of the bits set currently set - for (size_t j=1; jjb)) + + /* find the ignore mask without potential for change with the most bits */ + + size_t jb=0; + tt_bitset jm=0; + + for (uint_least64_t j=1; jjb)) + { + jb = nb; + jm = bj; + } } + return ignore.expand_and(jm); } - return set_bits(ignore, jm); -} // ---------------------------------------------------------------------------------------- -// desc +// parseline // ---------------------------------------------------------------------------------------- -void truthtable_desc_t::help(unsigned cur, std::vector list, - uint_least64_t state, uint_least64_t val, std::vector &timing_index) +void truthtable_parser::parseline(unsigned cur, std::vector list, + tt_bitset state, uint_least64_t val, std::vector &timing_index) { pstring elem = list[cur].trim(); uint_least64_t start = 0; @@ -323,26 +335,28 @@ void truthtable_desc_t::help(unsigned cur, std::vector list, nl_assert_always(false, "unknown input value (not 0, 1, or X)"); for (uint_least64_t i = start; i <= end; i++) { - const uint_least64_t nstate = state | (i << cur); + tt_bitset nstate = state; + if (i==1) + nstate.set(cur); if (cur < m_num_bits - 1) { - help(cur + 1, list, nstate, val, timing_index); + parseline(cur + 1, list, nstate, val, timing_index); } else { // cutoff previous inputs and outputs for ignore - if (m_outs[nstate] != m_outs.adjust(all_set) && m_outs[nstate] != val) + if (m_outs[nstate] != m_outs.mask() && m_outs[nstate] != val) nl_exception(plib::pfmt("Error in truthtable: State {1} already set, {2} != {3}\n") - .x(nstate,"04")(m_outs[nstate])(val) ); + .x(nstate.as_uint(),"04")(m_outs[nstate])(val) ); m_outs.set(nstate, val); - for (unsigned j=0; j &truthtable, uint_least64_t disabled_ignore) +void truthtable_parser::parse(const std::vector &truthtable, uint_least64_t disabled_ignore) { unsigned line = 0; @@ -355,7 +369,7 @@ void truthtable_desc_t::setup(const std::vector &truthtable, uint_least line++; for (unsigned j=0; j < m_size; j++) - m_outs.set(j, all_set); + m_outs.set(j, tt_bitset::all_bits()); for (int j=0; j < 16; j++) m_timing_nt[j] = netlist_time::zero(); @@ -372,14 +386,19 @@ void truthtable_desc_t::setup(const std::vector &truthtable, uint_least std::vector times(plib::psplit(io[2], ",")); nl_assert_always(times.size() == m_NO, "timing count not matching"); - uint_least64_t val = 0; + tt_bitset val = 0; std::vector tindex; + /* + * FIXME: evaluation of outputs should be done in parseline to + * enable the use of inputs for output values, i.e. "I1" or "~I1" + * in addition to "0" and "1". + */ for (unsigned j=0; j(times[j].trim().as_long())); @@ -390,7 +409,7 @@ void truthtable_desc_t::setup(const std::vector &truthtable, uint_least tindex.push_back(k); //[j] = k; } - help(0, inout, 0 , val, tindex); + parseline(0, inout, 0 , val, tindex); if (line < truthtable.size()) ttline = truthtable[line]; else @@ -398,37 +417,34 @@ void truthtable_desc_t::setup(const std::vector &truthtable, uint_least line++; } - // determine ignore - std::vector ign(m_size, all_set); + // determine ignore mask by looping over all input combinations + std::vector ign(m_size); + for (tt_bitset &x : ign) + x.set(); - for (uint_least64_t i=0; i(desc.name, desc.classname, desc.def_param, s); } break #define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \ - ENTRYY(n, 4, s); ENTRYY(n, 5, s); ENTRYY(n, 6, s) + ENTRYY(n, 4, s); ENTRYY(n, 5, s); ENTRYY(n, 6, s); \ + ENTRYY(n, 7, s); ENTRYY(n, 8, s) void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile) { diff --git a/src/lib/netlist/devices/nlid_truthtable.h b/src/lib/netlist/devices/nlid_truthtable.h index 040372f1c4a..2ffd2dd7396 100644 --- a/src/lib/netlist/devices/nlid_truthtable.h +++ b/src/lib/netlist/devices/nlid_truthtable.h @@ -23,7 +23,7 @@ : nld_truthtable_t(owner, name, family_TTL(), &m_ttbl, m_desc) { } \ private: \ static truthtable_t m_ttbl; \ - static const pstring m_desc[]; \ + static std::vector m_desc; \ } @@ -49,15 +49,18 @@ namespace netlist template<> struct uint_for_size<4> { typedef uint_least32_t type; }; template<> struct uint_for_size<8> { typedef uint_least64_t type; }; - template + template NETLIB_OBJECT(truthtable_t) { private: detail::family_setter_t m_fam; public: - static constexpr int m_num_bits = m_NI; - static constexpr int m_size = (1 << (m_num_bits)); + typedef typename uint_for_size::value>::type type_t; + + static constexpr std::size_t m_num_bits = m_NI; + static constexpr std::size_t m_size = (1 << (m_num_bits)); + static constexpr type_t m_outmask = ((1 << m_NO) - 1); struct truthtable_t { @@ -65,15 +68,11 @@ namespace netlist : m_initialized(false) {} bool m_initialized; - typename uint_for_size::value>::type m_outs[m_size]; + type_t m_outs[m_size]; uint_least8_t m_timing[m_size * m_NO]; netlist_time m_timing_nt[16]; }; - template - nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam, - truthtable_t *ttp, const pstring *desc); - template nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam, truthtable_t *ttp, const std::vector &desc) @@ -83,11 +82,10 @@ namespace netlist , m_active(*this, "m_active", 1) , m_ttp(ttp) { - m_desc = desc; - init(); + init(desc); } - void init(); + void init(const std::vector &desc); NETLIB_RESETI() { @@ -105,7 +103,6 @@ namespace netlist process(); } - public: void inc_active() NL_NOEXCEPT override { if (m_NI > 1) @@ -132,8 +129,6 @@ namespace netlist } } - //logic_input_t m_I[m_NI]; - //logic_output_t m_Q[m_NO]; plib::uninitialised_array_t m_I; plib::uninitialised_array_t m_Q; @@ -146,69 +141,78 @@ namespace netlist { netlist_time mt = netlist_time::zero(); - uint_least64_t state = 0; + type_t nstate = 0; if (m_NI > 1) { - auto ign = m_ign; + type_t ign = m_ign; if (!doOUT) for (std::size_t i = 0; i < m_NI; i++) { m_I[i].activate(); - state |= (m_I[i]() << i); + nstate |= (m_I[i]() << i); mt = std::max(this->m_I[i].net().time(), mt); } else - for (std::size_t i = 0; i < m_NI; ign >>= 1, i++) + for (std::size_t i = 0; i < m_NI; i++) { if ((ign & 1)) m_I[i].activate(); - state |= (m_I[i]() << i); + nstate |= (m_I[i]() << i); + ign >>= 1; } } else { if (!doOUT) - for (std::size_t i = 0; i < m_NI; i++) - { - state |= (m_I[i]() << i); - mt = std::max(this->m_I[i].net().time(), mt); - } + { + nstate |= m_I[0](); + mt = std::max(this->m_I[0].net().time(), mt); + } else - for (std::size_t i = 0; i < m_NI; i++) - state |= (m_I[i]() << i); + nstate |= m_I[0](); } - auto nstate = state; - const auto outstate = m_ttp->m_outs[nstate]; - const auto out = outstate & ((1 << m_NO) - 1); + const type_t outstate = m_ttp->m_outs[nstate]; + type_t out = outstate & m_outmask; m_ign = outstate >> m_NO; - const auto timebase = nstate * m_NO; + const std::size_t timebase = nstate * m_NO; if (doOUT) { - for (std::size_t i = 0; i < m_NO; i++) - m_Q[i].push((out >> i) & 1, m_ttp->m_timing_nt[m_ttp->m_timing[timebase + i]]); + auto *t = &m_ttp->m_timing[timebase]; + for (std::size_t i = 0; i < m_NO; ++i) + { + m_Q[i].push(out & 1, m_ttp->m_timing_nt[*t]); + ++t; + out >>= 1; + } } 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]]); + { + auto *t = &m_ttp->m_timing[timebase]; + for (std::size_t i = 0; i < m_NO; ++i) + { + m_Q[i].net().set_Q_time(out & 1, mt + m_ttp->m_timing_nt[*t]); + ++t; + out >>= 1; + } + } if (m_NI > 1) { - auto ign(m_ign); - for (std::size_t i = 0; ign != 0; ign >>= 1, i++) + type_t ign(m_ign); + for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I) if (ign & 1) - m_I[i].inactivate(); + I->inactivate(); } } /* FIXME: check width */ - state_var_u32 m_ign; + state_var m_ign; state_var_s32 m_active; truthtable_t * m_ttp; - std::vector m_desc; }; class netlist_base_factory_truthtable_t : public factory::element_t diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 9f2ecd098cd..1984380e583 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -29,7 +29,8 @@ // ---------------------------------------------------------------------------------------- /*! netlist_sig_t is the type used for logic signals. */ -using netlist_sig_t = std::uint32_t; +//using netlist_sig_t = std::uint32_t; +using netlist_sig_t = std::uint8_t; //============================================================ // MACROS / New Syntax diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index 57b6a03f031..47a1c9131d7 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -31,7 +31,13 @@ */ #define USE_MEMPOOL (0) -#define USE_TRUTHTABLE (1) +/* + * FIXME: Using truthtable is a lot slower than the explicit device + * in breakout. Performance drops by 20%. This can be fixed by + * setting param USE_DEACTIVATE for the device. + */ + +#define USE_TRUTHTABLE_7448 (1) // How many times do we try to resolve links (connections) #define NL_MAX_LINK_RESOLVE_LOOPS (100) diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index 8da1f2c5423..e5edfd189ed 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -28,6 +28,10 @@ template class uninitialised_array_t { public: + + typedef C* iterator; + typedef const C* const_iterator; + uninitialised_array_t() { } @@ -38,7 +42,7 @@ public: (*this)[i].~C(); } - size_t size() { return N; } + size_t size() const { return N; } C& operator[](const std::size_t &index) noexcept { @@ -57,6 +61,15 @@ public: new (&m_buf[index]) C(std::forward(args)...); } + iterator begin() const noexcept { return reinterpret_cast(&m_buf[0]); } + iterator end() const noexcept { return reinterpret_cast(&m_buf[N]); } + + iterator begin() noexcept { return reinterpret_cast(&m_buf[0]); } + iterator end() noexcept { return reinterpret_cast(&m_buf[N]); } + + const_iterator cbegin() const noexcept { return reinterpret_cast(&m_buf[0]); } + const_iterator cend() const noexcept { return reinterpret_cast(&m_buf[N]); } + protected: private: