// Copyright(c) 2018-2020, Intel Corporation
//
// 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 Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE
// 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.
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#include <algorithm>
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include <uuid/uuid.h>
#include <opae/cxx/core/handle.h>
#include <opae/cxx/core/properties.h>
#include <opae/cxx/core/shared_buffer.h>
#include <opae/cxx/core/token.h>
#include <opae/cxx/core/version.h>
using namespace opae::fpga::types;
static const char* NLB0_AFUID = "D8424DC4-A4A3-C413-F89E-433683F9040B";
static const uint64_t CL = 64;
static const uint64_t KB = 1024;
static const uint64_t MB = KB * 1024;
static const uint64_t LOG2_CL = 6;
static const size_t LPBK1_DSM_SIZE = 2 * MB;
static const size_t LPBK1_BUFFER_SIZE = 1 * MB;
static const size_t LPBK1_BUFFER_ALLOCATION_SIZE = 2 * MB;
static const uint64_t CSR_SRC_ADDR = 0x0120;
static const uint32_t CSR_DST_ADDR = 0x0128;
static const uint32_t CSR_CTL = 0x0138;
static const uint32_t CSR_CFG = 0x0140;
static const uint32_t CSR_NUM_LINES = 0x0130;
static const uint32_t DSM_STATUS_TEST_COMPLETE = 0x40;
static const uint64_t CSR_AFU_DSM_BASEL = 0x0110;
static inline uint64_t cacheline_aligned_addr(uint64_t num) {
return num >> LOG2_CL;
}
int main(int argc, char* argv[]) {
if ((argc > 1) && ((std::string(argv[1]) == std::string("-v")) ||
(std::string(argv[1]) == std::string("--version")))) {
std::cout << "hello_cxxcore " << OPAE_VERSION << " "
<< OPAE_GIT_COMMIT_HASH;
if (OPAE_GIT_SRC_TREE_DIRTY) std::cout << "*";
std::cout << std::endl;
return 0;
}
std::cout << "Using OPAE C++ Core library version '" << version::as_string()
<< "' build '" << version::build() << "'\n";
// look for accelerator with NLB0_AFUID
properties::ptr_t filter = properties::get();
filter->guid.parse(NLB0_AFUID);
filter->type = FPGA_ACCELERATOR;
std::vector<token::ptr_t> tokens = token::enumerate({filter});
// assert we have found at least one
if (tokens.size() < 1) {
std::cerr << "accelerator not found\n";
return -1;
}
token::ptr_t tok = tokens[0];
// open accelerator and map MMIO
handle::ptr_t accel = handle::open(tok, FPGA_OPEN_SHARED);
// allocate buffers
shared_buffer::ptr_t dsm = shared_buffer::allocate(accel, LPBK1_DSM_SIZE);
shared_buffer::ptr_t inp =
shared_buffer::allocate(accel, LPBK1_BUFFER_ALLOCATION_SIZE);
shared_buffer::ptr_t out =
shared_buffer::allocate(accel, LPBK1_BUFFER_ALLOCATION_SIZE);
std::cout << "Running Test\n";
// initialize buffers
std::fill_n(dsm->c_type(), LPBK1_DSM_SIZE, 0);
std::fill_n(inp->c_type(), LPBK1_BUFFER_SIZE, 0xAF);
std::fill_n(out->c_type(), LPBK1_BUFFER_SIZE, 0xBE);
accel->reset();
accel->write_csr64(CSR_AFU_DSM_BASEL, dsm->io_address());
accel->write_csr32(CSR_CTL, 0);
accel->write_csr32(CSR_CTL, 1);
accel->write_csr64(CSR_SRC_ADDR, cacheline_aligned_addr(inp->io_address()));
accel->write_csr64(CSR_DST_ADDR, cacheline_aligned_addr(out->io_address()));
accel->write_csr32(CSR_NUM_LINES, LPBK1_BUFFER_SIZE / (1 * CL));
accel->write_csr32(CSR_CFG, 0x42000);
// get ptr to device status memory - test complete
// temporarily "borrow" a raw pointer to the buffer
// status_ptr can be dangling pointer if dsm is the only reference
// and it is reset or goes out of scope before status_ptr
volatile uint8_t* status_ptr = dsm->c_type() + DSM_STATUS_TEST_COMPLETE;
// start the test
accel->write_csr32(CSR_CTL, 3);
// wait for test completion
while (0 == ((*status_ptr) * 0x1)) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
// stop the device
accel->write_csr32(CSR_CTL, 7);
// check output buffer contents
std::pair<volatile uint8_t*, volatile uint8_t*> mm = std::mismatch(
inp->c_type(), inp->c_type() + LPBK1_BUFFER_SIZE, out->c_type());
if (mm.second < out->c_type() + LPBK1_BUFFER_SIZE) {
std::cerr << "output does NOT match input at offset: "
<< (mm.second - out->c_type()) << "\n";
return -1;
}
std::cout << "Done Running Test\n";
return 0;
}