/*************************************************************************** * 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 OSCILLOSCOPEDATA_H #define OSCILLOSCOPEDATA_H #include #include 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*)) // 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 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 LogicChunk; typedef DataChunk FloatingChunk; template class DCArray { public: DCArray() { memset( m_data, 0, DATA_CHUNK_ARRAY_SIZE*sizeof(DataChunk *) ); m_allocatedUpTo = 0; } ~DCArray() { for ( uint i=0; i * 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; m_allocatedUpTo = upTo; } DataChunk * 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 class StoredData { public: StoredData() { memset( m_data, 0, DCARRAY_ARRAY_SIZE*sizeof(DCArray *) ); 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 * dcArray( unsigned pos ) const { return (pos < m_allocatedUpTo) ? m_data[pos] : 0l; } /** * Initialises all data to 0 */ void reset() { for ( uint i=0; i= 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; m_allocatedUpTo = upTo; } DCArray * m_data[DCARRAY_ARRAY_SIZE]; uint m_allocatedUpTo; private: // We don't want to accidently copy a shedload of data StoredData( const StoredData & ); }; /** @author David Saxton */ class ProbeData : public TQObject { 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( TQColor color ); /** * @returns the colour that is used to display the probe in the oscilloscope */ TQColor 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; TQColor 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 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 m_data; friend class OscilloscopeView; }; #endif