Skip to content

Commit

Permalink
Now collecting timing data from Greenpak4Delay (in delay-line mode only)
Browse files Browse the repository at this point in the history
azonenberg committed Jun 6, 2017
1 parent 4d4f489 commit b76069b
Showing 6 changed files with 346 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/gp4tchar/gp4tchar.h
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ bool MeasureLUTDelays(Socket& sock, hdevice hdev);
bool MeasurePinToPinDelays(Socket& sock, hdevice hdev);
bool MeasureCrossConnectionDelays(Socket& sock, hdevice hdev);
bool MeasureInverterDelays(Socket& sock, hdevice hdev);
bool MeasureDelayLineDelays(Socket& sock, hdevice hdev);

void WaitForKeyPress();

2 changes: 1 addition & 1 deletion src/gp4tchar/main.cpp
Original file line number Diff line number Diff line change
@@ -139,9 +139,9 @@ int main(int argc, char* argv[])
return 1;
if(!MeasureInverterDelays(sock, hdev))
return 1;
*/
if(!MeasureDelayLineDelays(sock, hdev))
return 1;
*/

//Save to disk
LogNotice("Saving timing data to file %s\n", tfname.c_str());
104 changes: 104 additions & 0 deletions src/gp4tchar/measurements.cpp
Original file line number Diff line number Diff line change
@@ -73,6 +73,15 @@ bool MeasureInverterDelay(
PTVCorner corner,
map<PTVCorner, CombinatorialDelay>& delays);

bool MeasureDelayLineDelay(
Socket& sock,
hdevice hdev,
int ndel,
int ntap,
bool glitchFilter,
PTVCorner corner,
map<PTVCorner, CombinatorialDelay>& delays);

bool ProgramAndMeasureDelay(
Socket& sock,
hdevice hdev,
@@ -929,3 +938,98 @@ bool MeasureInverterDelay(

return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Characterize delay lines

bool MeasureDelayLineDelays(Socket& sock, hdevice hdev)
{
LogNotice("Measuring delay line delays...\n");
LogIndenter li;

//Test conditions (TODO: pass this in from somewhere?)
PTVCorner corner(PTVCorner::SPEED_TYPICAL, 25, 3300);

for(unsigned int ndel = 0; ndel < g_calDevice.GetDelayCount(); ndel++)
{
auto line = g_calDevice.GetDelay(ndel);

for(unsigned int ntap=1; ntap<=4; ntap ++)
{
//First round: no glitch filter
map<PTVCorner, CombinatorialDelay> delays;
if(!MeasureDelayLineDelay(sock, hdev, ndel, ntap, false, corner, delays))
return false;
for(auto it : delays)
line->SetUnfilteredDelay(ntap, it.first, it.second);

//Do it again with the glitch filter on
delays.clear();
if(!MeasureDelayLineDelay(sock, hdev, ndel, ntap, true, corner, delays))
return false;
for(auto it : delays)
line->SetFilteredDelay(ntap, it.first, it.second);
}
}

return true;
}

bool MeasureDelayLineDelay(
Socket& sock,
hdevice hdev,
int ndel,
int ntap,
bool glitchFilter,
PTVCorner corner,
map<PTVCorner, CombinatorialDelay>& delays)
{
//Create the device object
Greenpak4Device device(part, unused_pull, unused_drive);
device.SetIOPrecharge(false);
device.SetDisableChargePump(false);
device.SetLDOBypass(false);
device.SetNVMRetryCount(1);

//Look up the DUT
auto delay = device.GetDelay(ndel);

//See which half of the device it's in. Use pins 3/4 or 13/14 as appropriate
int src = 3;
int dst = 4;
if(delay->GetMatrix() == 1)
{
src = 13;
dst = 14;
}

//Configure the input pin
auto vss = device.GetGround();
auto srciob = device.GetIOB(src);
srciob->SetInput("OE", vss);
auto din = srciob->GetOutput("OUT");

//Configure the delay line
delay->SetInput("IN", din);
delay->SetTap(ntap);
delay->SetGlitchFilter(glitchFilter);

//Configure the output pin
auto vdd = device.GetPower();
auto dstiob = device.GetIOB(dst);
dstiob->SetInput("IN", delay->GetOutput("OUT"));
dstiob->SetInput("OE", vdd);
dstiob->SetDriveType(Greenpak4IOB::DRIVE_PUSHPULL);
dstiob->SetDriveStrength(Greenpak4IOB::DRIVE_2X);

//Generate a bitstream
vector<uint8_t> bitstream;
device.WriteToBuffer(bitstream, 0, false);
//device.WriteToFile("/tmp/test.txt", 0, false); //for debug in case of failure

//Get the delays
if(!ProgramAndMeasureDelayAcrossVoltageCorners(sock, hdev, bitstream, src, dst, corner, true, delays))
return false;

return true;
}
4 changes: 2 additions & 2 deletions src/greenpak4/Greenpak4BitstreamEntity.h
Original file line number Diff line number Diff line change
@@ -157,8 +157,8 @@ class Greenpak4BitstreamEntity
virtual void PrintTimingData() const;
virtual void PrintExtraTimingData(PTVCorner corner) const;

void SaveTimingData(FILE* fp, bool last);
bool LoadTimingData(json_object* object);
virtual void SaveTimingData(FILE* fp, bool last);
virtual bool LoadTimingData(json_object* object);

protected:

203 changes: 203 additions & 0 deletions src/greenpak4/Greenpak4Delay.cpp
Original file line number Diff line number Diff line change
@@ -187,3 +187,206 @@ bool Greenpak4Delay::Save(bool* bitstream)

return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Timing analysis

void Greenpak4Delay::PrintTimingData() const
{
LogNotice("%s\n", GetDescription().c_str());

//Combinatorial delays
LogIndenter li;
for(auto& it : m_unfilteredDelays)
{
auto corner = it.first.second;
LogNotice("%s\n", corner.toString().c_str());

LogIndenter li2;
PrintExtraTimingData(corner);
}

//TODO: Setup/hold margins
}

void Greenpak4Delay::PrintExtraTimingData(PTVCorner corner) const
{
for(auto it : m_unfilteredDelays)
{
//Skip results for other process corners
if(it.first.second != corner)
continue;

char ntap[] = "0";
ntap[0] += it.first.first;
string ioname = string("OUT (T") + ntap + "/n)";

LogNotice("%10s to %10s: %6.3f ns rising, %6.3f ns falling\n",
"IN",
ioname.c_str(),
it.second.m_rising,
it.second.m_falling);
}

for(auto it : m_filteredDelays)
{
//Skip results for other process corners
if(it.first.second != corner)
continue;

char ntap[] = "0";
ntap[0] += it.first.first;
string ioname = string("OUT (T") + ntap + "/f)";

LogNotice("%10s to %10s: %6.3f ns rising, %6.3f ns falling\n",
"IN",
ioname.c_str(),
it.second.m_rising,
it.second.m_falling);
}
}

bool Greenpak4Delay::GetCombinatorialDelay(
string srcport,
string dstport,
PTVCorner corner,
CombinatorialDelay& delay) const
{
if( (srcport != "IN") || (dstport != "OUT") )
return false;

if(m_glitchFilter)
{
auto it = m_filteredDelays.find(TimingCondition(m_delayTap, corner));
if(it == m_filteredDelays.end())
return false;
delay = it->second;
return true;
}

else
{
auto it = m_unfilteredDelays.find(TimingCondition(m_delayTap, corner));
if(it == m_unfilteredDelays.end())
return false;
delay = it->second;
return true;
}

//Don't call base class, we handle everything here
}

void Greenpak4Delay::SaveTimingData(FILE* fp, bool last)
{
if(m_unfilteredDelays.empty())
return;

fprintf(fp, " \"%s\":\n [\n", GetDescription().c_str());

auto end = m_unfilteredDelays.end();
end--;
for(auto& it : m_unfilteredDelays)
{
auto corner = it.first.second;

//Loop over each process corner and export the data

fprintf(fp, " {\n");
fprintf(fp, " \"process\" : \"%s\",\n", corner.GetSpeedAsString().c_str());
fprintf(fp, " \"temp\" : \"%d\",\n", corner.GetTemp());
fprintf(fp, " \"voltage_mv\" : \"%d\",\n", corner.GetVoltage());

fprintf(fp, " \"delays\" :\n [\n");
SaveTimingData(fp, corner);
fprintf(fp, " ]\n");

//key is last element, we're done
if(it.first == end->first)
fprintf(fp, " }\n");
else
fprintf(fp, " },\n");
}

if(last)
fprintf(fp, " ]\n");
else
fprintf(fp, " ],\n");
}

void Greenpak4Delay::SaveTimingData(FILE* fp, PTVCorner corner)
{
for(auto it : m_filteredDelays)
{
auto cond = it.first;
auto delay = it.second;
if(cond.second != corner)
continue;

fprintf(fp, " {\n");
fprintf(fp, " \"type\" : \"filtered\",\n");
fprintf(fp, " \"tap\" : \"%d\",\n", cond.first);
fprintf(fp, " \"rising\" : \"%f\",\n", delay.m_rising);
fprintf(fp, " \"falling\" : \"%f\"\n", delay.m_falling);
fprintf(fp, " },\n");
}

for(auto it : m_unfilteredDelays)
{
auto cond = it.first;
auto delay = it.second;
if(cond.second != corner)
continue;

fprintf(fp, " {\n");
fprintf(fp, " \"type\" : \"unfiltered\",\n");
fprintf(fp, " \"tap\" : \"%d\",\n", cond.first);
fprintf(fp, " \"rising\" : \"%f\",\n", delay.m_rising);
fprintf(fp, " \"falling\" : \"%f\"\n", delay.m_falling);
fprintf(fp, " },\n");
}

//don't call base class, nothing for it to do
}

bool Greenpak4Delay::LoadExtraTimingData(PTVCorner corner, string delaytype, json_object* object)
{
//always need rising/falling data no matter what it is
json_object* rising;
if(!json_object_object_get_ex(object, "rising", &rising))
{
LogError("No rising info for this corner\n");
return false;
}
float nrising = json_object_get_double(rising);

json_object* falling;
if(!json_object_object_get_ex(object, "falling", &falling))
{
LogError("No falling info for this corner\n");
return false;
}
float nfalling = json_object_get_double(falling);
auto delay = CombinatorialDelay(nrising, nfalling);

//always have a tap delay
json_object* tap;
if(!json_object_object_get_ex(object, "tap", &tap))
{
LogError("No tap info for this corner\n");
return false;
}
int ntap = json_object_get_int(tap);

if(delaytype == "filtered")
SetFilteredDelay(ntap, corner, delay);
else if(delaytype == "unfiltered")
SetUnfilteredDelay(ntap, corner, delay);
else
{
LogError("Don't know how to parse \"%s\"\n", delaytype.c_str());
return false;
}

//no need to call base class, it's an empty stub
return true;
}
35 changes: 35 additions & 0 deletions src/greenpak4/Greenpak4Delay.h
Original file line number Diff line number Diff line change
@@ -49,6 +49,34 @@ class Greenpak4Delay : public Greenpak4BitstreamEntity

virtual bool CommitChanges();

void SetTap(int tap)
{ m_delayTap = tap; }

void SetGlitchFilter(bool enable)
{ m_glitchFilter = enable; }

typedef std::pair<int, PTVCorner> TimingCondition;

void SetUnfilteredDelay(int ntap, PTVCorner c, CombinatorialDelay d)
{ m_unfilteredDelays[TimingCondition(ntap, c)] = d; }

void SetFilteredDelay(int ntap, PTVCorner c, CombinatorialDelay d)
{ m_filteredDelays[TimingCondition(ntap, c)] = d; }

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Timing stuff

virtual void PrintTimingData() const;
virtual void PrintExtraTimingData(PTVCorner corner) const;

virtual void SaveTimingData(FILE* fp, bool last);

virtual bool GetCombinatorialDelay(
std::string srcport,
std::string dstport,
PTVCorner corner,
CombinatorialDelay& delay) const;

protected:
Greenpak4EntityOutput m_input;

@@ -63,6 +91,13 @@ class Greenpak4Delay : public Greenpak4BitstreamEntity
} m_mode;

bool m_glitchFilter;

//Timing data
std::map<TimingCondition, CombinatorialDelay > m_unfilteredDelays; //no glitch filter
std::map<TimingCondition, CombinatorialDelay > m_filteredDelays; //with glitch filter

virtual void SaveTimingData(FILE* fp, PTVCorner corner);
virtual bool LoadExtraTimingData(PTVCorner corner, std::string delaytype, json_object* object);
};

#endif //Greenpak4Delay_h

0 comments on commit b76069b

Please sign in to comment.