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.
pull/53/head
Christophe Favergeon 3 years ago
parent 5783c6e509
commit 7de5cc0caf

1
.gitignore vendored

@ -27,3 +27,4 @@ Documentation/html/*
Doxygen/history.txt
Doxygen/dsp.dxy
__pycache__/
*.pyd

@ -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)

@ -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 <iostream>
template<typename IN, int inputSize>
class Sink: public GenericSink<IN, inputSize>
{
public:
Sink(FIFOBase<IN> &src):GenericSink<IN,inputSize>(src){};
int run()
{
IN *b=this->getReadBuffer();
printf("Sink\n");
for(int i=0;i<inputSize;i++)
{
std::cout << b[i].re << " + I" << b[i].im << std::endl;
}
return(0);
};
};
template<typename OUT,int outputSize>
class Source;
template<int outputSize>
class Source<complex,outputSize>: GenericSource<complex,outputSize>
{
public:
Source(FIFOBase<complex> &dst):GenericSource<complex,outputSize>(dst),mCounter(0){};
int run(){
complex *b=this->getWriteBuffer();
printf("Source\n");
for(int i=0;i<outputSize;i++)
{
b[i].re = (float32_t)mCounter++;
b[i].im = 0.0;
}
return(0);
};
int mCounter;
};
template<typename IN, int inputSize,typename OUT,int outputSize>
class ProcessingNode: public GenericNode<IN,inputSize,OUT,outputSize>
{
public:
ProcessingNode(FIFOBase<IN> &src,FIFOBase<OUT> &dst,int,const char*,int):GenericNode<IN,inputSize,OUT,outputSize>(src,dst){};
int run(){
printf("ProcessingNode\n");
IN *a=this->getReadBuffer();
OUT *b=this->getWriteBuffer();
b[0] =(OUT)a[3];
return(0);
};
};
#endif

@ -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)

@ -0,0 +1,20 @@
#ifndef _CUSTOM_H_
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct {
float re;
float im;
} complex;
#ifdef __cplusplus
}
#endif
#endif

@ -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<complex,FIFOSIZE0,0> fifo0(buf0);
FIFO<complex,FIFOSIZE1,1> fifo1(buf1);
FIFO<complex,FIFOSIZE2,1> fifo2(buf2);
FIFO<complex,FIFOSIZE3,1> fifo3(buf3);
FIFO<complex,FIFOSIZE4,1> fifo4(buf4);
/*
Create node objects
*/
Duplicate3<complex,5,complex,5,complex,5,complex,5> dup(fifo1,fifo2,fifo3,fifo4);
ProcessingNode<complex,7,complex,5> filter(fifo0,fifo1,4,"Test",someVariable);
Sink<complex,5> sa(fifo2);
Sink<complex,5> sb(fifo3);
Sink<complex,5> sc(fifo4);
Source<complex,5> 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);
}

@ -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

@ -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)

@ -0,0 +1,11 @@
#include <cstdio>
#include <cstdint>
#include "scheduler.h"
int main(int argc, char const *argv[])
{
int error;
printf("Start\n");
uint32_t nbSched=scheduler(&error,1);
return 0;
}

@ -0,0 +1,99 @@
digraph structs {
node [shape=plaintext]
rankdir=LR
edge [arrowsize=0.5]
fontname="times"
dup [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD PORT="i"><FONT POINT-SIZE="9.0">i</FONT></TD>
<TD ALIGN="CENTER" ROWSPAN="3">dup<BR/>(Duplicate3)</TD>
<TD PORT="oa"><FONT POINT-SIZE="9.0">oa</FONT></TD>
</TR>
<TR>
<TD></TD>
<TD PORT="ob"><FONT POINT-SIZE="9.0">ob</FONT></TD>
</TR><TR>
<TD></TD>
<TD PORT="oc"><FONT POINT-SIZE="9.0">oc</FONT></TD>
</TR>
</TABLE>>];
filter [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">filter<BR/>(ProcessingNode)</TD>
</TR>
</TABLE>>];
sa [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">sa<BR/>(Sink)</TD>
</TR>
</TABLE>>];
sb [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">sb<BR/>(Sink)</TD>
</TR>
</TABLE>>];
sc [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">sc<BR/>(Sink)</TD>
</TR>
</TABLE>>];
source [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">source<BR/>(Source)</TD>
</TR>
</TABLE>>];
source:i -> filter:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >7</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,label="complex(11)"]
filter:i -> dup:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,label="complex(5)"]
dup:oa -> sa:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,label="complex(5)"]
dup:ob -> sb:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,label="complex(5)"]
dup:oc -> sc:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >5</FONT>
</TD></TR></TABLE>>,label="complex(5)"]
}

@ -163,6 +163,35 @@ private:
FIFOBase<OUT2> &mDst2;
};
template<typename IN, int inputSize,
typename OUT1, int output1Size,
typename OUT2, int output2Size,
typename OUT3, int output3Size>
class GenericNode13:public NodeBase
{
public:
GenericNode13(FIFOBase<IN> &src,
FIFOBase<OUT1> &dst1,
FIFOBase<OUT2> &dst2,
FIFOBase<OUT3> &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<IN> &mSrc;
FIFOBase<OUT1> &mDst1;
FIFOBase<OUT2> &mDst2;
FIFOBase<OUT3> &mDst3;
};
template<typename IN1, int input1Size,typename IN2, int input2Size,typename OUT, int outputSize>
class GenericNode21:public NodeBase
{
@ -287,6 +316,72 @@ protected:
};
template<typename IN, int inputSize,typename OUT1,int output1Size,typename OUT2,int output2Size>
class Duplicate2;
template<typename IN, int inputSize>
class Duplicate2<IN,inputSize,IN,inputSize,IN,inputSize>: public GenericNode12<IN,inputSize,IN,inputSize,IN,inputSize>
{
public:
Duplicate2(FIFOBase<IN> &src,FIFOBase<IN> &dst1,FIFOBase<IN> &dst2):
GenericNode12<IN,inputSize,IN,inputSize,IN,inputSize>(src,dst1,dst2){};
int run(){
IN *a=this->getReadBuffer();
IN *b1=this->getWriteBuffer1();
IN *b2=this->getWriteBuffer2();
for(int i = 0; i<inputSize; i++)
{
b1[i] = a[i];
b2[i] = a[i];
}
return(0);
};
};
template<typename IN, int inputSize,
typename OUT1,int output1Size,
typename OUT2,int output2Size,
typename OUT3,int output3Size>
class Duplicate3;
template<typename IN, int inputSize>
class Duplicate3<IN,inputSize,
IN,inputSize,
IN,inputSize,
IN,inputSize>:
public GenericNode13<IN,inputSize,
IN,inputSize,
IN,inputSize,
IN,inputSize>
{
public:
Duplicate3(FIFOBase<IN> &src,
FIFOBase<IN> &dst1,
FIFOBase<IN> &dst2,
FIFOBase<IN> &dst3):
GenericNode13<IN,inputSize,
IN,inputSize,
IN,inputSize,
IN,inputSize>(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<inputSize; i++)
{
b1[i] = a[i];
b2[i] = a[i];
b3[i] = a[i];
}
return(0);
};
};
#if !defined(CHECKERROR)
#define CHECKERROR if (sdfError < 0) \
{\

@ -136,6 +136,31 @@ class MFCC(GenericNode):
def typeName(self):
return "MFCC"
class Duplicate2(GenericNode):
def __init__(self,name,theType,inLength):
GenericNode.__init__(self,name)
self.addInput("i",theType,inLength)
self.addOutput("oa",theType,inLength)
self.addOutput("ob",theType,inLength)
@property
def typeName(self):
return "Duplicate2"
class Duplicate3(GenericNode):
def __init__(self,name,theType,inLength):
GenericNode.__init__(self,name)
self.addInput("i",theType,inLength)
self.addOutput("oa",theType,inLength)
self.addOutput("ob",theType,inLength)
self.addOutput("oc",theType,inLength)
@property
def typeName(self):
return "Duplicate3"
#############################
#
# Host only Nodes

@ -55,6 +55,36 @@ class SDFType:
def bytes(self):
return(0)
class CStructType(SDFType):
"""A C structure
All structures with same name must have same size in bytes
Name must be a valid C and Python identifier
"""
def __init__(self,name,python_name,size_in_bytes):
self._name=name
self._python_name=python_name
self._size_in_bytes=size_in_bytes
def __eq__(self, other):
return(SDFType.__eq__(self,other) and self._name == other._name)
@property
def bytes(self):
return(self._size_in_bytes)
@property
def ctype(self):
return(self._name)
@property
def nptype(self):
return(self._python_name)
@property
def graphViztype(self):
return(self._name)
class CType(SDFType):
"""A C Scalar element"""
def __init__(self,typeid):

Loading…
Cancel
Save