1 // license:BSD-3-Clause
2 // copyright-holders:Couriersud
3 /*****************************************************************************
4 
5     74123 monoflop emulator - see 74123.h for pin out and truth table
6 
7     Formulas came from the TI datasheet revised on March 1998
8 
9  *****************************************************************************/
10 
11 #include "emu.h"
12 #include "machine/74123.h"
13 #include "machine/rescap.h"
14 
15 //#define VERBOSE 1
16 #include "logmacro.h"
17 
18 
19 //**************************************************************************
20 //  LIVE DEVICE
21 //**************************************************************************
22 
23 // device type definition
24 DEFINE_DEVICE_TYPE(TTL74123, ttl74123_device, "ttl74123", "74123 TTL")
25 
26 //-------------------------------------------------
27 //  ttl74123_device - constructor
28 //-------------------------------------------------
29 
ttl74123_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)30 ttl74123_device::ttl74123_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
31 	: device_t(mconfig, TTL74123, tag, owner, clock),
32 		m_timer(nullptr),
33 		m_connection_type(TTL74123_NOT_GROUNDED_NO_DIODE),
34 		m_res(1.0),
35 		m_cap(1.0),
36 		m_a(0),
37 		m_b(0),
38 		m_clear(0),
39 		m_output_changed_cb(*this)
40 {
41 }
42 
43 //-------------------------------------------------
44 //  device_start - device-specific startup
45 //-------------------------------------------------
46 
device_start()47 void ttl74123_device::device_start()
48 {
49 	m_output_changed_cb.resolve_safe();
50 
51 	m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ttl74123_device::clear_callback),this));
52 
53 	/* register for state saving */
54 	save_item(NAME(m_a));
55 	save_item(NAME(m_b));
56 	save_item(NAME(m_clear));
57 }
58 
59 
60 //-------------------------------------------------
61 //  device_reset - device-specific reset
62 //-------------------------------------------------
63 
device_reset()64 void ttl74123_device::device_reset()
65 {
66 	set_output();
67 }
68 
69 
70 
71 //-------------------------------------------------
72 //  compute_duration - compute timer duration
73 //-------------------------------------------------
74 
compute_duration()75 attotime ttl74123_device::compute_duration()
76 {
77 	double duration;
78 
79 	switch (m_connection_type)
80 	{
81 	case TTL74123_NOT_GROUNDED_NO_DIODE:
82 		duration = 0.28 * m_res * m_cap * (1.0 + (700.0 / m_res));
83 		break;
84 
85 	case TTL74123_NOT_GROUNDED_DIODE:
86 		duration = 0.25 * m_res * m_cap * (1.0 + (700.0 / m_res));
87 		break;
88 
89 	case TTL74123_GROUNDED:
90 	default:
91 		if (m_cap < CAP_U(0.1))
92 		{
93 			/* this is really a curve - a very flat one in the 0.1uF-.01uF range */
94 			duration = 0.32 * m_res * m_cap;
95 		}
96 		else
97 		{
98 			duration = 0.33 * m_res * m_cap;
99 		}
100 		break;
101 	}
102 
103 	return attotime::from_double(duration);
104 }
105 
106 
107 //-------------------------------------------------
108 //  timer_running - is the timer running?
109 //-------------------------------------------------
110 
timer_running()111 int ttl74123_device::timer_running()
112 {
113 	return (m_timer->remaining() > attotime::zero) &&
114 			(m_timer->remaining() != attotime::never);
115 }
116 
117 
118 /*-------------------------------------------------
119     TIMER_CALLBACK_MEMBER( output_callback )
120 -------------------------------------------------*/
121 
TIMER_CALLBACK_MEMBER(ttl74123_device::output_callback)122 TIMER_CALLBACK_MEMBER( ttl74123_device::output_callback )
123 {
124 	m_output_changed_cb(param);
125 }
126 
127 
128 //-------------------------------------------------
129 //  set_output - set the output line state
130 //-------------------------------------------------
131 
set_output()132 void ttl74123_device::set_output()
133 {
134 	int output = timer_running();
135 
136 	machine().scheduler().timer_set( attotime::zero, timer_expired_delegate(FUNC(ttl74123_device::output_callback ),this), output);
137 
138 	LOG("74123:  Output: %d\n", output);
139 }
140 
141 
142 /*-------------------------------------------------
143     TIMER_CALLBACK_MEMBER( clear_callback )
144 -------------------------------------------------*/
145 
TIMER_CALLBACK_MEMBER(ttl74123_device::clear_callback)146 TIMER_CALLBACK_MEMBER( ttl74123_device::clear_callback )
147 {
148 	int output = timer_running();
149 
150 	m_output_changed_cb(output);
151 }
152 
153 //-------------------------------------------------
154 //  start_pulse - begin timing
155 //-------------------------------------------------
156 
start_pulse()157 void ttl74123_device::start_pulse()
158 {
159 	attotime duration = compute_duration();
160 
161 	if(timer_running())
162 	{
163 		/* retriggering, but not if we are called to quickly */
164 		attotime delay_time = attotime(0, ATTOSECONDS_PER_SECOND * m_cap * 220);
165 
166 		if(m_timer->elapsed() >= delay_time)
167 		{
168 			m_timer->adjust(duration);
169 
170 			LOG("74123:  Retriggering pulse.  Duration: %f\n", duration.as_double());
171 		}
172 		else
173 		{
174 			LOG("74123:  Retriggering failed.\n");
175 		}
176 	}
177 	else
178 	{
179 		/* starting */
180 		m_timer->adjust(duration);
181 
182 		set_output();
183 
184 		LOG("74123:  Starting pulse.  Duration: %f\n", duration.as_double());
185 	}
186 }
187 
188 
189 //-------------------------------------------------
190 //  a_w - write register a data
191 //-------------------------------------------------
192 
WRITE_LINE_MEMBER(ttl74123_device::a_w)193 WRITE_LINE_MEMBER( ttl74123_device::a_w )
194 {
195 	/* start/regtrigger pulse if B=HI and falling edge on A (while clear is HI) */
196 	if (!state && m_a && m_b && m_clear)
197 	{
198 		start_pulse();
199 	}
200 
201 	m_a = state;
202 }
203 
204 
205 //-------------------------------------------------
206 //  b_w - write register b data
207 //-------------------------------------------------
208 
WRITE_LINE_MEMBER(ttl74123_device::b_w)209 WRITE_LINE_MEMBER( ttl74123_device::b_w)
210 {
211 	/* start/regtrigger pulse if A=LO and rising edge on B (while clear is HI) */
212 	if (state && !m_b && !m_a && m_clear)
213 	{
214 		start_pulse();
215 	}
216 
217 	m_b = state;
218 }
219 
220 
221 //-------------------------------------------------
222 //  clear_w - write register clear data
223 //-------------------------------------------------
224 
WRITE_LINE_MEMBER(ttl74123_device::clear_w)225 WRITE_LINE_MEMBER( ttl74123_device::clear_w)
226 {
227 	/* start/regtrigger pulse if B=HI and A=LO and rising edge on clear */
228 	if (state && !m_a && m_b && !m_clear)
229 	{
230 		start_pulse();
231 	}
232 	else if (!state)  /* clear the output  */
233 	{
234 		m_timer->adjust(attotime::zero);
235 
236 		LOG("74123:  Cleared\n");
237 	}
238 	m_clear = state;
239 }
240 
241 
242 //-------------------------------------------------
243 //  reset_w - reset device
244 //-------------------------------------------------
245 
WRITE_LINE_MEMBER(ttl74123_device::reset_w)246 WRITE_LINE_MEMBER( ttl74123_device::reset_w)
247 {
248 	set_output();
249 }
250