Skip to content

Commit

Permalink
Began work on loading timing data from JSON
Browse files Browse the repository at this point in the history
azonenberg committed Jun 4, 2017
1 parent 57950d4 commit e1c9b44
Showing 9 changed files with 355 additions and 27 deletions.
77 changes: 71 additions & 6 deletions src/gp4tchar/main.cpp
Original file line number Diff line number Diff line change
@@ -28,6 +28,8 @@ using namespace std;

DevkitCalibration g_devkitCal;

bool LoadTimingData(string fname);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Entry point

@@ -120,19 +122,25 @@ int main(int argc, char* argv[])
return 1;
}

//Measure delay through each element
if(!MeasurePinToPinDelays(sock, hdev))
//Load timing data from disk
LogNotice("Loading timing data...\n");
string tfname = "timing.json";
if(!LoadTimingData(tfname))
return 1;

//Measure delay through each element
//if(!MeasurePinToPinDelays(sock, hdev))
// return 1;
//if(!MeasureCrossConnectionDelays(sock, hdev))
// return 1;
//if(!MeasureLutDelays(sock, hdev))
// return 1;

//Save to disk
string fout = "timing.json";
LogNotice("Saving timing data to file %s\n", fout.c_str());
g_calDevice.SaveTimingData(fout.c_str());

/*
LogNotice("Saving timing data to file %s\n", tfname.c_str());
g_calDevice.SaveTimingData(tfname.c_str());
*/
//Print output
LogNotice("Dumping timing data...\n");
{
@@ -149,6 +157,63 @@ int main(int argc, char* argv[])
return 0;
}

bool LoadTimingData(string fname)
{
//Open the file (non-existence is a legal no-op, return success silently)
FILE* fp = fopen(fname.c_str(), "rb");
if(fp == NULL)
return true;
if(0 != fseek(fp, 0, SEEK_END))
{
LogError("Failed to seek to end of timing data file %s\n", fname.c_str());
fclose(fp);
return false;
}
size_t len = ftell(fp);
if(0 != fseek(fp, 0, SEEK_SET))
{
LogError("Failed to seek to start of timing data file %s\n", fname.c_str());
return false;
}
char* json_string = new char[len + 1];
json_string[len] = '\0';
if(len != fread(json_string, 1, len, fp))
{
LogError("Failed to read contents of timing data file %s\n", fname.c_str());
delete[] json_string;
fclose(fp);
return false;
}
fclose(fp);

//Parse the JSON
json_tokener* tok = json_tokener_new();
if(!tok)
{
LogError("Failed to create JSON tokenizer object\n");
delete[] json_string;
return false;
}
json_tokener_error err;
json_object* object = json_tokener_parse_verbose(json_string, &err);
if(NULL == object)
{
const char* desc = json_tokener_error_desc(err);
LogError("JSON parsing failed (err = %s)\n", desc);
delete[] json_string;
return false;
}

//Load stuff
if(!g_calDevice.LoadTimingData(object))
return false;

//Done
json_object_put(object);
json_tokener_free(tok);
return true;
}

void WaitForKeyPress()
{
LogNotice("Press any key to continue . . .\n");
3 changes: 0 additions & 3 deletions src/gp4tchar/measurements.cpp
Original file line number Diff line number Diff line change
@@ -364,9 +364,6 @@ bool MeasurePinToPinDelays(Socket& sock, hdevice hdev)
iob->SetOutputDelay(Greenpak4IOB::DRIVE_1X, corner, CombinatorialDelay(obuf_x1.m_value, -1));
iob->SetOutputDelay(Greenpak4IOB::DRIVE_2X, corner, CombinatorialDelay(obuf_x2.m_value, -1));
}

//DEBUG
return true;
}
}

152 changes: 152 additions & 0 deletions src/greenpak4/Greenpak4BitstreamEntity.cpp
Original file line number Diff line number Diff line change
@@ -372,3 +372,155 @@ void Greenpak4BitstreamEntity::SaveTimingData(FILE* fp, PTVCorner corner)
fprintf(fp, " },\n");
}
}

/**
@brief Load our delay info
*/
bool Greenpak4BitstreamEntity::LoadTimingData(json_object* object)
{
for(int i=0; i<json_object_array_length(object); i++)
{
auto child = json_object_array_get_idx(object, i);
if(!LoadTimingDataForCorner(child))
return false;
}

return true;
}

/**
@brief Loads delay info for a single process-corner object in the JSON file
*/
bool Greenpak4BitstreamEntity::LoadTimingDataForCorner(json_object* object)
{
//Look up the corner info
json_object* process;
if(!json_object_object_get_ex(object, "process", &process))
{
LogError("No process info for this corner\n");
return false;
}
string sprocess = json_object_get_string(process);

json_object* temp;
if(!json_object_object_get_ex(object, "temp", &temp))
{
LogError("No temp info for this corner\n");
return false;
}
int ntemp = json_object_get_int(temp);

json_object* voltage;
if(!json_object_object_get_ex(object, "voltage_mv", &voltage))
{
LogError("No voltage info for this corner\n");
return false;
}
int nvoltage = json_object_get_int(voltage);

//TODO: move this into PTVCorner class?
PTVCorner::ProcessSpeed speed;
if(sprocess == "fast")
speed = PTVCorner::SPEED_FAST;
else if(sprocess == "slow")
speed = PTVCorner::SPEED_SLOW;
else if(sprocess == "typical")
speed = PTVCorner::SPEED_TYPICAL;

//This is the process corner we're loading
PTVCorner corner(speed, ntemp, nvoltage);

//This is the actual timing data!
json_object* delays;
if(!json_object_object_get_ex(object, "delays", &delays))
{
LogError("No delay info for this corner\n");
return false;
}

//Now that we know where to put it, we can load the actual timing data
for(int i=0; i<json_object_array_length(delays); i++)
{
auto child = json_object_array_get_idx(delays, i);

//We need to know the type of delay. "propagation" is handled by us
//Anything else is a derived class
json_object* type;
if(!json_object_object_get_ex(child, "type", &type))
{
LogError("No type info for this delay value\n");
return false;
}
string stype = json_object_get_string(type);

//Load rising/falling delays and save them
if(stype == "propagation")
{
if(!LoadPropagationDelay(corner, child))
return false;
continue;
}

//Nope, something special
if(!LoadExtraTimingData(corner, stype, child))
return false;
}

return true;
}

/**
@brief Loads propagation delay for a single endpoint and process corner
*/
bool Greenpak4BitstreamEntity::LoadPropagationDelay(PTVCorner corner, json_object* object)
{
//Pull out all of the json stuff
json_object* from;
if(!json_object_object_get_ex(object, "from", &from))
{
LogError("No source for this delay\n");
return false;
}
string sfrom = json_object_get_string(from);

json_object* to;
if(!json_object_object_get_ex(object, "to", &to))
{
LogError("No dest for this delay\n");
return false;
}
string sto = json_object_get_string(to);

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

//Finally, we can actually save the delay!
m_pinToPinDelays[corner][PinPair(sfrom, sto)] = CombinatorialDelay(nrising, nfalling);

return true;
}

/**
@brief Loads timing data other than normal propagation info
Base class implementation should never be called (base class should override) if there's any extra data,
but we need a default implementation to avoid every derived class having an empty stub
*/
bool Greenpak4BitstreamEntity::LoadExtraTimingData(PTVCorner /*corner*/, string /*delaytype*/, json_object* /*object*/)
{
LogWarning("Greenpak4BitstreamEntity: Don't know what to do with delay type %s\n", delaytype.c_str());
return true;
}
6 changes: 6 additions & 0 deletions src/greenpak4/Greenpak4BitstreamEntity.h
Original file line number Diff line number Diff line change
@@ -28,6 +28,8 @@ class Greenpak4NetlistEntity;
#include <vector>
#include <xbpar.h>

#include <json-c/json.h>

class Greenpak4EntityOutput;

/**
@@ -156,6 +158,7 @@ class Greenpak4BitstreamEntity
virtual void PrintExtraTimingData(PTVCorner corner) const;

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

protected:

@@ -216,6 +219,9 @@ class Greenpak4BitstreamEntity
std::map<PTVCorner, DelayMap> m_pinToPinDelays;

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

#endif
94 changes: 77 additions & 17 deletions src/greenpak4/Greenpak4Device.cpp
Original file line number Diff line number Diff line change
@@ -964,6 +964,22 @@ void Greenpak4Device::SetNVMRetryCount(int count)
m_nvmLoadRetryCount = count;
}

string Greenpak4Device::GetPartAsString()
{
switch(m_part)
{
case GREENPAK4_SLG46140:
return "SLG46140";

case GREENPAK4_SLG46620:
return "SLG46620";

case GREENPAK4_SLG46621:
return "SLG46621";
}
return "(unknown)\n";
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// File I/O

@@ -1270,25 +1286,9 @@ void Greenpak4Device::SaveTimingData(string fname)
return;
}

string part;
switch(m_part)
{
case GREENPAK4_SLG46140:
part = "SLG46140";
break;

case GREENPAK4_SLG46620:
part = "SLG46620";
break;

case GREENPAK4_SLG46621:
part = "SLG46621";
break;
}

//Header
fprintf(fp, "{\n");
fprintf(fp, " \"part\" : \"%s\",\n", part.c_str());
fprintf(fp, " \"part\" : \"%s\",\n", GetPartAsString().c_str());

//Timing data for each IP block
for(size_t i=0; i<m_bitstuff.size(); i++)
@@ -1298,3 +1298,63 @@ void Greenpak4Device::SaveTimingData(string fname)
fprintf(fp, "}\n");
fclose(fp);
}

bool Greenpak4Device::LoadTimingData(json_object* object)
{
//Make a map of description -> entity
map<string, Greenpak4BitstreamEntity*> bmap;
for(auto p : m_bitstuff)
bmap[p->GetDescription()] = p;

json_object_iterator end = json_object_iter_end(object);
for(json_object_iterator it = json_object_iter_begin(object);
!json_object_iter_equal(&it, &end);
json_object_iter_next(&it))
{
//See what we got
string name = json_object_iter_peek_name(&it);
json_object* child = json_object_iter_peek_value(&it);

//Part should be first key. If it doesn't match our part, complain
if(name == "part")
{
if(!json_object_is_type(child, json_type_string))
{
LogError("timing data part should be of type string but isn't\n");
return false;
}
string expected_part = json_object_get_string(child);

if(GetPartAsString() != expected_part)
{
LogError("Timing data is for part %s but we're a %s\n",
expected_part.c_str(),
GetPartAsString().c_str());
return false;
}
continue;
}

//Anything else should be an IP block
//If it doesn't exist, complain
if(bmap.find(name) == bmap.end())
{
LogError("Site \"%s\" is in timing data file, but not this device\n",
name.c_str());
return false;
}

//Child should be an array of process corner, info tuples
if(!json_object_is_type(child, json_type_array))
{
LogError("ip block should be of type array but isn't\n");
return false;
}

//It exists, load it
if(!bmap[name]->LoadTimingData(child))
return false;
}

return true;
}
3 changes: 3 additions & 0 deletions src/greenpak4/Greenpak4Device.h
Original file line number Diff line number Diff line change
@@ -53,6 +53,8 @@ class Greenpak4Device
GREENPAK4_PART GetPart()
{ return m_part; }

std::string GetPartAsString();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// POWER RAILS

@@ -331,6 +333,7 @@ class Greenpak4Device

void PrintTimingData() const;
void SaveTimingData(std::string fname);
bool LoadTimingData(json_object* object);

protected:

44 changes: 44 additions & 0 deletions src/greenpak4/Greenpak4IOB.cpp
Original file line number Diff line number Diff line change
@@ -396,3 +396,47 @@ void Greenpak4IOB::SaveTimingData(FILE* fp, PTVCorner corner)
//do base class at end
Greenpak4BitstreamEntity::SaveTimingData(fp, corner);
}

bool Greenpak4IOB::LoadExtraTimingData(PTVCorner corner, string delaytype, json_object* object)
{
/*
//Pull out all of the json stuff
json_object* from;
if(!json_object_object_get_ex(object, "from", &from))
{
LogError("No source for this delay\n");
return false;
}
string sfrom = json_object_get_string(from);
json_object* to;
if(!json_object_object_get_ex(object, "to", &to))
{
LogError("No dest for this delay\n");
return false;
}
string sto = json_object_get_string(to);
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);
//Finally, we can actually save the delay!
m_pinToPinDelays[corner][PinPair(sfrom, sto)] = CombinatorialDelay(nrising, nfalling);
*/

//no need to call base class, it's an empty stub
return true;
}
1 change: 1 addition & 0 deletions src/greenpak4/Greenpak4IOB.h
Original file line number Diff line number Diff line change
@@ -209,6 +209,7 @@ class Greenpak4IOB : public Greenpak4BitstreamEntity
std::map< DriveCondition, CombinatorialDelay > m_outputDelays;

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

#endif
2 changes: 1 addition & 1 deletion src/greenpak4/Greenpak4Netlist.cpp
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ Greenpak4Netlist::Greenpak4Netlist(string fname, string constraint_file)
json_string[len] = '\0';
if(len != fread(json_string, 1, len, fp))
{
LogError("Failed read contents of netlist file %s\n", fname.c_str());
LogError("Failed to read contents of netlist file %s\n", fname.c_str());
m_parseOK = false;
delete[] json_string;
fclose(fp);

0 comments on commit e1c9b44

Please sign in to comment.