blob: 94ec3a21a389eea12d0d4c65f0e1c69c1497de32 [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
@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 ("./mapModel")
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()
add_custom_target(model_execution
COMMAND «getProperty(PropertyKeys.PROJECT_NAME
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
IF "%1"=="" (GOTO :help)
::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.
ECHO [proc] Build clean: Removing subdirectories \build, \lib, and \bin
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
)
IF EXIST .\bin (
DEL /f /S /Q .\bin 1>nul
RD /S /Q .\bin
)
)
:: configuring
IF "%doConfigure%"=="1" (
ECHO.
ECHO [proc] Configure all: %configCmd%
%configCmd% )
:: building
IF "%doBuild%"=="1" (
ECHO.
ECHO [proc] Build all: %buildCmd%
%buildCmd% )
GOTO :EOF
:help
ECHO.
ECHO Usage: build [--clean] [--configure] [--build] [--help]
ECHO.
ECHO At least one command option must be passed.
ECHO.
ECHO Options:
ECHO --clean performs build clean
ECHO --configure configures the simulation project
ECHO --build builds the simulation project
ECHO --help shows command help
ECHO.
:EOF
'''
def String getRunScript() '''
«val executableName = super.getProperty(PropertyKeys.PROJECT_NAME
@ECHO OFF
SET runCmd=.\build\«getModulePath()»\Debug\«executableName».exe -t «getSimulationDuration()» -r «getTraceFormats()» -o «getTracePath()»
ECHO [proc] Run simulation: %runCmd%
%runCmd%
'''
private def String getTraceFormats() {
var result = "";
var useDefault = true;
for (TraceType type : TraceType.values()) {
if (Boolean.parseBoolean(super.getProperty(type.toString(), "false"))) {
result += (useDefault ? "" : " ") + type.getName
useDefault = false;
}
}
return useDefault ? TraceType.BTF.getName : result;
}
private def String getSimulationDuration() {
return super.getProperty(PropertyKeys.SIM_DURATION_IN_MS, "1000")
}
private def String getTracePath() {
return Paths.get(super.getProperty(PropertyKeys.TRACE_FOLDER, "./traces")).toString
}
}