diff options
| author | Eric Dao <eric@erickhangdao.com> | 2025-03-10 17:54:31 -0400 |
|---|---|---|
| committer | Eric Dao <eric@erickhangdao.com> | 2025-03-10 17:54:31 -0400 |
| commit | ab224e2e6ba65f5a369ec392f99cd8845ad06c98 (patch) | |
| tree | a1e757e9341863ed52b8ad4c5a1c45933aab9da4 /python/openvino/runtime/coredla_device/stream_controller | |
| parent | 40da1752f2c8639186b72f6838aa415e854d0b1d (diff) | |
| download | thesis-master.tar.gz thesis-master.tar.bz2 thesis-master.zip | |
Diffstat (limited to 'python/openvino/runtime/coredla_device/stream_controller')
7 files changed, 803 insertions, 0 deletions
diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/dla_registers.h b/python/openvino/runtime/coredla_device/stream_controller/app/dla_registers.h new file mode 100644 index 0000000..d77c5ab --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/dla_registers.h @@ -0,0 +1,45 @@ +// Copyright 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. + +//the numbers below are byte addresses, must be a multiple of 4 since each access is 32 bits +static const uint32_t DLA_DMA_CSR_OFFSET_INTERRUPT_CONTROL = 512; //0x200 +static const uint32_t DLA_DMA_CSR_OFFSET_INTERRUPT_MASK = 516; +static const uint32_t DLA_DMA_CSR_OFFSET_CONFIG_BASE_ADDR = 528; //0x210 +static const uint32_t DLA_DMA_CSR_OFFSET_CONFIG_RANGE_MINUS_TWO = 532; +static const uint32_t DLA_DMA_CSR_OFFSET_INPUT_OUTPUT_BASE_ADDR = 536; +static const uint32_t DLA_DMA_CSR_OFFSET_DESC_DIAGNOSTICS = 540; +static const uint32_t DLA_DMA_CSR_OFFSET_INTERMEDIATE_BASE_ADDR = 544; //0x220 +static const uint32_t DLA_DMA_CSR_OFFSET_COMPLETION_COUNT = 548; +static const uint32_t DLA_DMA_CSR_OFFSET_CLOCKS_ACTIVE_LO = 576; //0x240 +static const uint32_t DLA_DMA_CSR_OFFSET_CLOCKS_ACTIVE_HI = 580; +static const uint32_t DLA_DMA_CSR_OFFSET_CLOCKS_ALL_JOBS_LO = 584; +static const uint32_t DLA_DMA_CSR_OFFSET_CLOCKS_ALL_JOBS_HI = 588; +static const uint32_t DLA_DMA_CSR_OFFSET_DEBUG_NETWORK_ADDR = 592; //0x250 +static const uint32_t DLA_DMA_CSR_OFFSET_DEBUG_NETWORK_VALID = 596; +static const uint32_t DLA_DMA_CSR_OFFSET_DEBUG_NETWORK_DATA = 600; + +//bit positions in interrupt control and mask +static const uint32_t DLA_DMA_CSR_INTERRUPT_ERROR_BIT = 0; +static const uint32_t DLA_DMA_CSR_INTERRUPT_DONE_BIT = 1; + +//bit positions in descriptor diagnostic +static const uint32_t DLA_DMA_CSR_DESC_DIAGNOSTICS_OVERFLOW_BIT = 0; +static const uint32_t DLA_DMA_CSR_DESC_DIAGNOSTICS_ALMOST_FULL_BIT = 1; +static const uint32_t DLA_DMA_CSR_DESC_DIAGNOSTICS_OUT_OF_INFERENCES_BIT = 2; + +//descriptor queue +//runtime knows how many jobs it has enqueued and how many jobs have finished +//runtime is responsible for not overflowing the descriptor queue, it must limit the number of outstanding jobs queued in hardware +static const uint32_t DLA_DMA_CSR_DESCRIPTOR_QUEUE_LOGICAL_SIZE = 64; //max number of jobs that runtime can enqueue +static const uint32_t DLA_DMA_CSR_DESCRIPTOR_QUEUE_WORDS_PER_JOB = 8; //how many words in the queue are needed to enqueue 1 job +static const uint32_t DLA_DMA_CSR_DESCRIPTOR_QUEUE_PHYSICAL_SIZE = DLA_DMA_CSR_DESCRIPTOR_QUEUE_LOGICAL_SIZE * DLA_DMA_CSR_DESCRIPTOR_QUEUE_WORDS_PER_JOB; //number of words in the hardware queue diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.c b/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.c new file mode 100644 index 0000000..1a12def --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.c @@ -0,0 +1,80 @@ +// Copyright 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 "message_handlers.h" +#include "stream_controller_messages.h" + +bool InitializeStreamControllerMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + InitializeStreamControllerPayload* pInitializePayload = (InitializeStreamControllerPayload*)pPayload; + this->InitializeStreamController(this, + pInitializePayload->_sourceBufferSize, + pInitializePayload->_dropSourceBuffers, + pInitializePayload->_numInferenceRequests); + this->SendMessage(this, MessageType_NoOperation, NULL, 0); + return true; +} + +bool ScheduleItemMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + volatile CoreDlaJobPayload* pCoreDlaJobPayload = (volatile CoreDlaJobPayload*)pPayload; + this->NewInferenceRequestReceived(this, pCoreDlaJobPayload); + this->SendMessage(this, MessageType_NoOperation, NULL, 0); + return true; +} + +bool PingMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + this->SendMessage(this, MessageType_Pong, NULL, 0); + return true; +} + +bool GetStatusMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + StatusMessagePayload statusMessagePayload; + statusMessagePayload._status = this->_status; + statusMessagePayload._statusLineNumber = this->_statusLineNumber; + statusMessagePayload._numReceivedSourceBuffers = this->_numReceivedSourceBuffers; + statusMessagePayload._numScheduledInferences = this->_numScheduledInferences; + statusMessagePayload._numExecutedJobs = this->_numExecutedJobs; + this->SendMessage(this, MessageType_Status, &statusMessagePayload, sizeof(statusMessagePayload)); + return true; +} + +bool ManualArmDmaTransferMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + ManualArmDmaTransferPayload* pManualArmDmaTransferPayload = (ManualArmDmaTransferPayload*)pPayload; + CoreDlaJobItem emptyJob = {}; + this->_debugJob = emptyJob; + this->_debugJob._payload._inputAddressDDR = pManualArmDmaTransferPayload->_inputAddressDDR; + this->_sourceBufferSize = pManualArmDmaTransferPayload->_sourceBufferSize; + bool fromHPS = (pManualArmDmaTransferPayload->_fromHPS != 0); + this->ArmDmaTransfer(this, &this->_debugJob, fromHPS); + this->SendMessage(this, MessageType_NoOperation, NULL, 0); + return true; +} + +bool ManualScheduleDlaInferenceMessageHandler(StreamController* this, volatile uint32_t* pPayload) +{ + ManualScheduleDlaInferencePayload* pManualScheduleDlaInferencePayload = (ManualScheduleDlaInferencePayload*)pPayload; + CoreDlaJobItem emptyJob = {}; + this->_debugJob = emptyJob; + this->_debugJob._payload._configurationBaseAddressDDR = pManualScheduleDlaInferencePayload->_configurationBaseAddressDDR; + this->_debugJob._payload._configurationSize = pManualScheduleDlaInferencePayload->_configurationSize; + this->_debugJob._payload._inputAddressDDR = pManualScheduleDlaInferencePayload->_inputAddressDDR; + this->ScheduleDlaInference(this, &this->_debugJob); + this->SendMessage(this, MessageType_NoOperation, NULL, 0); + return true; +} + + diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.h b/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.h new file mode 100644 index 0000000..a7e5187 --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/message_handlers.h @@ -0,0 +1,22 @@ +// Copyright 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. + +#pragma once +#include "stream_controller.h" + +extern bool InitializeStreamControllerMessageHandler(StreamController* this, volatile uint32_t* pPayload); +extern bool ScheduleItemMessageHandler(StreamController* this, volatile uint32_t* pPayload); +extern bool PingMessageHandler(StreamController* this, volatile uint32_t* pPayload); +extern bool GetStatusMessageHandler(StreamController* this, volatile uint32_t* pPayload); +extern bool ManualArmDmaTransferMessageHandler(StreamController* this, volatile uint32_t* pPayload); +extern bool ManualScheduleDlaInferenceMessageHandler(StreamController* this, volatile uint32_t* pPayload); diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.c b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.c new file mode 100644 index 0000000..ad8b372 --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.c @@ -0,0 +1,426 @@ +// Copyright 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 "stream_controller.h" +#include "message_handlers.h" +#include "sys/alt_cache.h" +#include "dla_registers.h" +#include <string.h> + +static const uint32_t messageReadyMagicNumber = 0x55225522; +static const uint32_t mailboxBaseAddress = 0x40000; +static const uint32_t mailboxSize = 0x1000; +static const uint32_t dlaBaseAddress = 0x30000; + +static void Start(StreamController* this); +static void Reset(StreamController* this); +static bool InitializeMsgDma(StreamController* this); +static bool ArmDmaTransfer(StreamController* this, CoreDlaJobItem* pFillJob, bool fromHPS); +static void RunEventLoop(StreamController* this); +static void WriteToDlaCsr(StreamController* this, uint32_t addr, uint32_t data); +static void InitializeStreamController(StreamController* this, uint32_t sourceBufferSize, uint32_t dropSourceBuffers, uint32_t numInferenceRequests); +static void SetStatus(StreamController* this, NiosStatusType statusType, uint32_t lineNumber); +static MessageType ReceiveMessage(StreamController* this, volatile MessageHeader* pReceiveMessage); +static bool SendMessage(StreamController* this, + MessageType messageType, + void* pPayload, + size_t payloadSize); +static void NewSourceBuffer(StreamController* this); +static void ScheduleDlaInference(StreamController* this, CoreDlaJobItem* pJob); +static void NewInferenceRequestReceived(StreamController* this, volatile CoreDlaJobPayload* pJobPayload); +static void MsgDmaIsr(void* pContext); + +int main() +{ + StreamController streamController = {}; + StreamController* this = &streamController; + + this->Start = Start; + this->Reset = Reset; + this->InitializeMsgDma = InitializeMsgDma; + this->ArmDmaTransfer = ArmDmaTransfer; + this->RunEventLoop = RunEventLoop; + this->WriteToDlaCsr = WriteToDlaCsr; + this->InitializeStreamController = InitializeStreamController; + this->SetStatus = SetStatus; + this->ReceiveMessage = ReceiveMessage; + this->SendMessage = SendMessage; + this->NewSourceBuffer = NewSourceBuffer; + this->ScheduleDlaInference = ScheduleDlaInference; + this->NewInferenceRequestReceived = NewInferenceRequestReceived; + + // Message handlers + this->GetStatusMessageHandler = GetStatusMessageHandler; + this->ScheduleItemMessageHandler = ScheduleItemMessageHandler; + this->PingMessageHandler = PingMessageHandler; + this->InitializeStreamControllerMessageHandler = InitializeStreamControllerMessageHandler; + this->ManualArmDmaTransferMessageHandler = ManualArmDmaTransferMessageHandler; + this->ManualScheduleDlaInferenceMessageHandler = ManualScheduleDlaInferenceMessageHandler; + + this->Reset(this); + this->Start(this); + + return 0; +} + +static void Start(StreamController* this) +{ + // Clear the mailbox memory + uint8_t* pMailbox = (uint8_t*)(mailboxBaseAddress); + memset(pMailbox, 0, mailboxSize); + + if (this->InitializeMsgDma(this)) + { + // Run the main event loop + this->RunEventLoop(this); + } +} + +static bool InitializeMsgDma(StreamController* this) +{ + this->_pMsgDevice = alt_msgdma_open(DLA_MSGDMA_0_CSR_NAME); + if (this->_pMsgDevice) + { + alt_msgdma_register_callback(this->_pMsgDevice, MsgDmaIsr, 0, this); + alt_dcache_flush_all(); + return true; + } + else + { + this->SetStatus(this, NiosStatusType_MsgDmaFailed, __LINE__); + return false; + } +} + +static bool ArmDmaTransfer(StreamController* this, CoreDlaJobItem* pFillJob, bool fromHPS) +{ + this->_pFillingImageJob = pFillJob; + + alt_u32* pWriteBuffer = (alt_u32*)this->_pFillingImageJob->_payload._inputAddressDDR; + alt_u32 length = this->_sourceBufferSize; + alt_u32 control = ALTERA_MSGDMA_DESCRIPTOR_CONTROL_TRANSFER_COMPLETE_IRQ_MASK; + + int r = 0; + if (fromHPS) + { + r = alt_msgdma_construct_extended_st_to_mm_descriptor(this->_pMsgDevice, + &this->_msgdmaDescriptor, + pWriteBuffer, + length, + control, + 0, + 0, + 1); + } + else + { + r = alt_msgdma_construct_extended_mm_to_st_descriptor(this->_pMsgDevice, + &this->_msgdmaDescriptor, + pWriteBuffer, + length, + control, + 0, + 0, + 1); + } + + if (r == 0) + { + r = alt_msgdma_extended_descriptor_async_transfer(this->_pMsgDevice, &this->_msgdmaDescriptor); + if (r != 0) + { + this->SetStatus(this, NiosStatusType_AsyncTransferFailed, __LINE__); + } + } + else + { + this->SetStatus(this, NiosStatusType_BadDescriptor, __LINE__); + } + + return (r == 0); +} + +static void RunEventLoop(StreamController* this) +{ + volatile MessageHeader* pReceiveMessage = (MessageHeader*)(mailboxBaseAddress); + + uint32_t previousIsrCount = this->_isrCount; + + while (true) + { + uint32_t isrCount = this->_isrCount; + + if (isrCount != previousIsrCount) + { + this->NewSourceBuffer(this); + } + + if (pReceiveMessage->_messageReadyMagicNumber == messageReadyMagicNumber) + { + this->ReceiveMessage(this, pReceiveMessage); + } + + previousIsrCount = isrCount; + } +} + +static MessageType ReceiveMessage(StreamController* this, volatile MessageHeader* pReceiveMessage) +{ + MessageType messageType = pReceiveMessage->_messageType; + uint32_t sequenceId = pReceiveMessage->_sequenceID; + this->_commandCounter++; + + bool ok = false; + + volatile uint32_t* pPayload = &pReceiveMessage->_payload; + + if (messageType == MessageType_GetStatus) + ok = this->GetStatusMessageHandler(this, pPayload); + else if (messageType == MessageType_ScheduleItem) + ok = this->ScheduleItemMessageHandler(this, pPayload); + else if (messageType == MessageType_Ping) + ok = this->PingMessageHandler(this, pPayload); + else if (messageType == MessageType_InitializeStreamController) + ok = this->InitializeStreamControllerMessageHandler(this, pPayload); + else if (messageType == MessageType_ManualArmDmaTransfer) + ok = this->ManualArmDmaTransferMessageHandler(this, pPayload); + else if (messageType == MessageType_ManualScheduleDlaInference) + ok = this->ManualScheduleDlaInferenceMessageHandler(this, pPayload); + + if (!ok) + this->SetStatus(this, NiosStatusType_BadMessage, __LINE__); + + pReceiveMessage->_messageReadyMagicNumber = sequenceId; + + if ((this->_lastReceiveSequenceID != 0) && ((this->_lastReceiveSequenceID + 1) != sequenceId)) + { + // If the DLA plugin has restarted, the first message will be InitializeStreamController + // with a sequence ID of 0 + if ((sequenceId != 0) || (messageType != MessageType_InitializeStreamController)) + this->SetStatus(this, NiosStatusType_BadMessageSequence, __LINE__); + } + + this->_lastReceiveSequenceID = sequenceId; + return messageType; +} + +static bool SendMessage(StreamController* this, + MessageType messageType, + void *pPayload, + size_t payloadSize) +{ + uint32_t mailboxSendAddress = mailboxBaseAddress + (mailboxSize / 2); + uint32_t* pMailbox = (uint32_t*)mailboxSendAddress; + MessageHeader* pSendMessage = (MessageHeader*)(pMailbox); + void* pPayloadDestination = &pSendMessage->_payload; + + pSendMessage->_messageType = messageType; + pSendMessage->_sequenceID = this->_sendSequenceID; + + if (payloadSize > 0) + memcpy(pPayloadDestination, pPayload, payloadSize); + + // Signal the message as ready + pSendMessage->_messageReadyMagicNumber = messageReadyMagicNumber; + + this->_sendSequenceID++; + return true; +} + +// We have received a new source buffer via the msgdma +static void NewSourceBuffer(StreamController* this) +{ + // Read the response to flush the buffer + CoreDlaJobItem* pJustFilledJob = this->_pFillingImageJob; + CoreDlaJobItem* pNextFillJob = NULL; + + uint32_t bufferSequence = this->_numReceivedSourceBuffers; + this->_numReceivedSourceBuffers++; + + // Have we just captured a manually armed DMA transfer? + if (pJustFilledJob == &this->_debugJob) + return; + + if (this->_dropSourceBuffers > 0) + { + // If _dropSourceBuffers = 1, we process 1, drop 1 etc + // if _dropSourceBuffers = 2, we process 1, drop 2, process 1, drop 2 etc + if (bufferSequence % (this->_dropSourceBuffers + 1) != 0) + { + // Drop this buffer, capture the next one in its place + this->ArmDmaTransfer(this, pJustFilledJob, true); + return; + } + } + + pJustFilledJob->_hasSourceBuffer = true; + + if (pJustFilledJob->_pNextJob->_hasSourceBuffer) + { + // No space in the next job, so keep filling the same job + pNextFillJob = pJustFilledJob; + + // It already has a buffer but we have to + // consider this as dropped as we will write another + // in its place + pNextFillJob->_hasSourceBuffer = false; + } + else + { + pNextFillJob = pJustFilledJob->_pNextJob; + } + + // Re-arm the DMA transfer + this->ArmDmaTransfer(this, pNextFillJob, true); + + // If there are less than two scheduled buffers, then we can schedule another one + // _pNextInferenceRequestJob is the executing job if it is marked as scheduled + + uint32_t nScheduled = 0; + if (this->_pNextInferenceRequestJob->_scheduledWithDLA) + nScheduled++; + if (this->_pNextInferenceRequestJob->_pNextJob->_scheduledWithDLA) + nScheduled++; + + if (nScheduled < 2) + this->ScheduleDlaInference(this, pJustFilledJob); +} + +static void NewInferenceRequestReceived(StreamController* this, volatile CoreDlaJobPayload* pJobPayload) +{ + // Once we have received all '_totalNumInferenceRequests' inference requests, + // we set the state to running and can now capture the input dma's + bool wasRunning = this->_running; + this->_numInferenceRequests++; + this->_running = (this->_numInferenceRequests >= this->_totalNumInferenceRequests); + + CoreDlaJobItem* pThisJob = this->_pNextInferenceRequestJob; + + // Store the job details and move to the next + uint32_t previousAddress = pThisJob->_payload._inputAddressDDR; + pThisJob->_payload = *pJobPayload; + + // This job has just completed so clear its state + pThisJob->_scheduledWithDLA = false; + pThisJob->_hasSourceBuffer = false; + + // The jobs are recycled by the DLA plugin so the inputAddrDDR should + // stay the same for each _jobs[n] + if ((pThisJob->_payload._inputAddressDDR != previousAddress) && (previousAddress != 0)) + this->SetStatus(this, NiosStatusType_Error, __LINE__); + + this->_pNextInferenceRequestJob = this->_pNextInferenceRequestJob->_pNextJob; + + if (wasRunning) + { + this->_numExecutedJobs++; + + // Check if we have any jobs ready to be scheduled. Maximum of 2 can have _scheduledWithDLA set + if (!this->_pNextInferenceRequestJob->_scheduledWithDLA && this->_pNextInferenceRequestJob->_hasSourceBuffer) + { + this->ScheduleDlaInference(this, this->_pNextInferenceRequestJob); + } + else if (!this->_pNextInferenceRequestJob->_pNextJob->_scheduledWithDLA && this->_pNextInferenceRequestJob->_pNextJob->_hasSourceBuffer) + { + this->ScheduleDlaInference(this, this->_pNextInferenceRequestJob->_pNextJob); + } + } + else if (this->_running) + { + // We have just started running + // Arm the DMA transfer to start receiving source buffers + this->ArmDmaTransfer(this, &this->_jobs[0], true); + } +} + +static void ScheduleDlaInference(StreamController* this, CoreDlaJobItem* pJob) +{ + // The DLA has an input FIFO. By setting the base address register, + // we add this request to the FIFO + pJob->_scheduledWithDLA = true; + this->_numScheduledInferences++; + + CoreDlaJobPayload* pJobPayload = &pJob->_payload; + this->WriteToDlaCsr(this, DLA_DMA_CSR_OFFSET_CONFIG_BASE_ADDR, pJobPayload->_configurationBaseAddressDDR); + this->WriteToDlaCsr(this, DLA_DMA_CSR_OFFSET_CONFIG_RANGE_MINUS_TWO, pJobPayload->_configurationSize); + this->WriteToDlaCsr(this, DLA_DMA_CSR_OFFSET_INPUT_OUTPUT_BASE_ADDR, pJobPayload->_inputAddressDDR); +} + +static void SetStatus(StreamController* this, NiosStatusType statusType, uint32_t lineNumber) +{ + this->_status = statusType; + this->_statusLineNumber = lineNumber; +} + +static void InitializeStreamController(StreamController* this, + uint32_t sourceBufferSize, + uint32_t dropSourceBuffers, + uint32_t numInferenceRequests) +{ + // This is called once when the inference app is run, + // so acts like a reset + this->_sourceBufferSize = sourceBufferSize; + this->_dropSourceBuffers = dropSourceBuffers; + this->_totalNumInferenceRequests = numInferenceRequests; + this->_jobs = malloc(sizeof(CoreDlaJobItem) * this->_totalNumInferenceRequests); + + // Reset any previous state + this->Reset(this); +} + +static void Reset(StreamController* this) +{ + CoreDlaJobItem emptyJob = {}; + uint32_t lastIndex = this->_totalNumInferenceRequests - 1; + + // Set up the circular job buffers + for (uint32_t i = 0; i < this->_totalNumInferenceRequests; i++) + { + this->_jobs[i] = emptyJob; + this->_jobs[i]._index = i; + uint32_t previousIndex = (i == 0) ? lastIndex : i - 1; + uint32_t nextIndex = (i == lastIndex) ? 0 : i + 1; + this->_jobs[i]._pPreviousJob = &this->_jobs[previousIndex]; + this->_jobs[i]._pNextJob = &this->_jobs[nextIndex]; + } + + this->_pNextInferenceRequestJob = &this->_jobs[0]; + this->_pFillingImageJob = &this->_jobs[0]; + this->_status = NiosStatusType_OK; + this->_statusLineNumber = 0; + this->_commandCounter = 0; + this->_numInferenceRequests = 0; + this->_numExecutedJobs = 0; + this->_numScheduledInferences = 0; + this->_lastReceiveSequenceID = 0; + this->_sendSequenceID = 0; + this->_running = false; + this->_isrCount = 0; + this->_numReceivedSourceBuffers = 0; +} + +static void WriteToDlaCsr(StreamController* this, uint32_t addr, uint32_t data) +{ + uint32_t* pRegister = (uint32_t*)(dlaBaseAddress + addr); + pRegister[0] = data; +} + +// Incrementing the ISR count here will result in NewSourceBuffer above being called +// in the event loop +static void MsgDmaIsr(void* pContext) +{ + StreamController* this = (StreamController*)pContext; + this->_isrCount++; +} + + diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.h b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.h new file mode 100644 index 0000000..8b19066 --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller.h @@ -0,0 +1,86 @@ +// Copyright 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. + +#pragma once + +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <stdio.h> +#include "altera_msgdma.h" +#include "system.h" +#include "stream_controller_messages.h" + +typedef struct CoreDlaJobItem +{ + uint32_t _index; + bool _hasSourceBuffer; + bool _scheduledWithDLA; + CoreDlaJobPayload _payload; + struct CoreDlaJobItem* _pPreviousJob; + struct CoreDlaJobItem* _pNextJob; +} CoreDlaJobItem; + +typedef struct StreamController +{ + void (*Start)(struct StreamController* this); + void (*Reset)(struct StreamController* this); + bool (*InitializeMsgDma)(struct StreamController* this); + bool (*ArmDmaTransfer)(struct StreamController* this, CoreDlaJobItem* pFillJob, bool fromHPS); + void (*RunEventLoop)(struct StreamController* this); + void (*WriteToDlaCsr)(struct StreamController* this, uint32_t addr, uint32_t data); + void (*InitializeStreamController)(struct StreamController* this, + uint32_t sourceBufferSize, + uint32_t dropSourceBuffers, + uint32_t numInferenceRequests); + void (*SetStatus)(struct StreamController* this, + NiosStatusType statusType, uint32_t lineNumber); + MessageType (*ReceiveMessage)(struct StreamController *this, volatile MessageHeader* pReceiveMessage); + bool (*SendMessage)(struct StreamController* this, + MessageType messageType, + void* pPayload, + size_t payloadSize); + void (*NewSourceBuffer)(struct StreamController* this); + void (*ScheduleDlaInference)(struct StreamController* this, CoreDlaJobItem* pJob); + void (*NewInferenceRequestReceived)(struct StreamController* this, volatile CoreDlaJobPayload* pJob); + + // Message handlers + bool (*GetStatusMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + bool (*ScheduleItemMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + bool (*PingMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + bool (*InitializeStreamControllerMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + bool (*ManualArmDmaTransferMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + bool (*ManualScheduleDlaInferenceMessageHandler)(struct StreamController* this, volatile uint32_t* pPayload); + + CoreDlaJobItem* _jobs; + CoreDlaJobItem* _pNextInferenceRequestJob; + CoreDlaJobItem* _pFillingImageJob; + CoreDlaJobItem _debugJob; + NiosStatusType _status; + uint32_t _statusLineNumber; + uint32_t _commandCounter; + uint32_t _sourceBufferSize; + uint32_t _dropSourceBuffers; + uint32_t _totalNumInferenceRequests; + uint32_t _numInferenceRequests; + uint32_t _numExecutedJobs; + uint32_t _numScheduledInferences; + uint32_t _lastReceiveSequenceID; + uint32_t _sendSequenceID; + bool _running; + uint32_t _numReceivedSourceBuffers; + volatile uint32_t _isrCount; + alt_msgdma_dev* _pMsgDevice; + alt_msgdma_extended_descriptor _msgdmaDescriptor; +} StreamController; diff --git a/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller_messages.h b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller_messages.h new file mode 100644 index 0000000..3891326 --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/app/stream_controller_messages.h @@ -0,0 +1,90 @@ +// Copyright 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. + +#pragma once +#include <stdint.h> + +typedef enum +{ + MessageType_Invalid, + MessageType_NoOperation, + MessageType_GetStatus, + MessageType_Status, + MessageType_ScheduleItem, + MessageType_Ping, + MessageType_Pong, + MessageType_InitializeStreamController, + MessageType_ManualArmDmaTransfer, + MessageType_ManualScheduleDlaInference +} MessageType; + +typedef enum +{ + NiosStatusType_OK = 1000, + NiosStatusType_Error, + NiosStatusType_BadMessage, + NiosStatusType_BadMessageSequence, + NiosStatusType_BadDescriptor, + NiosStatusType_AsyncTransferFailed, + NiosStatusType_MsgDmaFailed, + NiosStatusType_InvalidParameter +} NiosStatusType; + +typedef struct +{ + uint32_t _messageReadyMagicNumber; + uint32_t _messageType; + uint32_t _sequenceID; + uint32_t _payload; +} MessageHeader; + +// Message payloads: + +typedef struct +{ + uint32_t _configurationBaseAddressDDR; + uint32_t _configurationSize; + uint32_t _inputAddressDDR; + uint32_t _outputAddressDDR; +} CoreDlaJobPayload; + +typedef struct +{ + uint32_t _sourceBufferSize; + uint32_t _dropSourceBuffers; + uint32_t _numInferenceRequests; +} InitializeStreamControllerPayload; + +typedef struct +{ + NiosStatusType _status; + uint32_t _statusLineNumber; + uint32_t _numReceivedSourceBuffers; + uint32_t _numScheduledInferences; + uint32_t _numExecutedJobs; +} StatusMessagePayload; + +typedef struct +{ + uint32_t _sourceBufferSize; + uint32_t _inputAddressDDR; + uint32_t _fromHPS; +} ManualArmDmaTransferPayload; + +typedef struct +{ + uint32_t _configurationBaseAddressDDR; + uint32_t _configurationSize; + uint32_t _inputAddressDDR; +} ManualScheduleDlaInferencePayload; + diff --git a/python/openvino/runtime/coredla_device/stream_controller/build.sh b/python/openvino/runtime/coredla_device/stream_controller/build.sh new file mode 100755 index 0000000..2d22c5e --- /dev/null +++ b/python/openvino/runtime/coredla_device/stream_controller/build.sh @@ -0,0 +1,54 @@ +#! /bin/bash +# Run in Nios V Command Shell, Quartus Prime 22.4 or later + +quartus_project=$1 +qsys_file=$2 +hex_file=$3 + +usage() +{ + echo "Usage:" + echo " build.sh <quartus_project_file> <qsys_file> <destination_hex_file>" +} + +if [ -z "$quartus_project" ]; then + usage + exit 1 +fi + +if [ -z "$qsys_file" ]; then + usage + exit 1 +fi + +if [ -z "$hex_file" ]; then + usage + exit 1 +fi + +if [ ! -f "$quartus_project" ]; then + echo Quartus project file not found "$quartus_project" + usage + exit 1 +fi + +if [ ! -f "$qsys_file" ]; then + echo qsys file not found "$qsys_file" + usage + exit 1 +fi + +# Export the bsp folder from the Quartus project, create the +# CMakeFiles.txt for the application, build the app, then +# build the stream_controller.hex binary, in the 'build' folder + +niosv-bsp -c --quartus-project=$quartus_project --qsys=$qsys_file --type=hal bsp/settings.bsp +niosv-app --bsp-dir=bsp --app-dir=app --srcs=app --elf-name=stream_controller.elf + +# cmake dependency, version 3.14.10 or later. https://cmake.org/download/ +cmake -B build -DCMAKE_BUILD_TYPE=Release app +cmake --build build +elf2hex build/stream_controller.elf -b 0x0 -w 32 -e 0x1ffff -r 4 -o build/stream_controller.hex +cp build/stream_controller.hex $hex_file + +exit 0 |
