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
|
/* poclAccel.cpp - Example HLS synthesizable accelerator implementing
the AlmaIF interface
Copyright (c) 2022 Topi Leppänen / Tampere University
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "poclAccel.h"
#define SLEEP_LOOP 50000
volatile int dummy = 0;
void poclAccel(volatile uint32_t Control[MEM_MAX_SIZE_WORD],
volatile uint32_t *output, volatile uint64_t cycle_counter) {
#pragma HLS INTERFACE bram port = Control storage_type = RAM_1P
#pragma HLS INTERFACE mode = m_axi port = output offset = off
#pragma HLS INTERFACE mode = ap_none port = cycle_counter
#pragma HLS INTERFACE ap_ctrl_none port = return
// Set initial values for info registers:
Control[ALMAIF_INFO_DEV_CLASS / 4] = 0xE; // Unused
Control[ALMAIF_INFO_DEV_ID / 4] = 0; // Unused
Control[ALMAIF_INFO_IF_TYPE / 4] = 3;
Control[ALMAIF_INFO_CORE_COUNT / 4] = 1;
Control[ALMAIF_INFO_CTRL_SIZE / 4] = 1024;
// The accelerator can choose the size of the queue (must be a power-of-two)
// Can be even 1, to make the packet handling easiest with static offsets
// The maximum size for this emulation to work is
// segment_size/AQL_PACKET_LENGTH
const uint32_t queue_length = 4;
// const uint32_t queue_length = segment_size / AQL_PACKET_LENGTH;
// Here we set the actual hardware memory region size. Even though the
// address spaces are equally sized, the actual memory region sizes
// don't have to be that big.The driver will adjust to these values.
Control[ALMAIF_INFO_CQMEM_SIZE_LOW / 4] =
AQL_PACKET_LENGTH * (queue_length + 1);
Control[ALMAIF_INFO_CQMEM_SIZE_HIGH / 4] = 0;
Control[ALMAIF_INFO_IMEM_SIZE / 4] = 0;
Control[ALMAIF_INFO_DMEM_SIZE_LOW / 4] =
MEM_MAX_SIZE_BYTES - 1024 - AQL_PACKET_LENGTH * (queue_length + 1);
Control[ALMAIF_INFO_DMEM_SIZE_HIGH / 4] = 0;
Control[ALMAIF_INFO_IMEM_START_LOW / 4] = 0;
Control[ALMAIF_INFO_IMEM_START_HIGH / 4] = 0;
Control[ALMAIF_INFO_CQMEM_START_LOW / 4] = BASE_ADDRESS + 1024;
Control[ALMAIF_INFO_CQMEM_START_HIGH / 4] = 0;
Control[ALMAIF_INFO_DMEM_START_LOW / 4] =
BASE_ADDRESS + 1024 + AQL_PACKET_LENGTH * (queue_length + 1);
Control[ALMAIF_INFO_DMEM_START_HIGH / 4] = 0;
Control[ALMAIF_INFO_FEATURE_FLAGS_LOW / 4] = 1;
Control[ALMAIF_INFO_PTR_SIZE / 4] = 4;
Control[ALMAIF_CONTROL_REG_COMMAND / 4] = ALMAIF_RESET_CMD;
const uint32_t CQInfoOffset = 1024 / 4;
const uint32_t CQOffset = 1024 / 4 + AQL_PACKET_LENGTH / 4;
while (1) {
// Don't start computing anything before hw reset is lifted.
int reset = Control[ALMAIF_CONTROL_REG_COMMAND / 4];
if (reset != ALMAIF_CONTINUE_CMD) {
continue;
}
int read_iter = Control[CQInfoOffset + 12];
// Compute packet location
uint32_t packet_loc =
(read_iter & (queue_length - 1)) * (AQL_PACKET_LENGTH / 4);
uint32_t packet_offset = CQOffset + packet_loc;
uint16_t packet_header = (uint16_t)(Control[packet_offset + 0]);
// The driver will mark the packet as not INVALID when it wants us to
// compute it
while (packet_header == AQL_PACKET_INVALID) {
// Control[75+2]=1;
packet_header = (uint16_t)Control[packet_offset + 0];
}
Control[75 + 11] = packet_header;
// uint16_t packet_dimensions = (uint16_t)(Control[packet_offset +
// 0] >> 16);
uint32_t packet_grid_size_x = Control[packet_offset + 3];
// uint32_t packet_grid_size_y = Control[packet_offset + 4];
// uint32_t packet_grid_size_z = Control[packet_offset + 5];
uint32_t packet_kernel_object = Control[packet_offset + 8];
// packet_kernel_object |= ((uint64_t)AQLstruct[9] << 32);
uint32_t packet_kernarg_address = Control[packet_offset + 10];
// packet_kernarg_address |= ((uint64_t)AQLstruct[11] << 32);
uint32_t packet_completion_sig_addr = Control[packet_offset + 14];
// packet_completion_sig_addr |= ((uint64_t)AQLstruct[15] << 32);
if (packet_header & (1 << AQL_PACKET_BARRIER_AND)) {
for (int i = 0; i < AQL_MAX_SIGNAL_COUNT; i++) {
uint32_t signal = Control[packet_offset + 2 + 2 * i];
if (signal != 0) {
while (output[signal / 4] == 0) {
for (int kk = 0; kk < SLEEP_LOOP; kk++) {
dummy++;
}
}
}
}
} else if (packet_header & (1 << AQL_PACKET_KERNEL_DISPATCH)) {
uint32_t index = packet_kernarg_address - BASE_ADDRESS;
uint32_t arg0 = Control[index / 4];
uint32_t arg1 = Control[index / 4 + 1];
uint32_t arg2 = Control[index / 4 + 2];
Control[packet_completion_sig_addr / 4 + 2] = cycle_counter;
Control[packet_completion_sig_addr / 4 + 3] = cycle_counter >> 32;
for (int i = 0; i < packet_grid_size_x; i++) {
// Do the operation based on the kernel_object (integer id)
switch (packet_kernel_object) {
case (POCL_CDBI_COPY_I8):
((uint8_t *)output)[arg1 + i] = ((uint8_t *)output)[arg0 + i];
break;
case (POCL_CDBI_ADD_I32):
output[arg2 / 4 + i] = output[arg0 / 4 + i] + output[arg1 / 4 + i];
break;
case (POCL_CDBI_MUL_I32):
output[arg2 / 4 + i] = output[arg0 / 4 + i] * output[arg1 / 4 + i];
break;
}
}
Control[packet_completion_sig_addr / 4 + 4] = cycle_counter;
Control[packet_completion_sig_addr / 4 + 5] = cycle_counter >> 32;
} else {
Control[75 + 17] = 99;
uint32_t index = packet_kernarg_address - BASE_ADDRESS;
uint32_t arg_addr = Control[index / 4];
continue;
}
// Completion signal is given as absolute address
if (packet_completion_sig_addr) {
packet_completion_sig_addr = packet_completion_sig_addr - BASE_ADDRESS;
Control[packet_completion_sig_addr / 4] = 1;
}
Control[packet_offset] = AQL_PACKET_INVALID;
read_iter++; // move on to the next AQL packet
Control[CQInfoOffset + 12] = read_iter;
}
}
|