summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nld_4053.cpp
blob: 38b37fd3393e4ac925b6154f1e6e4b246ba57ac2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
 * nld_4053.cpp
 *
 *  CD4053: Triple 2-Channel Analog Multiplexer/Demultiplexer
 *
 *          +--------------+
 *  INOUTBY |1     ++    16| VDD
 *  INOUTBX |2           15| OUTINB
 *  INOUTCY |3           14| OUTINA
 *   OUTINC |4    4053   13| INOUTAY
 *  INOUTCX |5           12| INOUTAX
 *      INH |6           11| A
 *      VEE |7           10| B
 *      VSS |8            9| C
 *          +--------------+
 *
 *  FIXME: These devices are slow (~125 ns). This is currently not reflected
 *
 *  Naming conventions follow National semiconductor datasheet
 *
 */


#include "nld_4053.h"

#include "analog/nlid_twoterm.h"
#include "solver/nld_solver.h"

namespace netlist
{
	namespace devices
	{
	NETLIB_OBJECT(CD4053_GATE)
	{
		NETLIB_CONSTRUCTOR_MODEL(CD4053_GATE, "CD4XXX")
		, m_RX(*this, "RX")
		, m_RY(*this, "RY")
		, m_select(*this, "S", NETLIB_DELEGATE(controls))
		, m_inhibit(*this, "INH", NETLIB_DELEGATE(controls))
		, m_VEE(*this, "VEE", NETLIB_DELEGATE(controls))
		, m_base_r(*this, "BASER", nlconst::magic(270.0))
		, m_lastx(*this, "m_lastx", false)
		, m_lasty(*this, "m_lasty", false)
		, m_select_state(*this, "m_select_state", false)
		, m_inhibit_state(*this, "m_inhibit_state", false)
		, m_supply(*this)
		{
			connect("RX.2", "RY.2");
			register_subalias("X", "RX.1");
			register_subalias("Y", "RY.1");
			register_subalias("XY", "RX.2");
		}

		NETLIB_RESETI()
		{
			update_state(true, false);
		}

	private:
		NETLIB_HANDLERI(controls)
		{
			bool newx = false, newy = false;
			if (!on(m_inhibit, m_inhibit_state))
			{
				if (!on(m_select, m_select_state))
				{
					newx = true;
				}
				else
				{
					newy = true;
				}
			}

			if (newx != m_lastx || newy != m_lasty)
				update_state(newx, newy);
		}

		bool on(analog_input_t &input, bool &state)
		{
			// digital inputs are based on VDD
			nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
			nl_fptype in = input() - m_supply.GND().Q_Analog();
			nl_fptype low = nlconst::magic(0.3) * sup;
			nl_fptype high = nlconst::magic(0.7) * sup;
			if (in < low)
			{
				state = false;
			}
			else if (in > high)
			{
				state = true;
			}
			return state;
		}

		void update_state(bool newx, bool newy)
		{
			// analog output is based on VEE
			const nl_fptype sup = (m_VEE() - m_supply.GND().Q_Analog());
			const nl_fptype Ron = m_base_r() * nlconst::magic(5.0) / sup;
			const nl_fptype Roff = plib::reciprocal(exec().gmin());
			const nl_fptype RX = newx ? Ron : Roff;
			const nl_fptype RY = newy ? Ron : Roff;
			if (m_RX.solver() == m_RY.solver())
			{
				m_RX.change_state([this, &RX, &RY]()
				{
					m_RX.set_R(RX);
					m_RY.set_R(RY);
				});
			}
			else
			{
				m_RX.change_state([this, &RX]()
				{
					m_RX.set_R(RX);
				});
				m_RY.change_state([this, &RY]()
				{
					m_RY.set_R(RY);
				});
			}
			m_lastx = newx;
			m_lasty = newy;
		}

		analog::NETLIB_SUB(R_base) m_RX;
		analog::NETLIB_SUB(R_base) m_RY;
		analog_input_t             m_select;
		analog_input_t             m_inhibit;
		analog_input_t             m_VEE;
		param_fp_t                 m_base_r;
		state_var<bool>            m_lastx;
		state_var<bool>            m_lasty;
		state_var<bool>            m_select_state;
		state_var<bool>            m_inhibit_state;
		nld_power_pins             m_supply;
	};

	NETLIB_DEVICE_IMPL(CD4053_GATE,         "CD4053_GATE",            "")
	} //namespace devices
} // namespace netlist