1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
// Copyright 2020-2023 Intel Corporation.
//
// This software and the related documents are Intel copyrighted materials,
// and your use of them is governed by the express license under which they
// were provided to you ("License"). Unless the License provides otherwise,
// you may not use, modify, copy, publish, distribute, disclose or transmit
// this software or the related documents without Intel's prior written
// permission.
//
// This software and the related documents are provided as is, with no express
// or implied warranties, other than those that are expressly stated in the
// License.
#include "mmd_wrapper.h"
#include "aocl_mmd.h" // aocl_mmd_***
#include "dla_dma_constants.h" // DLA_DMA_CSR_OFFSET_***
#include <cassert> // assert
#include <cstddef> // size_t
#include <iostream> // std::cerr
#include <stdexcept> // std::runtime_error
#include <string> // std::string
// All board variants must obey the CoreDLA CSR spec, which says that all access must be
// - 32 bits in size
// - address must be 4 byte aligned
// - within the address range, CSR size is 2048 bytes
constexpr uint64_t DLA_CSR_ALIGNMENT = 4;
constexpr uint64_t DLA_CSR_SIZE = 2048;
// assert(status == 0) is removed by the c++ processor when compiling in release mode
// this is a handy workaround for suppressing the compiler warning about an unused variable
template <class T>
void suppress_warning_unused_varible(const T &) {}
MmdWrapper::MmdWrapper() {
// Open the MMD
constexpr size_t MAX_BOARD_NAMES_LEN = 4096;
char name[MAX_BOARD_NAMES_LEN];
size_t sz;
int status = aocl_mmd_get_offline_info(AOCL_MMD_BOARD_NAMES, MAX_BOARD_NAMES_LEN, name, &sz);
if (status) {
std::string msg = "Failed to query a board name from MMD. Perhaps no FPGA device is available?";
throw std::runtime_error(msg);
}
int handle = aocl_mmd_open(name);
if (handle < 0) {
std::string msg = "Failed to open MMD";
throw std::runtime_error(msg);
}
handle_ = handle;
// Query some board-specific information from the MMD. Some values can be hardcoded constants
// where different boards have different constants, e.g. capacity of FPGA DDR. Others values may
// be determined experimentally e.g. start and stop a counter with a known duration in between to
// measure the clk_dla frequency.
maxInstances_ = dla_mmd_get_max_num_instances();
ddrSizePerInstance_ = dla_mmd_get_ddr_size_per_instance();
coreDlaClockFreq_ = dla_mmd_get_coredla_clock_freq(handle_);
// On DE10 Agilex boards with GCC 8.3.0, we noticed that the clock frequency was being read as 0,
// around 50% of the time, and around 10% of the time on GCC 9.2.0, causing failures on perf_est
// tests. This retry loop will recall the function until the coreDlaClockFreq is non zero, or
// it exhausts 10 retries.
// We have no idea why this happens currently, but it typically passes by the second try.
int clockFreqRetries = 10;
while (coreDlaClockFreq_ == 0 && clockFreqRetries > 0) {
coreDlaClockFreq_ = dla_mmd_get_coredla_clock_freq(handle_);
clockFreqRetries--;
}
ddrClockFreq_ = dla_mmd_get_ddr_clock_freq();
}
MmdWrapper::~MmdWrapper() {
// Close the MMD
int status = aocl_mmd_close(handle_);
if (status) {
// Avoid throwning an exception from a Destructor. We are ultimately
// part of a (virtual) OpenVINO destructor, so we should follow the
// noexcept(true) that it advertises. Perhaps we can close the mmd
// as a separate step prior to destruction to make signaling errors
// easier?
std::cerr << "Failed to close MMD" << std::endl;
std::cerr << "Error status " << status << std::endl;
std::exit(1);
}
}
void MmdWrapper::RegisterISR(interrupt_service_routine_signature func, void *data) const {
// register an interrupt handler
int status = aocl_mmd_set_interrupt_handler(handle_, func, data);
if (status) {
std::string msg = "Failed to register an interrupt handler with MMD";
throw std::runtime_error(msg);
}
}
void MmdWrapper::WriteToCsr(int instance, uint32_t addr, uint32_t data) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr + sizeof(uint32_t) <= DLA_CSR_SIZE);
assert(addr % DLA_CSR_ALIGNMENT == 0);
int status = dla_mmd_csr_write(handle_, instance, addr, &data);
assert(status == 0);
suppress_warning_unused_varible(status);
}
uint32_t MmdWrapper::ReadFromCsr(int instance, uint32_t addr) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr + sizeof(uint32_t) <= DLA_CSR_SIZE);
assert(addr % DLA_CSR_ALIGNMENT == 0);
uint32_t data;
int status = dla_mmd_csr_read(handle_, instance, addr, &data);
assert(status == 0);
suppress_warning_unused_varible(status);
return data;
}
void MmdWrapper::WriteToDDR(int instance, uint64_t addr, uint64_t length, const void *data) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr + length <= ddrSizePerInstance_);
int status = dla_mmd_ddr_write(handle_, instance, addr, length, data);
assert(status == 0);
suppress_warning_unused_varible(status);
}
void MmdWrapper::ReadFromDDR(int instance, uint64_t addr, uint64_t length, void *data) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr + length <= ddrSizePerInstance_);
int status = dla_mmd_ddr_read(handle_, instance, addr, length, data);
assert(status == 0);
suppress_warning_unused_varible(status);
}
#ifndef STREAM_CONTROLLER_ACCESS
// Stream controller access is not supported by the platform abstraction
bool MmdWrapper::bIsStreamControllerValid(int instance) const { return false; }
// 32-bit handshake with each Stream Controller CSR
void MmdWrapper::WriteToStreamController(int instance, uint32_t addr, uint64_t length, const void *data) const {
assert(false);
}
void MmdWrapper::ReadFromStreamController(int instance, uint32_t addr, uint64_t length, void *data) const {
assert(false);
}
#else
// If the mmd layer supports accesses to the Stream Controller
bool MmdWrapper::bIsStreamControllerValid(int instance) const {
assert(instance >= 0 && instance < maxInstances_);
bool status = dla_is_stream_controller_valid(handle_, instance);
return status;
}
// 32-bit handshake with each Stream Controller CSR
void MmdWrapper::WriteToStreamController(int instance, uint32_t addr, uint64_t length, const void *data) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr % sizeof(uint32_t) == 0);
assert(length % sizeof(uint32_t) == 0);
int status = dla_mmd_stream_controller_write(handle_, instance, addr, length, data);
assert(status == 0);
suppress_warning_unused_varible(status);
}
void MmdWrapper::ReadFromStreamController(int instance, uint32_t addr, uint64_t length, void *data) const {
assert(instance >= 0 && instance < maxInstances_);
assert(addr % sizeof(uint32_t) == 0);
assert(length % sizeof(uint32_t) == 0);
int status = dla_mmd_stream_controller_read(handle_, instance, addr, length, data);
assert(status == 0);
suppress_warning_unused_varible(status);
}
#endif
|