Skip to content

Commit

Permalink
Refactored bitstream loading to make better use of exceptions. Contin…
Browse files Browse the repository at this point in the history
…ued work on UltraScale jtaghal support.
  • Loading branch information
azonenberg committed Feb 27, 2018
1 parent a402e3f commit 5a83172
Show file tree
Hide file tree
Showing 14 changed files with 350 additions and 114 deletions.
63 changes: 63 additions & 0 deletions Xilinx3DFPGABitstream.cpp
@@ -0,0 +1,63 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2018 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Implementation of Xilinx3DFPGABitstream
*/
#include "jtaghal.h"

using namespace std;

/**
@brief Initializes this object to empty
*/
Xilinx3DFPGABitstream::Xilinx3DFPGABitstream()
{

}

/**
@brief Free bitstream memory
*/
Xilinx3DFPGABitstream::~Xilinx3DFPGABitstream()
{
for(auto b : m_bitstreams)
delete b;
m_bitstreams.clear();
}

string Xilinx3DFPGABitstream::GetDescription()
{
char retval[1024];
snprintf(retval, sizeof(retval), "bitstream \"%s\" (%s %s) for device \"%s\" (%zu blocks)",
desc.c_str(), date.c_str(), time.c_str(), devname.c_str(), m_bitstreams.size());
return retval;
}
56 changes: 56 additions & 0 deletions Xilinx3DFPGABitstream.h
@@ -0,0 +1,56 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2018 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Declaration of Xilinx3DFPGABitstream
*/

#ifndef Xilinx3DFPGABitstream_h
#define Xilinx3DFPGABitstream_h

/**
@brief A bitstream for Xilinx 3D FPGAs (multiple dies on a passive interposer, each with their own bitstream)
\ingroup libjtaghal
*/
class Xilinx3DFPGABitstream : public XilinxFPGABitstream
{
public:
Xilinx3DFPGABitstream();
virtual ~Xilinx3DFPGABitstream();

virtual std::string GetDescription();

std::vector<XilinxFPGABitstream*> m_bitstreams;
};

#endif

23 changes: 13 additions & 10 deletions Xilinx7SeriesDevice.cpp
Expand Up @@ -261,7 +261,18 @@ void Xilinx7SeriesDevice::InternalErase()

FirmwareImage* Xilinx7SeriesDevice::LoadFirmwareImage(const unsigned char* data, size_t len)
{
return static_cast<FirmwareImage*>(XilinxFPGA::ParseBitstreamCore(data, len));
XilinxFPGABitstream* bitstream = new XilinxFPGABitstream;
try
{
XilinxFPGA::ParseBitstreamCore(bitstream, data, len);
}
catch(const JtagException& ex)
{
delete bitstream;
throw ex;
}

return static_cast<FirmwareImage*>(bitstream);
}

void Xilinx7SeriesDevice::Program(FirmwareImage* image)
Expand Down Expand Up @@ -517,7 +528,7 @@ void XilinxSpartan6Device::ReadWordsConfigRegister(unsigned int reg, uint16_t* d
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Bitstream parsing

XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
void Xilinx7SeriesDevice::ParseBitstreamInternals(
const unsigned char* data,
size_t len,
XilinxFPGABitstream* bitstream,
Expand All @@ -529,7 +540,6 @@ XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
unsigned char syncword[4] = {0xaa, 0x99, 0x55, 0x66};
if(0 != memcmp(data+fpos, syncword, sizeof(syncword)))
{
delete bitstream;
throw JtagExceptionWrapper(
"No valid sync word found",
"");
Expand Down Expand Up @@ -635,7 +645,6 @@ XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
{
LogWarning("[Xilinx7SeriesDevice] Invalid register address 0x%x in config frame at bitstream offset %02x\n",
frame.bits.reg_addr, (int)fpos);
delete bitstream;
throw JtagExceptionWrapper(
"Invalid register address in bitstream",
"");
Expand Down Expand Up @@ -663,7 +672,6 @@ XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
//Expect 1 word
if(frame.bits.count != 1)
{
delete bitstream;
throw JtagExceptionWrapper(
"Invalid write (not 1 word) to CMD register in config frame",
"");
Expand All @@ -687,7 +695,6 @@ XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
//Expect 1 word
if(frame.bits.count != 1)
{
delete bitstream;
throw JtagExceptionWrapper(
"Invalid write (not 1 word) to IDCODE register in config frame",
"");
Expand Down Expand Up @@ -733,15 +740,11 @@ XilinxFPGABitstream* Xilinx7SeriesDevice::ParseBitstreamInternals(
}
else
{
delete bitstream;
throw JtagExceptionWrapper(
"Invalid frame type",
"");
}
}

//All OK
return bitstream;
}

void Xilinx7SeriesDevice::Reboot()
Expand Down
4 changes: 2 additions & 2 deletions Xilinx7SeriesDevice.h
Expand Up @@ -2,7 +2,7 @@
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2016 Andrew D. Zonenberg *
* Copyright (c) 2012-2018 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
Expand Down Expand Up @@ -329,7 +329,7 @@ class Xilinx7SeriesDevice : public XilinxFPGA
void ReadWordsConfigRegister(unsigned int reg, uint32_t* dout, unsigned int count);
void WriteWordConfigRegister(unsigned int reg, uint32_t value);

virtual XilinxFPGABitstream* ParseBitstreamInternals(
virtual void ParseBitstreamInternals(
const unsigned char* data,
size_t len,
XilinxFPGABitstream* bitstream,
Expand Down
22 changes: 10 additions & 12 deletions XilinxFPGA.cpp
Expand Up @@ -2,7 +2,7 @@
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2016 Andrew D. Zonenberg *
* Copyright (c) 2012-2018 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
Expand Down Expand Up @@ -67,15 +67,17 @@ XilinxFPGA::~XilinxFPGA()
@throw JtagException if the bitstream is malformed or for the wrong device family
@param bitstream The bitstream object being initialized
@param data Pointer to the bitstream data
@param len Length of the bitstream
@return A bitstream suitable for loading into this device
*/
FPGABitstream* XilinxFPGA::ParseBitstreamCore(const unsigned char* data, size_t len)
void XilinxFPGA::ParseBitstreamCore(
XilinxFPGABitstream* bitstream,
const unsigned char* data,
size_t len)
{
XilinxFPGABitstream* bitstream = new XilinxFPGABitstream;

//TODO: Some kind of ID code in FPGABitstream object so we can tell what type it is?

/**
Expand All @@ -100,8 +102,8 @@ FPGABitstream* XilinxFPGA::ParseBitstreamCore(const unsigned char* data, size_t
"");
}

//Make sure it's larger than 4KB (no valid bitstream is that small, and it means we don't need to length-check
//the headers as much
//Make sure it's larger than 4KB.
//No valid bitstream is that small, and it means we don't need to length-check the headers as much
if(len < 4096)
{
throw JtagExceptionWrapper(
Expand Down Expand Up @@ -202,7 +204,7 @@ FPGABitstream* XilinxFPGA::ParseBitstreamCore(const unsigned char* data, size_t

default:
//no idea
return NULL;
LogWarning("Unknown bitstream header block \"%c\"\n", record_type);
}

if(record_type == 'e')
Expand All @@ -217,8 +219,6 @@ FPGABitstream* XilinxFPGA::ParseBitstreamCore(const unsigned char* data, size_t
//Should be all FF's, then an AA
if(data[fpos] != 0xff)
{
delete bitstream;

LogError(
"[XilinxFPGA] Expected 0xFF filler at end of bitstream headers (position 0x%x), found 0x%02x instead\n",
(int)fpos,
Expand All @@ -235,15 +235,13 @@ FPGABitstream* XilinxFPGA::ParseBitstreamCore(const unsigned char* data, size_t
}
if(fpos == len)
{
delete bitstream;

throw JtagExceptionWrapper(
"Unexpected end of bitstream found",
"");
}

//Call the derived class function to read the bulk bitstream data
return ParseBitstreamInternals(data, len, bitstream, fpos);
ParseBitstreamInternals(data, len, bitstream, fpos);
}

bool XilinxFPGA::HasIndirectFlashSupport()
Expand Down
6 changes: 3 additions & 3 deletions XilinxFPGA.h
Expand Up @@ -2,7 +2,7 @@
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2016 Andrew D. Zonenberg *
* Copyright (c) 2012-2018 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
Expand Down Expand Up @@ -50,7 +50,7 @@ class XilinxFPGA : public XilinxDevice

protected:
//Static function for parsing bitstream headers (common to all Xilinx devices)
FPGABitstream* ParseBitstreamCore(const unsigned char* data, size_t len);
void ParseBitstreamCore(XilinxFPGABitstream* bitstream, const unsigned char* data, size_t len);\

/**
@brief Parse a full bitstream image (specific to the derived FPGA family)
Expand All @@ -63,7 +63,7 @@ class XilinxFPGA : public XilinxDevice
@param fpos Position in the bitstream image to start parsing (after the end of headers)
@param bVerbose Set to true for verbose debug output on bitstream internals
*/
virtual XilinxFPGABitstream* ParseBitstreamInternals(
virtual void ParseBitstreamInternals(
const unsigned char* data,
size_t len,
XilinxFPGABitstream* bitstream,
Expand Down

0 comments on commit 5a83172

Please sign in to comment.