1 /***************************************************************************
2  *   Copyright (C) 2005 by David Saxton                                    *
3  *   david@bluehaze.org                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10 
11 #include "component.h"
12 #include "gpsimprocessor.h"
13 #include "pin.h"
14 #include "simulator.h"
15 #include "switch.h"
16 
17 // #include <k3staticdeleter.h>
18 
19 #include <QTimer>
20 #include <QSet>
21 #include <QGlobalStatic>
22 
23 #include <cassert>
24 
25 using namespace std;
26 
27 //BEGIN class Simulator
28 // Simulator *Simulator::m_pSelf = 0;
29 // static K3StaticDeleter<Simulator> staticSimulatorDeleter;
30 
31 Q_GLOBAL_STATIC(Simulator, globalSimulator);
32 
isDestroyedSim()33 bool Simulator::isDestroyedSim() {
34     return globalSimulator.isDestroyed();
35 }
36 
self()37 Simulator *Simulator::self() {
38 // 	if (!m_pSelf)
39 // 		staticSimulatorDeleter.setObject(m_pSelf, new Simulator());
40 //
41 // 	return m_pSelf;
42     return globalSimulator;
43 }
44 
Simulator()45 Simulator::Simulator()
46 		:  m_bIsSimulating(false), m_llNumber(0), m_stepNumber(0), m_currentChain(0) {
47 	m_gpsimProcessors = new list<GpsimProcessor*>;
48 	m_componentCallbacks = new list<ComponentCallback>;
49 	m_components	   = new list<Component*>;
50 	m_ordinaryCircuits = new list<Circuit*>;
51 
52 // use integer math for these, update period is double.
53 	unsigned max = unsigned(LOGIC_UPDATE_RATE / LINEAR_UPDATE_RATE);
54 
55 	for (unsigned i = 0; i < max; i++) {
56 		m_pStartStepCallback[i] = nullptr;
57 	}
58 
59 	LogicConfig lc;
60 
61 	m_pChangedLogicStart = new LogicOut(lc, false);
62 	m_pChangedLogicLast  = m_pChangedLogicStart;
63 
64 	m_pChangedCircuitStart = new Circuit;
65 	m_pChangedCircuitLast  = m_pChangedCircuitStart;
66 
67 	m_stepTimer = new QTimer(this);
68 	connect(m_stepTimer, SIGNAL(timeout()), this, SLOT(step()));
69 
70     slotSetSimulating(true); // start the timer
71 }
72 
~Simulator()73 Simulator::~Simulator() {
74 	delete m_pChangedLogicStart;
75 	delete m_pChangedCircuitStart;
76 
77 	delete m_gpsimProcessors;
78 	delete m_components;
79 	delete m_componentCallbacks;
80 	delete m_ordinaryCircuits;
81 }
82 
time() const83 long long Simulator::time() const {
84     return m_stepNumber * LOGIC_UPDATE_PER_STEP + m_llNumber;
85 }
86 
87 
step()88 void Simulator::step() {
89 	if (!m_bIsSimulating) return;
90 
91 	// We are called a thousand times a second (the maximum allowed by QTimer),
92 	// so divide the LINEAR_UPDATE_RATE by 1e3 for the number of loops we need
93 	// to do.
94 	const unsigned maxSteps = unsigned(LINEAR_UPDATE_RATE / SIMULATOR_STEP_INTERVAL_MS);
95 
96 	for (unsigned i = 0; i < maxSteps; ++i) {
97         // here starts 1 linear step
98 		m_stepNumber++;
99 
100 		// Update the non-logic parts of the simulation
101 		{
102 			list<Component*>::iterator components_end = m_components->end();
103 
104 			for (list<Component*>::iterator component = m_components->begin(); component != components_end; component++) {
105 				(*component)->stepNonLogic();
106 			}
107 		}
108 
109 		{
110 			list<Circuit*>::iterator circuits_end = m_ordinaryCircuits->end();
111 
112 			for (list<Circuit*>::iterator circuit = m_ordinaryCircuits->begin(); circuit != circuits_end; circuit++) {
113 				(*circuit)->doNonLogic();
114 			}
115 		}
116 
117 		// Update the logic parts of our simulation
118 		//const unsigned max = unsigned(LOGIC_UPDATE_RATE / LINEAR_UPDATE_RATE); // 2015.09.27 - use contants for logic updates
119 
120 		for (m_llNumber = 0; m_llNumber < LOGIC_UPDATE_PER_STEP; ++m_llNumber) {
121             // here starts 1 logic update
122 			// Update the logic components
123 			{
124 				list<ComponentCallback>::iterator callbacks_end = m_componentCallbacks->end();
125 
126 				for (list<ComponentCallback>::iterator callback = m_componentCallbacks->begin(); callback != callbacks_end; callback++) {
127 					callback->callback();
128 				}
129 			}
130 
131 			if (m_pStartStepCallback[m_llNumber]) {
132 				list<ComponentCallback*>::iterator callbacks_end = m_pStartStepCallback[m_llNumber]->end();
133 
134 				for (list<ComponentCallback*>::iterator callback = m_pStartStepCallback[m_llNumber]->begin(); callback != callbacks_end; callback++) {
135 					(*callback)->callback();
136 					// should we delete the list entry? no
137 				}
138 			}
139 
140 			delete m_pStartStepCallback[m_llNumber];
141 			m_pStartStepCallback[m_llNumber] = nullptr;
142 
143 #ifndef NO_GPSIM
144 			// Update the gpsim processors
145 			{
146 				list<GpsimProcessor*>::iterator processors_end = m_gpsimProcessors->end();
147 
148 				for (list<GpsimProcessor*>::iterator processor = m_gpsimProcessors->begin(); processor != processors_end; processor++) {
149 					(*processor)->executeNext();
150 				}
151 			}
152 #endif
153 
154 			// why do we change this here instead of later?
155 			int prevChain = m_currentChain;
156 			m_currentChain ^= 1;
157 
158 			// Update the non-logic circuits
159 			if (Circuit *changed = m_pChangedCircuitStart->nextChanged(prevChain)) {
160                 QSet<Circuit*> canAddChangedSet;
161 				for (   Circuit *circuit = changed;
162                         circuit && (!canAddChangedSet.contains(circuit));
163                         circuit = circuit->nextChanged(prevChain)) {
164 					circuit->setCanAddChanged(true);
165                     canAddChangedSet.insert(circuit);
166                 }
167 
168 				m_pChangedCircuitStart->setNextChanged(nullptr, prevChain);
169 				m_pChangedCircuitLast = m_pChangedCircuitStart;
170 
171 				do {
172 					Circuit *next = changed->nextChanged(prevChain);
173 					changed->setNextChanged(nullptr, prevChain);
174 					changed->doLogic();
175 					changed = next;
176 				} while (changed);
177 			}
178 
179 			// Call the logic callbacks
180 			if (LogicOut *changed = m_pChangedLogicStart->nextChanged(prevChain)) {
181 				for (LogicOut *out = changed; out; out = out->nextChanged(prevChain))
182 					out->setCanAddChanged(true);
183 
184 				m_pChangedLogicStart->setNextChanged(nullptr, prevChain);
185 				m_pChangedLogicLast = m_pChangedLogicStart;
186 
187 				do {
188 					LogicOut *next = changed->nextChanged(prevChain);
189 					changed->setNextChanged(nullptr, prevChain);
190 
191 					double v = changed->isHigh() ? changed->outputHighVoltage() : 0.0;
192 
193 					for (PinList::iterator it = changed->pinListBegin; it != changed->pinListEnd; ++it) {
194 						if (Pin *pin = *it)
195 							pin->setVoltage(v);
196 					}
197 
198 					LogicIn *logicCallback = changed;
199 
200 					while (logicCallback) {
201 						logicCallback->callCallback();
202 						logicCallback = logicCallback->nextLogic();
203 					}
204 
205 					changed = next;
206 				} while (changed);
207 			}
208 		}
209 	}
210 }
211 
slotSetSimulating(bool simulate)212 void Simulator::slotSetSimulating(bool simulate) {
213 	if (m_bIsSimulating == simulate) return;
214 
215     if (simulate) {
216         m_stepTimer->start(SIMULATOR_STEP_INTERVAL_MS);
217     } else {
218         m_stepTimer->stop();
219     }
220 
221 	m_bIsSimulating = simulate;
222 	emit simulatingStateChanged(simulate);
223 }
224 
createLogicChain(LogicOut * logicOut,const LogicInList & logicInList,const PinList & pinList)225 void Simulator::createLogicChain(LogicOut *logicOut, const LogicInList &logicInList, const PinList &pinList) {
226 	if (!logicOut) return;
227 
228 	bool state = logicOut->outputState();
229 
230 	logicOut->setUseLogicChain(true);
231 	logicOut->pinList = pinList;
232 	logicOut->pinListBegin = logicOut->pinList.begin();
233 	logicOut->pinListEnd = logicOut->pinList.end();
234 
235 	LogicIn *last = logicOut;
236 
237 	const LogicInList::const_iterator end = logicInList.end();
238 
239 	for (LogicInList::const_iterator it = logicInList.begin(); it != end; ++it) {
240 		LogicIn *next = *it;
241 		last->setNextLogic(next);
242 		last->setLastState(state);
243 		last = next;
244 	}
245 
246 	last->setNextLogic(nullptr);
247 	last->setLastState(state);
248 
249 	// Mark it as changed, if it isn't already changed...
250 	LogicOut *changed = m_pChangedLogicStart->nextChanged(m_currentChain);
251 
252 	while (changed) {
253 		if (changed == logicOut) return;
254 
255 		changed = changed->nextChanged(m_currentChain);
256 	}
257 
258 	addChangedLogic(logicOut);
259 	logicOut->setCanAddChanged(false);
260 
261 	if (!m_logicChainStarts.contains(logicOut))
262 		m_logicChainStarts << logicOut;
263 }
264 
attachGpsimProcessor(GpsimProcessor * cpu)265 void Simulator::attachGpsimProcessor(GpsimProcessor *cpu) {
266 	m_gpsimProcessors->push_back(cpu);
267 }
268 
detachGpsimProcessor(GpsimProcessor * cpu)269 void Simulator::detachGpsimProcessor(GpsimProcessor *cpu) {
270 	m_gpsimProcessors->remove(cpu);
271 }
272 
attachComponentCallback(Component * component,VoidCallbackPtr function)273 void Simulator::attachComponentCallback(Component *component, VoidCallbackPtr function) {
274 	m_componentCallbacks->push_back(ComponentCallback(component, function));
275 }
276 
attachComponent(Component * component)277 void Simulator::attachComponent(Component *component) {
278 	if (!component || !component->doesStepNonLogic())
279 		return;
280 
281 	m_components->push_back(component);
282 }
283 
detachComponent(Component * component)284 void Simulator::detachComponent(Component *component) {
285 	m_components->remove(component);
286 	detachComponentCallbacks(*component);
287 }
288 
289 static Component *compx;
290 
pred1(ComponentCallback & x)291 bool pred1(ComponentCallback &x) {
292 	return x.component() == compx;
293 }
294 
detachComponentCallbacks(Component & component)295 void Simulator::detachComponentCallbacks(Component &component) {
296 	compx = &component;
297 	m_componentCallbacks->remove_if(pred1);
298 }
299 
attachCircuit(Circuit * circuit)300 void Simulator::attachCircuit(Circuit *circuit) {
301 	if (!circuit) return;
302 
303 	m_ordinaryCircuits->push_back(circuit);
304 
305 //	if ( circuit->canAddChanged() ) {
306 	addChangedCircuit(circuit);
307 	circuit->setCanAddChanged(false);
308 //	}
309 }
310 
removeLogicInReferences(LogicIn * logicIn)311 void Simulator::removeLogicInReferences(LogicIn *logicIn) {
312 	if (!logicIn) return;
313 
314 	QList<LogicOut*>::iterator end = m_logicChainStarts.end();
315 
316 	for (QList<LogicOut*>::iterator it = m_logicChainStarts.begin(); it != end; ++it) {
317 		LogicIn *logicCallback = *it;
318 
319 		while (logicCallback) {
320 			if (logicCallback->nextLogic() == logicIn)
321 				logicCallback->setNextLogic(logicCallback->nextLogic()->nextLogic());
322 
323 			logicCallback = logicCallback->nextLogic();
324 		}
325 	}
326 }
327 
removeLogicOutReferences(LogicOut * logic)328 void Simulator::removeLogicOutReferences(LogicOut *logic) {
329 	m_logicChainStarts.removeAll(logic);
330 
331 	// Any changes to the code below will probably also apply to Simulator::detachCircuit
332 	if (m_pChangedLogicLast == logic) {
333 		LogicOut *previous_1 = nullptr;
334 		LogicOut *previous_2 = nullptr;
335 
336 		for (LogicOut *logic = m_pChangedLogicStart; logic;) {
337 			if (previous_1)
338 				previous_2 = previous_1;
339 
340 			previous_1 = logic;
341 			logic = logic->nextChanged(m_currentChain);
342 		}
343 
344 		m_pChangedLogicLast = previous_2;
345 	}
346 
347 	for (unsigned chain = 0; chain < 2; ++chain) {
348 		for (LogicOut *prevChanged = m_pChangedLogicStart; prevChanged; prevChanged = prevChanged->nextChanged(chain)) {
349 			LogicOut *nextChanged = prevChanged->nextChanged(chain);
350 
351 			if (nextChanged == logic)
352 				prevChanged->setNextChanged(nextChanged->nextChanged(chain), chain);
353 		}
354 	}
355 }
356 
detachCircuit(Circuit * circuit)357 void Simulator::detachCircuit(Circuit *circuit) {
358 	if (!circuit) return;
359 
360 	m_ordinaryCircuits->remove(circuit);
361 
362 	// Any changes to the code below will probably also apply to Simulator::removeLogicOutReferences
363 
364 	if (m_pChangedCircuitLast == circuit) {
365 		Circuit *previous_1 = nullptr;
366 		Circuit *previous_2 = nullptr;
367 
368 		for (Circuit * circuit = m_pChangedCircuitStart; circuit;) {
369 			if (previous_1)
370 				previous_2 = previous_1;
371 
372 			previous_1 = circuit;
373 			circuit = circuit->nextChanged(m_currentChain);
374 		}
375 
376 		m_pChangedCircuitLast = previous_2;
377 	}
378 
379 	for (unsigned chain = 0; chain < 2; ++chain) {
380 		for (Circuit *prevChanged = m_pChangedCircuitStart; prevChanged; prevChanged = prevChanged->nextChanged(chain)) {
381 			Circuit *nextChanged = prevChanged->nextChanged(chain);
382 
383 			if (nextChanged == circuit)
384 				prevChanged->setNextChanged(nextChanged->nextChanged(chain), chain);
385 		}
386 	}
387 }
388 
389 //END class Simulator
390