174 lines
5.7 KiB
C++
174 lines
5.7 KiB
C++
#include "C64SerialAnalyzer.h"
|
|
#include "C64SerialAnalyzerSettings.h"
|
|
#include <AnalyzerChannelData.h>
|
|
|
|
C64SerialAnalyzer::C64SerialAnalyzer()
|
|
: Analyzer2(), mSettings(new C64SerialAnalyzerSettings()),
|
|
mSimulationInitilized(false) {
|
|
SetAnalyzerSettings(mSettings.get());
|
|
}
|
|
|
|
C64SerialAnalyzer::~C64SerialAnalyzer() { KillThread(); }
|
|
|
|
void C64SerialAnalyzer::SetupResults() {
|
|
mResults.reset(new C64SerialAnalyzerResults(this, mSettings.get()));
|
|
SetAnalyzerResults(mResults.get());
|
|
mResults->AddChannelBubblesWillAppearOn(mSettings->mDataChannel);
|
|
}
|
|
|
|
U64 C64SerialAnalyzer::AdvanceTo(U64 sample) {
|
|
mData->AdvanceToAbsPosition(sample);
|
|
mClock->AdvanceToAbsPosition(sample);
|
|
//mAttention->AdvanceToAbsPosition(sample);
|
|
|
|
return sample;
|
|
}
|
|
|
|
bool C64SerialAnalyzer::ReceiveByte() {
|
|
// Advance until both clock and data lines are asserted.
|
|
while (mData->GetBitState() == BIT_LOW ||
|
|
mClock->GetBitState() == BIT_LOW) {
|
|
AdvanceTo(std::min(mData->GetSampleOfNextEdge(),
|
|
mClock->GetSampleOfNextEdge()));
|
|
}
|
|
|
|
bool eoi = mData->GetSampleOfNextEdge() < mClock->GetSampleOfNextEdge();
|
|
if (eoi) {
|
|
// An EOI happened, go back to idle after finishing.
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::X,
|
|
mSettings->mClockChannel);
|
|
}
|
|
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::Start,
|
|
mSettings->mDataChannel);
|
|
U64 start_sample = AdvanceTo(mClock->GetSampleOfNextEdge());
|
|
|
|
// Receive a byte
|
|
U8 byte = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
AdvanceTo(mClock->GetSampleOfNextEdge());
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::Dot,
|
|
mSettings->mDataChannel);
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::UpArrow,
|
|
mSettings->mClockChannel);
|
|
|
|
byte |= mData->GetBitState() << i;
|
|
|
|
AdvanceTo(mClock->GetSampleOfNextEdge());
|
|
mResults->AddMarker(mClock->GetSampleNumber(),
|
|
AnalyzerResults::DownArrow,
|
|
mSettings->mClockChannel);
|
|
}
|
|
|
|
// We have a byte to save
|
|
Frame frame;
|
|
frame.mData1 = byte;
|
|
frame.mType = static_cast<U8>(mState);
|
|
frame.mStartingSampleInclusive = start_sample;
|
|
frame.mEndingSampleInclusive = mData->GetSampleNumber();
|
|
|
|
mResults->AddFrame(frame);
|
|
mResults->CommitResults();
|
|
ReportProgress(frame.mEndingSampleInclusive);
|
|
|
|
// Wait until data is high and back down.
|
|
if (mData->GetBitState() == BIT_LOW) {
|
|
AdvanceTo(mData->GetSampleOfNextEdge());
|
|
}
|
|
AdvanceTo(mData->GetSampleOfNextEdge());
|
|
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::Stop,
|
|
mSettings->mDataChannel);
|
|
|
|
return eoi;
|
|
}
|
|
|
|
enum class FrameType {
|
|
Attention,
|
|
Talking,
|
|
};
|
|
|
|
void C64SerialAnalyzer::Update() {
|
|
mResults->AddMarker(mClock->GetSampleNumber(), AnalyzerResults::Dot,
|
|
mSettings->mAttentionChannel);
|
|
|
|
if (mState == State::Idle) {
|
|
// Advance until both clock and data lines are asserted.
|
|
while (mData->GetBitState() == BIT_HIGH ||
|
|
mClock->GetBitState() == BIT_HIGH) {
|
|
AdvanceTo(std::min(mData->GetSampleOfNextEdge(),
|
|
mClock->GetSampleOfNextEdge()));
|
|
}
|
|
|
|
// Check if attention was asserted.
|
|
BitState old_attention = mAttention->GetBitState();
|
|
mAttention->AdvanceToAbsPosition(mClock->GetSampleOfNextEdge());
|
|
BitState new_attention = mAttention->GetBitState();
|
|
|
|
if (new_attention == BIT_LOW) {
|
|
mState = State::Attention;
|
|
} else if (old_attention == BIT_LOW) {
|
|
// If attention was low but is now high, check if talking continues.
|
|
if (mData->GetSampleOfNextEdge() > mClock->GetSampleOfNextEdge()) {
|
|
mState = State::Talking;
|
|
} else {
|
|
AdvanceTo(mAttention->GetSampleNumber());
|
|
}
|
|
} else {
|
|
mState = State::Talking;
|
|
}
|
|
} else if (mState == State::Attention) {
|
|
ReceiveByte();
|
|
mState = State::Idle;
|
|
} else if (mState == State::Talking) {
|
|
bool eoi = ReceiveByte();
|
|
|
|
if (eoi) {
|
|
mState = State::Idle;
|
|
}
|
|
} else if (mState == State::TurnAround) {
|
|
}
|
|
}
|
|
|
|
void C64SerialAnalyzer::WorkerThread() {
|
|
mSampleRateHz = GetSampleRate();
|
|
|
|
mAttention = GetAnalyzerChannelData(mSettings->mAttentionChannel);
|
|
mData = GetAnalyzerChannelData(mSettings->mDataChannel);
|
|
mClock = GetAnalyzerChannelData(mSettings->mClockChannel);
|
|
|
|
mState = State::Idle;
|
|
while (true) {
|
|
Update();
|
|
CheckIfThreadShouldExit();
|
|
}
|
|
}
|
|
|
|
bool C64SerialAnalyzer::NeedsRerun() { return false; }
|
|
|
|
U32 C64SerialAnalyzer::GenerateSimulationData(
|
|
U64 minimum_sample_index, U32 device_sample_rate,
|
|
SimulationChannelDescriptor **simulation_channels) {
|
|
if (mSimulationInitilized == false) {
|
|
mSimulationDataGenerator.Initialize(GetSimulationSampleRate(),
|
|
mSettings.get());
|
|
mSimulationInitilized = true;
|
|
}
|
|
|
|
return mSimulationDataGenerator.GenerateSimulationData(
|
|
minimum_sample_index, device_sample_rate, simulation_channels);
|
|
}
|
|
|
|
U32 C64SerialAnalyzer::GetMinimumSampleRateHz() {
|
|
// return mSettings->mBitRate * 4;
|
|
return 4000000;
|
|
}
|
|
|
|
const char *C64SerialAnalyzer::GetAnalyzerName() const { return "C64 Serial"; }
|
|
|
|
const char *GetAnalyzerName() { return "C64 Serial"; }
|
|
|
|
Analyzer *CreateAnalyzer() { return new C64SerialAnalyzer(); }
|
|
|
|
void DestroyAnalyzer(Analyzer *analyzer) { delete analyzer; }
|