You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
6.9 KiB
249 lines
6.9 KiB
/***************************************************************************
|
|
* Copyright (C) 2005 by David Saxton *
|
|
* david@bluehaze.org *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
|
|
#ifndef SIMULATOR_H
|
|
#define SIMULATOR_H
|
|
|
|
#include "circuit.h"
|
|
#include "logic.h"
|
|
|
|
/**
|
|
This should be a multiple of 1000. It is the number of times a second that
|
|
linear elements are updated.
|
|
*/
|
|
const int LINEAR_UPDATE_RATE = int(1e4);
|
|
|
|
/**
|
|
This should be a multiple of 1000. It is the number of times a second that
|
|
logic elements are updated.
|
|
*/
|
|
const int LOGIC_UPDATE_RATE = int(1e6);
|
|
|
|
|
|
class Circuit;
|
|
class CircuitDocument;
|
|
class Component;
|
|
class ComponentCallback;
|
|
class ECNode;
|
|
class GpsimProcessor;
|
|
class LogicIn;
|
|
class LogicOut;
|
|
class Switch;
|
|
class Wire;
|
|
|
|
typedef TQValueList<ECNode*> ECNodeList;
|
|
typedef TQValueList<LogicIn*> LogicInList;
|
|
|
|
typedef void(Component::*VoidCallbackPtr)();
|
|
|
|
template <typename T>
|
|
class LinkedList
|
|
{
|
|
public:
|
|
LinkedList( T * data ) { m_pData = data; m_pNext = 0l; }
|
|
T * data() const { return m_pData; }
|
|
|
|
LinkedList<T> * m_pNext;
|
|
|
|
protected:
|
|
T * m_pData;
|
|
};
|
|
|
|
|
|
class ComponentCallback
|
|
{
|
|
public:
|
|
ComponentCallback( Component * component, VoidCallbackPtr function )
|
|
{
|
|
m_pComponent = component;
|
|
m_pFunction = function;
|
|
}
|
|
|
|
void callback() { (m_pComponent->*m_pFunction)(); }
|
|
Component * component() const { return m_pComponent; }
|
|
|
|
protected:
|
|
Component * m_pComponent;
|
|
VoidCallbackPtr m_pFunction;
|
|
};
|
|
|
|
|
|
/**
|
|
This singleton class oversees all simulation (keeping in sync linear, nonlinear,
|
|
logic, external simulators (such as gpsim), mechanical simulation, etc).
|
|
@author David Saxton
|
|
*/
|
|
class Simulator : public TQObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
static Simulator * self();
|
|
~Simulator();
|
|
|
|
/**
|
|
* Number of (1/LOGIC_UPDATE_RATE) intervals that the simulator has been
|
|
* stepping for.
|
|
*/
|
|
long long time() const { return m_stepNumber*(long long)(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE) + m_llNumber; }
|
|
/**
|
|
* Initializes a new logic chain.
|
|
*/
|
|
void createLogicChain( LogicOut * logicOut, const LogicInList & logicInList, const PinList & pinList );
|
|
/**
|
|
* Adds the given LogicOut to the list of changed LogicOuts
|
|
*/
|
|
void addChangedLogic( LogicOut * changed )
|
|
{
|
|
m_pChangedLogicLast->setNextChanged( changed, m_currentChain );
|
|
m_pChangedLogicLast = changed;
|
|
}
|
|
/**
|
|
* Remove pointers to the given LogicOut, called when it is deleted for
|
|
* safety reasons.
|
|
*/
|
|
void removeLogicOutReferences( LogicOut * logic );
|
|
/**
|
|
* Remove pointers to the given LogicIn, called when it is deleted for
|
|
* safety reasons. Simulator does not have any references to LogicIns
|
|
* itself - instead, they are removed from logic chains which are
|
|
* currently marked as changed.
|
|
*/
|
|
void removeLogicInReferences( LogicIn * logic );
|
|
/**
|
|
* Adds the given Circuit to the list of changed Circuits
|
|
*/
|
|
void addChangedCircuit( Circuit * changed )
|
|
{
|
|
m_pChangedCircuitLast->setNextChanged( changed, m_currentChain );
|
|
m_pChangedCircuitLast = changed;
|
|
}
|
|
inline void addStepCallback( int at, LinkedList<ComponentCallback> * ccb );
|
|
/**
|
|
* Add the given processor to the simulator. GpsimProcessor::step will
|
|
* be called while present in the simulator (it is at GpsimProcessor's
|
|
* disgression whether to actually step, depending on its running
|
|
* status).
|
|
* @see detachGpsimProcessor( GpsimProcessor * cpu );
|
|
*/
|
|
void attachGpsimProcessor( GpsimProcessor * cpu );
|
|
/**
|
|
* Remove the given processor from the simulation loop
|
|
*/
|
|
void detachGpsimProcessor( GpsimProcessor * cpu );
|
|
/**
|
|
* Attach the component callback to the simulator. This will be called
|
|
* during the logic update loop, at LOGIC_UPDATE_RATE times per second (so
|
|
* make sure the function passed is an efficient one!).
|
|
*/
|
|
void attachComponentCallback( Component * component, VoidCallbackPtr function );
|
|
/**
|
|
* Removes the callbacks for the given component from the simulator.
|
|
*/
|
|
void detachComponentCallbacks( Component * component );
|
|
/**
|
|
* Attach the component to the simulator.
|
|
*/
|
|
void attachComponent( Component * component );
|
|
/**
|
|
* Detaches the component from the simulator.
|
|
*/
|
|
void detachComponent( Component * component );
|
|
/**
|
|
* Attach a circuit to the simulator
|
|
*/
|
|
void attachCircuit( Circuit * circuit );
|
|
/**
|
|
* Detach a circuit from the simulator.
|
|
*/
|
|
void detachCircuit( Circuit * circuit );
|
|
/**
|
|
* Attaches the switch to the simulator (only needed when the switch has
|
|
* started bouncing.
|
|
*/
|
|
void attachSwitch( Switch * sw );
|
|
/**
|
|
* Detaches the switch from the simulator (called when the switch has
|
|
* stopped bouncing).
|
|
*/
|
|
void detachSwitch( Switch * sw );
|
|
/**
|
|
* @return whether or not we are currently simulating stuff
|
|
* @see slotSetSimulating
|
|
*/
|
|
bool isSimulating() const { return m_bIsSimulating; }
|
|
|
|
public slots:
|
|
/**
|
|
* Set whether or not to simulate at the moment.
|
|
* @see isSimulating
|
|
*/
|
|
void slotSetSimulating( bool simulate );
|
|
|
|
signals:
|
|
/**
|
|
* Emitted when the simulating state changes.
|
|
* @see slotSetSimulating
|
|
*/
|
|
void simulatingStateChanged( bool isSimulating );
|
|
|
|
private slots:
|
|
void step();
|
|
|
|
protected:
|
|
template <typename T>
|
|
void attach( LinkedList<T> ** start, T * data );
|
|
template <typename T>
|
|
void detach( LinkedList<T> ** start, T * data );
|
|
template <typename T>
|
|
void detachAll( LinkedList<T> * list );
|
|
|
|
bool m_bIsSimulating;
|
|
static Simulator * m_pSelf;
|
|
|
|
///List of LogicOuts that are at the start of a LogicChain
|
|
TQValueList<LogicOut*> m_logicChainStarts;
|
|
|
|
LogicOut * m_pChangedLogicStart;
|
|
LogicOut * m_pChangedLogicLast;
|
|
|
|
Circuit * m_pChangedCircuitStart;
|
|
Circuit * m_pChangedCircuitLast;
|
|
|
|
LinkedList<GpsimProcessor> * m_gpsimProcessors;
|
|
LinkedList<Component> * m_components;
|
|
LinkedList<ComponentCallback> * m_componentCallbacks;
|
|
LinkedList<Circuit> * m_ordinaryCircuits;
|
|
LinkedList<Switch> * m_switches;
|
|
|
|
LinkedList<ComponentCallback> * m_pStartStepCallback[LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE];
|
|
LinkedList<ComponentCallback> * m_pNextStepCallback[LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE];
|
|
|
|
private:
|
|
Simulator();
|
|
long m_llNumber;
|
|
long long m_stepNumber;
|
|
unsigned char m_currentChain;
|
|
};
|
|
|
|
|
|
inline void Simulator::addStepCallback( int at, LinkedList<ComponentCallback> * ccb )
|
|
{
|
|
if ( !m_pStartStepCallback[at] )
|
|
m_pStartStepCallback[at] = ccb;
|
|
|
|
else
|
|
m_pNextStepCallback[at]->m_pNext = ccb;
|
|
|
|
m_pNextStepCallback[at] = ccb;
|
|
}
|
|
|
|
#endif
|