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: azonenberg/openfpga
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0a23f0ee14bd
Choose a base ref
...
head repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f16d4e88d13d
Choose a head ref
  • 2 commits
  • 7 files changed
  • 1 contributor

Commits on Jul 13, 2017

  1. Copy the full SHA
    1bc4a73 View commit details
  2. Copy the full SHA
    f16d4e8 View commit details
87 changes: 8 additions & 79 deletions src/gpkjson/main.cpp
Original file line number Diff line number Diff line change
@@ -131,23 +131,17 @@ int main(int argc, char* argv[])
//Initialize the device
Greenpak4Device device(part);
if(!device.ReadFromFile(fname))
return 1;

/*
//Parse the unplaced netlist
//We need to load the netlist first to handle the unused_* attributes
LogNotice("\nLoading Yosys JSON file \"%s\".\n", fname.c_str());
Greenpak4Netlist netlist(fname, pcfname);
if(!netlist.Validate())
return 1;
{
//return 1;
}

//Print configuration
LogNotice("\nDevice configuration:\n");
{
LogIndenter li;

string dev = "<invalid>";
switch(part)
switch(device.GetPart())
{
case Greenpak4Device::GREENPAK4_SLG46620:
dev = "SLG46620V";
@@ -165,88 +159,23 @@ int main(int argc, char* argv[])
LogNotice("Target device: %s\n", dev.c_str());
LogNotice("VCC range: not yet implemented\n");

string pull;
string drive;
switch(unused_pull)
{
case Greenpak4IOB::PULL_NONE:
pull = "float";
break;
case Greenpak4IOB::PULL_DOWN:
pull = "pull down with ";
break;
case Greenpak4IOB::PULL_UP:
pull = "pull up with ";
break;
default:
LogError("Invalid pull direction\n");
return 1;
}
if(unused_pull != Greenpak4IOB::PULL_NONE)
{
switch(unused_drive)
{
case Greenpak4IOB::PULL_10K:
drive = "10K";
break;
case Greenpak4IOB::PULL_100K:
drive = "100K";
break;
case Greenpak4IOB::PULL_1M:
drive = "1M";
break;
default:
LogError("Invalid pull strength\n");
return 1;
}
}
LogNotice("Unused pins: %s%s\n", pull.c_str(), drive.c_str());
/*
LogNotice("User ID code: %02x\n", userid);
LogNotice("Read protection: %s\n", readProtect ? "enabled" : "disabled");
LogNotice("I/O precharge: %s\n", ioPrecharge ? "enabled" : "disabled");
LogNotice("Charge pump: %s\n", disableChargePump ? "off" : "auto");
LogNotice("LDO: %s\n", ldoBypass ? "bypassed" : "enabled");
LogNotice("Boot retry: %d times\n", bootRetry);
*/
}

//Create the device and initialize all IO pins
Greenpak4Device device(part, unused_pull, unused_drive);
device.SetIOPrecharge(ioPrecharge);
device.SetDisableChargePump(disableChargePump);
device.SetLDOBypass(ldoBypass);
device.SetNVMRetryCount(bootRetry);
//Attempt to load the timing data file, if present
//FIXME: get this from a sane location and make it chip specific
string tfname = "../../../timing.json";
LogNotice("\nLoading timing data file \"%s\"\n", tfname.c_str());
if(!device.LoadTimingData(tfname))
LogWarning("Timing data file not found, unable to do timing-driven placement or evaluate post-PAR timing\n");
//Do the actual P&R
LogNotice("\nImplementing top-level module \"%s\".\n", netlist.GetTopModule()->GetName().c_str());
if(!DoPAR(&netlist, &device))
return 1;
//Write the final bitstream
LogNotice("\nWriting final bitstream to output file \"%s\", using ID code 0x%x.\n",
ofname.c_str(), (int)userid);
LogNotice("\nWriting final bitstream to output file \"%s\"\n", ofname.c_str());
{
LogIndenter li;
if(!device.WriteToFile(ofname, userid, readProtect))
if(!device.WriteToJSON(ofname, "Bitstream"))
return 1;
}
*/
return 0;
}

81 changes: 52 additions & 29 deletions src/greenpak4/Greenpak4BitstreamEntity.cpp
Original file line number Diff line number Diff line change
@@ -121,35 +121,6 @@ bool Greenpak4BitstreamEntity::IsGeneralFabricInput(string port) const
return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Debug log helpers

string Greenpak4BitstreamEntity::GetOutputName()
{
auto mate = m_parnode->GetMate();
if(mate == NULL)
return "";
auto entity = static_cast<Greenpak4NetlistEntity*>(mate->GetData());

//If it's an IOB, return the IOB name
if(dynamic_cast<Greenpak4NetlistPort*>(entity))
return entity->m_name;

//Nope, it's a cell
auto cell = dynamic_cast<Greenpak4NetlistCell*>(entity);
if(!cell)
return "error";

//Look up our first output port... HACK!
//TODO: Fix this
string portname = GetOutputPorts()[0];

//Find the net we connect to
if(cell->m_connections.find(portname) == cell->m_connections.end())
return "error";
return cell->m_connections[portname][0]->m_name; //FIXME:VECTOR
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Load/save helpers

@@ -226,6 +197,58 @@ bool Greenpak4BitstreamEntity::WriteMatrixSelector(
return true;
}

void Greenpak4BitstreamEntity::ReadMatrixSelector(
bool* bitstream,
unsigned int wordpos,
unsigned int matrix,
Greenpak4EntityOutput& signal)
{
//TODO
LogVerbose("Reading matrix selector for %s\n", GetDescription().c_str());

unsigned int nbits = m_device->GetMatrixBits();
unsigned int startbit = m_device->GetMatrixBase(matrix) + wordpos * nbits;

//Need to flip bit ordering since lowest array index is the MSB
unsigned int netnum = 0;
for(unsigned int i=0; i<nbits; i++)
{
if(bitstream[startbit + i])
netnum |= (1 << i);
}

LogVerbose("Got netnum %d\n", netnum);
LogIndenter li;

//Convert the net number back to an EntityOutput
//For now, do this exhaustively (TODO be smart about it?)
int nhits = 0;
for(size_t i=0; i<m_device->GetEntityCount(); i++)
{
auto entity = m_device->GetEntity(i);
auto outputs = entity->GetOutputPorts();
for(auto pname : outputs)
{
//Skip mismatched net numbers
auto output = entity->GetOutput(pname);
if(output.GetNetNumber() != netnum)
continue;

//TODO: Properly handle paired entities (e.g. LUT/PGEN)
//TODO: Properly handle configuration if the primitive has multiple ports mapping to one net (e.g. Q/nQ)
if(output.GetMatrix() == matrix || output.HasDual() )
{
LogVerbose("HIT: %s\n", output.GetOutputName().c_str());
signal = output;
nhits ++;
}
}
}

if(nhits != 1)
LogWarning("Did not get exactly one hit in ReadMatrixSelector\n");
}

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

13 changes: 6 additions & 7 deletions src/greenpak4/Greenpak4BitstreamEntity.h
Original file line number Diff line number Diff line change
@@ -84,13 +84,6 @@ class Greenpak4BitstreamEntity
PARGraphNode* GetPARNode()
{ return m_parnode; }

/**
@brief Gets the net name of our output
FIXME: this is fundamentally wrong, this should be a function on EntityOutput instead
*/
std::string GetOutputName();

/**
@brief Returns true if this entity maps to a node in the netlist.
*/
@@ -181,6 +174,12 @@ class Greenpak4BitstreamEntity
Greenpak4EntityOutput signal,
bool cross_matrix = false);

void ReadMatrixSelector(
bool* bitstream,
unsigned int wordpos,
unsigned int matrix,
Greenpak4EntityOutput& signal);

///The device we're attached to
Greenpak4Device* m_device;

55 changes: 55 additions & 0 deletions src/greenpak4/Greenpak4Device.cpp
Original file line number Diff line number Diff line change
@@ -1260,6 +1260,61 @@ bool Greenpak4Device::WriteToFile(string fname, uint8_t userid, bool readProtect
return ok;
}

bool Greenpak4Device::WriteToJSON(string fname, string top)
{
//Open the file
FILE* fp = fopen(fname.c_str(), "w");
if(!fp)
{
LogError("Couldn't open %s for writing\n", fname.c_str());
return false;
}

//Write the header
fprintf(fp, "{\n");
fprintf(fp, " \"creator\": \"gpkjson\",\n");
fprintf(fp, " \"modules\": {\n");

//Write the top-level module header
fprintf(fp, " \"%s\": {\n", top.c_str());
fprintf(fp, " \"attributes\": {\n");
fprintf(fp, " \"top\": 1\n");
fprintf(fp, " },\n");

//Write ports
//For now, name one pin for each IOB that's used
//vector<string> portnames;
for(auto it : m_iobs)
{
auto iob = it.second;

auto oe = iob->GetOutputEnable();

//Input or unused
if(oe.IsPowerRail() && oe.GetPowerRailValue() == 0)
{
}

//Output or bidir
else
{
LogNotice("Pin %s is output or bidir\n", iob->GetDescription().c_str());
}
}

//Done with module
fprintf(fp, " }\n");

//TODO: Spit out generic cell library stuff so Yosys can import it correctly?
//Alternatively, don't have those cells at all and rely on Yosys to import cells_greenpak4 first?

//Done
fprintf(fp, " }\n");
fprintf(fp, "}\n");
fclose(fp);
return true;
}

/**
@brief Writes a bitstream to an in-memory netlist
*/
10 changes: 10 additions & 0 deletions src/greenpak4/Greenpak4Device.h
Original file line number Diff line number Diff line change
@@ -50,14 +50,24 @@ class Greenpak4Device
//Write our config to a bitfile
bool WriteToFile(std::string fname, uint8_t userid, bool readProtect);

//Write our config to a cell-level JSON netlist
bool WriteToJSON(std::string fname, std::string top);

//Write to an in-memory array
bool WriteToBuffer(std::vector<uint8_t>& bitstream, uint8_t userid, bool readProtect);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Config accessors

GREENPAK4_PART GetPart()
{ return m_part; }

std::string GetPartAsString();

//TODO: save and query userid from bitstream

//TODO: read protection, precharge, etc, cal, etc status

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

3 changes: 3 additions & 0 deletions src/greenpak4/Greenpak4IOB.h
Original file line number Diff line number Diff line change
@@ -139,6 +139,9 @@ class Greenpak4IOB : public Greenpak4BitstreamEntity
Greenpak4EntityOutput GetOutputSignal()
{ return m_outputSignal; }

Greenpak4EntityOutput GetOutputEnable()
{ return m_outputEnable; }

bool IsAnalogIbuf()
{ return (m_inputThreshold == THRESHOLD_ANALOG); }

Loading