blob: fcaf471e3245962b123e13f9684226ededb25311 [file] [log] [blame]
package templates
import com.inchron.realtime.root.model.CallSequenceItem
import com.inchron.realtime.root.model.GenericSystem
import com.inchron.realtime.root.model.SemaphoreAccessType
import com.inchron.realtime.root.model.TimeDistributionType
import com.inchron.realtime.root.model.TimeUnit
import java.util.ArrayList
import java.util.List
import java.util.Set
import org.eclipse.app4mc.amalthea.model.Amalthea
import org.eclipse.app4mc.amalthea.model.AsynchronousServerCall
import org.eclipse.app4mc.amalthea.model.CallGraph
import org.eclipse.app4mc.amalthea.model.CallSequence
import org.eclipse.app4mc.amalthea.model.ChannelReceive
import org.eclipse.app4mc.amalthea.model.ChannelSend
import org.eclipse.app4mc.amalthea.model.CustomEventTrigger
import org.eclipse.app4mc.amalthea.model.ExecutionNeed
import org.eclipse.app4mc.amalthea.model.Group
import org.eclipse.app4mc.amalthea.model.HwFeature
import org.eclipse.app4mc.amalthea.model.ISR
import org.eclipse.app4mc.amalthea.model.InterProcessTrigger
import org.eclipse.app4mc.amalthea.model.LabelAccess
import org.eclipse.app4mc.amalthea.model.ModeLabelAccess
import org.eclipse.app4mc.amalthea.model.ModeSwitch
import org.eclipse.app4mc.amalthea.model.Need
import org.eclipse.app4mc.amalthea.model.NeedConstant
import org.eclipse.app4mc.amalthea.model.NeedDeviation
import org.eclipse.app4mc.amalthea.model.Preemption
import org.eclipse.app4mc.amalthea.model.ProbabilitySwitch
import org.eclipse.app4mc.amalthea.model.Process
import org.eclipse.app4mc.amalthea.model.ProcessingUnit
import org.eclipse.app4mc.amalthea.model.Runnable
import org.eclipse.app4mc.amalthea.model.RunnableCall
import org.eclipse.app4mc.amalthea.model.RunnableModeSwitch
import org.eclipse.app4mc.amalthea.model.RunnableProbabilitySwitch
import org.eclipse.app4mc.amalthea.model.SemaphoreAccess
import org.eclipse.app4mc.amalthea.model.SemaphoreAccessEnum
import org.eclipse.app4mc.amalthea.model.SenderReceiverRead
import org.eclipse.app4mc.amalthea.model.SenderReceiverWrite
import org.eclipse.app4mc.amalthea.model.SynchronousServerCall
import org.eclipse.app4mc.amalthea.model.Task
import org.eclipse.app4mc.amalthea.model.TaskRunnableCall
import org.eclipse.app4mc.amalthea.model.Time
import org.eclipse.app4mc.amalthea.model.util.DeploymentUtil
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType
import org.eclipse.emf.common.util.EMap
import org.eclipse.emf.ecore.util.EcoreUtil
import templates.utils.AmltCacheModel
/**
* This class is responsible to convert Amalthea SW Model eleemnts to corresponding Inchron elements and invoke other transformation classes
*/
public class SWTransformer extends AbstractAmaltheaInchronTransformer {
/**
* Creating a Inchron Process element from Amalthea ISR element
*/
def create inchronModelFactory.createProcess createProcess(ISR amltISR){
it.isr = true
it.name=amltISR.name
/*-Building a cache of Stimuli name and the "List of Process" elements to which it is associated to */
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
amltISR.stimuli.forEach[stimuli |
amltCache.cacheAmltStimuliInchronProcessMap(stimuli.getName, it)
]
}
/**
* Creating a Inchron Process element from Amalthea Task element
*/
def create inchronModelFactory.createProcess createProcess(Task amltTask){
it.isr = false
it.name=amltTask.name
//TODO: schedule between runnables for co-operative
if(amltTask.preemption == Preemption.NON_PREEMPTIVE || amltTask.preemption == Preemption.COOPERATIVE){
it.preemptable=false
}else{
it.preemptable=true
}
if(amltTask.callGraph !=null){
/*-building a inchron CallGraph element from amalthea CallGraph */
it.callGraph=createCallGraph(amltTask.callGraph)
}
/*-Building a cache of Stimuli name and the "List of Process" elements to which it is associated to */
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
amltTask.stimuli.forEach[stimuli |
amltCache.cacheAmltStimuliInchronProcessMap(stimuli.getName, it)
]
}
/**
* This method is used to create a Inchron CallGraph element from Amalthea CallGraph element
*/
def create inchronModelFactory.createCallGraph createCallGraph(CallGraph amltCallGraph){
amltCallGraph.graphEntries.forEach[amltGraphEntry|
if(amltGraphEntry instanceof CallSequence){
it.graphEntries.add(createCallSequence(amltGraphEntry as CallSequence))
}else if(amltGraphEntry instanceof ModeSwitch){
it.graphEntries.add(createModeSwitch(amltGraphEntry as ModeSwitch))
}else if(amltGraphEntry instanceof ProbabilitySwitch){
it.graphEntries.add(createProbabilitySwitch(amltGraphEntry as ProbabilitySwitch))
}
]
}
/**
* This method is used to create inchron CallSequence object from Amalthea CallSequence element.
*
* Below are the CallSequence items are currently supported:
* <br>1.TaskRunnableCall
* <br>2.InterProcessTrigger
*
*/
def create inchronModelFactory.createCallSequence createCallSequence(CallSequence amltCallSequence){
it.name=amltCallSequence.name
amltCallSequence?.calls.forEach[amltCallsequenceItem|
//todo: handle other CallSequenceItem's
if(amltCallsequenceItem instanceof TaskRunnableCall){
it.calls.add(createFunctionCall(amltCallsequenceItem as TaskRunnableCall))
}
if (amltCallsequenceItem instanceof InterProcessTrigger) {
it.calls.add(createActivationItem(amltCallsequenceItem as InterProcessTrigger))
}
]
}
/**
* This method is used to create inchron InterProcessTrigger element from Amalthea ActivationItem element
*/
def create inchronModelFactory.createActivationItem createActivationItem(InterProcessTrigger trigger) {
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
val tasks = amltCache.interProcessTriggerRelationsMap.get(trigger.stimulus.name);
val inchronConnection=amltCache.inchronConnectionElementsMap.get(trigger.stimulus.name)
it.connection =inchronConnection
if(tasks !=null){
for ( task : tasks) {
val inchronActivateProcess=createActivateProcess(trigger, task as Task)
inchronConnection.activations.add(inchronActivateProcess)
}
}else{
//Note: This is the case where Stimulus is not InterProcessStimulus or there are no Process elements to which this stimulus is triggering
}
}
/**
* This method is used to create inchron ActivateProcess element from Amalthea InterProcessTrigger
*/
def create inchronModelFactory.createActivateProcess createActivateProcess(InterProcessTrigger trigger, Task amltTask) {
it.target = createProcess(amltTask);
it.offset = trigger.counter.offset as int
it.period = trigger.counter.prescaler as int
}
def create inchronModelFactory.createModeSwitch createModeSwitch(ModeSwitch amltModeSwitch){
//TODO: need to enhance it in near future
}
def create inchronModelFactory.createProbabilitySwitch createProbabilitySwitch(ProbabilitySwitch amltProbabilitySwitch){
//TODO: need to enhance it in near future
}
/**
* This method is used to create inchron FunctionCall element from RunnableCall element
*/
def create inchronModelFactory.createFunctionCall createFunctionCall(RunnableCall amltRunnableCall){
var amltProcess=amltRunnableCall.getParentContainer(Process)
var inchronComponent=createComponent(amltProcess)
val inchronGenericSystem= getInchronGenericSystem(amltProcess)
if(inchronGenericSystem !=null){
inchronGenericSystem.components.add(inchronComponent)
}
var inchronFunction=createFunction(amltProcess, amltRunnableCall.runnable)
inchronComponent.functions.add(inchronFunction)
it.function=inchronFunction
}
/**
* This method is used to create inchron FunctionCall element from TaskRunnableCall element
*/
def create inchronModelFactory.createFunctionCall createFunctionCall(TaskRunnableCall amltTaskRunnableCall){
var amltProcess=amltTaskRunnableCall.getParentContainer(Process)
var inchronComponent=createComponent(amltProcess)
val inchronGenericSystem= getInchronGenericSystem(amltProcess)
if(inchronGenericSystem !=null){
inchronGenericSystem.components.add(inchronComponent)
}
var inchronFunction=createFunction(amltProcess, amltTaskRunnableCall.runnable)
it.function=inchronFunction
inchronComponent.functions.add(inchronFunction)
it.offset=amltTaskRunnableCall?.counter?.offset.intValue
it.period=amltTaskRunnableCall?.counter?.prescaler.intValue
}
/**
* This method is used to fetch the inchron GenericSystem object for a specific Amalthea Process element
*/
def GenericSystem getInchronGenericSystem(Process amltProcess) {
val Set<ProcessingUnit> cores=DeploymentUtil.getAssignedCoreForProcess(amltProcess as Process, EcoreUtil.getRootContainer(amltProcess) as Amalthea)
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
//TODO: write validaiton to assure that only 1 core is present
//TODO: currently taking 1st core
if(cores.size>0){
//TODO: clarify if this approach is OK !!
val amltCore=cores.get(0)
val amltMicroController=amltCore.eContainer
val inchronGenericSystem=amltCache.mappingAmltMicroController_GenericSystem.get(amltMicroController)
return inchronGenericSystem
}
}
def create inchronModelFactory.createComponent createComponent(Process amltProcess){
it.name=amltProcess.name
}
def create inchronModelFactory.createFunction createFunction(Process amltProcess, Runnable amltRunnable){
it.name=amltRunnable.name
it.callGraph=inchronModelFactory.createCallGraph
val inchronCallSequence=inchronModelFactory.createCallSequence
it.callGraph.graphEntries.add(inchronCallSequence)
amltRunnable?.runnableItems.forEach[amltRunnableItem|
if(amltRunnableItem instanceof AsynchronousServerCall){
}
else if(amltRunnableItem instanceof ChannelReceive){
}
else if(amltRunnableItem instanceof ChannelSend){
}
else if(amltRunnableItem instanceof CustomEventTrigger){
}
else if(amltRunnableItem instanceof Group){
}
else if(amltRunnableItem instanceof LabelAccess){
}
else if(amltRunnableItem instanceof ModeLabelAccess){
}
else if(amltRunnableItem instanceof RunnableCall){
inchronCallSequence.calls.add(createFunctionCall( amltRunnableItem))
}else if(amltRunnableItem instanceof ExecutionNeed){//Earlier it was RunnableInstructions
inchronCallSequence.calls.add(createResourceConsumption(amltProcess, amltRunnableItem))
}
else if(amltRunnableItem instanceof RunnableModeSwitch){
}
else if(amltRunnableItem instanceof RunnableProbabilitySwitch){
}
else if(amltRunnableItem instanceof SemaphoreAccess){
inchronCallSequence.calls.addAll(semaphoreInterruptCreation(amltRunnableItem))
}
else if(amltRunnableItem instanceof SenderReceiverRead){
}
else if(amltRunnableItem instanceof SenderReceiverWrite){
}
else if(amltRunnableItem instanceof SynchronousServerCall){
}
]
}
def create inchronModelFactory.createSemaphoreAccess createSemaphoreAccess(SemaphoreAccess amltAccess) {
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
val amltSemaphoreName=amltAccess?.semaphore?.name
//TODO CREATE THIS THE RIGHT WAY!
var inchronSemaphore = amltCache.getInchronSemaphoreCacheElement(amltSemaphoreName)// = createSemaphore(amltSemaphore);
//SemaphoreAccessType.;
//amltAccess.access;
switch (amltAccess.access) {
case SemaphoreAccessEnum.RELEASE: {
it.type = SemaphoreAccessType.RELEASE
}
case SemaphoreAccessEnum.EXCLUSIVE: {
it.type = SemaphoreAccessType.EXCLUSIVE
}
case SemaphoreAccessEnum.REQUEST : {
it.type = SemaphoreAccessType.REQUEST
}
}
it.semaphore = inchronSemaphore;
}
def List<CallSequenceItem> semaphoreInterruptCreation(SemaphoreAccess amltAccess){
val List<CallSequenceItem> items=new ArrayList
switch (amltAccess.access) {
case SemaphoreAccessEnum.RELEASE: {
items.add(createSemaphoreAccess(amltAccess))
items.add(createResumeAllInterrupts(amltAccess))
}
case SemaphoreAccessEnum.EXCLUSIVE: {
//TODO:check semantics
items.add(createSuspendAllInterrupts(amltAccess))
items.add(createSemaphoreAccess(amltAccess))
}
case SemaphoreAccessEnum.REQUEST : {
items.add(createSuspendAllInterrupts(amltAccess))
items.add(createSemaphoreAccess(amltAccess))
}
}
return items
}
/*
* LL: SemaphoreAccess object should be mandatorily supplied here, as Xtend caches the elements based on input parameters
*/
def create inchronModelFactory.createSuspendAllInterrupts createSuspendAllInterrupts(SemaphoreAccess amltAccess) {
it.offset=0
it.period=0
}
/*
* LL: SemaphoreAccess object should be mandatorily supplied here, as Xtend caches the elements based on input parameters
*/
def create inchronModelFactory.createResumeAllInterrupts createResumeAllInterrupts(SemaphoreAccess amltAccess) {
it.offset=0
it.period=0
}
def create inchronModelFactory.createResourceConsumption createResourceConsumption(Process amltProcess, ExecutionNeed amltRunnableInstructions){
val AmltCacheModel amltCache=customObjsStore.getInstance(AmltCacheModel)
if(amltProcess instanceof Task){
var listOfTaskAllocations=amltCache.tasks_TaskAllocationMap.get(amltProcess as Task)
listOfTaskAllocations?.forEach[amltTaskAllocation|
var amltScheduler=amltTaskAllocation.scheduler
var amltSchedulerAllocation=amltCache.taskScheduler_schedulerAllocationMap.get(amltScheduler)
//TODO: What if affinity is not set and core should be derived from SchedulerMapping?
var List cores1=amltTaskAllocation.affinity
var List cores2 =(amltSchedulerAllocation.responsibility)
//to obtain only common Core objects across both lists
cores1.retainAll(cores2)
//TODO: write assumptions about core mapping of tasks (if it is 1 to 1 mapping ?)
if(cores1.size==1){
var timeDistribution=inchronModelFactory.createTimeDistribution
//TODO: uniform as a starting point --- more complex distributions need to be simulated
timeDistribution.type = TimeDistributionType.UNIFORM
timeDistribution.bcet = getRuntimeForRunnableInstruction(amltRunnableInstructions, TimeType.BCET, cores1.get(0) as ProcessingUnit);
timeDistribution.wcet = getRuntimeForRunnableInstruction(amltRunnableInstructions, TimeType.WCET, cores1.get(0) as ProcessingUnit);
timeDistribution.mean = getRuntimeForRunnableInstruction(amltRunnableInstructions, TimeType.ACET, cores1.get(0) as ProcessingUnit);
it.timeDistribution = timeDistribution
}
]
}
}
//TODO: Check if some of this methods can be part of AMALTHEA
//TODO: set getInstructionCountForInstruction to public in APP4MC UTILS
def com.inchron.realtime.root.model.Time getRuntimeForRunnableInstruction(ExecutionNeed amltRunnableInstructions, TimeType timeType, ProcessingUnit core) {
//TODO: handle extended instructions
var amltInstructions = getInstructionCountForInstruction(amltRunnableInstructions.^default, timeType);
val hwFeatureFromExecutionNeed = getHwFeatureFromExecutionNeed(amltRunnableInstructions,core)
var amltTime = RuntimeUtil.getExecutionTimeForExecutionNeedValueCount(amltInstructions, core, hwFeatureFromExecutionNeed,null);
return getInchronTimeValue(amltTime);
}
def HwFeature getHwFeatureFromExecutionNeed(ExecutionNeed executionNeed, ProcessingUnit processingUnit){
val EMap<String, Need> defaultMap = executionNeed.^default
if(defaultMap.size>0){
val processingUnitDefinition = processingUnit.definition
if(processingUnitDefinition!=null){
for(feature: processingUnitDefinition?.features){
//TODO:At present supporting only HwFeatureCategory with name "Instructions"
if(feature.containingCategory?.name.equals("Instructions")){
return feature
}
}
}
}
return null
}
def Long getInstructionCountForInstruction(EMap<String, Need> defaultMap, TimeType execTimeType) {
for(need: defaultMap.values){
if(need instanceof NeedDeviation) {
var NeedDeviation instDeviation = need as NeedDeviation ;
switch(execTimeType) {
case ACET: {
return RuntimeUtil.getMean(instDeviation.getDeviation().getDistribution(), instDeviation.getDeviation().getLowerBound().getValue(), instDeviation.getDeviation().getUpperBound().getValue())
}
case BCET: {
return instDeviation.getDeviation().getLowerBound().getValue()
}
case WCET: {
return instDeviation.getDeviation().getUpperBound().getValue();
}
default:
return RuntimeUtil.getMean(instDeviation.getDeviation().getDistribution(), instDeviation.getDeviation().getLowerBound().getValue(), instDeviation.getDeviation().getUpperBound().getValue())
}
} else if(need instanceof NeedConstant) {
return (need as NeedConstant).getValue();
}
}
return 0L;
}
def com.inchron.realtime.root.model.Time getInchronTimeValue(Time amltTime) {
var result = inchronModelFactory.createTime
result.value = amltTime.value.longValue;
switch (amltTime.unit.getName) {
case "s": {
result.unit = TimeUnit.S
}
case "ms": {
result.unit = TimeUnit.MS
}
case "us": {
result.unit = TimeUnit.US
}
case "ns": {
result.unit = TimeUnit.NS
}
case "ps": {
result.unit = TimeUnit.PS
}
}
return result;
}
}