summaryrefslogtreecommitdiffstats
path: root/src/oscilloscopedata.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/oscilloscopedata.h')
-rw-r--r--src/oscilloscopedata.h365
1 files changed, 365 insertions, 0 deletions
diff --git a/src/oscilloscopedata.h b/src/oscilloscopedata.h
new file mode 100644
index 0000000..cbabdac
--- /dev/null
+++ b/src/oscilloscopedata.h
@@ -0,0 +1,365 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * *
+ * 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 OSCILLOSCOPEDATA_H
+#define OSCILLOSCOPEDATA_H
+
+#include <qcolor.h>
+#include <qobject.h>
+
+typedef long long llong;
+typedef unsigned long long ullong;
+typedef unsigned int uint;
+
+#define DATA_CHUNK_SIZE (8192/sizeof(T))
+#define DATA_CHUNK_ARRAY_SIZE ((8192-sizeof(uint))/sizeof(DataChunk<T>*))
+
+// Allow a minimum of 64 megabytes of stored data (67108864 bytes)
+/// \todo The maximum allowed amount of stored data should be configurable or
+/// more intelligent (e.g. taking into account the number of probes or the
+/// amount of physical memory on the system).
+#define DCARRAY_ARRAY_SIZE ((67108864/(8192*DATA_CHUNK_ARRAY_SIZE))+1)
+
+
+/**
+For use in LogicProbe: Every time the input changes state, the new input state
+is recorded in value, along with the simulator time that it occurs at.
+ */
+class LogicDataPoint
+{
+ public:
+ LogicDataPoint()
+ {
+ value = 0;
+ time = 0;
+ }
+ LogicDataPoint( bool v, ullong t )
+ {
+ value = v;
+ time = t;
+ }
+ bool value : 1;
+ ullong time : 63;
+};
+
+
+template <typename T>
+class DataChunk
+{
+ public:
+ DataChunk() { memset( data, 0, DATA_CHUNK_SIZE*sizeof(T) ); }
+
+ T data[ DATA_CHUNK_SIZE ];
+
+ private:
+ // We don't want to accidently copy a shedload of data
+ DataChunk( const DataChunk & );
+};
+
+typedef DataChunk<LogicDataPoint> LogicChunk;
+typedef DataChunk<float> FloatingChunk;
+
+
+template <typename T>
+class DCArray
+{
+ public:
+ DCArray()
+ {
+ memset( m_data, 0, DATA_CHUNK_ARRAY_SIZE*sizeof(DataChunk<T> *) );
+ m_allocatedUpTo = 0;
+ }
+ ~DCArray()
+ {
+ for ( uint i=0; i<m_allocatedUpTo; ++i)
+ delete m_data[i];
+ }
+
+ inline DataChunk<T> * chunk( uint i )
+ {
+ if ( i >= m_allocatedUpTo )
+ allocateUpTo(i+1024);
+
+ if ( i >= DATA_CHUNK_ARRAY_SIZE )
+ return 0l;
+
+ return m_data[i];
+ }
+ uint allocatedUpTo() const { return m_allocatedUpTo; }
+
+
+ protected:
+ void allocateUpTo( uint upTo )
+ {
+ if ( upTo > DATA_CHUNK_ARRAY_SIZE )
+ upTo = DATA_CHUNK_ARRAY_SIZE;
+
+ for ( uint i=m_allocatedUpTo; i<upTo; ++i )
+ m_data[i] = new DataChunk<T>;
+ m_allocatedUpTo = upTo;
+ }
+
+ DataChunk<T> * m_data[DATA_CHUNK_ARRAY_SIZE];
+ uint m_allocatedUpTo;
+
+ private:
+ // We don't want to accidently copy a shedload of data
+ DCArray( const DCArray & );
+};
+
+
+template <typename T>
+class StoredData
+{
+ public:
+ StoredData()
+ {
+ memset( m_data, 0, DCARRAY_ARRAY_SIZE*sizeof(DCArray<T> *) );
+ m_allocatedUpTo = 0;
+ }
+ ~StoredData()
+ {
+ reset();
+ }
+
+ inline T & operator[]( ullong i )
+ {
+ return dataAt(i);
+ }
+ inline T & dataAt( ullong i, ullong * insertPos = 0 )
+ {
+ ullong c = i % DATA_CHUNK_SIZE;
+ ullong b = ullong((i-c)/DATA_CHUNK_SIZE) % DATA_CHUNK_ARRAY_SIZE;
+ ullong a = ullong((ullong((i-c)/DATA_CHUNK_SIZE)-b)/DATA_CHUNK_ARRAY_SIZE);
+
+ if ( a >= m_allocatedUpTo )
+ allocateUpTo(a+1);
+
+ if ( a >= DCARRAY_ARRAY_SIZE )
+ {
+ a = DCARRAY_ARRAY_SIZE - 1;
+ if ( insertPos )
+ *insertPos = toPos( a, b, c );
+ }
+
+ return m_data[a]->chunk(b)->data[c];
+ }
+
+ ullong toPos( ullong a, ullong b, ullong c ) const
+ {
+ return (((a*DATA_CHUNK_ARRAY_SIZE)+b)*DATA_CHUNK_SIZE)+c;
+ }
+
+ uint allocatedUpTo() const { return m_allocatedUpTo; }
+
+ DCArray<T> * dcArray( unsigned pos ) const
+ {
+ return (pos < m_allocatedUpTo) ? m_data[pos] : 0l;
+ }
+
+ /**
+ * Initialises all data to 0
+ */
+ void reset()
+ {
+ for ( uint i=0; i<m_allocatedUpTo; ++i)
+ delete m_data[i];
+ m_allocatedUpTo = 0;
+ }
+
+ protected:
+ void allocateUpTo( uint upTo )
+ {
+ if ( upTo >= DCARRAY_ARRAY_SIZE )
+ {
+ // Shuffle all data (getting rid of the oldest data)
+ delete m_data[0];
+ for ( unsigned i = 1; i < m_allocatedUpTo; ++i )
+ m_data[i-1] = m_data[i];
+
+ upTo = DCARRAY_ARRAY_SIZE;
+ m_allocatedUpTo--;
+ }
+
+ for ( unsigned i = m_allocatedUpTo; i < upTo; ++i )
+ m_data[i] = new DCArray<T>;
+
+ m_allocatedUpTo = upTo;
+ }
+ DCArray<T> * m_data[DCARRAY_ARRAY_SIZE];
+
+ uint m_allocatedUpTo;
+
+ private:
+ // We don't want to accidently copy a shedload of data
+ StoredData( const StoredData<T> & );
+};
+
+
+/**
+@author David Saxton
+ */
+class ProbeData : public QObject
+{
+ Q_OBJECT;
+ public:
+ ProbeData( int id );
+ ~ProbeData();
+
+ /**
+ * @returns unique id for oscilloscope, set on construction
+ */
+ int id() const { return m_id; }
+ /**
+ * Set the proportion (0 = top, 1 = bottom) of the way down the
+ * oscilloscope view that the probe output is drawn. If the proportion
+ * is out of range ( <0, or >1), then the drawPosition is set to 0/1
+ */
+ void setDrawPosition( float drawPosition ) { m_drawPosition = drawPosition; }
+ /**
+ * Returns the draw position. Default is 0.5.
+ * @see setDrawPosition
+ */
+ float drawPosition() const { return m_drawPosition; }
+ /**
+ * Set the colour that is used to display the probe in the oscilloscope.
+ * Default is black.
+ */
+ void setColor( QColor color );
+ /**
+ * @returns the colour that is used to display the probe in the oscilloscope
+ */
+ QColor color() const { return m_color; }
+// /**
+// * Will not record any data when paused
+// */
+// void setPaused( bool isPaused ) { b_isPaused = isPaused; }
+ /**
+ * Returns the time (in Simulator time) that this probe was created at,
+ * or last reset.
+ */
+ ullong resetTime() const { return m_resetTime; }
+ /**
+ * Erases all recorded data, and sets m_resetTime to the current
+ * simulator time.
+ */
+ virtual void eraseData() = 0;
+ /**
+ * Searches for and returns the position of the last DataPoint that was
+ * added before or at the given Simulator time. If no DataPoints were
+ * were recorded before the given time, then will return the one closest
+ * to the given time. Will return 0 if no DataPoints have been recorded
+ * yet.
+ */
+ virtual ullong findPos( llong time ) const = 0;
+
+ ullong insertPos() const { return m_insertPos; }
+
+ signals:
+ /**
+ * Emitted when an attribute that affects how the probe is drawn in the
+ * oscilloscope is changed.
+ */
+ void displayAttributeChanged();
+
+ protected:
+ const int m_id;
+ float m_drawPosition;
+ ullong m_insertPos;
+// bool b_isPaused;
+ ullong m_resetTime;
+ QColor m_color;
+};
+
+
+/**
+@author David Saxton
+*/
+class LogicProbeData : public ProbeData
+{
+ public:
+ LogicProbeData( int id );
+
+ /**
+ * Appends the data point to the set of data.
+ */
+ void addDataPoint( LogicDataPoint data )
+ {
+ ullong next = m_insertPos++;
+ m_data.dataAt( next, & m_insertPos ) = data;
+ }
+
+ virtual void eraseData();
+ virtual ullong findPos( llong time ) const;
+
+ protected:
+ StoredData<LogicDataPoint> m_data;
+ friend class OscilloscopeView;
+};
+
+
+/**
+@author David Saxton
+*/
+class FloatingProbeData : public ProbeData
+{
+ public:
+ enum Scaling { Linear, Logarithmic };
+
+ FloatingProbeData( int id );
+
+ /**
+ * Appends the data point to the set of data.
+ */
+ void addDataPoint( float data ) { m_data[m_insertPos++] = data; }
+ /**
+ * Converts the insert position to a Simulator time.
+ */
+ ullong toTime( ullong at ) const;
+ /**
+ * Sets the scaling to use in the oscilloscope display.
+ */
+ void setScaling( Scaling scaling );
+ /**
+ * @return the scaling used for the oscilloscope display.
+ */
+ Scaling scaling() const { return m_scaling; }
+ /**
+ * Sets the value to use as the upper absolute value in the display.
+ */
+ void setUpperAbsValue( double upperAbsValue );
+ /**
+ * @return the upper absolute value to use in the display.
+ */
+ double upperAbsValue() const { return m_upperAbsValue; }
+ /**
+ * Sets the value to use as the lower absolute value in the display
+ * (this is only used with logarithmic scaling).
+ */
+ void setLowerAbsValue( double lowerAbsValue );
+ /**
+ * @return the lower absolute value to use in the display (this is
+ * only used with logarithmic scaling).
+ */
+ double lowerAbsValue() const { return m_lowerAbsValue; }
+
+ virtual void eraseData();
+ virtual ullong findPos( llong time ) const;
+
+ protected:
+ Scaling m_scaling;
+ double m_upperAbsValue;
+ double m_lowerAbsValue;
+ StoredData<float> m_data;
+ friend class OscilloscopeView;
+};
+
+
+#endif