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
parent
5783c6e509
commit
7de5cc0caf
@ -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)"]
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
Loading…
Reference in New Issue