pikapython/package/Arm2D/arm_2d_async.c
2021-11-09 22:19:51 +08:00

997 lines
31 KiB
C

/*
* Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ----------------------------------------------------------------------
* Project: Arm-2D Library
* Title: arm-2d_async.c
* Description: Pixel pipeline extensions for support hardware acceleration.
*
* $Date: 29. April 2021
* $Revision: V.0.8.0
*
* Target Processor: Cortex-M cores
*
* -------------------------------------------------------------------- */
/*============================ INCLUDES ======================================*/
#define __ARM_2D_IMPL__
#include "arm_2d.h"
#include "__arm_2d_impl.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__ARM_2D_HAS_ASYNC__) && __ARM_2D_HAS_ASYNC__
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wreserved-identifier"
# pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
# pragma clang diagnostic ignored "-Wcast-qual"
# pragma clang diagnostic ignored "-Wcast-align"
# pragma clang diagnostic ignored "-Wextra-semi-stmt"
# pragma clang diagnostic ignored "-Wsign-conversion"
# pragma clang diagnostic ignored "-Wunused-function"
# pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
# pragma clang diagnostic ignored "-Wdouble-promotion"
# pragma clang diagnostic ignored "-Wunused-parameter"
# pragma clang diagnostic ignored "-Wimplicit-float-conversion"
# pragma clang diagnostic ignored "-Wimplicit-int-conversion"
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
# pragma clang diagnostic ignored "-Wsign-compare"
# pragma clang diagnostic ignored "-Wmissing-prototypes"
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
# pragma clang diagnostic ignored "-Wswitch-enum"
# pragma clang diagnostic ignored "-Wswitch"
# pragma clang diagnostic ignored "-Wimplicit-fallthrough"
# pragma clang diagnostic ignored "-Wgnu-statement-expression"
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
# pragma diag_suppress 174,177,188,68,513,144
#elif defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wswitch"
# pragma GCC diagnostic ignored "-Wenum-compare"
# pragma GCC diagnostic ignored "-Wpedantic"
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
/*============================ MACROS ========================================*/
#ifndef __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE
# define __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE 4
#endif
#if __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE < 4
# warning The __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE should be larger than or\
equal to 3, set it to the default value 4.
# undef __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE
# define __ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE 4
#endif
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ PROTOTYPES ====================================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ IMPLEMENTATION ================================*/
/*----------------------------------------------------------------------------*
* Subtask Pool *
*----------------------------------------------------------------------------*/
static void __arm_2d_sub_task_booking(uint_fast16_t hwCount)
{
arm_irq_safe {
ARM_2D_CTRL.hwBookCount += hwCount;
}
}
static void __arm_2d_sub_task_cancel_booking(void)
{
arm_irq_safe {
ARM_2D_CTRL.hwBookCount = 0;
}
}
static uint_fast16_t __arm_2d_sub_task_available_count(void)
{
uint_fast16_t hwResult = 0;
arm_irq_safe {
hwResult = ARM_2D_CTRL.hwFreeCount;
hwResult = (hwResult > ARM_2D_CTRL.hwBookCount)
? hwResult - ARM_2D_CTRL.hwBookCount
: 0;
}
return hwResult;
}
static
__arm_2d_sub_task_t *__arm_2d_sub_task_new(void)
{
__arm_2d_sub_task_t *ptTask = NULL;
arm_irq_safe {
if (NULL != ARM_2D_CTRL.ptFreeList) {
ARM_LIST_STACK_POP(ARM_2D_CTRL.ptFreeList, ptTask);
if (ARM_2D_CTRL.hwBookCount) {
ARM_2D_CTRL.hwBookCount--;
}
ARM_2D_CTRL.hwFreeCount--;
}
}
memset(ptTask, 0 ,sizeof(__arm_2d_sub_task_t));
return ptTask;
}
static
void __arm_2d_sub_task_free(__arm_2d_sub_task_t *ptTask)
{
if (NULL == ptTask) {
return ;
}
arm_irq_safe {
ARM_LIST_STACK_PUSH(ARM_2D_CTRL.ptFreeList, ptTask);
ARM_2D_CTRL.hwFreeCount++;
}
}
/*----------------------------------------------------------------------------*
* Subtask FIFO *
*----------------------------------------------------------------------------*/
#if 0
__WEAK
void arm_2d_notif_sub_task_fifo_task_arrive(void)
{
}
#endif
static
void __arm_2d_sub_task_add(__arm_2d_sub_task_t *ptTask)
{
assert(NULL != ptTask);
//bool bIsEmpty = false;
arm_irq_safe {
//bIsEmpty = (0 == ARM_2D_CTRL.hwTaskCount);
ARM_LIST_QUEUE_ENQUEUE( ARM_2D_CTRL.TaskFIFO.ptHead,
ARM_2D_CTRL.TaskFIFO.ptTail,
ptTask);
ARM_2D_CTRL.hwTaskCount++;
}
#if 0
if (bIsEmpty) {
arm_2d_notif_sub_task_fifo_task_arrive();
}
#endif
}
static
__arm_2d_sub_task_t * __arm_2d_sub_task_fetch(void)
{
__arm_2d_sub_task_t *ptTask = NULL;
arm_irq_safe {
if (NULL != ARM_2D_CTRL.TaskFIFO.ptHead) {
ARM_LIST_QUEUE_DEQUEUE( ARM_2D_CTRL.TaskFIFO.ptHead,
ARM_2D_CTRL.TaskFIFO.ptTail,
ptTask);
ARM_2D_CTRL.hwTaskCount--;
}
}
return ptTask;
}
/*----------------------------------------------------------------------------*
* Subtask Processing *
*----------------------------------------------------------------------------*/
static
arm_fsm_rt_t __arm_2d_call_default_io( __arm_2d_sub_task_t *ptTask,
uint_fast8_t chInterfaceIndex)
{
assert(NULL != ptTask);
arm_fsm_rt_t tResult = (arm_fsm_rt_t)ARM_2D_ERR_NOT_SUPPORT;
ARM_2D_IMPL(arm_2d_op_t, ptTask->ptOP);
uint_fast8_t chAccPreference = OP_CORE.Preference.u2ACCMethods;
do {
if (chAccPreference != ARM_2D_PREF_ACC_SW_ONLY) {
/* call hardware accelerator */
/*! \note the HW accelerator service routine will check the paratmer
*! and decide whether the requested service is supported or
*! not:
*! - if it is not supported, ARM_2D_ERR_NOT_SUPPORT will be
*! returned.
*!
*! - if it is supported and the service is to be done later,
*! the sub-task will be queued and arm_fsm_rt_async is
*! returned. Once the sub-task is complete,
*! __arm_2d_notify_sub_task_cpl() should be called by HW
*! accelerator service routine/tasks.
*!
*! - if it is supported and the service is complete immediately
*! the arm_fsm_rt_cpl is returned.
*!
*! - if there are any error detected, negative error code will be
*! returned.
*/
ARM_2D_TRY_ACCELERATION( chInterfaceIndex, __arm_2d_io_func_t );
assert(tResult != arm_fsm_rt_on_going);
switch (tResult) {
case arm_fsm_rt_wait_for_obj:
/*! \note the HW accelerator wants to sync-up with user
*! application
*/
if (chAccPreference == ARM_2D_PREF_ACC_DONT_CARE) {
/* since people choose don't care, then use SW */
break;
}
return tResult;
case arm_fsm_rt_on_going:
/*! \note HW accelerator should NOT return on_going otherwise
*! it will be treated as ARM_2D_ERR_IO_BUSY
*/
if (chAccPreference == ARM_2D_PREF_ACC_DONT_CARE) {
/* since people choose don't care, then use SW */
break;
}
return (arm_fsm_rt_t)ARM_2D_ERR_IO_BUSY;
case ARM_2D_ERR_NOT_SUPPORT:
break;
case arm_fsm_rt_async:
case arm_fsm_rt_cpl:
default:
/* other errors */
return tResult;
}
if ( (chAccPreference == ARM_2D_PREF_ACC_HW_ONLY)
&& (ARM_2D_ERR_NOT_SUPPORT == tResult)) {
//! the hardware acceleration isn't avaialble
break;
}
}
/* call default software implementation */
/*! \note the default software implemenation will only return following
*! values:
*! - arm_fsm_rt_cpl the service is complete.
*! - arm_fsm_rt_on_going the software algorithm wants to yield
*! - arm_fsm_rt_wait_for_obj the software algorithm wants to sync
*! with user application
*! - arm_fsm_rt_async the software algorithm is implemented
*! in asynchronous mode
*! - negative error code
*/
ARM_2D_RUN_DEFAULT( chInterfaceIndex, __arm_2d_io_func_t );
} while(0);
return tResult;
}
__WEAK
void arm_2d_notif_aync_op_cpl(uintptr_t pUserParam)
{
}
static void __arm_2d_notify_op_cpl(arm_2d_op_core_t *ptOP, arm_fsm_rt_t tResult)
{
assert(tResult != arm_fsm_rt_async);
assert(tResult != arm_fsm_rt_on_going);
assert(tResult != arm_fsm_rt_wait_for_obj);
//! error detected
if (tResult < 0) {
//! update error info
ptOP->tResult = tResult;
ptOP->Status.bIOError = true;
}
//! handle target OP
if (0 == ptOP->Status.u4SubTaskCount) {
//! this is the last sub task
//! no error has ever happened
if (ptOP->tResult >= 0) {
ptOP->tResult = tResult;
}
//! call Operation Complete event handler
if (NULL != ptOP->evt2DOpCpl.fnHandler) {
(ptOP->evt2DOpCpl.fnHandler) ( ptOP,
ptOP->tResult,
ptOP->evt2DOpCpl.pTarget);
ptOP->evt2DOpCpl.fnHandler = NULL;
}
/*! \note complete doesn't mean no err */
ptOP->Status.bOpCpl = true;
//! reset preference
ptOP->Preference.u2ACCMethods = 0;
/*! arm_thread_safe */
arm_irq_safe {
//! only clear busy flag after bOpCpl is set properly.
ptOP->Status.bIsBusy = false;
arm_2d_notif_aync_op_cpl(ptOP->pUserParam);
}
}
}
__WEAK
void arm_2d_notif_aync_sub_task_cpl(uintptr_t pUserParam)
{
}
/*! \note This API should be called by both arm_2d_task and hardware
*! accelerator to indicate the completion of a sub task
*/
void __arm_2d_notify_sub_task_cpl( __arm_2d_sub_task_t *ptTask,
arm_fsm_rt_t tResult,
bool bFromHW)
{
ARM_2D_UNUSED(bFromHW);
arm_2d_op_core_t *ptOP = ptTask->ptOP;
assert(NULL != ptTask);
assert(NULL != ptOP);
assert(ptOP->Status.u4SubTaskCount > 0);
//! free sub task
__arm_2d_sub_task_free(ptTask);
//if (bFromHW) {
arm_2d_notif_aync_sub_task_cpl(ptOP->pUserParam);
//}
ptOP->Status.u4SubTaskCount--;
__arm_2d_notify_op_cpl(ptOP, tResult);
}
/*! \note You can override this to add support for new types of interface
*! \param ptTask pointer of target sub task
*! \return the result
*/
arm_fsm_rt_t __arm_2d_sub_task_dispatch(__arm_2d_sub_task_t *ptTask)
{
arm_fsm_rt_t tResult = (arm_fsm_rt_t)ARM_2D_ERR_INVALID_OP;
//ARM_2D_IMPL(arm_2d_op_t, ptTask->ptOP);
//if (ptTask->chLowLeveIOIndex < dimof(__ARM_2D_IO_TABLE.OP)) {
tResult = __arm_2d_call_default_io( ptTask, ptTask->chLowLeveIOIndex);
//}
return tResult;
}
#define __ARM_2D_BACKEND_TASK_RESET_FSM() do {this.chState = START;} while(0);
/*! \brief arm-2d pixel pipeline backend task entery
*! \note This function is *TRHEAD-SAFE*
*! \param none
*! \retval arm_fsm_rt_cpl The sub-task FIFO is empty, the caller, i.e. the host
*! RTOS thread can block itself by waiting for a semaphore which is
*! set by arm_2d_notif_sub_task_fifo_task_arrive()
*! \retval arm_fsm_rt_on_going The arm_2d_task issued one sub-task without
*! problem and it yields.
*! \retval arm_fsm_rt_async You shouldn't see this value
*! \retval arm_fsm_rt_wait_for_obj some algorithm or hardware accelerator wants
*! to sync-up with applications.
*! \retval (<0) Serious error is detected.
*/
static
arm_fsm_rt_t __arm_2d_backend_task(arm_2d_task_t *ptThis)
{
enum {
START = 0,
FETCH,
DISPATCH,
};
switch(this.chState) {
case START:
this.tResult = (arm_fsm_rt_t)ARM_2D_ERR_INVALID_OP;
this.chState++;
//break;
case FETCH:
//! fetch a sub task from FIFO
this.ptTask = __arm_2d_sub_task_fetch();
if (NULL == this.ptTask) {
__ARM_2D_BACKEND_TASK_RESET_FSM();
return arm_fsm_rt_cpl;
}
this.chState++;
//break;
case DISPATCH:
//! dispatch sub tasks
this.tResult =
__arm_2d_sub_task_dispatch((__arm_2d_sub_task_t *)this.ptTask);
if ( (arm_fsm_rt_on_going == this.tResult) //!< sub task wants to yield
|| (arm_fsm_rt_wait_for_obj == this.tResult)) { //!< sub task wants to sync-up with applications
return this.tResult;
}
if (this.tResult != arm_fsm_rt_async) {
//! get result immediately
__arm_2d_notify_sub_task_cpl(
(__arm_2d_sub_task_t *)this.ptTask,
this.tResult,
false);
}
/*! \note (arm_fsm_rt_async == tResult) means the sub task hasn't
*! been handled yet
*/
__ARM_2D_BACKEND_TASK_RESET_FSM();
//! unsupported operation
if (ARM_2D_ERR_INVALID_OP == this.tResult){
return this.tResult;
}
break;
}
return arm_fsm_rt_on_going;
}
/*! \brief arm-2d pixel pipeline backend task entery
*! \note This function is *TRHEAD-SAFE*
*! \param none
*! \retval arm_fsm_rt_cpl The OPCODE FIFO is empty, the caller, i.e. the host
*! RTOS thread can block itself by waiting for a semaphore which is
*! set by arm_2d_notif_sub_task_fifo_task_arrive()
*! \retval arm_fsm_rt_on_going The frontend issued one OPCODE without
*! problem and it yields.
*! \retval arm_fsm_rt_async You shouldn't see this value
*! \retval arm_fsm_rt_wait_for_obj some algorithm or hardware accelerator wants
*! to sync-up with applications.
*! \retval (<0) Serious error is detected.
*/
static
arm_fsm_rt_t __arm_2d_frontend_task(arm_2d_task_t *ptThis)
{
arm_2d_op_core_t *ptOP = NULL;
arm_fsm_rt_t tResult;
arm_irq_safe {
ARM_LIST_QUEUE_PEEK(ARM_2D_CTRL.OPFIFO.ptHead,
ARM_2D_CTRL.OPFIFO.ptTail,
ptOP);
}
if (NULL == ptOP) {
return arm_fsm_rt_cpl;
}
tResult = __arm_2d_op_frontend_op_decoder(ptOP);
if ((arm_fsm_rt_cpl == tResult) || (tResult < 0)) {
arm_irq_safe {
ARM_LIST_QUEUE_DEQUEUE( ARM_2D_CTRL.OPFIFO.ptHead,
ARM_2D_CTRL.OPFIFO.ptTail,
ptOP);
}
ptOP->Status.u4SubTaskCount = 0;
__arm_2d_notify_op_cpl(ptOP, tResult);
} else if (arm_fsm_rt_async == tResult) {
arm_irq_safe {
ARM_LIST_QUEUE_DEQUEUE( ARM_2D_CTRL.OPFIFO.ptHead,
ARM_2D_CTRL.OPFIFO.ptTail,
ptOP);
}
}
/* release resources here */
__arm_2d_sub_task_cancel_booking();
if ( arm_fsm_rt_wait_for_obj == tResult
|| arm_fsm_rt_wait_for_res == tResult) {
return tResult;
}
assert(arm_fsm_rt_on_going != tResult);
return arm_fsm_rt_on_going;
}
/*! \brief arm-2d pixel pipeline task entery
*! \note This function is *TRHEAD-SAFE*
*! \param none
*! \retval arm_fsm_rt_cpl The sub-task FIFO is empty, the caller, i.e. the host
*! RTOS thread can block itself by waiting for a semaphore which is
*! set by arm_2d_notif_sub_task_fifo_task_arrive()
*! \retval arm_fsm_rt_on_going The arm_2d_task issued one sub-task without
*! problem and it yields.
*! \retval arm_fsm_rt_async You shouldn't see this value
*! \retval arm_fsm_rt_wait_for_obj some algorithm or hardware accelerator wants
*! to sync-up with applications.
*! \retval (<0) Serious error is detected.
*/
arm_fsm_rt_t arm_2d_task(arm_2d_task_t *ptThis)
{
arm_fsm_rt_t tResult;
do {
tResult = __arm_2d_backend_task(ptThis);
if (arm_fsm_rt_cpl != tResult) {
break;
}
tResult = __arm_2d_frontend_task(ptThis);
if (arm_fsm_rt_on_going == tResult){
continue;
}
break;
} while(true);
return tResult;
}
/*----------------------------------------------------------------------------*
* Overridden Implementations *
*----------------------------------------------------------------------------*/
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_op_frontend_on_leave( arm_2d_op_core_t *ptThis,
arm_fsm_rt_t tResult)
{
if (!ARM_2D_RUNTIME_FEATURE.HAS_DEDICATED_THREAD_FOR_2D_TASK) {
arm_fsm_rt_t tTaskResult;
arm_2d_task_t tTaskCB = {0};
do {
tTaskResult = arm_2d_task(&tTaskCB);
} while(arm_fsm_rt_on_going == tTaskResult);
if (tTaskResult < 0) {
//! a serious error is detected
tResult = tTaskResult;
} else if (arm_fsm_rt_wait_for_obj == tTaskResult) {
tResult = tTaskResult;
} else {
tResult = this.tResult;
}
}
return tResult;
}
__WEAK
void arm_2d_notif_new_op_arrive(uintptr_t pUserParam)
{
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_op_frontend(arm_2d_op_core_t *ptThis)
{
bool bEmptyQueue = false;
arm_fsm_rt_t tResult;
arm_irq_safe {
if (NULL == ARM_2D_CTRL.OPFIFO.ptHead) {
bEmptyQueue = true;
}
ARM_LIST_QUEUE_ENQUEUE( ARM_2D_CTRL.OPFIFO.ptHead,
ARM_2D_CTRL.OPFIFO.ptTail,
ptThis);
}
tResult = __arm_2d_op_frontend_on_leave(ptThis, this.tResult);
if (bEmptyQueue) {
arm_2d_notif_new_op_arrive(this.pUserParam);
}
return tResult;
}
__OVERRIDE_WEAK
bool __arm_2d_op_ensure_resource( arm_2d_op_core_t *ptOP,
uint_fast16_t hwRequired)
{
bool bResult = false;
ARM_2D_UNUSED(ptOP);
arm_irq_safe {
bResult = (__arm_2d_sub_task_available_count() >= hwRequired);
if (bResult) {
__arm_2d_sub_task_booking(hwRequired);
}
}
return bResult;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_tile_process(
arm_2d_op_t *ptThis,
__arm_2d_tile_param_t *ptParam)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 0,
.Param.tTileProcess = *ptParam,
};
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_fill(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptTarget)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 1,
.Param.tFill = {
.tSource = *ptSource,
.tTarget = *ptTarget,
},
};
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_fill_with_mask(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptSourceMask,
__arm_2d_tile_param_t *ptTarget,
__arm_2d_tile_param_t *ptTargetMask)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 1,
.Param.tFillMask = {
.use_as____arm_2d_param_fill_t = {
.tSource = *ptSource,
.tTarget = *ptTarget,
},
},
};
if (NULL == ptSourceMask){
ptTask->Param.tFillMask.tSrcMask.bInvalid = true;
} else {
ptTask->Param.tFillMask.tSrcMask = *ptSourceMask;
}
if (NULL == ptTargetMask){
ptTask->Param.tFillMask.tDesMask.bInvalid = true;
} else {
ptTask->Param.tFillMask.tDesMask = *ptTargetMask;
}
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_copy(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptTarget,
arm_2d_size_t * ptCopySize)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 0,
.Param.tCopy = {
.tSource = *ptSource,
.tTarget = *ptTarget,
.tCopySize = *ptCopySize,
},
};
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_copy_with_mask(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptSourceMask,
__arm_2d_tile_param_t *ptTarget,
__arm_2d_tile_param_t *ptTargetMask,
arm_2d_size_t * __RESTRICT ptCopySize)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 0,
.Param.tCopyMask = {
.use_as____arm_2d_param_copy_t = {
.tSource = *ptSource,
.tTarget = *ptTarget,
.tCopySize = *ptCopySize,
},
},
};
if (NULL == ptSourceMask){
ptTask->Param.tCopyMask.tSrcMask.bInvalid = true;
} else {
ptTask->Param.tCopyMask.tSrcMask = *ptSourceMask;
}
if (NULL == ptTargetMask){
ptTask->Param.tCopyMask.tDesMask.bInvalid = true;
} else {
ptTask->Param.tCopyMask.tDesMask = *ptTargetMask;
}
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_fill_origin(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptOrigin,
__arm_2d_tile_param_t *ptTarget)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 1,
.Param.tFillOrig = {
.use_as____arm_2d_param_fill_t = {
.tSource = *ptSource,
.tTarget = *ptTarget,
},
.tOrigin = *ptOrigin,
},
};
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
__OVERRIDE_WEAK
arm_fsm_rt_t __arm_2d_issue_sub_task_copy_origin(
arm_2d_op_cp_t *ptThis,
__arm_2d_tile_param_t *ptSource,
__arm_2d_tile_param_t *ptOrigin,
__arm_2d_tile_param_t *ptTarget,
arm_2d_size_t * __RESTRICT ptCopySize)
{
__arm_2d_sub_task_t *ptTask = __arm_2d_sub_task_new();
assert(NULL != ptTask);
(*ptTask) = (__arm_2d_sub_task_t) {
.ptOP = &(ptThis->use_as__arm_2d_op_core_t),
.chLowLeveIOIndex = 0,
.Param.tCopyOrig = {
.use_as____arm_2d_param_copy_t = {
.tSource = *ptSource,
.tTarget = *ptTarget,
.tCopySize = *ptCopySize,
},
.tOrigin = *ptOrigin,
},
};
OP_CORE.Status.u4SubTaskCount++;
__arm_2d_sub_task_add(ptTask);
return arm_fsm_rt_async;
}
/*! \brief initialise the whole arm-2d service
*! \param none
*! \return none
*/
void __arm_2d_async_init(void)
{
//! initialise sub task pool
do {
static __arm_2d_sub_task_t
s_tDefaultTaskPool[__ARM_2D_DEFAULT_SUB_TASK_POOL_SIZE];
arm_foreach(__arm_2d_sub_task_t, s_tDefaultTaskPool) {
__arm_2d_sub_task_free(_);
}
} while(0);
}
__WEAK
bool arm_2d_port_wait_for_async(uintptr_t pUserParam)
{
return false;
}
__OVERRIDE_WEAK
/*! \brief sync up with operation
*! \retval true operation is busy
*! \retval false operation isn't busy
*/
bool arm_2d_op_wait_async(arm_2d_op_core_t *ptOP)
{
ARM_2D_IMPL(arm_2d_op_core_t, ptOP)
volatile arm_2d_op_status_t *ptStatus
= (volatile arm_2d_op_status_t *)&(this.Status);
bool bIsBusy = false;
do {
bIsBusy = ptStatus->bIsBusy;
if (!bIsBusy) {
break;
}
if (!arm_2d_port_wait_for_async(this.pUserParam)) {
break;
}
} while(bIsBusy);
return !bIsBusy;
}
__OVERRIDE_WEAK
/*! \brief sync up with operation
*! \retval true operation is busy
*! \retval false operation isn't busy
*/
bool __arm_2d_op_acquire(arm_2d_op_core_t *ptOP)
{
ARM_2D_IMPL(arm_2d_op_core_t, ptOP)
volatile arm_2d_op_status_t *ptStatus
= (volatile arm_2d_op_status_t *)&(this.Status);
bool bResult = false;
do {
arm_irq_safe {
bResult = ptStatus->bIsBusy;
if (!bResult) {
this.tResult = arm_fsm_rt_async;
ptStatus->tValue = 0; //! reset status
ptStatus->bIsBusy = true; //! set busy flag
}
}
if (!bResult) {
break;
}
if (!arm_2d_port_wait_for_async(this.pUserParam)) {
break;
}
} while (bResult);
return !bResult;
}
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
# pragma diag_warning 174,177,188,68,513,144
#elif defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#endif