blob: dcc298dfc574adeafcf9bbf78758998061684153 [file] [log] [blame]
/**
* *******************************************************************************
* Copyright (c) 2019-2021 Robert Bosch GmbH.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
* *******************************************************************************
*/
package org.eclipse.app4mc.amlt2systemc.m2t.transformers
import com.google.inject.Inject
import com.google.inject.Singleton
import org.eclipse.app4mc.amalthea.model.Amalthea
import org.eclipse.app4mc.amalthea.model.util.ModelUtil
import org.eclipse.app4mc.amlt2systemc.m2t.module.BaseTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.module.PropertyKeys
import org.eclipse.app4mc.amlt2systemc.m2t.module.PropertyKeys.TraceType
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.event.EventModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.hw.HwModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.hw.MemoryTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.hw.ProcessingUnitTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.mapping.MappingModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.os.OsModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.stimuli.StimuliModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.transformers.sw.SWModelTransformer
import org.eclipse.app4mc.amlt2systemc.m2t.utils.TuSort
import org.eclipse.app4mc.transformation.util.OutputBuffer
import org.eclipse.app4mc.util.sessionlog.SessionLogger
import java.nio.file.Paths
import org.eclipse.app4mc.transformation.TransformationConstants
@Singleton
class AmaltheaTransformer extends BaseTransformer {
@Inject OutputBuffer outputBuffer
@Inject SWModelTransformer swModelTransformer
@Inject OsModelTransformer osModelTransformer
@Inject MappingModelTransformer mappingModelTransformer
@Inject HwModelTransformer hwModelTransformer
@Inject EventModelTransformer eventModelTransformer
@Inject StimuliModelTransformer stimuliModelTransformer
@Inject ProcessingUnitTransformer processingUnitTransformer
@Inject MemoryTransformer memoryTransformer
@Inject SessionLogger logger;
static def getModulePath() {
return "amaltheaTop"
}
def getModuleName() {
return getModulePath() + "/amalthea"
}
def void transform(Amalthea[] amaltheas) {
if (amaltheas === null || amaltheas.empty) {
logger.error("Input Amalthea model(s) invalid (received null).")
return
}
// make sure all submodels are present in at least one input model
// Note: chose index 0 at will, any list element would do just fine
adjustModel(amaltheas.get(0))
hwModelTransformer.transform(amaltheas.map[it.hwModel])
swModelTransformer.transform(amaltheas.map[it.swModel])
mappingModelTransformer.transform(amaltheas.map[it.mappingModel])
osModelTransformer.transform(amaltheas.map[it.osModel])
eventModelTransformer.transform(amaltheas.map[it.eventModel])
stimuliModelTransformer.transform(amaltheas.map[it.stimuliModel])
outputBuffer.appendTo("INC", getModuleName(), toH())
outputBuffer.appendTo("SRC", getModuleName(), toCpp()) // swModels, hwModels, mappingModels, osModels, eventModels, stimuliModels))
outputBuffer.appendTo("OTHER", getModulePath() + "/CMakeLists.txt", getCMake());
outputBuffer.appendTo("OTHER", "/build.bat", getBuildScript());
outputBuffer.appendTo("OTHER", "/run.bat", getRunScript());
}
private def void adjustModel(Amalthea amalthea) {
// ensure that the following sub models are available
ModelUtil.getOrCreateSwModel(amalthea);
ModelUtil.getOrCreateOsModel(amalthea);
ModelUtil.getOrCreateHwModel(amalthea);
ModelUtil.getOrCreateMappingModel(amalthea);
ModelUtil.getOrCreateEventModel(amalthea);
ModelUtil.getOrCreateStimuliModel(amalthea);
}
private def String toH() '''
//top level header
'''
private def String toCpp() '''
#include "APP4MCsim.h"
#include "Tracer/TracerFactory.h"
#include "SimParamParser.h"
#include "«getModuleName()».h"
//include model elements
«FOR obj : TuSort.byModule(hwModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
«FOR obj : TuSort.byModule(swModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
«FOR obj : TuSort.byModule(osModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
«FOR obj : TuSort.byModule(mappingModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
«FOR obj : TuSort.byModule(eventModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
«FOR obj : TuSort.byModule(stimuliModelTransformer.cache.values)»
#include "«obj.module».h"
«ENDFOR»
//include processing units and memories for tracing -----
«FOR tu : processingUnitTransformer.cache.values»
#include "«tu.module».h"
«ENDFOR»
«FOR tu : memoryTransformer.cache.values»
#include "«tu.module».h"
«ENDFOR»
// tracing includes -----------------
INITIALIZE_EASYLOGGINGPP;
int sc_main(int argc, char *argv[]) {
//static code ----------------------
sc_core::sc_set_time_resolution(1.0,sc_core::SC_NS);
//throw error if object already exists, default behavior will rename second object and merely issue a warning (W505)
sc_core::sc_report_handler::set_actions("object already exists",sc_core::SC_THROW);
START_EASYLOGGINGPP(argc, argv);
SimParam params;
SimParamParser::parse(argc, argv, params);
//end static code ------------------
VLOG(0) << "build simulation model";
/* Hardware */
//always initialize hardware model first, as it relies on
//hierarchical top->down construction, cross-references
//from other models' instantiation might interfere with that pattern
«FOR obj : TuSort.byModule(hwModelTransformer.cache.values
«obj.call»;
«ENDFOR»
/* Software */
«FOR obj : TuSort.byModule(swModelTransformer.cache.values
«obj.call»;
«ENDFOR»
/* OS */
«FOR obj : TuSort.byModule(osModelTransformer.cache.values
«obj.call»;
«ENDFOR»
/* Mapping */
«FOR obj : TuSort.byModule(mappingModelTransformer.cache.values
«obj.call»;
«ENDFOR»
/* Event */
«FOR obj : TuSort.byModule(eventModelTransformer.cache.values
«obj.call»;
«ENDFOR»
/* Stimuli */
«FOR obj : TuSort.byModule(stimuliModelTransformer.cache.values
«obj.call»;
«ENDFOR»
VLOG(0) << "simulation model complete";
//static code ----------------------
auto vcdPath = TraceManager::createTraceFilePath("trace").string();
sc_core::sc_trace_file *tf = sc_core::sc_create_vcd_trace_file(vcdPath.c_str());
//trace processing units and memories -----
«FOR tu : processingUnitTransformer.cache.values»
sc_trace(tf, &*«tu.call»(), "«tu.module.replaceAll("/", "_")»");
«ENDFOR»
«FOR tu : memoryTransformer.cache.values»
sc_trace(tf, &*«tu.call»(), "«tu.module.replaceAll("/", "_")»");
«ENDFOR»
//run simulation
try {
VLOG(0) << "starting simulation";
sc_core::sc_start(params.simulationTimeInMs, sc_core::SC_MS);
}
catch (sc_core::sc_report e) {
const char* file = e.get_file_name();
const int line = e.get_line_number();
const char* msg = e.get_msg();
VLOG(0) << msg << "\nin file: " << file << "\nline: " << line;
return -1;
}
sc_core::sc_close_vcd_trace_file(tf);
VLOG(0) << "simulation done ";
return 0;
}
'''
def String getCMake() '''
include_directories(${PROJECT_SOURCE_DIR})
add_executable getProperty(PropertyKeys.PROJECT_NAME
"${PROJECT_SOURCE_DIR}/«getModuleName()».cpp"
)
target_link_librariesgetProperty(PropertyKeys.PROJECT_NAME app4mc.sim_lib)
target_include_directoriesgetProperty(PropertyKeys.PROJECT_NAME PUBLIC app4mc.sim_lib)
add_subdirectory ("./hwModel")
add_subdirectory ("./swModel")
add_subdirectory ("./mappingModel")
add_subdirectory ("./eventModel")
add_subdirectory ("./stimuliModel")
add_subdirectory ("./osModel")
«IF Integer.parseInt(super.getProperty("CmakeUnityBuildTUPerCore","0")) > 0»
# set the unity-batch-size to a Processorcount dependend value, for more efficient compiling
if(COMMAND calc_unity_batch_size)
calc_unity_batch_sizegetProperty(PropertyKeys.PROJECT_NAME «super.getProperty("CmakeUnityBuildTUPerCore")»)
endif()
«ENDIF»
# use /bigobj to ensure big models to build with MSVC (e.g. FMTV WATERS Challenge 2017)
if(MSVC)
add_definitions(/bigobj)
message("Set /bigobj for big object files in MSVC")
endif()
if(MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
message("Set -Wa,-mbig-obj for big object files in MINGW")
endif()
«val simDuration = super.getProperty(PropertyKeys.SIM_DURATION_IN_MS, "1000"
«var tracePath = Paths.get(super.getProperty(PropertyKeys.TRACE_FOLDER, "./traces"))»
add_custom_target(model_execution
COMMAND «getProperty(PropertyKeys.PROJECT_NAME -t «simDuration» -r «getTraceFormatId()» -o «tracePath.toString()»
WORKING_DIRECTORY "${MODEL_WORKING_DIR}"
)
install(
TARGETS «getProperty(PropertyKeys.PROJECT_NAME
RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/bin/examples/
)
'''
def String getBuildScript() '''
@ECHO OFF
SET doClean=0
SET cleanCmd=cmake --build ./build --config Debug --target clean
SET doConfigure=0
SET configCmd=cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -H./ -B./build
SET doBuild=0
SET buildCmd=cmake --build ./build --config Debug --target install
::Loop through command line arguments
:loop
IF NOT "%1"=="" (
If "%1"=="--clean" SET doClean=1
If "%1"=="--configure" SET doConfigure=1
If "%1"=="--build" SET doBuild=1
If "%1"=="--help" GOTO :help
SHIFT
GOTO :loop
)
:: cleaning
IF "%doClean%"=="1" (
ECHO [proc] Build clean: Removing \build and \lib subdirectories
IF EXIST .\build (
DEL /f /S /Q .\build 1>nul
RD /S /Q .\build
)
IF EXIST .\lib (
DEL /f /S /Q .\lib 1>nul
RD /S /Q .\lib
)
)
:: configuring
IF "%doConfigure%"=="1" (
ECHO [proc] Configure all: %configCmd%
%configCmd% )
:: building
IF "%doBuild%"=="1" (
ECHO [proc] Build all: %buildCmd%
%buildCmd% )
GOTO :EOF
:help
ECHO Help: Command line options:
ECHO -c, --clean: run build clean
ECHO --configure: run project configuration
ECHO -h, --help: show command help
:EOF
'''
def String getRunScript() '''
«val simDuration = super.getProperty(PropertyKeys.SIM_DURATION_IN_MS, "1000"
«val executableName = super.getProperty(PropertyKeys.PROJECT_NAME
«var tracePath = Paths.get(super.getProperty(PropertyKeys.TRACE_FOLDER, "./traces"))»
@ECHO OFF
SET runCmd=.\build\«getModulePath()»\Debug\«executableName».exe -t «simDuration» -r «getTraceFormatId()» -o «tracePath.toString()»
ECHO [proc] Run simulation: %runCmd%
%runCmd%
'''
private def String getTraceFormatId() {
val traceType = super.getProperty(PropertyKeys.TRACE_TYPE, TraceType.BtfTracer.getName)
for (TraceType type : TraceType.values()) {
if (type.getName().equals(traceType)) {
return type.getId()
}
}
return TraceType.BtfTracer.id
}
}