Added support for custom datatype for Python code generated by SDF

pull/53/head
Christophe Favergeon 3 years ago
parent 7de5cc0caf
commit e7010120fd

@ -22,28 +22,52 @@ DEBUGSCHED=False
FIFOSIZE0=256
buf0=np.zeros(FIFOSIZE0,dtype=np.float32)
buf0=np.empty(FIFOSIZE0,dtype=np.float32)
for i in range(FIFOSIZE0):
buf0[i] = 0
FIFOSIZE1=256
buf1=np.zeros(FIFOSIZE1,dtype=np.float32)
buf1=np.empty(FIFOSIZE1,dtype=np.float32)
for i in range(FIFOSIZE1):
buf1[i] = 0
FIFOSIZE2=256
buf2=np.zeros(FIFOSIZE2,dtype=np.float32)
buf2=np.empty(FIFOSIZE2,dtype=np.float32)
for i in range(FIFOSIZE2):
buf2[i] = 0
FIFOSIZE3=512
buf3=np.zeros(FIFOSIZE3,dtype=np.float32)
buf3=np.empty(FIFOSIZE3,dtype=np.float32)
for i in range(FIFOSIZE3):
buf3[i] = 0
FIFOSIZE4=512
buf4=np.zeros(FIFOSIZE4,dtype=np.float32)
buf4=np.empty(FIFOSIZE4,dtype=np.float32)
for i in range(FIFOSIZE4):
buf4[i] = 0
FIFOSIZE5=512
buf5=np.zeros(FIFOSIZE5,dtype=np.float32)
buf5=np.empty(FIFOSIZE5,dtype=np.float32)
for i in range(FIFOSIZE5):
buf5[i] = 0
FIFOSIZE6=256
buf6=np.zeros(FIFOSIZE6,dtype=np.float32)
buf6=np.empty(FIFOSIZE6,dtype=np.float32)
for i in range(FIFOSIZE6):
buf6[i] = 0
FIFOSIZE7=256
buf7=np.zeros(FIFOSIZE7,dtype=np.float32)
buf7=np.empty(FIFOSIZE7,dtype=np.float32)
for i in range(FIFOSIZE7):
buf7[i] = 0
def scheduler(dispbuf):

@ -22,19 +22,34 @@ DEBUGSCHED=False
FIFOSIZE0=384
buf0=np.zeros(FIFOSIZE0,dtype=np.int16)
buf0=np.empty(FIFOSIZE0,dtype=np.int16)
for i in range(FIFOSIZE0):
buf0[i] = 0
FIFOSIZE1=768
buf1=np.zeros(FIFOSIZE1,dtype=np.int16)
buf1=np.empty(FIFOSIZE1,dtype=np.int16)
for i in range(FIFOSIZE1):
buf1[i] = 0
FIFOSIZE2=1024
buf2=np.zeros(FIFOSIZE2,dtype=np.int16)
buf2=np.empty(FIFOSIZE2,dtype=np.int16)
for i in range(FIFOSIZE2):
buf2[i] = 0
FIFOSIZE3=377
buf3=np.zeros(FIFOSIZE3,dtype=np.int16)
buf3=np.empty(FIFOSIZE3,dtype=np.int16)
for i in range(FIFOSIZE3):
buf3[i] = 0
FIFOSIZE4=754
buf4=np.zeros(FIFOSIZE4,dtype=np.int16)
buf4=np.empty(FIFOSIZE4,dtype=np.int16)
for i in range(FIFOSIZE4):
buf4[i] = 0
def scheduler(mfccConfig,dispbuf):

@ -22,10 +22,16 @@ DEBUGSCHED=False
FIFOSIZE0=128
buf0=np.zeros(FIFOSIZE0,dtype=np.int16)
buf0=np.empty(FIFOSIZE0,dtype=np.int16)
for i in range(FIFOSIZE0):
buf0[i] = 0
FIFOSIZE1=128
buf1=np.zeros(FIFOSIZE1,dtype=np.int16)
buf1=np.empty(FIFOSIZE1,dtype=np.int16)
for i in range(FIFOSIZE1):
buf1[i] = 0
def scheduler():

@ -42,7 +42,7 @@ public:
printf("Sink\n");
for(int i=0;i<inputSize;i++)
{
std::cout << b[i].re << " + I" << b[i].im << std::endl;
std::cout << b[i].re << " + I " << b[i].im << std::endl;
}
return(0);
};

@ -0,0 +1,87 @@
###########################################
# Project: CMSIS DSP Library
# Title: appnodes.py
# Description: Application nodes for Example 4
#
# $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.
############################################
from cmsisdsp.sdf.nodes.simu import *
from custom import *
from cmsisdsp.sdf.nodes.Duplicate import *
class Sink(GenericSink):
def __init__(self,inputSize,fifoin):
GenericSink.__init__(self,inputSize,fifoin)
def run(self):
# The null sink must at least get a buffer from the FIFO
# or the FIFO will never be emptied
# and the scheduling will fail
print("Sink")
i=self.getReadBuffer()
for c in i:
print("%f + I %f" % (c.re,c.im))
return(0)
class ProcessingNode(GenericNode):
def __init__(self,inputSize,outputSize,fifoin,fifoout,i,s,v):
GenericNode.__init__(self,inputSize,outputSize,fifoin,fifoout)
def run(self):
print("ProcessingNode");
a=self.getReadBuffer()
b=self.getWriteBuffer()
# Python objects have reference semantic and not
# value semantic.
# So in a write buffer, we can change the
# fields of an object but we should not
# replace the object and risk creating sharing
# Duplicating the a object may be ok
b[0]=a[3]
return(0)
class Source(GenericSource):
def __init__(self,outputSize,fifoout):
GenericSource.__init__(self,outputSize,fifoout)
self._counter=0
def run(self):
print("Source");
a=self.getWriteBuffer()
# Python objects have reference semantic and not
# value semantic.
# So in a write buffer, we can change the
# fields of an object but we should not
# replace the object and risk creating sharing
# Creating a new object may be ok
for i in range(self._outputSize):
#a[i].re = 1.0*self._counter
#a[i].im = 0.0
a[i] = MyComplex(1.0*self._counter, 0.0)
self._counter = self._counter + 1
return(0)

@ -0,0 +1,13 @@
import numpy as np
class MyComplex:
def __init__(self,re=0,im=0):
self.re = re
self.im = im
def __str__(self):
return("%f + I %f" % (self.re, self.im))
def __repr__(self):
return("MyComplex(%f,%f)" % (self.re, self.im))

@ -34,7 +34,15 @@ class ProcessingNode(Node):
### Define nodes
complexType=CStructType("complex","Complex",8)
# Node datatype
# WARNING : In Python there is reference semantic for
# the objects. But in C++, the struct have value semantic.
# So in Python implementation of the node, the reference
# shoudl never be shared.
# Modify the fields of the objects, or create a totally new
# object.
complexType=CStructType("complex","MyComplex",8)
src=Source("source",complexType,5)
b=ProcessingNode("filter",complexType,7,5)
@ -65,15 +73,23 @@ conf.cOptionalArgs="int someVariable"
#conf.prefix="sched1"
#print(g.nullVector())
sched = g.computeSchedule()
sched1 = g.computeSchedule()
#print(sched.schedule)
print("Schedule length = %d" % sched.scheduleLength)
print("Memory usage %d bytes" % sched.memory)
print("Schedule length = %d" % sched1.scheduleLength)
print("Memory usage %d bytes" % sched1.memory)
#
#conf.codeArray=True
sched.ccode("generated",conf)
# C++ implementation
sched1.ccode("generated",conf)
sched2 = g.computeSchedule()
# Python implementation
#conf.prefix="sched1"
conf.pyOptionalArgs="someVariable"
#conf.dumpFIFO=True
sched2.pythoncode(".",config=conf)
with open("test.dot","w") as f:
sched.graphviz(f)
sched1.graphviz(f)

@ -0,0 +1,12 @@
import sched as s
from custom import *
# Only ONE FileSink can be used since the data will be dumped
# into this global buffer for display with Matplotlib
# It will have to be cleaned and reworked in future to use better
# mechanism of communication with the main code
print("Start")
nb,error = s.scheduler("test")
print("Nb sched = %d" % nb)

@ -0,0 +1,180 @@
#
# 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.
#
import sys
import numpy as np
import cmsisdsp as dsp
from cmsisdsp.sdf.nodes.simu import *
from appnodes import *
from custom import *
DEBUGSCHED=False
#
# FIFO buffers
#
FIFOSIZE0=11
buf0=np.empty(FIFOSIZE0,dtype=object)
for i in range(FIFOSIZE0):
buf0[i] = MyComplex()
FIFOSIZE1=5
buf1=np.empty(FIFOSIZE1,dtype=object)
for i in range(FIFOSIZE1):
buf1[i] = MyComplex()
FIFOSIZE2=5
buf2=np.empty(FIFOSIZE2,dtype=object)
for i in range(FIFOSIZE2):
buf2[i] = MyComplex()
FIFOSIZE3=5
buf3=np.empty(FIFOSIZE3,dtype=object)
for i in range(FIFOSIZE3):
buf3[i] = MyComplex()
FIFOSIZE4=5
buf4=np.empty(FIFOSIZE4,dtype=object)
for i in range(FIFOSIZE4):
buf4[i] = MyComplex()
def scheduler(someVariable):
sdfError=0
nbSchedule=0
debugCounter=1
#
# Create FIFOs objects
#
fifo0=FIFO(FIFOSIZE0,buf0)
fifo1=FIFO(FIFOSIZE1,buf1)
fifo2=FIFO(FIFOSIZE2,buf2)
fifo3=FIFO(FIFOSIZE3,buf3)
fifo4=FIFO(FIFOSIZE4,buf4)
#
# Create node objects
#
dup = Duplicate3(5,5,5,5,fifo1,fifo2,fifo3,fifo4)
filter = ProcessingNode(7,5,fifo0,fifo1,4,"Test",someVariable)
sa = Sink(5,fifo2)
sb = Sink(5,fifo3)
sc = Sink(5,fifo4)
source = Source(5,fifo0)
while((sdfError==0) and (debugCounter > 0)):
nbSchedule = nbSchedule + 1
sdfError = source.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = filter.run()
if sdfError < 0:
break
sdfError = dup.run()
if sdfError < 0:
break
sdfError = sc.run()
if sdfError < 0:
break
sdfError = sb.run()
if sdfError < 0:
break
sdfError = sa.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = filter.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = dup.run()
if sdfError < 0:
break
sdfError = sc.run()
if sdfError < 0:
break
sdfError = sb.run()
if sdfError < 0:
break
sdfError = sa.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = filter.run()
if sdfError < 0:
break
sdfError = dup.run()
if sdfError < 0:
break
sdfError = sc.run()
if sdfError < 0:
break
sdfError = sb.run()
if sdfError < 0:
break
sdfError = sa.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = filter.run()
if sdfError < 0:
break
sdfError = source.run()
if sdfError < 0:
break
sdfError = dup.run()
if sdfError < 0:
break
sdfError = sc.run()
if sdfError < 0:
break
sdfError = sb.run()
if sdfError < 0:
break
sdfError = sa.run()
if sdfError < 0:
break
sdfError = filter.run()
if sdfError < 0:
break
sdfError = dup.run()
if sdfError < 0:
break
sdfError = sc.run()
if sdfError < 0:
break
sdfError = sb.run()
if sdfError < 0:
break
sdfError = sa.run()
if sdfError < 0:
break
debugCounter = debugCounter - 1
return(nbSchedule,sdfError)

@ -364,7 +364,7 @@ public:
GenericNode13<IN,inputSize,
IN,inputSize,
IN,inputSize,
IN,inputSize>(src,dst1,dst2,dst2){};
IN,inputSize>(src,dst1,dst2,dst3){};
int run(){
IN *a=this->getReadBuffer();

@ -0,0 +1,56 @@
###########################################
# Project: CMSIS DSP Library
# Title: Duplicate.py
# Description: Duplicate nodes
#
# $Date: 08 September 2022
#
# 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.
############################################
from .simu import *
import cmsisdsp as dsp
class Duplicate2(GenericNode12):
def __init__(self,inputSize,outputSize1,outputSize2,fifoin,fifoout1,fifoout2):
GenericNode12.__init__(self,inputSize,outputSize1,outputSize2,fifoin,fifoout1,fifoout2)
def run(self):
a=self.getReadBuffer()
b=self.getWriteBuffer1()
c=self.getWriteBuffer2()
b[:] = a[:]
c[:] = a[:]
return(0)
class Duplicate3(GenericNode13):
def __init__(self,inputSize,outputSize1,outputSize2,outputSize3,fifoin,fifoout1,fifoout2,fifoout3):
GenericNode13.__init__(self,inputSize,outputSize1,outputSize2,outputSize3,fifoin,fifoout1,fifoout2,fifoout3)
def run(self):
a=self.getReadBuffer()
b=self.getWriteBuffer1()
c=self.getWriteBuffer2()
d=self.getWriteBuffer3()
b[:] = copy.deepcopy(a[:])
c[:] = copy.deepcopy(a[:])
d[:] = copy.deepcopy(a[:])
return(0)

@ -29,6 +29,7 @@
"""
import numpy as np
import copy
class FIFOBase:
pass
@ -43,7 +44,17 @@ class FIFO(FIFOBase):
def getWriteBuffer(self,nb):
if (self._readPos > 0):
self._buffer[:self._writePos-self._readPos] = self._buffer[self._readPos:self._writePos]
# The objects are recycled because contrary to C++
# the objects don't have value semantic but reference
# semantic.
# We want to be sure that we don't create sharing by
# copying references
# So if we have N distincts objects before, we must have
# N distinct object afters (but permuted circularly)
temp = np.empty(self._readPos,dtype=self._buffer.dtype)
temp[:] = self._buffer[:self._readPos]
self._buffer[:-self._readPos] = self._buffer[self._readPos:]
self._buffer[-self._readPos:] = temp[:]
self._writePos = self._writePos - self._readPos
self._readPos = 0
@ -95,6 +106,30 @@ class GenericNode12:
def getReadBuffer(self):
return(self._src.getReadBuffer(self._inputSize))
class GenericNode13:
def __init__(self,inputSize, outputSize1,outputSize2,outputSize3,fifoin,fifoout1,fifoout2,fifoout3):
self._src = fifoin
self._dst1 = fifoout1
self._dst2 = fifoout2
self._dst3 = fifoout3
self._inputSize = inputSize
self._outputSize1 = outputSize1
self._outputSize2 = outputSize2
self._outputSize3 = outputSize3
def getWriteBuffer1(self):
return(self._dst1.getWriteBuffer(self._outputSize1))
def getWriteBuffer2(self):
return(self._dst2.getWriteBuffer(self._outputSize2))
def getWriteBuffer3(self):
return(self._dst3.getWriteBuffer(self._outputSize3))
def getReadBuffer(self):
return(self._src.getReadBuffer(self._inputSize))
class GenericNode21:
def __init__(self,inputSize1,inputSize2, outputSize,fifoin1,fifoin2,fifoout):
self._src1 = fifoin1

@ -31,7 +31,10 @@ DEBUGSCHED=False
{% for id in range(nbFifos) %}
FIFOSIZE{{id}}={{fifos[id].length}}
{{config.prefix}}buf{{id}}=np.zeros(FIFOSIZE{{id}},dtype=np.{{fifos[id].theType.nptype}})
{{config.prefix}}buf{{id}}=np.empty(FIFOSIZE{{id}},dtype={{fifos[id].theType.nptype}})
for i in range(FIFOSIZE{{id}}):
{{config.prefix}}buf{{id}}[i] = {{fifos[id].theType.fillValue}}
{% endfor %}

@ -55,6 +55,11 @@ class SDFType:
def bytes(self):
return(0)
@property
def fillValue(self):
return(0)
class CStructType(SDFType):
"""A C structure
@ -69,6 +74,10 @@ class CStructType(SDFType):
def __eq__(self, other):
return(SDFType.__eq__(self,other) and self._name == other._name)
@property
def fillValue(self):
return("%s()" % self._python_name)
@property
def bytes(self):
return(self._size_in_bytes)
@ -79,7 +88,7 @@ class CStructType(SDFType):
@property
def nptype(self):
return(self._python_name)
return("object")
@property
def graphViztype(self):
@ -151,29 +160,29 @@ class CType(SDFType):
@property
def nptype(self):
if self._id == F64:
return("float64")
return("np.float64")
elif self._id == F32:
return("float32")
return("np.float32")
elif self._id == F16:
return("float16")
return("np.float16")
elif self._id == Q31:
return("int32")
return("np.int32")
elif self._id == Q15:
return("int16")
return("np.int16")
elif self._id == Q7:
return("int8")
return("np.int8")
elif self._id == UINT32:
return("uint32")
return("np.uint32")
elif self._id == UINT16:
return("uint16")
elif self._id == UINT8:
return("uint8")
return("np.uint8")
elif self._id == SINT32:
return("int32")
return("np.int32")
elif self._id == SINT16:
return("int16")
return("np.int16")
elif self._id == SINT8:
return("int8")
return("np.int8")
else:
return("void")

Loading…
Cancel
Save