Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SWD Analyzer plugin improvement #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ src/SWDTypes.cpp
src/SWDTypes.h
src/SWDUtils.cpp
src/SWDUtils.h
src/VersionInfo.h
src/VersionInfo.cpp
)

add_analyzer_plugin(swd_analyzer SOURCES ${SOURCES})

add_custom_command(TARGET ${CMAKE_PROJECT_NAME} PRE_BUILD COMMAND ${CMAKE_COMMAND} -P "${CMAKE_SOURCE_DIR}/src/PluginVersion.cmake")
4 changes: 2 additions & 2 deletions cmake/ExternalAnalyzerSDK.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(FetchContent)

# Use the C++11 standard
set(CMAKE_CXX_STANDARD 11)
# Use the C++17 standard
set(CMAKE_CXX_STANDARD 17)

set(CMAKE_CXX_STANDARD_REQUIRED YES)

Expand Down
41 changes: 41 additions & 0 deletions src/PluginVersion.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Get repo clean status from git
execute_process(
COMMAND git diff --quiet --exit-code
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_REPO_CHANGED
)
#message("Info: Git repo changed is ${GIT_REPO_CHANGED} (0 - Not changed, 1 - Changed)")

if(${GIT_REPO_CHANGED} EQUAL 0)
# Get hash of last commit
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
# Since there are changes in repo detected hash will be zeroed
set(GIT_COMMIT_HASH "0000000")
endif()
#message("Info: Git hash is ${GIT_COMMIT_HASH}")

execute_process(
COMMAND git rev-list --all --count
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_REV_COUNT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#message("Info: Git revisions count is ${GIT_REV_COUNT}")
math(EXPR GIT_BUILD "${GIT_REV_COUNT}+${GIT_REPO_CHANGED}")
#message("Info: Build #${GIT_BUILD}")

# Hardcode version parts
set(PROJECT_VERSION_MAJOR 2)
set(PROJECT_VERSION_MINOR 0)
set(PROJECT_VERSION_PATCH 0)
math(EXPR PROJECT_VERSION_BUILD "${GIT_REV_COUNT}+${GIT_REPO_CHANGED}")
message("Info: Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_BUILD} ... ${GIT_COMMIT_HASH}")

message("Info: Updating ${CMAKE_SOURCE_DIR}/../src/VersionInfo.cpp")
file(WRITE ${CMAKE_SOURCE_DIR}/../src/VersionInfo.cpp "#include \"VersionInfo.h\"\n\nconst struct VersionInfo VERSION_INFO =\n{\n ${PROJECT_VERSION_MAJOR}u,\n ${PROJECT_VERSION_MINOR}u,\n ${PROJECT_VERSION_PATCH}u,\n ${PROJECT_VERSION_BUILD}u,\n __DATE__,\n __TIME__,\n \"${GIT_COMMIT_HASH}\"\n};\n")
162 changes: 132 additions & 30 deletions src/SWDAnalyzer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <vector>
#include <algorithm>

#include <AnalyzerChannelData.h>
Expand All @@ -7,7 +6,86 @@
#include "SWDAnalyzerSettings.h"
#include "SWDUtils.h"

SWDAnalyzer::SWDAnalyzer() : mSimulationInitilized( false )
// Sequence condition matrix
const std::vector<SWDAnalyzer::SWDSequenceCondition> SWDAnalyzer::SEQUENCE_CONDITIONS = {
// protocol, allowed previous frames, is swdSequence compare method, swdSequence object
// 50,... - SWD line reset. At least 50 SWCLKTCK cycles with SWDIOTMS HIGH.
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD },
{},
&SWDParser::IsLineReset,
&SWDParser::GetLineReset,
&SWDParser::SetLineReset },
// 16 - JTAG-to-SWD select sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD, DebugProtocol::DPROTOCOL_JTAG },
{ SwdFrameTypes::SWD_FT_LINE_RESET },
&SWDParser::IsJtagToSwd,
&SWDParser::GetJtagToSwd,
&SWDParser::SetJtagToSwd },
// 16 - SWD-to-JTAG select sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD, DebugProtocol::DPROTOCOL_JTAG },
{ SwdFrameTypes::SWD_FT_LINE_RESET },
&SWDParser::IsSwdToJtag,
&SWDParser::GetSwdToJtag,
&SWDParser::SetSwdToJtag },
// 16 - SWD-to-DS select sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD, DebugProtocol::DPROTOCOL_JTAG },
{ SwdFrameTypes::SWD_FT_LINE_RESET },
&SWDParser::IsSwdToDs,
&SWDParser::GetSwdToDs,
&SWDParser::SetSwdToDs },
// 31 - JTAG-to-DS select sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD, DebugProtocol::DPROTOCOL_JTAG },
{ SwdFrameTypes::SWD_FT_LINE_RESET, SwdFrameTypes::SWD_FT_JTAG_TLR },
&SWDParser::IsJtagToDs,
&SWDParser::GetJtagToDs,
&SWDParser::SetJtagToDs },
// 12,46 - SWD read/write operation
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD },
{ SwdFrameTypes::SWD_FT_LINE_RESET, SwdFrameTypes::SWD_FT_IDLE_CYCLE, SwdFrameTypes::SWD_FT_OPERATION,
SwdFrameTypes::SWD_FT_ERROR },
&SWDParser::IsOperation,
&SWDParser::GetOperation,
&SWDParser::SetOperation },
// 1,... - SWD idle cycles. SWCLKTCK cycles with SWDIOTMS LOW
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD },
{ SwdFrameTypes::SWD_FT_LINE_RESET, SwdFrameTypes::SWD_FT_IDLE_CYCLE, SwdFrameTypes::SWD_FT_OPERATION },
&SWDParser::IsIdleCycles,
&SWDParser::GetIdleCycles,
&SWDParser::SetIdleCycles },
// 5,0 - Enters to JTAG Test-Logic-Reset state
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_SWD, DebugProtocol::DPROTOCOL_JTAG },
{},
&SWDParser::IsJtagTlr,
&SWDParser::GetJtagTlr,
&SWDParser::SetJtagTlr },
// 8,... - Selection Alert preamble. At least 8 SWCLKTCK cycles with SWDIOTMS HIGH.
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_DORMANT },
{},
&SWDParser::IsDsSelectionAlertPreamble,
&SWDParser::GetDsSelectionAlertPreamble,
&SWDParser::SetDsSelectionAlertPreamble },
// 128 - Selection Alert sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_DORMANT },
{},
&SWDParser::IsDsSelectionAlert,
&SWDParser::GetDsSelectionAlert,
&SWDParser::SetDsSelectionAlert },
// 4 - Activation Code preamble. 4 SWCLKTCK cycles with SWDIOTMS LOW
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_DORMANT },
{ SwdFrameTypes::SWD_FT_DS_SEL_ALERT },
&SWDParser::IsDsActivationCodePreamble,
&SWDParser::GetDsActivationCodePreamble,
&SWDParser::SetDsActivationCodePreamble },
// 8,12 - Activation Code sequence
{ { DebugProtocol::DPROTOCOL_UNKNOWN, DebugProtocol::DPROTOCOL_DORMANT },
{ SwdFrameTypes::SWD_FT_DS_ACTIVATION_CODE_PREAMBLE },
&SWDParser::IsDsActivationCode,
&SWDParser::GetDsActivationCode,
&SWDParser::SetDsActivationCode },
};


SWDAnalyzer::SWDAnalyzer() : Analyzer2(), mSWDIO(), mSWCLK(), mSimulationInitilized( false )
{
SetAnalyzerSettings( &mSettings );
}
Expand Down Expand Up @@ -37,40 +115,59 @@ void SWDAnalyzer::WorkerThread()

mSWDParser.Setup( mSWDIO, mSWCLK, this );

// these are our three objects that SWDParser will fill with data
// on calls to IsOperation or IsLineReset
SWDOperation tran;
SWDLineReset reset;
SWDBit error_bit;

mSWDParser.Clear();

// For every new bit the parser extracts from the stream,
// ask if this can be a valid operation or line reset.
// A valid operation will have the constant part of the request correctly set,
// and also the parity bits will be correct.
// A valid line reset has at least 50 high bits in succession.
// Set parser initial values
mSWDParser.SetCurrentProtocol( mSettings.mDProtocol );
mSWDParser.SetLastFrameType( mSettings.mLastFrame );
mSWDParser.SetDPVersion( mSettings.mDPVersion );
mSWDParser.SetNumTurnarounds( mSettings.mNumTurnarounds );
mSWDParser.SetOverrunDetection( mSettings.mOverrunDetection );
mSWDParser.SetSelectRegister( mSettings.mSelectRegister );

SWDErrorBits& errorBits = mSWDParser.GetErrorBits();
for( ;; )
{
if( mSWDParser.IsOperation( tran ) )
{
tran.AddFrames( mResults.get() );
tran.AddMarkers( mResults.get() );
bool conditionMeet = false;
SwdFrameTypes lastFrame = mSWDParser.GetLastFrameType();
DebugProtocol dProtocol = mSWDParser.GetCurrentProtocol();

mResults->CommitResults();
}
else if( mSWDParser.IsLineReset( reset ) )
for( const SWDSequenceCondition& cond : SEQUENCE_CONDITIONS )
{
reset.AddFrames( mResults.get() );

mResults->CommitResults();
if( cond.protocols.count( dProtocol ) != 0 )
{
if (cond.previousFrames.empty() || (std::find(cond.previousFrames.begin(), cond.previousFrames.end(), lastFrame) != cond.previousFrames.end()))
{
bool sequenceMached = std::invoke( cond.CompareFn, mSWDParser );
if( sequenceMached )
{
conditionMeet = true;
if( !errorBits.bits.empty() )
{
errorBits.SetProtocol( dProtocol );
errorBits.AddFrames( mResults.get() );
mResults->CommitResults();
errorBits.Clear();
}
SWDBaseSequnce& sequence = std::invoke( cond.GetSequence, mSWDParser );
sequence.AddFrames( mResults.get() );
sequence.AddMarkers( mResults.get() );

mResults->CommitResults();

std::invoke( cond.UpdateStatus, mSWDParser );
break;
}
}
}
}
else
if( !conditionMeet )
{
// This is neither a valid transaction nor a valid reset,
// so remove the first bit and try again.
// We're dropping the error bit into oblivion.
error_bit = mSWDParser.PopFrontBit();
// so collect these bits and go forward.
mSWDParser.BufferBits( 1 ); // Make sure at least one bit is placed on the buffer
errorBits.bits.push_back( mSWDParser.PopFrontBit() );
mSWDParser.SetErrorBits();
}

ReportProgress( mSWDIO->GetSampleNumber() );
Expand All @@ -82,16 +179,21 @@ bool SWDAnalyzer::NeedsRerun()
return false;
}

U32 SWDAnalyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate,
SimulationChannelDescriptor** simulation_channels )
DPVersion SWDAnalyzer::GetDPVersion() const
{
return mSWDParser.GetDPVersion();
}

U32 SWDAnalyzer::GenerateSimulationData( U64 minimumSampleIndex, U32 deviceSampleRate,
SimulationChannelDescriptor** simulationChannels )
{
if( !mSimulationInitilized )
{
mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), &mSettings );
mSimulationInitilized = true;
}

return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels );
return mSimulationDataGenerator.GenerateSimulationData( minimumSampleIndex, deviceSampleRate, simulationChannels );
}

U32 SWDAnalyzer::GetMinimumSampleRateHz()
Expand Down
32 changes: 24 additions & 8 deletions src/SWDAnalyzer.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef SWD_ANALYZER_H
#define SWD_ANALYZER_H

#include <set>

#include <Analyzer.h>

#include "SWDAnalyzerSettings.h"
Expand All @@ -14,18 +16,21 @@ class SWDAnalyzer : public Analyzer2
public:
SWDAnalyzer();
virtual ~SWDAnalyzer();
virtual void SetupResults();
virtual void WorkerThread();
virtual void SetupResults() override;
virtual void WorkerThread() override;

virtual U32 GenerateSimulationData( U64 newestSampleRequested, U32 sampleRate,
SimulationChannelDescriptor** simulationChannels ) override;
virtual U32 GetMinimumSampleRateHz() override;

virtual U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channels );
virtual U32 GetMinimumSampleRateHz();
virtual const char* GetAnalyzerName() const override;
virtual bool NeedsRerun() override;

virtual const char* GetAnalyzerName() const;
virtual bool NeedsRerun();
DPVersion GetDPVersion() const;

protected: // vars
SWDAnalyzerSettings mSettings;
std::auto_ptr<SWDAnalyzerResults> mResults;
std::unique_ptr<SWDAnalyzerResults> mResults;

AnalyzerChannelData* mSWDIO;
AnalyzerChannelData* mSWCLK;
Expand All @@ -35,10 +40,21 @@ class SWDAnalyzer : public Analyzer2
SWDParser mSWDParser;

bool mSimulationInitilized;

struct SWDSequenceCondition
{
std::set<DebugProtocol> protocols;
std::set<SwdFrameTypes> previousFrames;
bool ( SWDParser::*CompareFn )();
SWDBaseSequnce& ( SWDParser::*GetSequence )();
void ( SWDParser::*UpdateStatus )();
};

static const std::vector<SWDSequenceCondition> SEQUENCE_CONDITIONS;
};

extern "C" ANALYZER_EXPORT const char* __cdecl GetAnalyzerName();
extern "C" ANALYZER_EXPORT Analyzer* __cdecl CreateAnalyzer();
extern "C" ANALYZER_EXPORT void __cdecl DestroyAnalyzer( Analyzer* analyzer );

#endif // SWD_ANALYZER_H
#endif // SWD_ANALYZER_H