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