1 // license:GPL-2.0+ 2 // copyright-holders:Couriersud 3 4 /// 5 /// \file param.h 6 /// 7 8 #ifndef NL_CORE_LOGIC_H_ 9 #define NL_CORE_LOGIC_H_ 10 11 #include "../nltypes.h" 12 #include "base_objects.h" 13 #include "logic_family.h" 14 #include "nets.h" 15 #include "state_var.h" 16 17 #include "../plib/plists.h" 18 #include "../plib/pstring.h" 19 20 #include <array> 21 #include <utility> 22 23 namespace netlist 24 { 25 // ----------------------------------------------------------------------------- 26 // logic_t 27 // ----------------------------------------------------------------------------- 28 29 class logic_t : public detail::core_terminal_t, public logic_family_t 30 { 31 public: 32 logic_t(device_t &dev, const pstring &aname, 33 state_e terminal_state, nldelegate delegate); 34 net()35 logic_net_t & net() noexcept 36 { 37 return plib::downcast<logic_net_t &>(core_terminal_t::net()); 38 } net()39 const logic_net_t & net() const noexcept 40 { 41 return plib::downcast<const logic_net_t &>(core_terminal_t::net()); 42 } 43 }; 44 45 // ----------------------------------------------------------------------------- 46 // logic_input_t 47 // ----------------------------------------------------------------------------- 48 49 class logic_input_t : public logic_t 50 { 51 public: 52 logic_input_t(device_t &dev, const pstring &aname, 53 nldelegate delegate); 54 operator()55 const netlist_sig_t &operator()() const noexcept 56 { 57 gsl_Expects(terminal_state() != STATE_INP_PASSIVE); 58 #if NL_USE_COPY_INSTEAD_OF_REFERENCE 59 return m_Q; 60 #else 61 return net().Q(); 62 #endif 63 } 64 inactivate()65 void inactivate() noexcept 66 { 67 if (!is_state(STATE_INP_PASSIVE)) 68 { 69 set_state(STATE_INP_PASSIVE); 70 net().remove_from_active_list(*this); 71 } 72 } 73 activate()74 void activate() noexcept 75 { 76 if (is_state(STATE_INP_PASSIVE)) 77 { 78 net().add_to_active_list(*this); 79 set_state(STATE_INP_ACTIVE); 80 } 81 } 82 activate_hl()83 void activate_hl() noexcept 84 { 85 if (is_state(STATE_INP_PASSIVE)) 86 { 87 net().add_to_active_list(*this); 88 set_state(STATE_INP_HL); 89 } 90 } 91 activate_lh()92 void activate_lh() noexcept 93 { 94 if (is_state(STATE_INP_PASSIVE)) 95 { 96 net().add_to_active_list(*this); 97 set_state(STATE_INP_LH); 98 } 99 } 100 }; 101 102 // ----------------------------------------------------------------------------- 103 // logic_output_t 104 // ----------------------------------------------------------------------------- 105 106 class logic_output_t : public logic_t 107 { 108 public: 109 110 /// \brief logic output constructor 111 /// 112 /// The third parameter does nothing. It is provided only for 113 /// compatibility with tristate_output_t in templatized device models 114 /// 115 /// \param dev Device owning this output 116 /// \param aname The name of this output 117 /// \param dummy Dummy parameter to allow construction like tristate output 118 /// 119 logic_output_t(device_t &dev, const pstring &aname, bool dummy = false); 120 121 void initial(netlist_sig_t val) noexcept; 122 push(const netlist_sig_t & newQ,const netlist_time & delay)123 void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept 124 { 125 gsl_Expects(delay >= netlist_time::zero()); 126 127 m_my_net.set_Q_and_push(newQ, delay); // take the shortcut 128 } 129 set_Q_time(const netlist_sig_t & newQ,const netlist_time_ext & at)130 void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept 131 { 132 m_my_net.set_Q_time(newQ, at); // take the shortcut 133 } 134 135 /// \brief Dummy implementation for templatized generic devices 136 /// 137 /// This function shall never be called. It is defined here so that 138 /// templatized generic device models do not have to do tons of 139 /// template magic. 140 /// 141 /// This function terminates if actually called. 142 /// set_tristate(netlist_sig_t v,netlist_time ts_off_on,netlist_time ts_on_off)143 [[noreturn]] static void set_tristate(netlist_sig_t v, 144 netlist_time ts_off_on, netlist_time ts_on_off) 145 { 146 plib::unused_var(v, ts_off_on, ts_on_off); 147 plib::terminate("set_tristate on logic_output should never be called!"); 148 } 149 private: 150 logic_net_t m_my_net; 151 }; 152 153 // ----------------------------------------------------------------------------- 154 // tristate_output_t 155 // ----------------------------------------------------------------------------- 156 157 /// \brief Tristate output 158 /// 159 /// In a lot of applications tristate enable inputs are just connected to 160 /// VCC/GND to permanently enable the outputs. In this case a pure 161 /// implementation using analog outputs would not perform well. 162 /// 163 /// For this object during creation it can be decided if a logic output or 164 /// a tristate output is used. Generally the owning device uses parameter 165 /// FORCE_TRISTATE_LOGIC to determine this. 166 /// 167 /// This is the preferred way to implement tristate outputs. 168 /// 169 170 class tristate_output_t : public logic_output_t 171 { 172 public: 173 174 tristate_output_t(device_t &dev, const pstring &aname, bool force_logic); 175 push(netlist_sig_t newQ,netlist_time delay)176 void push(netlist_sig_t newQ, netlist_time delay) noexcept 177 { 178 if (!m_tristate) 179 logic_output_t::push(newQ, delay); 180 m_last_logic = newQ; 181 } 182 set_tristate(netlist_sig_t v,netlist_time ts_off_on,netlist_time ts_on_off)183 void set_tristate(netlist_sig_t v, 184 netlist_time ts_off_on, netlist_time ts_on_off) noexcept 185 { 186 if (!m_force_logic) 187 if (v != m_tristate) 188 { 189 logic_output_t::push((v != 0) ? OUT_TRISTATE() : m_last_logic, v ? ts_off_on : ts_on_off); 190 m_tristate = v; 191 } 192 } 193 is_force_logic()194 bool is_force_logic() const noexcept 195 { 196 return m_force_logic; 197 } 198 199 private: 200 using logic_output_t::initial; 201 using logic_output_t::set_Q_time; 202 state_var<netlist_sig_t> m_last_logic; 203 state_var<netlist_sig_t> m_tristate; 204 bool m_force_logic; 205 }; 206 207 } // namespace netlist 208 209 210 #endif // NL_CORE_LOGIC_H_ 211