From 7de5cc0caf283282056af2e9c305ef3bdd623ae8 Mon Sep 17 00:00:00 2001 From: Christophe Favergeon Date: Wed, 7 Sep 2022 15:14:15 +0200 Subject: [PATCH] Improvement to SDF Possibility to use a C struct as type for the IO. Added Duplicate2 and Duplicate3 nodes. Added an example (example8) to demonstrate and test those new features. --- .gitignore | 3 +- SDFTools/examples/CMakeLists.txt | 1 + SDFTools/examples/example8/AppNodes.h | 93 ++++++++++++ SDFTools/examples/example8/CMakeLists.txt | 13 ++ SDFTools/examples/example8/custom.h | 20 +++ .../examples/example8/generated/scheduler.cpp | 143 ++++++++++++++++++ .../examples/example8/generated/scheduler.h | 25 +++ SDFTools/examples/example8/graph.py | 79 ++++++++++ SDFTools/examples/example8/main.cpp | 11 ++ SDFTools/examples/example8/test.dot | 99 ++++++++++++ SDFTools/examples/example8/test.pdf | Bin 0 -> 24999 bytes SDFTools/sdf/src/GenericNodes.h | 95 ++++++++++++ cmsisdsp/sdf/scheduler/standard.py | 25 +++ cmsisdsp/sdf/types.py | 30 ++++ 14 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 SDFTools/examples/example8/AppNodes.h create mode 100644 SDFTools/examples/example8/CMakeLists.txt create mode 100644 SDFTools/examples/example8/custom.h create mode 100644 SDFTools/examples/example8/generated/scheduler.cpp create mode 100644 SDFTools/examples/example8/generated/scheduler.h create mode 100644 SDFTools/examples/example8/graph.py create mode 100644 SDFTools/examples/example8/main.cpp create mode 100644 SDFTools/examples/example8/test.dot create mode 100644 SDFTools/examples/example8/test.pdf diff --git a/.gitignore b/.gitignore index 04a72323..a3304d22 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ build Documentation/html/* Doxygen/history.txt Doxygen/dsp.dxy -__pycache__/ \ No newline at end of file +__pycache__/ +*.pyd diff --git a/SDFTools/examples/CMakeLists.txt b/SDFTools/examples/CMakeLists.txt index e0ac9db5..3a47beb1 100755 --- a/SDFTools/examples/CMakeLists.txt +++ b/SDFTools/examples/CMakeLists.txt @@ -50,3 +50,4 @@ add_subdirectory(example1 bin_example1) add_subdirectory(example2 bin_example2) add_subdirectory(example3 bin_example3) add_subdirectory(example6 bin_example6) +add_subdirectory(example8 bin_example8) diff --git a/SDFTools/examples/example8/AppNodes.h b/SDFTools/examples/example8/AppNodes.h new file mode 100644 index 00000000..2a967c73 --- /dev/null +++ b/SDFTools/examples/example8/AppNodes.h @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------- + * Project: CMSIS DSP Library + * Title: AppNodes.h + * Description: Application nodes for Example 1 + * + * $Date: 29 July 2021 + * $Revision: V1.10.0 + * + * Target Processor: Cortex-M and Cortex-A cores + * -------------------------------------------------------------------- */ +/* + * 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. + */ +#ifndef _APPNODES_H_ +#define _APPNODES_H_ + +#include + +template +class Sink: public GenericSink +{ +public: + Sink(FIFOBase &src):GenericSink(src){}; + + int run() + { + IN *b=this->getReadBuffer(); + printf("Sink\n"); + for(int i=0;i +class Source; + +template +class Source: GenericSource +{ +public: + Source(FIFOBase &dst):GenericSource(dst),mCounter(0){}; + + int run(){ + complex *b=this->getWriteBuffer(); + + printf("Source\n"); + for(int i=0;i +class ProcessingNode: public GenericNode +{ +public: + ProcessingNode(FIFOBase &src,FIFOBase &dst,int,const char*,int):GenericNode(src,dst){}; + + int run(){ + printf("ProcessingNode\n"); + IN *a=this->getReadBuffer(); + OUT *b=this->getWriteBuffer(); + b[0] =(OUT)a[3]; + return(0); + }; + +}; + +#endif \ No newline at end of file diff --git a/SDFTools/examples/example8/CMakeLists.txt b/SDFTools/examples/example8/CMakeLists.txt new file mode 100644 index 00000000..83f7c875 --- /dev/null +++ b/SDFTools/examples/example8/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 3.14) +include(CMakePrintHelpers) + +project(Example8) + + +add_executable(example8 main.cpp) + +sdf(example8) +add_sdf_dir(example8) + +target_include_directories(example8 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(example8 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/generated) diff --git a/SDFTools/examples/example8/custom.h b/SDFTools/examples/example8/custom.h new file mode 100644 index 00000000..0ed497ee --- /dev/null +++ b/SDFTools/examples/example8/custom.h @@ -0,0 +1,20 @@ +#ifndef _CUSTOM_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + float re; + float im; +} complex; + + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/SDFTools/examples/example8/generated/scheduler.cpp b/SDFTools/examples/example8/generated/scheduler.cpp new file mode 100644 index 00000000..3b320e24 --- /dev/null +++ b/SDFTools/examples/example8/generated/scheduler.cpp @@ -0,0 +1,143 @@ +/* + +Generated with CMSIS-DSP SDF Scripts. +The generated code is not covered by CMSIS-DSP license. + +The support classes and code is covered by CMSIS-DSP license. + +*/ + + +#include "arm_math.h" +#include "custom.h" +#include "GenericNodes.h" +#include "AppNodes.h" +#include "scheduler.h" + +/*********** + +FIFO buffers + +************/ +#define FIFOSIZE0 11 +#define FIFOSIZE1 5 +#define FIFOSIZE2 5 +#define FIFOSIZE3 5 +#define FIFOSIZE4 5 + +#define BUFFERSIZE0 11 +complex buf0[BUFFERSIZE0]={0}; + +#define BUFFERSIZE1 5 +complex buf1[BUFFERSIZE1]={0}; + +#define BUFFERSIZE2 5 +complex buf2[BUFFERSIZE2]={0}; + +#define BUFFERSIZE3 5 +complex buf3[BUFFERSIZE3]={0}; + +#define BUFFERSIZE4 5 +complex buf4[BUFFERSIZE4]={0}; + + +uint32_t scheduler(int *error,int someVariable) +{ + int sdfError=0; + uint32_t nbSchedule=0; + int32_t debugCounter=1; + + /* + Create FIFOs objects + */ + FIFO fifo0(buf0); + FIFO fifo1(buf1); + FIFO fifo2(buf2); + FIFO fifo3(buf3); + FIFO fifo4(buf4); + + /* + Create node objects + */ + Duplicate3 dup(fifo1,fifo2,fifo3,fifo4); + ProcessingNode filter(fifo0,fifo1,4,"Test",someVariable); + Sink sa(fifo2); + Sink sb(fifo3); + Sink sc(fifo4); + Source source(fifo0); + + /* Run several schedule iterations */ + while((sdfError==0) && (debugCounter > 0)) + { + /* Run a schedule iteration */ + sdfError = source.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = filter.run(); + CHECKERROR; + sdfError = dup.run(); + CHECKERROR; + sdfError = sc.run(); + CHECKERROR; + sdfError = sb.run(); + CHECKERROR; + sdfError = sa.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = filter.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = dup.run(); + CHECKERROR; + sdfError = sc.run(); + CHECKERROR; + sdfError = sb.run(); + CHECKERROR; + sdfError = sa.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = filter.run(); + CHECKERROR; + sdfError = dup.run(); + CHECKERROR; + sdfError = sc.run(); + CHECKERROR; + sdfError = sb.run(); + CHECKERROR; + sdfError = sa.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = filter.run(); + CHECKERROR; + sdfError = source.run(); + CHECKERROR; + sdfError = dup.run(); + CHECKERROR; + sdfError = sc.run(); + CHECKERROR; + sdfError = sb.run(); + CHECKERROR; + sdfError = sa.run(); + CHECKERROR; + sdfError = filter.run(); + CHECKERROR; + sdfError = dup.run(); + CHECKERROR; + sdfError = sc.run(); + CHECKERROR; + sdfError = sb.run(); + CHECKERROR; + sdfError = sa.run(); + CHECKERROR; + + debugCounter--; + nbSchedule++; + } + *error=sdfError; + return(nbSchedule); +} diff --git a/SDFTools/examples/example8/generated/scheduler.h b/SDFTools/examples/example8/generated/scheduler.h new file mode 100644 index 00000000..7f544ec6 --- /dev/null +++ b/SDFTools/examples/example8/generated/scheduler.h @@ -0,0 +1,25 @@ +/* + +Generated with CMSIS-DSP SDF Scripts. +The generated code is not covered by CMSIS-DSP license. + +The support classes and code is covered by CMSIS-DSP license. + +*/ + +#ifndef _SCHED_H_ +#define _SCHED_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern uint32_t scheduler(int *error,int someVariable); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/SDFTools/examples/example8/graph.py b/SDFTools/examples/example8/graph.py new file mode 100644 index 00000000..ae39ba1e --- /dev/null +++ b/SDFTools/examples/example8/graph.py @@ -0,0 +1,79 @@ +from cmsisdsp.sdf.scheduler import * + +### Define new types of Nodes + +class Node(GenericNode): + def __init__(self,name,theType,inLength,outLength): + GenericNode.__init__(self,name) + self.addInput("i",theType,inLength) + self.addOutput("o",theType,outLength) + +class Sink(GenericSink): + def __init__(self,name,theType,inLength): + GenericSink.__init__(self,name) + self.addInput("i",theType,inLength) + + @property + def typeName(self): + return "Sink" + +class Source(GenericSource): + def __init__(self,name,theType,inLength): + GenericSource.__init__(self,name) + self.addOutput("o",theType,inLength) + + @property + def typeName(self): + return "Source" + +class ProcessingNode(Node): + @property + def typeName(self): + return "ProcessingNode" + + + +### Define nodes +complexType=CStructType("complex","Complex",8) + +src=Source("source",complexType,5) +b=ProcessingNode("filter",complexType,7,5) +b.addLiteralArg(4) +b.addLiteralArg("Test") +b.addVariableArg("someVariable") +na = Sink("sa",complexType,5) +nb = Sink("sb",complexType,5) +nc = Sink("sc",complexType,5) +dup=Duplicate3("dup",complexType,5) + +g = Graph() + +g.connect(src.o,b.i) +g.connect(b.o,dup.i) +g.connect(dup.oa,na.i) +g.connect(dup.ob,nb.i) +g.connect(dup.oc,nc.i) + + +print("Generate graphviz and code") + +conf=Configuration() +conf.debugLimit=1 +conf.cOptionalArgs="int someVariable" +#conf.displayFIFOSizes=True +# Prefix for global FIFO buffers +#conf.prefix="sched1" + +#print(g.nullVector()) +sched = g.computeSchedule() +#print(sched.schedule) +print("Schedule length = %d" % sched.scheduleLength) +print("Memory usage %d bytes" % sched.memory) +# + +#conf.codeArray=True +sched.ccode("generated",conf) + +with open("test.dot","w") as f: + sched.graphviz(f) + diff --git a/SDFTools/examples/example8/main.cpp b/SDFTools/examples/example8/main.cpp new file mode 100644 index 00000000..b0cb113f --- /dev/null +++ b/SDFTools/examples/example8/main.cpp @@ -0,0 +1,11 @@ +#include +#include +#include "scheduler.h" + +int main(int argc, char const *argv[]) +{ + int error; + printf("Start\n"); + uint32_t nbSched=scheduler(&error,1); + return 0; +} \ No newline at end of file diff --git a/SDFTools/examples/example8/test.dot b/SDFTools/examples/example8/test.dot new file mode 100644 index 00000000..178f4722 --- /dev/null +++ b/SDFTools/examples/example8/test.dot @@ -0,0 +1,99 @@ + + + +digraph structs { + node [shape=plaintext] + rankdir=LR + edge [arrowsize=0.5] + fontname="times" + + + +dup [label=< + + + + + + + + + + + + + + + + +
idup
(Duplicate3)
oa
ob
oc
>]; + +filter [label=< + + + + +
filter
(ProcessingNode)
>]; + +sa [label=< + + + + +
sa
(Sink)
>]; + +sb [label=< + + + + +
sb
(Sink)
>]; + +sc [label=< + + + + +
sc
(Sink)
>]; + +source [label=< + + + + +
source
(Source)
>]; + + + +source:i -> filter:i [headlabel=< +
7 +
>,taillabel=< +
5 +
>,label="complex(11)"] + +filter:i -> dup:i [headlabel=< +
5 +
>,taillabel=< +
5 +
>,label="complex(5)"] + +dup:oa -> sa:i [headlabel=< +
5 +
>,taillabel=< +
5 +
>,label="complex(5)"] + +dup:ob -> sb:i [headlabel=< +
5 +
>,taillabel=< +
5 +
>,label="complex(5)"] + +dup:oc -> sc:i [headlabel=< +
5 +
>,taillabel=< +
5 +
>,label="complex(5)"] + + +} diff --git a/SDFTools/examples/example8/test.pdf b/SDFTools/examples/example8/test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1d2051e5926484c9374ae5ec5d3917841254a776 GIT binary patch literal 24999 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 literal 0 HcmV?d00001 diff --git a/SDFTools/sdf/src/GenericNodes.h b/SDFTools/sdf/src/GenericNodes.h index a9e7fd12..12cba304 100755 --- a/SDFTools/sdf/src/GenericNodes.h +++ b/SDFTools/sdf/src/GenericNodes.h @@ -163,6 +163,35 @@ private: 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(){return mDst1.getWriteBuffer(output1Size);}; + OUT2 * getWriteBuffer2(){return mDst2.getWriteBuffer(output2Size);}; + OUT3 * getWriteBuffer3(){return mDst3.getWriteBuffer(output3Size);}; + + IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);}; + +private: + FIFOBase &mSrc; + FIFOBase &mDst1; + FIFOBase &mDst2; + FIFOBase &mDst3; + +}; + template class GenericNode21:public NodeBase { @@ -287,6 +316,72 @@ protected: }; +template +class Duplicate2; + +template +class Duplicate2: public GenericNode12 +{ +public: + Duplicate2(FIFOBase &src,FIFOBase &dst1,FIFOBase &dst2): + GenericNode12(src,dst1,dst2){}; + + int run(){ + 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,dst2){}; + + int run(){ + IN *a=this->getReadBuffer(); + IN *b1=this->getWriteBuffer1(); + IN *b2=this->getWriteBuffer2(); + IN *b3=this->getWriteBuffer3(); + for(int i = 0; i