saleae-iec-analyser/source/C64SerialAnalyzer.cpp

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; }