Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: be8f84cb09b0
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 83e4fb3b6fa8
Choose a head ref
  • 4 commits
  • 4 files changed
  • 1 contributor

Commits on Nov 6, 2020

  1. Copy the full SHA
    8036035 View commit details
  2. EyePattern: used simple LCG rather than libc rand() for antialiasing …

    …(~20% speedup). Moved some sanity checks outside inner loop
    azonenberg committed Nov 6, 2020
    Copy the full SHA
    cef868e View commit details
  3. Copy the full SHA
    ffb1b16 View commit details
  4. Copy the full SHA
    83e4fb3 View commit details
Showing with 145 additions and 73 deletions.
  1. +74 −67 scopeprotocols/EyePattern.cpp
  2. +1 −0 scopeprotocols/SDCmdDecoder.cpp
  3. +63 −5 scopeprotocols/SDDataDecoder.cpp
  4. +7 −1 scopeprotocols/SDDataDecoder.h
141 changes: 74 additions & 67 deletions scopeprotocols/EyePattern.cpp
Original file line number Diff line number Diff line change
@@ -65,13 +65,25 @@ EyeWaveform::~EyeWaveform()

void EyeWaveform::Normalize()
{
//Normalize it
size_t len = m_width * m_height;

//Find the peak amplitude
//Preprocessing
int64_t nmax = 0;
for(size_t i=0; i<len; i++)
nmax = max(m_accumdata[i], nmax);
int64_t halfwidth = m_width/2;
size_t blocksize = halfwidth * sizeof(int64_t);
for(size_t y=0; y<m_height; y++)
{
int64_t* row = m_accumdata + y*m_width;

//Find peak amplitude
for(size_t x=halfwidth; x<m_width; x++)
nmax = max(row[x], nmax);

//Copy right half to left half
memcpy(row, row+halfwidth, blocksize);

//Fix singularity at midpoint (TODO: better option)
row[halfwidth+1] = row[halfwidth+2];
row[halfwidth] = row[halfwidth-1];
}
if(nmax == 0)
nmax = 1;
float norm = 2.0f / nmax;
@@ -82,6 +94,7 @@ void EyeWaveform::Normalize()
2.0 means mapping values to [0, 2] and saturating anything above 1.
*/
norm *= m_saturationLevel;
size_t len = m_width * m_height;
for(size_t i=0; i<len; i++)
m_outdata[i] = min(1.0f, m_accumdata[i] * norm);
}
@@ -431,89 +444,83 @@ void EyePattern::Refresh()
clock_edges[i] += cap->m_uiWidth / 2;
}

uint32_t prng = 0xdeadbeef;

//Process the eye
size_t cend = clock_edges.size();
float yscale = m_height / GetVoltageRange();
float ymid = m_height / 2;
float yoff = -center*yscale + ymid;
size_t iclock = 0;
size_t wend = waveform->m_samples.size()-1;
for(size_t i=0; i<wend; i++)
if(m_xscale > FLT_EPSILON)
{
//If scale isn't defined yet, early out
if(m_xscale < FLT_EPSILON)
break;

//Stop when we get to the end of the clock
if(iclock + 1 >= cend)
break;

//Find time of this sample.
//If it's past the end of the current UI, move to the next clock edge
int64_t tnext = clock_edges[iclock + 1];
int64_t twidth = tnext - clock_edges[iclock];
int64_t tstart = waveform->m_offsets[i] * waveform->m_timescale + waveform->m_triggerPhase;
int64_t offset = tstart - clock_edges[iclock];
if(offset < -10)
continue;
if(offset > twidth)
for(size_t i=0; i<wend; i++)
{
//Move to the next clock edge
iclock ++;
//Stop when we get to the end of the clock
if(iclock + 1 >= cend)
break;

//Figure out the offset to the next edge
offset = tstart - tnext;
}
//Find time of this sample.
//If it's past the end of the current UI, move to the next clock edge
int64_t tnext = clock_edges[iclock + 1];
int64_t twidth = tnext - clock_edges[iclock];
int64_t tstart = waveform->m_offsets[i] * waveform->m_timescale + waveform->m_triggerPhase;
int64_t offset = tstart - clock_edges[iclock];
if(offset < -10)
continue;
if(offset > twidth)
{
//Move to the next clock edge
iclock ++;
if(iclock + 1 >= cend)
break;

//LogDebug("%zu, %zd\n", i, offset);
//Figure out the offset to the next edge
offset = tstart - tnext;
}

//Interpolate voltage
int64_t dt = (waveform->m_offsets[i+1] - waveform->m_offsets[i]) * waveform->m_timescale;
float pixel_x_f = (offset - m_xoff) * m_xscale;
float pixel_x_fround = floor(pixel_x_f);
float dv = waveform->m_samples[i+1] - waveform->m_samples[i];
float dx_frac = (pixel_x_f - pixel_x_fround ) / (dt * m_xscale );
float nominal_voltage = waveform->m_samples[i] + dv*dx_frac;
//LogDebug("%zu, %zd\n", i, offset);

//Antialiasing: jitter the fractional X position by up to 1ps to fill in blank spots
pixel_x_f -= m_xscale * 0.5;
pixel_x_f += (rand() & 0xff) * m_xscale / 255.0f;
//Interpolate voltage
int64_t dt = (waveform->m_offsets[i+1] - waveform->m_offsets[i]) * waveform->m_timescale;
float pixel_x_f = (offset - m_xoff) * m_xscale;
float pixel_x_fround = floor(pixel_x_f);
float dv = waveform->m_samples[i+1] - waveform->m_samples[i];
float dx_frac = (pixel_x_f - pixel_x_fround ) / (dt * m_xscale );
float nominal_voltage = waveform->m_samples[i] + dv*dx_frac;

//LogDebug("%zu, %zd, %f\n", i, offset, pixel_x_f);
//Antialiasing: jitter the fractional X position by up to 1ps to fill in blank spots
pixel_x_f -= m_xscale * 0.5;
pixel_x_f += (prng & 0xff) * m_xscale / 255.0f;
prng = 0x343fd * prng + 0x269ec3;

//Find (and sanity check) the Y coordinate
float nominal_pixel_y = nominal_voltage*yscale + yoff;
size_t y1 = static_cast<size_t>(nominal_pixel_y);
if(y1 >= (m_height-1))
continue;
//LogDebug("%zu, %zd, %f\n", i, offset, pixel_x_f);

//Calculate how much of the pixel's intensity to put in each row
float yfrac = nominal_pixel_y - y1;
int bin2 = yfrac * 64;
int bin1 = 64 - bin2;
int64_t* row1 = data + y1*m_width;
int64_t* row2 = row1 + m_width;

//Plot each point 3 times for center/left/right portions of the eye
int64_t pixel_x_round = round(pixel_x_f);
int64_t pixel_x_round2 = round(pixel_x_f + m_xscale*cap->m_uiWidth);
int64_t pixel_x_round3 = round(pixel_x_f - m_xscale*cap->m_uiWidth);
int64_t xpos[] = { pixel_x_round, pixel_x_round2, pixel_x_round3 };
int64_t w = m_width;
for(auto x : xpos)
{
if( (x+1 < w) && (x >= 0) )
//Find (and sanity check) the Y coordinate
float nominal_pixel_y = nominal_voltage*yscale + yoff;
size_t y1 = static_cast<size_t>(nominal_pixel_y);
if(y1 >= (m_height-1))
continue;

//Calculate how much of the pixel's intensity to put in each row
float yfrac = nominal_pixel_y - y1;
int bin2 = yfrac * 64;
int bin1 = 64 - bin2;
int64_t* row1 = data + y1*m_width;
int64_t* row2 = row1 + m_width;

//Plot each point (this only draws the right half of the eye, we copy to the left later)
int64_t pixel_x_round = round(pixel_x_f);
if( (pixel_x_round+1 < (int64_t)m_width) && (pixel_x_round >= 0) )
{
row1[x+0] += bin1 * dx_frac;
row1[x+1] += bin1 * (1-dx_frac);
row2[x+0] += bin2 * dx_frac;
row2[x+1] += bin2 * (1-dx_frac);
row1[pixel_x_round+0] += bin1 * dx_frac;
row1[pixel_x_round+1] += bin1 * (1-dx_frac);
row2[pixel_x_round+0] += bin2 * dx_frac;
row2[pixel_x_round+1] += bin2 * (1-dx_frac);
}
}
}
fflush(stdout);

//Count total number of UIs we've integrated
cap->IntegrateUIs(clock_edges.size());
1 change: 1 addition & 0 deletions scopeprotocols/SDCmdDecoder.cpp
Original file line number Diff line number Diff line change
@@ -376,6 +376,7 @@ void SDCmdDecoder::Refresh()
cap->m_samples.push_back(SDCmdSymbol(SDCmdSymbol::TYPE_ERROR, b));
}

pack->m_len = end - pack->m_offset;
m_packets.push_back(pack);
pack = NULL;

68 changes: 63 additions & 5 deletions scopeprotocols/SDDataDecoder.cpp
Original file line number Diff line number Diff line change
@@ -43,17 +43,14 @@ using namespace std;
// Construction / destruction

SDDataDecoder::SDDataDecoder(const string& color)
: Filter(OscilloscopeChannel::CHANNEL_TYPE_COMPLEX, color, CAT_MEMORY)
: PacketDecoder(OscilloscopeChannel::CHANNEL_TYPE_COMPLEX, color, CAT_MEMORY)
{
//Remove the x1 SPI inputs
m_inputs.clear();
m_signalNames.clear();

CreateInput("clk");
CreateInput("dat3");
CreateInput("dat2");
CreateInput("dat1");
CreateInput("dat0");
CreateInput("cmdbus");
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -83,6 +80,9 @@ bool SDDataDecoder::ValidateChannel(size_t i, StreamDescriptor stream)
return true;
}

if( (i == 5) && (dynamic_cast<SDCmdDecoder*>(stream.m_channel) != NULL) )
return true;

return false;
}

@@ -104,6 +104,8 @@ void SDDataDecoder::SetDefaultName()

void SDDataDecoder::Refresh()
{
ClearPackets();

//Make sure we've got valid inputs
if(!VerifyAllInputsOK())
{
@@ -117,6 +119,7 @@ void SDDataDecoder::Refresh()
auto data2 = GetDigitalInputWaveform(2);
auto data1 = GetDigitalInputWaveform(3);
auto data0 = GetDigitalInputWaveform(4);
auto cmdbus = dynamic_cast<SDCmdDecoder*>(GetInput(5).m_channel);

//Sample the data
DigitalWaveform d0;
@@ -137,6 +140,9 @@ void SDDataDecoder::Refresh()
cap->m_startTimestamp = clk->m_startTimestamp;
cap->m_startPicoseconds = clk->m_startPicoseconds;

Packet* pack = NULL;
Packet* last_cmdbus_packet = NULL;

//Loop over the data and look for transactions
enum
{
@@ -171,6 +177,27 @@ void SDDataDecoder::Refresh()
cap->m_samples.push_back(SDDataSymbol(SDDataSymbol::TYPE_START, 0));
bytes_left = 512;
state = STATE_DATA_HIGH;

//Find the command bus packet that triggered this data bus transaction
auto cmd_packet = FindCommandBusPacket(cmdbus, d0.m_offsets[i]);

//If it's the same as our last packet, or doesn't exist, don't make a new packet
if( (cmd_packet == last_cmdbus_packet) || (cmd_packet == NULL) )
pack = NULL;

//New packet, process stuff
else
{
pack = new Packet;
pack->m_offset = d0.m_offsets[i];
pack->m_len = 0;
pack->m_headers = cmd_packet->m_headers;
pack->m_displayForegroundColor = cmd_packet->m_displayForegroundColor;
pack->m_displayBackgroundColor = cmd_packet->m_displayBackgroundColor;
m_packets.push_back(pack);

last_cmdbus_packet = cmd_packet;
}
}

//Idle
@@ -294,3 +321,34 @@ string SDDataDecoder::GetText(int i)
}
return "";
}

vector<string> SDDataDecoder::GetHeaders()
{
vector<string> ret;
ret.push_back("Type");
ret.push_back("Code");
ret.push_back("Command");
ret.push_back("Info");
return ret;
}

Packet* SDDataDecoder::FindCommandBusPacket(SDCmdDecoder* decode, int64_t timestamp)
{
//TODO: more efficient than linear search
Packet* ret = NULL;
auto packets = decode->GetPackets();
for(auto p : packets)
{
//If it's not a command, ignore it
if(p->m_headers["Type"] != "Command")
continue;

//If it's after the timestamp, we're done
if(p->m_offset > timestamp)
break;

ret = p;

}
return ret;
}
8 changes: 7 additions & 1 deletion scopeprotocols/SDDataDecoder.h
Original file line number Diff line number Diff line change
@@ -36,6 +36,9 @@
#ifndef SDDataDecoder_h
#define SDDataDecoder_h

#include "../scopehal/PacketDecoder.h"
#include "SDCmdDecoder.h"

class SDDataSymbol
{
public:
@@ -68,13 +71,15 @@ class SDDataSymbol

typedef Waveform<SDDataSymbol> SDDataWaveform;

class SDDataDecoder : public Filter
class SDDataDecoder : public PacketDecoder
{
public:
SDDataDecoder(const std::string& color);

virtual void Refresh();

std::vector<std::string> GetHeaders();

static std::string GetProtocolName();
virtual void SetDefaultName();

@@ -87,6 +92,7 @@ class SDDataDecoder : public Filter
PROTOCOL_DECODER_INITPROC(SDDataDecoder)

protected:
Packet* FindCommandBusPacket(SDCmdDecoder* decode, int64_t timestamp);
};

#endif