Skip to content

Commit

Permalink
Merge pull request #3 from saleae/feature/both-edges
Browse files Browse the repository at this point in the history
Feature: Dual Edge Support
  • Loading branch information
Marcus10110 authored Nov 30, 2022
2 parents 2dadf5a + d304fbe commit f7c2a73
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 31 deletions.
127 changes: 112 additions & 15 deletions src/SimpleParallelAnalyzer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "SimpleParallelAnalyzer.h"
#include "SimpleParallelAnalyzerSettings.h"
#include <AnalyzerChannelData.h>
#include <cassert>
#include <algorithm>

SimpleParallelAnalyzer::SimpleParallelAnalyzer()
: Analyzer2(), mSettings( new SimpleParallelAnalyzerSettings() ), mSimulationInitilized( false )
Expand All @@ -26,7 +28,7 @@ void SimpleParallelAnalyzer::WorkerThread()
mSampleRateHz = GetSampleRate();

AnalyzerResults::MarkerType clock_arrow;
if( mSettings->mClockEdge == AnalyzerEnums::NegEdge )
if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::NegEdge )
clock_arrow = AnalyzerResults::DownArrow;
else
clock_arrow = AnalyzerResults::UpArrow;
Expand All @@ -51,16 +53,22 @@ void SimpleParallelAnalyzer::WorkerThread()

U32 num_data_lines = mData.size();

if( mSettings->mClockEdge == AnalyzerEnums::NegEdge )
if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::NegEdge )
{
if( mClock->GetBitState() == BIT_LOW )
mClock->AdvanceToNextEdge();
}
else
else if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::NegEdge )
{
if( mClock->GetBitState() == BIT_HIGH )
mClock->AdvanceToNextEdge();
}
else if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::DualEdge )
{
// handling both edges is different enough to warrant a separate implementation.
DecodeBothEdges();
return;
}

mClock->AdvanceToNextEdge(); // this is the data-valid edge

Expand All @@ -73,18 +81,7 @@ void SimpleParallelAnalyzer::WorkerThread()
U64 sample = mClock->GetSampleNumber();
mResults->AddMarker( sample, clock_arrow, mSettings->mClockChannel );

U16 result = 0;

for( U32 i = 0; i < num_data_lines; i++ )
{
mData[ i ]->AdvanceToAbsPosition( sample );
if( mData[ i ]->GetBitState() == BIT_HIGH )
{
result |= mDataMasks[ i ];
}
mResults->AddMarker( sample, AnalyzerResults::Dot, mDataChannels[ i ] );
}

U16 result = GetWordAtLocation( sample );

FrameV2 frame_v2;
frame_v2.AddInteger( "data", result );
Expand Down Expand Up @@ -218,6 +215,106 @@ const char* SimpleParallelAnalyzer::GetAnalyzerName() const
return "Simple Parallel";
}


void SimpleParallelAnalyzer::DecodeBothEdges()
{
// helper to allow us to successfully report the last edge, even if there are no more edges in the capture.
// Normally, in order to report a specific edge, the following edge must be found first.
// If that following edge does not exist, and never will exist, instead we advance a intermediate amount, and return false.
// If there is another edge, we advance to it and return true.
// force_advance optionally ensures we advance to the next edge. If there are no more edges in the data, this will never return.
auto advance_to_next_edge_or_fail = [&]( bool force_advance ) -> bool {
if( mClock->DoMoreTransitionsExistInCurrentData() || force_advance )
{
mClock->AdvanceToNextEdge();
return true;
}
int64_t estimated_frame_size = mLastFrameWidth > 0 ? std::max<int64_t>( static_cast<int64_t>( mLastFrameWidth * 0.1 ), 2 ) : 10;
if( mClock->WouldAdvancingCauseTransition( estimated_frame_size ) )
{
// this condition will only be true if we're very lucky, and we're processing data while recording in real time.
mClock->AdvanceToNextEdge();
return true;
}
mClock->Advance( estimated_frame_size );
return false;
};

// Frames start at the active edge, and extend to the following edge -1. (or they extend to an estimated width, if no more data is
// found.)
// we must advance past the active edge before committing the result from that edge.

// has_pending_frame indicates that we have a word to store after the previous cycle.
bool has_pending_frame = false;
uint16_t previous_value = 0;
uint64_t previous_sample = 0;

for( ;; )
{
// advance to the next active edge.
auto found_next_edge = advance_to_next_edge_or_fail( !has_pending_frame );
auto location = mClock->GetSampleNumber();
uint64_t progress_update = 0;
if( has_pending_frame )
{
// store the previous frame.
progress_update = AddFrame( previous_value, previous_sample, location - 1 );
has_pending_frame = false;
}
if( found_next_edge )
{
has_pending_frame = true;
previous_sample = location;
previous_value = GetWordAtLocation( location );

mResults->AddMarker( location, mClock->GetBitState() == BIT_LOW ? AnalyzerResults::DownArrow : AnalyzerResults::UpArrow,
mSettings->mClockChannel );
}

if( progress_update > 0 )
{
ReportProgress( progress_update );
}
}
}

uint16_t SimpleParallelAnalyzer::GetWordAtLocation( uint64_t sample_number )
{
uint16_t result = 0;

int num_data_lines = mData.size();

for( int i = 0; i < num_data_lines; i++ )
{
mData[ i ]->AdvanceToAbsPosition( sample_number );
if( mData[ i ]->GetBitState() == BIT_HIGH )
{
result |= mDataMasks[ i ];
}
mResults->AddMarker( sample_number, AnalyzerResults::Dot, mDataChannels[ i ] );
}

return result;
}

uint64_t SimpleParallelAnalyzer::AddFrame( uint16_t value, uint64_t starting_sample, uint64_t ending_sample )
{
assert( starting_sample <= ending_sample );
FrameV2 frame_v2;
frame_v2.AddInteger( "data", value );

Frame frame;
frame.mData1 = value;
frame.mFlags = 0;
frame.mStartingSampleInclusive = starting_sample;
frame.mEndingSampleInclusive = ending_sample;
mResults->AddFrame( frame );
mResults->AddFrameV2( frame_v2, "data", frame.mStartingSampleInclusive, frame.mEndingSampleInclusive );
mResults->CommitResults();
mLastFrameWidth = std::max<uint64_t>( ending_sample - starting_sample, 1 );
return ending_sample;
}

const char* GetAnalyzerName()
{
return "Simple Parallel";
Expand Down
9 changes: 7 additions & 2 deletions src/SimpleParallelAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ class SimpleParallelAnalyzer : public Analyzer2
#pragma warning( \
disable : 4251 ) // warning C4251: 'SerialAnalyzer::<...>' : class <...> needs to have dll-interface to be used by clients of class

std::auto_ptr<SimpleParallelAnalyzerSettings> mSettings;
std::auto_ptr<SimpleParallelAnalyzerResults> mResults;
void DecodeBothEdges();
uint16_t GetWordAtLocation( uint64_t sample_number );
uint64_t AddFrame( uint16_t value, uint64_t starting_sample, uint64_t ending_sample );
int64_t mLastFrameWidth = -1; // holds the width of the last frame, in samples, or -1 if no previous frames created.

std::unique_ptr<SimpleParallelAnalyzerSettings> mSettings;
std::unique_ptr<SimpleParallelAnalyzerResults> mResults;

std::vector<AnalyzerChannelData*> mData;
std::vector<U16> mDataMasks;
Expand Down
21 changes: 13 additions & 8 deletions src/SimpleParallelAnalyzerSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

#pragma warning( disable : 4996 ) // warning C4996: 'sprintf': This function or variable may be unsafe

SimpleParallelAnalyzerSettings::SimpleParallelAnalyzerSettings() : mClockChannel( UNDEFINED_CHANNEL ), mClockEdge( AnalyzerEnums::PosEdge )
SimpleParallelAnalyzerSettings::SimpleParallelAnalyzerSettings()
: mClockChannel( UNDEFINED_CHANNEL ), mClockEdge( ParallelAnalyzerClockEdge::PosEdge )
{
U32 count = 16;
for( U32 i = 0; i < count; i++ )
Expand All @@ -30,9 +31,10 @@ SimpleParallelAnalyzerSettings::SimpleParallelAnalyzerSettings() : mClockChannel

mClockEdgeInterface.reset( new AnalyzerSettingInterfaceNumberList() );
mClockEdgeInterface->SetTitleAndTooltip( "Clock State", "Define whether the data is valid on Clock rising or falling edge" );
mClockEdgeInterface->AddNumber( AnalyzerEnums::PosEdge, "Rising edge", "" );
mClockEdgeInterface->AddNumber( AnalyzerEnums::NegEdge, "Falling edge", "" );
mClockEdgeInterface->SetNumber( mClockEdge );
mClockEdgeInterface->AddNumber( static_cast<double>( ParallelAnalyzerClockEdge::PosEdge ), "Rising edge", "" );
mClockEdgeInterface->AddNumber( static_cast<double>( ParallelAnalyzerClockEdge::NegEdge ), "Falling edge", "" );
mClockEdgeInterface->AddNumber( static_cast<double>( ParallelAnalyzerClockEdge::DualEdge ), "Dual edge", "" );
mClockEdgeInterface->SetNumber( static_cast<double>( mClockEdge ) );


for( U32 i = 0; i < count; i++ )
Expand Down Expand Up @@ -87,7 +89,7 @@ bool SimpleParallelAnalyzerSettings::SetSettingsFromInterfaces()
}

mClockChannel = mClockChannelInterface->GetChannel();
mClockEdge = AnalyzerEnums::EdgeDirection( U32( mClockEdgeInterface->GetNumber() ) );
mClockEdge = static_cast<ParallelAnalyzerClockEdge>( U32( mClockEdgeInterface->GetNumber() ) );

ClearChannels();
for( U32 i = 0; i < count; i++ )
Expand All @@ -111,7 +113,7 @@ void SimpleParallelAnalyzerSettings::UpdateInterfacesFromSettings()
}

mClockChannelInterface->SetChannel( mClockChannel );
mClockEdgeInterface->SetNumber( mClockEdge );
mClockEdgeInterface->SetNumber( static_cast<double>( mClockEdge ) );
}

void SimpleParallelAnalyzerSettings::LoadSettings( const char* settings )
Expand All @@ -127,7 +129,9 @@ void SimpleParallelAnalyzerSettings::LoadSettings( const char* settings )
}

text_archive >> mClockChannel;
text_archive >> *( U32* )&mClockEdge;
U32 edge;
text_archive >> edge;
mClockEdge = static_cast<ParallelAnalyzerClockEdge>( edge );

ClearChannels();
for( U32 i = 0; i < count; i++ )
Expand All @@ -154,7 +158,8 @@ const char* SimpleParallelAnalyzerSettings::SaveSettings()
}

text_archive << mClockChannel;
text_archive << mClockEdge;
U32 edge = static_cast<U32>( mClockEdge );
text_archive << edge;

return SetReturnString( text_archive.GetString() );
}
14 changes: 11 additions & 3 deletions src/SimpleParallelAnalyzerSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
#include <AnalyzerSettings.h>
#include <AnalyzerTypes.h>

// originally from AnalyzerEnums::EdgeDirection { PosEdge, NegEdge };
enum class ParallelAnalyzerClockEdge
{
PosEdge = AnalyzerEnums::PosEdge,
NegEdge = AnalyzerEnums::NegEdge,
DualEdge
};

class SimpleParallelAnalyzerSettings : public AnalyzerSettings
{
public:
Expand All @@ -19,13 +27,13 @@ class SimpleParallelAnalyzerSettings : public AnalyzerSettings
std::vector<Channel> mDataChannels;
Channel mClockChannel;

AnalyzerEnums::EdgeDirection mClockEdge;
ParallelAnalyzerClockEdge mClockEdge;

protected:
std::vector<AnalyzerSettingInterfaceChannel*> mDataChannelsInterface;

std::auto_ptr<AnalyzerSettingInterfaceChannel> mClockChannelInterface;
std::auto_ptr<AnalyzerSettingInterfaceNumberList> mClockEdgeInterface;
std::unique_ptr<AnalyzerSettingInterfaceChannel> mClockChannelInterface;
std::unique_ptr<AnalyzerSettingInterfaceNumberList> mClockEdgeInterface;
};

#endif // SIMPLEPARALLEL_ANALYZER_SETTINGS
17 changes: 14 additions & 3 deletions src/SimpleParallelSimulationDataGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,18 @@ void SimpleParallelSimulationDataGenerator::Initialize( U32 simulation_sample_ra
mDataMasks.push_back( val );
}

if( mSettings->mClockEdge == AnalyzerEnums::NegEdge )
if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::NegEdge )
{
mClock = mSimulationData.Add( mSettings->mClockChannel, mSimulationSampleRateHz, BIT_LOW );
else
}
else if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::PosEdge )
{
mClock = mSimulationData.Add( mSettings->mClockChannel, mSimulationSampleRateHz, BIT_HIGH );
}
else if( mSettings->mClockEdge == ParallelAnalyzerClockEdge::DualEdge )
{
mClock = mSimulationData.Add( mSettings->mClockChannel, mSimulationSampleRateHz, BIT_HIGH );
}

mValue = 0;
}
Expand All @@ -54,7 +62,10 @@ U32 SimpleParallelSimulationDataGenerator::GenerateSimulationData( U64 largest_s
else
mData[ i ]->TransitionIfNeeded( BIT_HIGH );
}
mClock->Transition();
if( mSettings->mClockEdge != ParallelAnalyzerClockEdge::DualEdge )
{
mClock->Transition();
}

mSimulationData.AdvanceAll( 1000 );
mClock->Transition();
Expand Down

0 comments on commit f7c2a73

Please sign in to comment.