mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-15 17:02:53 +08:00
997 lines
31 KiB
C
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
|