Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 80 additions & 37 deletions examples/basic-example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,63 @@
#error "Missing location macros for example"
#endif

// Given by the example
static constexpr char kBitstream[] = EXAMPLE_BITSTREAM_LOCATION;
static constexpr char kXclBin[] = EXAMPLE_DEFAULT_XCLBIN_LOCATION;

// Given by the design
static constexpr uint64_t kAccelAddress = EXAMPLE_ACCEL_ADDR;
static constexpr uint64_t kDmaAddress = EXAMPLE_DMA_ADDR;
static constexpr uint64_t kAddrWriteInputCols = 24;
static constexpr uint64_t kAddrWriteOutputCols = 40;
static constexpr uint64_t kAddrReadInputCols = 32;
static constexpr uint64_t kAddrReadOutputCols = 48;

// Data parameters
using DataType = uint16_t;
static constexpr int input_a_cols = 400;
static constexpr int input_a_rows = 2;
static constexpr int input_b_cols = 4;
static constexpr int input_b_rows = input_a_cols;
static constexpr int output_cols = input_b_cols;
static constexpr int output_rows = input_a_rows;
static constexpr int word_size = sizeof(DataType);

// Fill data
void FillData(DataType* A, DataType* B, DataType* C) {
for (uint32_t row = 0; row < input_b_cols; ++row) {
for (uint32_t col = 0; col < input_a_cols; ++col) {
A[((row % input_a_rows) * input_a_cols) + (col % input_a_cols)] =
row * col;
B[((col % input_b_rows) * input_b_cols) + (row % input_b_cols)] =
row * col;
C[((row % output_rows) * output_cols) + (col % output_cols)] = 0;
}
}
}

// Addresses of the accelerator
static constexpr uint64_t kAccelNumDataAddr = 0x20;
static constexpr uint kNumData = 64;
// Print results
void PrintData(DataType* C) {
std::cout << "Output: " << std::endl;
for (int i = 0; i < output_rows; ++i) {
for (int j = 0; j < output_cols; ++j) {
std::cout << C[i * output_cols + j] << " ";
}
std::cout << std::endl;
}
}

int main() {
// NOTE: This is a basic example. Error checking has been removed to keep
// simplicity but it is always recommended
using namespace cynq; // NOLINT

const int input_size = kNumData * sizeof(float);
const int output_size = kNumData * sizeof(float);
const size_t input_size =
(input_a_cols * input_a_rows + input_b_cols * input_b_rows) * word_size;
const size_t output_size = output_cols * output_rows * word_size;

// Create the platform
std::cout << "----- Initialising platform -----" << std::endl;
std::shared_ptr<IHardware> platform =
IHardware::Create(HardwareArchitecture::UltraScale, kBitstream, kXclBin);

Expand All @@ -50,48 +89,52 @@ int main() {
std::shared_ptr<IDataMover> mover = platform->GetDataMover(kDmaAddress);

// Create buffers for input and output
std::shared_ptr<IMemory> in_mem =
mover->GetBuffer(input_size, MemoryType::Dual);
std::shared_ptr<IMemory> out_mem =
mover->GetBuffer(output_size, MemoryType::Dual);
std::cout << "----- Creating memory -----" << std::endl;
std::shared_ptr<IMemory> in_mem = mover->GetBuffer(input_size);
std::shared_ptr<IMemory> out_mem = mover->GetBuffer(output_size);

// Get the host pointers for input/outut
std::shared_ptr<float> in_data = in_mem->HostAddress<float>();
std::shared_ptr<float> out_data = out_mem->HostAddress<float>();

// Fill data on *in_data*...

// Start the accel in autorestart
accel->Start(StartMode::Continuous);

// Read the defaults:
uint32_t incols = 0;
uint32_t outcols = 0;
std::cout << "----- Loading input -----" << std::endl;
DataType* A = in_mem->HostAddress<DataType>().get();
DataType* B = A + (input_a_cols * input_a_rows);
DataType* C = out_mem->HostAddress<DataType>().get();

accel->Read(32, &incols, 1);
accel->Read(48, &outcols, 1);
std::cout << "Initial InCols: " << incols << std::endl;
std::cout << "Initial OutCols: " << outcols << std::endl;
// Fill the data
FillData(A, B, C);

// Configure the accel
incols = kNumData;
outcols = kNumData;
accel->Write(24, &incols, 1);
accel->Write(40, &outcols, 1);

accel->Read(32, &incols, 1);
accel->Read(48, &outcols, 1);
std::cout << "Configured InCols: " << incols << std::endl;
std::cout << "Configured OutCols: " << outcols << std::endl;
// Synchronise data buffer
std::cout << "----- Synchronise Input -----" << std::endl;
in_mem->Sync(SyncType::HostToDevice);

// Start the accel
accel->Start(StartMode::Continuous);
// Check the control register
auto devstatus = accel->GetStatus();
std::cout << "\tAccel Status: " << static_cast<int>(devstatus) << std::endl;

std::cout << "----- Configuring accelerator -----" << std::endl;
// Configure params
accel->Write(kAddrWriteInputCols, &input_a_cols, 1);
accel->Write(kAddrWriteOutputCols, &output_cols, 1);
// Check params
int res_input_a_cols = 0;
int res_output_cols = 0;
accel->Read(kAddrReadInputCols, &res_input_a_cols, 1);
accel->Read(kAddrReadOutputCols, &res_output_cols, 1);

std::cout << "----- Moving the data -----" << std::endl;
// Move the data
in_mem->Sync(SyncType::HostToDevice);
mover->Upload(in_mem, in_mem->Size(), ExecutionType::Sync);
mover->Download(out_mem, out_mem->Size(), ExecutionType::Sync);
mover->Upload(in_mem, in_mem->Size(), 0, ExecutionType::Sync);
mover->Download(out_mem, out_mem->Size(), 0, ExecutionType::Sync);

// Stop the accel
accel->Stop();

std::cout << "----- Synchronising output -----" << std::endl;
out_mem->Sync(SyncType::DeviceToHost);

// Read the output on *out_data*
PrintData(C);

return 0;
}
40 changes: 33 additions & 7 deletions include/cynq/datamover.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@
#include "cynq/status.hpp"

namespace cynq {

struct HardwareParameters;

/**
* @brief Define an abstract representation of the data mover parameters
* with some prefilled fields
*/
struct DataMoverParameters {
/** HW Parameters */
std::shared_ptr<HardwareParameters> hw_params_;
/** Virtual destructor required for the inheritance */
virtual ~DataMoverParameters() = default;
};

struct HardwareParameters;

/**
* @brief Interface for standardising the API of DataMover for a specific
* device:
Expand Down Expand Up @@ -55,8 +71,8 @@ class IDataMover {
*
* @return std::shared_ptr<IMemory>
*/
virtual std::shared_ptr<IMemory> GetBuffer(const size_t size,
const MemoryType type) = 0;
virtual std::shared_ptr<IMemory> GetBuffer(
const size_t size, const MemoryType type = MemoryType::Dual) = 0;
/**
* @brief Upload method
* This method moves the data from the host to the device using a DMA engine.
Expand All @@ -68,13 +84,15 @@ class IDataMover {
* @param size Size in bytes of data being uploaded in the memory device by
* making use of the buffer.
*
* @param offset Offset in bytes where the device pointer should start
*
* @param exetype The execution type to use for the upload, this is either
* sync (synchronous) or async (asynchronous) execution.
*
* @return Status
*/
virtual Status Upload(const std::shared_ptr<IMemory> mem, const size_t size,
const ExecutionType exetype) = 0;
const size_t offset, const ExecutionType exetype) = 0;
/**
* @brief Download method
*
Expand All @@ -83,20 +101,23 @@ class IDataMover {
* @param size Size in bytes of data being downloaded from the memory device
* by making use of the buffer.
*
* @param offset Offset in bytes where the device pointer should start
*
* @param exetype The execution type to use for the download, this is either
* sync (synchronous) or async (asynchronous) execution.
*
* @return Status
*/
virtual Status Download(const std::shared_ptr<IMemory> mem, const size_t size,
const ExecutionType exetype) = 0;
const size_t offset, const ExecutionType exetype) = 0;
/**
* @brief Sync method
* Synchronizes data movements in case of asynchronous Upload/Download.
*
* @param type sync type. Depending on the transaction, it will trigger sync
* @return Status
*/
virtual Status Sync() = 0;
virtual Status Sync(const SyncType type) = 0;
/**
* @brief GetStatus method
* Returns the status of the data mover in terms of transactions.
Expand All @@ -119,6 +140,10 @@ class IDataMover {
* A 64 bit unsigned integer representing the beginning address of the
* IDataMover.
*
* @param hwparams
* Hardware-specific parameters to configure the data mover and grab the
* correct memory blocks
*
* @return std::shared_ptr<IDataMover>
* This is a shared_ptr with reference counting, the type will depend
* on the value of impl, the options are the following:
Expand All @@ -127,7 +152,8 @@ class IDataMover {
* None -> nullptr
*
*/
static std::shared_ptr<IDataMover> Create(IDataMover::Type impl,
const uint64_t addr);
static std::shared_ptr<IDataMover> Create(
IDataMover::Type impl, const uint64_t addr,
std::shared_ptr<HardwareParameters> hwparams);
};
} // namespace cynq
2 changes: 1 addition & 1 deletion include/cynq/enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ enum class ExecutionType {
*/
enum class DeviceStatus {
/** Uknown status for IAccelerator **/
Unknown,
Unknown = -1,
/** Done status for IAccelerator **/
Done,
/** Idle status for IAccelerator **/
Expand Down
6 changes: 5 additions & 1 deletion include/cynq/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ class IMemory {
* Pointer of the address that belongs to the device, used for mapping memory
* to the device.
*
* @param moverptr
* Pointer to platform specific properties
*
* @return std::shared_ptr<IMemory>
* This is a shared_ptr with reference counting, the type will depend
* on the value of impl, the options are the following:
Expand All @@ -116,7 +119,8 @@ class IMemory {
*/
static std::shared_ptr<IMemory> Create(IMemory::Type impl,
const std::size_t size,
uint8_t* hostptr, uint8_t* devptr);
uint8_t* hostptr, uint8_t* devptr,
void* moverptr);

protected:
/**
Expand Down
2 changes: 2 additions & 0 deletions include/cynq/status.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ struct Status {
CONFIGURATION_ERROR, /** Configuration error*/
REGISTER_IO_ERROR, /** Register MMIO error */
NOT_IMPLEMENTED, /** Not implemented error */
MEMBER_ABSENT, /** Missing member */
RESOURCE_BUSY, /** Busy */
};

int code; /** Code of the error */
Expand Down
29 changes: 23 additions & 6 deletions include/cynq/ultrascale/hardware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,30 @@
#include <memory>
#include <string>

#include "cynq/enums.hpp"
#include "cynq/hardware.hpp"
#include "cynq/status.hpp"
#include "cynq/xrt/accelerator.hpp"
#include "cynq/xrt/datamover.hpp"
#include <xrt/xrt.h>
#include <xrt/xrt/xrt_device.h>

#include <cynq/enums.hpp>
#include <cynq/hardware.hpp>
#include <cynq/status.hpp>
#include <cynq/xrt/accelerator.hpp>
#include <cynq/xrt/datamover.hpp>

namespace cynq {
/**
* @brief Specialisation of the parameters given by the UltraScale. It
* is based on the PYNQ and XRT
*/
struct UltraScaleParameters : public HardwareParameters {
/** XRT Device linked to the FPGA */
xrt::device device_;
/** XRT class representing the xclbin object */
xrt::xclbin xclbin_;

/** Virtual destructor required for the inheritance */
virtual ~UltraScaleParameters() = default;
};

/**
* @brief UltraScale class
* Provides an interface to access IP Cores in Xilinx FPGAs, the compatible
Expand Down Expand Up @@ -100,7 +117,7 @@ class UltraScale : public IHardware {

private:
/** Parameters used for internal hardware configuration */
std::unique_ptr<HardwareParameters> parameters_;
std::shared_ptr<HardwareParameters> parameters_;
/**
* @brief Loads the bitstream
*
Expand Down
Loading