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

Commits on Oct 21, 2016

  1. Copy the full SHA
    c373a89 View commit details
  2. Copy the full SHA
    a543ce7 View commit details
  3. Copy the full SHA
    1124dde View commit details
Showing with 207 additions and 68 deletions.
  1. +6 −35 src/gp4prog/main.cpp
  2. +10 −1 src/gpdevboard/gpdevboard.h
  3. +128 −7 src/gpdevboard/utils.cpp
  4. +63 −25 tests/greenpak4/HIL_PGA.cpp
41 changes: 6 additions & 35 deletions src/gp4prog/main.cpp
Original file line number Diff line number Diff line change
@@ -45,7 +45,6 @@ int main(int argc, char* argv[])
bool programNvram = false;
bool force = false;
uint8_t patternId = 0;
bool patternIdSpecified = false;
bool readProtect = false;
double voltage = 0.0;
vector<int> nets;
@@ -147,8 +146,6 @@ int main(int argc, char* argv[])
force = true;
else if(s == "--pattern-id")
{
patternIdSpecified = true;

if(i+1 < argc)
{
char *arg = argv[++i];
@@ -333,43 +330,17 @@ int main(int argc, char* argv[])
//If we're programming, do that first
if(!downloadFilename.empty())
{
vector<uint8_t> newBitstream = ReadBitstream(downloadFilename);
if(newBitstream.empty())
return 1;
if(newBitstream.size() != BitstreamLength(detectedPart) / 8)
//Read the bitstream and check that it's the right size
vector<uint8_t> newBitstream;
if(!ReadBitstream(downloadFilename, newBitstream, detectedPart);
{
LogError("Provided bitstream has incorrect length for selected part\n");
SetStatusLED(hdev, 0);
return 1;
}

//TODO: Make this work for chips other than SLG46620V?

//Set trim value reg<1981:1975>
newBitstream[246] |= rcFtw << 7;
newBitstream[247] |= rcFtw >> 1;

//Set pattern ID reg<2031:2038>
if(patternIdSpecified)
{
newBitstream[253] |= patternId << 7;
newBitstream[254] |= patternId >> 1;
}

//Read out the pattern ID and print it
unsigned int patternID =
( (newBitstream[254] << 1) & 0xff ) |
( (newBitstream[253] >> 7) & 0xff );
LogNotice("Bitstream ID code: 0x%02x\n", patternID);

//Set read protection reg<2039>
//OR with the existing value: we can set the read protect bit here, but not overwrite the bit if
//it was set by gp4par. If you REALLY need to unprotect a bitstream, do it by hand in a text editor.
newBitstream[254] |= ((uint8_t)readProtect) << 7;
if(newBitstream[254] & 0x80)
LogNotice("Read protection: enabled\n");
else
LogNotice("Read protection: disabled\n");
//Tweak the bitstream to apply all of the changes specified on the command line
if(!TweakBitstream(newBitstream, detectedPart, rcFtw, patternID, readProtect))
return 1;

if(!programNvram)
{
11 changes: 10 additions & 1 deletion src/gpdevboard/gpdevboard.h
Original file line number Diff line number Diff line change
@@ -272,6 +272,15 @@ bool TrimOscillator(hdevice hdev, SilegoPart part, double voltage, unsigned freq
bool SocketTest(hdevice hdev, SilegoPart part);

std::vector<uint8_t> BitstreamFromHex(std::string hex);
std::vector<uint8_t> ReadBitstream(std::string fname);
bool ReadBitstream(std::string fname, std::vector<uint8_t>& bitstream, SilegoPart part);

bool TweakBitstream(
std::vector<uint8_t>& bitstream,
SilegoPart part,
uint8_t oscTrim,
uint8_t patternID,
bool readProtect);

bool TestSetup(hdevice hdev, std::string fname, int rcOscFreq, double voltage, SilegoPart targetPart);

#endif
135 changes: 128 additions & 7 deletions src/gpdevboard/utils.cpp
Original file line number Diff line number Diff line change
@@ -293,7 +293,6 @@ size_t BitstreamLength(SilegoPart part)
}
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Socket test

@@ -495,13 +494,13 @@ vector<uint8_t> BitstreamFromHex(string hex)
return bitstream;
}

vector<uint8_t> ReadBitstream(string fname)
bool ReadBitstream(string fname, vector<uint8_t>& bitstream, SilegoPart part)
{
FILE* fp = fopen(fname.c_str(), "rt");
if(!fp)
{
LogError("Couldn't open %s for reading\n", fname.c_str());
return {};
return false;
}

char signature[64];
@@ -512,10 +511,9 @@ vector<uint8_t> ReadBitstream(string fname)
{
LogError("%s is not a GreenPAK bitstream\n", fname.c_str());
fclose(fp);
return {};
return false;
}

vector<uint8_t> bitstream;
while(!feof(fp))
{
int index;
@@ -527,7 +525,7 @@ vector<uint8_t> ReadBitstream(string fname)
{
LogError("%s contains a malformed GreenPAK bitstream\n", fname.c_str());
fclose(fp);
return {};
return false;
}

if(byteindex >= (int)bitstream.size())
@@ -537,5 +535,128 @@ vector<uint8_t> ReadBitstream(string fname)

fclose(fp);

return bitstream;
//TODO: check ID words?

//Verify that the bitstream is a sane length
if(bitstream.size() != BitstreamLength(part) / 8)
{
LogError("Provided bitstream has incorrect length for selected part\n");
return false;
}

return true;
}

/**
@brief Take a bitstream and modify some of the configuration
OR in the read protect and pattern ID... only meaningful if the old values were unprotected and 0 resp
*/
bool TweakBitstream(vector<uint8_t>& bitstream, SilegoPart part, uint8_t oscTrim, uint8_t patternID, bool readProtect)
{
LogNotice("Applying requested configuration to bitstream\n");
LogIndenter li;

//TODO: implement for other parts
if(part != SilegoPart::SLG46620V)
{
LogError("TweakBitstream only implemented for SLG46620V\n");
return false;
}

//Set trim value reg<1981:1975>
bitstream[246] &= 0xFE;
bitstream[247] &= 0x01;
bitstream[246] |= oscTrim << 7;
bitstream[247] |= oscTrim >> 1;
LogVerbose("Oscillator trim value: %d\n", oscTrim);

//Set pattern ID reg<2031:2038>
if(patternID != 0)
{
bitstream[253] &= 0xFE;
bitstream[254] &= 0x01;
}
bitstream[253] |= patternID << 7;
bitstream[254] |= patternID >> 1;
LogNotice("Bitstream ID code: 0x%02x\n", patternID);

//Set read protection reg<2039>
//OR with the existing value: we can set the read protect bit here, but not overwrite the bit if
//it was set by gp4par. If you REALLY need to unprotect a bitstream, do it by hand in a text editor.
bitstream[254] |= ((uint8_t)readProtect) << 7;
if(bitstream[254] & 0x80)
LogNotice("Read protection: enabled\n");
else
LogNotice("Read protection: disabled\n");

return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helper for HiL tests

/**
@brief Wrapper around the test to do some board setup etc
*/
bool TestSetup(hdevice hdev, string fname, int rcOscFreq, double voltage, SilegoPart targetPart)
{
//Make sure we have the right part
if(!VerifyDevicePresent(hdev, targetPart))
{
LogNotice("Couldn't find the expected part, giving up\n");
return false;
}

//Make sure the board is electrically functional
if(!SocketTest(hdev, targetPart))
{
LogError("Target board self-test failed\n");
return false;
}

//Trim the oscillator
uint8_t rcFtw = 0;
if(!TrimOscillator(hdev, targetPart, voltage, rcOscFreq, rcFtw))
return false;

//No need to reset board, the trim does that for us

//Read the bitstream
vector<uint8_t> bitstream;
if(!ReadBitstream(fname, bitstream, targetPart))
return false;

//Apply the oscillator trim
if(!TweakBitstream(bitstream, targetPart, rcFtw, 0xCC, false))
return false;

//Program the device
LogNotice("Downloading bitstream to board\n");
if(!DownloadBitstream(hdev, bitstream, DownloadMode::EMULATION))
return false;

//Developer board I/O pins become stuck after both SRAM and NVM programming;
//resetting them explicitly makes LEDs and outputs work again.
LogDebug("Resetting board I/O pins after programming\n");
IOConfig ioConfig;
for(size_t i = 2; i <= 20; i++)
ioConfig.driverConfigs[i] = TP_RESET;
if(!SetIOConfig(hdev, ioConfig))
return false;

//Configure the signal generator for Vdd
LogNotice("Setting Vdd to %.3g V\n", voltage);
if(!ConfigureSiggen(hdev, 1, voltage))
return false;

//Final fault check after programming
if(!CheckStatus(hdev))
{
LogError("Fault condition detected during final check\n");
return false;
}

LogNotice("Test setup complete\n");
return true;
}
88 changes: 63 additions & 25 deletions tests/greenpak4/HIL_PGA.cpp
Original file line number Diff line number Diff line change
@@ -21,10 +21,7 @@

using namespace std;

bool RunTest(hdevice hdev, string bitstream, int rcOscFreq);

//The device our test is targeting
const SilegoPart g_targetPart = SilegoPart::SLG46620V;
bool RunTest(hdevice hdev);

int main(int argc, char* argv[])
{
@@ -47,46 +44,87 @@ int main(int argc, char* argv[])
if(!SetStatusLED(hdev, 1))
return 1;

//Run the test
if(!RunTest(hdev, argv[1], 25000))
//Prepare to run the test
if(!TestSetup(hdev, argv[1], 25000, 3.3, SilegoPart::SLG46620V))
{
SetStatusLED(hdev, 0);
Reset(hdev);
return 1;
}

//Run the actual test case
LogNotice("\n");
LogNotice("Running application test case\n");
if(!RunTest(hdev))
{
SetStatusLED(hdev, 0);
Reset(hdev);
return 1;
}

//Turn off the LED before declaring success
LogVerbose("\n");
LogVerbose("Test complete, resetting board\n");
SetStatusLED(hdev, 0);
Reset(hdev);
USBCleanup(hdev);
return 0;
}

/**
@brief Wrapper around the test to do some board setup etc
@brief The actual application-layer test
*/
bool RunTest(hdevice hdev, string bitstream, int rcOscFreq)
bool RunTest(hdevice hdev)
{
//We're targeting a SLG46620V so make sure we've got one there
if(!VerifyDevicePresent(hdev, g_targetPart))
{
LogNotice("Couldn't find the expected part, giving up\n");
LogIndenter li;

//Set up the I/O config we need for this test (?)
IOConfig ioConfig;
for(size_t i = 2; i <= 20; i++)
ioConfig.driverConfigs[i] = TP_RESET;
if(!SetIOConfig(hdev, ioConfig))
return false;
}

//Make sure the board is electrically functional
if(!SocketTest(hdev, g_targetPart))
const int INPUT_PIN = 8;
const int OUTPUT_PIN = 7;

//Sweep input and verify output
LogVerbose("Running PGA voltage sweep\n");
LogVerbose("|%10s|%10s|%10s|%10s|%10s|%10s|\n", "Requested", "Actual", "Output", "Expected", "Error", "% error");
double step = 0.05;
for(double vtest = step; vtest < 0.51; vtest += step)
{
LogError("Target board self-test failed\n");
return false;
}
//Set up a signal generator on the input
if(!ConfigureSiggen(hdev, INPUT_PIN, vtest))
return false;

//TODO: take this as a parameter?
double voltage = 3.3;
//Read the input
if(!SelectADCChannel(hdev, INPUT_PIN))
return false;
double vin;
if(!ReadADC(hdev, vin))
return false;

//Trim the oscillator
uint8_t rcFtw = 0;
if(!TrimOscillator(hdev, g_targetPart, voltage, rcOscFreq, rcFtw))
return false;
//Read the output
if(!SelectADCChannel(hdev, OUTPUT_PIN))
return false;
double vout;
if(!ReadADC(hdev, vout))
return false;

double expected = vin * 2;
double error = expected - vout;
double pctError = (error * 100) / expected;

//No need to reset board, the trim does that for us
LogVerbose("|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|\n", vtest, vin, vout, expected, error, pctError);

//TODO: Decide on an appropriate tolerance
if(pctError > 5)
{
LogError("Percent error is too big, test failed\n");
return false;
}
}

return true;
}