summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nld_schmitt.cpp
blob: c36ce978b0d54322778306c4dab93e356c4cde28 (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
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/*
 * nld_schmitt.cpp
 *
 */

#include "nld_schmitt.h"

#include "netlist/analog/nlid_twoterm.h"
#include "netlist/devices/nlid_system.h"
#include "netlist/nl_base.h"
#include "netlist/nl_errstr.h"
#include "netlist/solver/nld_solver.h"

namespace netlist
{
	namespace devices
	{

		/*
		 * Over-simplified TTL Schmitt trigger model
		 * It's good enough to work for 74xx/74LSxx if it isn't abused too badly
		 * It would need major changes to support 4000 or 74HCxx behaviour
		 * The input is over-simplified - it's actually more like a resistor in series with a diode, and can only source current
		 * Similarly, high output can only source current and low output can only sink current
		 * Propagation delays are ignored
		 *
		 */

		class schmitt_trigger_model_t : public param_model_t
		{
		public:
			schmitt_trigger_model_t(device_t &device, const pstring &name, const pstring &val)
				: param_model_t(device, name, val)
				, m_VTP(*this, "VTP")
				, m_VTM(*this, "VTM")
				, m_VI(*this, "VI")
				, m_RI(*this, "RI")
				, m_VOH(*this, "VOH")
				, m_ROH(*this, "ROH")
				, m_VOL(*this, "VOL")
				, m_ROL(*this, "ROL")
				, m_TPLH(*this, "TPLH")
				, m_TPHL(*this, "TPHL")
			{
			}

			value_t m_VTP;
			value_t m_VTM;
			value_t m_VI;
			value_t m_RI;
			value_t m_VOH;
			value_t m_ROH;
			value_t m_VOL;
			value_t m_ROL;
			value_t m_TPLH;
			value_t m_TPHL;
		};

		NETLIB_OBJECT(schmitt_trigger)
		{
			NETLIB_CONSTRUCTOR(schmitt_trigger)
				, m_A(*this, "A")
				, m_supply(*this)
				, m_RVI(*this, "RVI")
				, m_RVO(*this, "RVO")
				, m_model(*this, "MODEL", "TTL_7414_GATE")
				, m_last_state(*this, "m_last_var", 1)
				, m_is_timestep(false)
			{
				register_subalias("Q", m_RVO.m_P);

				connect(m_A, m_RVI.m_P);
				connect(m_supply.GND(), m_RVI.m_N);
				connect(m_supply.GND(), m_RVO.m_N);
			}

		protected:
			NETLIB_RESETI()
			{
				m_last_state = 1;
				m_RVI.reset();
				m_RVO.reset();
				m_is_timestep = m_RVO.m_P.net().solver()->has_timestep_devices();
				m_RVI.set_G_V_I(plib::reciprocal(m_model.m_RI()), m_model.m_VI, nlconst::zero());
				m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
			}

			NETLIB_UPDATEI()
			{
				const auto va(m_A.Q_Analog() - m_supply.GND().Q_Analog());
				if (m_last_state)
				{
					if (va < m_model.m_VTM)
					{
						m_last_state = 0;
						if (m_is_timestep)
							m_RVO.update();
						m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
						m_RVO.solve_later();
					}
				}
				else
				{
					if (va > m_model.m_VTP)
					{
						m_last_state = 1;
						if (m_is_timestep)
							m_RVO.update();
						m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
						m_RVO.solve_later();
					}
				}
			}

		private:
			analog_input_t m_A;
			NETLIB_NAME(power_pins) m_supply;
			analog::NETLIB_SUB(twoterm) m_RVI;
			analog::NETLIB_SUB(twoterm) m_RVO;
			schmitt_trigger_model_t m_model;
			state_var<int> m_last_state;
			bool m_is_timestep;
		};

		NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL")

	} // namespace devices
} // namespace netlist