/* ---------------------------------------------------------------------- * Project: CMSIS DSP Library * Title: GenericNodes.h * Description: C++ support templates for the compute graph with static scheduler * * $Date: 29 July 2021 * $Revision: V1.10.0 * * Target Processor: Cortex-M and Cortex-A cores * -------------------------------------------------------------------- */ /* * Copyright (C) 2010-2022 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. */ #ifndef _SCHEDGEN_H_ #define _SCHEDGEN_H_ #include /* Defined in cg_status.h by default but user may want to use a different header to define the error codes of the application */ #define CG_SKIP_EXECUTION_ID_CODE (-5) #define CG_BUFFER_ERROR_ID_CODE (-6) // FIFOS #ifdef DEBUGSCHED #include template struct debugtype{ typedef T type; }; template<> struct debugtype{ typedef int type; }; template using Debug = struct debugtype; #endif template class FIFOBase{ public: virtual T* getWriteBuffer(int nb)=0; virtual T* getReadBuffer(int nb)=0; virtual bool willUnderflowWith(int nb) const = 0; virtual bool willOverflowWith(int nb) const = 0; virtual int nbSamplesInFIFO() const = 0; }; template class FIFO; /* Real FIFO, Synchronous */ template class FIFO: public FIFOBase { public: FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay) {}; FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {}; /* Not used in synchronous mode */ bool willUnderflowWith(int nb) const override {return false;}; bool willOverflowWith(int nb) const override {return false;}; int nbSamplesInFIFO() const override {return 0;}; T * getWriteBuffer(int nb) override { T *ret; if (readPos > 0) { memcpy((void*)mBuffer,(void*)(mBuffer+readPos),(writePos-readPos)*sizeof(T)); writePos -= readPos; readPos = 0; } ret = mBuffer + writePos; writePos += nb; return(ret); }; T* getReadBuffer(int nb) override { T *ret = mBuffer + readPos; readPos += nb; return(ret); } #ifdef DEBUGSCHED void dump() { int nb=0; std::cout << std::endl; for(int i=0; i < length ; i++) { std::cout << (typename Debug::type)mBuffer[i] << " "; nb++; if (nb == 10) { nb=0; std::cout << std::endl; } } std::cout << std::endl; std::cout << std::endl; } #endif protected: T *mBuffer; int readPos,writePos; }; /* Buffer, Synchronous */ template class FIFO: public FIFOBase { public: FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay) {}; FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {}; /* Not used in synchronous mode */ bool willUnderflowWith(int nb) const override {return false;}; bool willOverflowWith(int nb) const override {return false;}; int nbSamplesInFIFO() const override {return 0;}; T * getWriteBuffer(int nb) override { return(mBuffer); }; T* getReadBuffer(int nb) override { return(mBuffer); } #ifdef DEBUGSCHED void dump() { int nb=0; std::cout << std::endl; for(int i=0; i < length ; i++) { std::cout << (typename Debug::type)mBuffer[i] << " "; nb++; if (nb == 10) { nb=0; std::cout << std::endl; } } std::cout << std::endl; std::cout << std::endl; } #endif protected: T *mBuffer; int readPos,writePos; }; /* Real FIFO, Asynchronous */ template class FIFO: public FIFOBase { public: FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay),nbSamples(delay) {}; FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay),nbSamples(delay) {}; /* Check for overflow must have been done before using this function */ T * getWriteBuffer(int nb) override { T *ret; if (readPos > 0) { memcpy((void*)mBuffer,(void*)(mBuffer+readPos),(writePos-readPos)*sizeof(T)); writePos -= readPos; readPos = 0; } ret = mBuffer + writePos; writePos += nb; nbSamples += nb; return(ret); }; /* Check for undeflow must have been done before using this function */ T* getReadBuffer(int nb) override { T *ret = mBuffer + readPos; readPos += nb; nbSamples -= nb; return(ret); } bool willUnderflowWith(int nb) const override { return((nbSamples - nb)<0); } bool willOverflowWith(int nb) const override { return((nbSamples + nb)>length); } int nbSamplesInFIFO() const override {return nbSamples;}; #ifdef DEBUGSCHED void dump() { int nb=0; std::cout << std::endl; std::cout << "FIFO nb samples = " << nbSamples << std::endl; for(int i=0; i < length ; i++) { std::cout << (typename Debug::type)mBuffer[i] << " "; nb++; if (nb == 10) { nb=0; std::cout << std::endl; } } std::cout << std::endl; std::cout << std::endl; } #endif protected: T *mBuffer; int readPos,writePos; int nbSamples; }; // GENERIC NODES class NodeBase { public: virtual int run()=0; virtual int prepareForRunning()=0; }; template class GenericNode:public NodeBase { public: GenericNode(FIFOBase &src,FIFOBase &dst):mSrc(src),mDst(dst){}; protected: OUT * getWriteBuffer(int nb = outputSize){return mDst.getWriteBuffer(nb);}; IN * getReadBuffer(int nb = inputSize){return mSrc.getReadBuffer(nb);}; bool willOverflow(int nb = outputSize){return mDst.willOverflowWith(nb);}; bool willUnderflow(int nb = inputSize){return mSrc.willUnderflowWith(nb);}; private: FIFOBase &mSrc; FIFOBase &mDst; }; template class GenericNode12:public NodeBase { public: GenericNode12(FIFOBase &src,FIFOBase &dst1,FIFOBase &dst2):mSrc(src), mDst1(dst1),mDst2(dst2){}; protected: OUT1 * getWriteBuffer1(int nb=output1Size){return mDst1.getWriteBuffer(nb);}; OUT2 * getWriteBuffer2(int nb=output2Size){return mDst2.getWriteBuffer(nb);}; IN * getReadBuffer(int nb=inputSize){return mSrc.getReadBuffer(nb);}; bool willOverflow1(int nb = output1Size){return mDst1.willOverflowWith(nb);}; bool willOverflow2(int nb = output2Size){return mDst2.willOverflowWith(nb);}; bool willUnderflow(int nb = inputSize){return mSrc.willUnderflowWith(nb);}; private: FIFOBase &mSrc; FIFOBase &mDst1; FIFOBase &mDst2; }; template class GenericNode13:public NodeBase { public: GenericNode13(FIFOBase &src, FIFOBase &dst1, FIFOBase &dst2, FIFOBase &dst3 ):mSrc(src), mDst1(dst1),mDst2(dst2),mDst3(dst3){}; protected: OUT1 * getWriteBuffer1(int nb=output1Size){return mDst1.getWriteBuffer(nb);}; OUT2 * getWriteBuffer2(int nb=output2Size){return mDst2.getWriteBuffer(nb);}; OUT3 * getWriteBuffer3(int nb=output3Size){return mDst3.getWriteBuffer(nb);}; IN * getReadBuffer(int nb=inputSize){return mSrc.getReadBuffer(nb);}; bool willOverflow1(int nb = output1Size){return mDst1.willOverflowWith(nb);}; bool willOverflow2(int nb = output2Size){return mDst2.willOverflowWith(nb);}; bool willOverflow3(int nb = output3Size){return mDst3.willOverflowWith(nb);}; bool willUnderflow(int nb = inputSize){return mSrc.willUnderflowWith(nb);}; private: FIFOBase &mSrc; FIFOBase &mDst1; FIFOBase &mDst2; FIFOBase &mDst3; }; template class GenericNode21:public NodeBase { public: GenericNode21(FIFOBase &src1,FIFOBase &src2,FIFOBase &dst):mSrc1(src1), mSrc2(src2), mDst(dst){}; protected: OUT * getWriteBuffer(int nb=outputSize){return mDst.getWriteBuffer(nb);}; IN1 * getReadBuffer1(int nb=input1Size){return mSrc1.getReadBuffer(nb);}; IN2 * getReadBuffer2(int nb=input2Size){return mSrc2.getReadBuffer(nb);}; bool willOverflow(int nb = outputSize){return mDst.willOverflowWith(nb);}; bool willUnderflow1(int nb = input1Size){return mSrc1.willUnderflowWith(nb);}; bool willUnderflow2(int nb = input2Size){return mSrc2.willUnderflowWith(nb);}; private: FIFOBase &mSrc1; FIFOBase &mSrc2; FIFOBase &mDst; }; template class GenericSource:public NodeBase { public: GenericSource(FIFOBase &dst):mDst(dst){}; protected: OUT * getWriteBuffer(int nb=outputSize){return mDst.getWriteBuffer(nb);}; bool willOverflow(int nb = outputSize){return mDst.willOverflowWith(nb);}; private: FIFOBase &mDst; }; template class GenericSink:public NodeBase { public: GenericSink(FIFOBase &src):mSrc(src){}; protected: IN * getReadBuffer(int nb=inputSize){return mSrc.getReadBuffer(nb);}; bool willUnderflow(int nb = inputSize){return mSrc.willUnderflowWith(nb);}; private: FIFOBase &mSrc; }; #define REPEAT(N) for(int i=0;i class Duplicate2; template class Duplicate2: public GenericNode12 { public: Duplicate2(FIFOBase &src,FIFOBase &dst1,FIFOBase &dst2): GenericNode12(src,dst1,dst2){}; int prepareForRunning() override { if (this->willUnderflow() || this->willOverflow1() || this->willOverflow2()) { return(CG_SKIP_EXECUTION_ID_CODE); // Skip execution } return(0); }; int run() override { IN *a=this->getReadBuffer(); IN *b1=this->getWriteBuffer1(); IN *b2=this->getWriteBuffer2(); for(int i = 0; i class Duplicate3; template class Duplicate3: public GenericNode13 { public: Duplicate3(FIFOBase &src, FIFOBase &dst1, FIFOBase &dst2, FIFOBase &dst3): GenericNode13(src,dst1,dst2,dst3){}; int prepareForRunning() override { if (this->willUnderflow() || this->willOverflow1() || this->willOverflow2() || this->willOverflow3() ) { return(CG_SKIP_EXECUTION_ID_CODE); // Skip execution } return(0); }; int run() override { IN *a=this->getReadBuffer(); IN *b1=this->getWriteBuffer1(); IN *b2=this->getWriteBuffer2(); IN *b3=this->getWriteBuffer3(); for(int i = 0; i