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