Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 28
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenEmbeddedC.tpl
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 // This file defines templates for transforming Modelica code to embeddedC
37 // code. They are used in the code generator phase of the compiler to write
38 // target code.
39 //
40 // There are two root templates intended to be called from the code generator:
41 // translateModel and translateFunctions. These templates do not return any
42 // result but instead write the result to files. All other templates return
43 // text and are used by the root templates (most of them indirectly).
44 //
45 // To future maintainers of this file:
46 //
47 // - A line like this
48 // # var = ""
49 // declares a text buffer that you can later append text to. It can also be
50 // passed to other templates that in turn can append text to it. In the new
51 // version of Susan it should be written like this instead:
52 // let &var = buffer ""
53 //
54 // - A line like this
55 // ..., Text var, ...
56 // declares that a template takes a tmext buffer as input parameter. In the
57 // new version of Susan it should be written like this instead:
58 // ..., Text &var, ...
59 //
60 // - A line like this:
61 // ..., var, ...
62 // passes a text buffer to a template. In the new version of Susan it should
63 // be written like this instead:
64 // ..., &var, ...
65 //
66 // - Style guidelines:
67 //
68 // - Try (hard) to limit each row to 80 characters
69 //
70 // - Code for a template should be indented with 2 spaces
71 //
72 // - Exception to this rule is if you have only a single case, then that
73 // single case can be written using no indentation
74 //
75 // This single case can be seen as a clarification of the input to the
76 // template
77 //
78 // - Code after a case should be indented with 2 spaces if not written on the
79 // same line
80
81 package CodegenEmbeddedC
82
83 import interface SimCodeTV;
84 import interface SimCodeBackendTV;
85
86 import CodegenUtil.*;
87 import CodegenUtilSimulation.*;
88 import ExpressionDumpTpl;
89 import DAEDumpTpl;
90
91 ✗ template mainFile(SimCode simCode)
92 ::=
93 let modelNamePrefixStr = modelNamePrefix(simCode)
94 match simCode
95 case simCode as SIMCODE(simulationSettingsOpt=NONE()) then
96 error(sourceInfo(), "Missing simulation settings")
97 case simCode as SIMCODE(modelInfo=MODELINFO(functions=functions, varInfo=varInfo as VARINFO(__), vars=vars as SIMVARS(__)),
98 extObjInfo=extObjInfo as EXTOBJINFO(vars=extObjVars),
99 simulationSettingsOpt=SOME(settings as SIMULATION_SETTINGS(__))) then
100 <<
101 #define fmi2TypesPlatform_h
102
103 #define fmi2TypesPlatform "default" /* Compatible */
104
105 typedef struct <%symbolName(modelNamePrefixStr,"fmi2Component_s")%>* fmi2Component;
106 typedef void* fmi2ComponentEnvironment; /* Pointer to FMU environment */
107 typedef void* fmi2FMUstate; /* Pointer to internal FMU state */
108 typedef unsigned int fmi2ValueReference;
109 typedef double fmi2Real;
110 typedef int fmi2Integer;
111 typedef int fmi2Boolean;
112 typedef char fmi2Char;
113 typedef const fmi2Char* fmi2String;
114 typedef char fmi2Byte;
115
116 #define fmi2True 1
117 #define fmi2False 0
118
119 #include "fmi2/fmi2Functions.h"
120
121 #include <stdint.h>
122 #include <stdio.h>
123
124 void ModelicaFormatMessage(const char *fmt, ...)
125 {
126 va_list args;
127 va_start(args, fmt);
128 vprintf(fmt, args);
129 va_end(args);
130 }
131
132 typedef struct <%symbolName(modelNamePrefixStr,"fmi2Component_s")%> {
133 fmi2Real currentTime;
134 <% match nVariablesReal(varInfo)
135 case 0 then ""
136 case n then 'fmi2Real fmi2RealVars[<%n%>];<%\n%>'
137 %><% match varInfo.numIntAlgVars
138 case 0 then ""
139 case n then 'fmi2Integer fmi2IntegerVars[<%n%>];<%\n%>'
140 %><% match varInfo.numBoolAlgVars
141 case 0 then ""
142 case n then 'fmi2Boolean fmi2BooleanVars[<%n%>];<%\n%>'
143 %><% match varInfo.numStringAlgVars
144 case 0 then ""
145 else error(sourceInfo(), "String variables not supported yet")
146 %><% match varInfo.numParams
147 case 0 then ""
148 case n then 'fmi2Real fmi2RealParameter[<%n%>];<%\n%>'
149 %><% match varInfo.numIntParams
150 case 0 then ""
151 case n then 'fmi2Integer fmi2IntegerParameter[<%n%>];<%\n%>'
152 %><% match varInfo.numBoolParams
153 case 0 then ""
154 case n then 'fmi2Boolean fmi2BooleanParameter[<%n%>];<%\n%>'
155 %><% match varInfo.numIntParams
156 case 0 then ""
157 case n then 'fmi2String fmi2StringParameter[<%n%>];<%\n%>'
158 %><% match listLength(extObjVars)
159 case 0 then ""
160 case n then 'void* extObjs[<%n%>];<%\n%>'
161 %>
162 } <%symbolName(modelNamePrefixStr,"fmi2Component")%>;
163
164 <%symbolName(modelNamePrefixStr,"fmi2Component")%> <%symbolName(modelNamePrefixStr,"component")%> = {
165 <% match nVariablesReal(varInfo)
166 case 0 then ""
167 else
168 <<
169 .fmi2RealVars = {
170 <%vars.stateVars |> var => startValue(var) %>
171 <%vars.derivativeVars |> var => startValue(var) %>
172 <%vars.algVars |> var => startValue(var) %>
173 <%vars.discreteAlgVars |> var => startValue(var) %>
174 <%vars.realOptimizeConstraintsVars |> var => startValue(var) %>
175 <%vars.realOptimizeFinalConstraintsVars |> var => startValue(var) %>
176 },<%\n%>
177 >>
178 %><% match varInfo.numIntAlgVars
179 case 0 then ""
180 else
181 <<
182 .fmi2IntegerVars = {
183 <%vars.intAlgVars |> var => startValue(var) %>
184 },<%\n%>
185 >>
186 %><% match varInfo.numBoolAlgVars
187 case 0 then ""
188 else
189 <<
190 .fmi2BooleanVars = {
191 <%vars.boolAlgVars |> var => startValue(var) %>
192 },<%\n%>
193 >>
194 %><% match varInfo.numStringAlgVars
195 case 0 then ""
196 else
197 <<
198 .fmi2StringVars = {
199 <%vars.stringAlgVars |> var => startValue(var) %>
200 },<%\n%>
201 >>
202 %><% match varInfo.numParams
203 case 0 then ""
204 else
205 <<
206 .fmi2RealParameter = {
207 <%vars.paramVars |> var => startValue(var) %>
208 },<%\n%>
209 >>
210 %><% match varInfo.numIntParams
211 case 0 then ""
212 else
213 <<
214 .fmi2IntegerParameter = {
215 <%vars.intParamVars |> var => startValue(var) %>
216 },<%\n%>
217 >>
218 %><% match varInfo.numBoolParams
219 case 0 then ""
220 else
221 <<
222 .fmi2BooleanParameter = {
223 <%vars.boolParamVars |> var => startValue(var) %>
224 },<%\n%>
225 >>
226 %><% match varInfo.numStringParamVars
227 case 0 then ""
228 else
229 <<
230 .fmi2StringParameter = {
231 <%vars.stringParamVars |> var => startValue(var) %>
232 },<%\n%>
233 >>
234 %>
235 };
236
237 #include <math.h>
238 /* TODO: Generate used builtin functions before SimCode */
239 static inline double om_mod(double x, double y)
240 {
241 return x-floor(x/y)*y;
242 }
243
244 <%functionsFile(functions, literals, externalFunctionIncludes)%>
245
246 fmi2Component <%symbolName(modelNamePrefixStr,"fmi2Instantiate")%>(fmi2String name, fmi2Type ty, fmi2String GUID, fmi2String resources, const fmi2CallbackFunctions* functions, fmi2Boolean visible, fmi2Boolean loggingOn)
247 {
248 static int initDone=0;
249 if (initDone) {
250 return NULL;
251 }
252 return &<%symbolName(modelNamePrefixStr,"component")%>;
253 }
254
255 fmi2Status <%symbolName(modelNamePrefixStr,"fmi2SetupExperiment")%>(fmi2Component comp, fmi2Boolean toleranceDefined, fmi2Real tolerance, fmi2Real startTime, fmi2Boolean stopTimeDefined, fmi2Real stopTime)
256 {
257 return fmi2OK;
258 }
259
260 fmi2Status <%symbolName(modelNamePrefixStr,"fmi2EnterInitializationMode")%>(fmi2Component comp)
261 {
262 <%callExternalObjectConstructors(extObjInfo)%>
263 return fmi2OK;
264 }
265
266 fmi2Status <%symbolName(modelNamePrefixStr,"fmi2ExitInitializationMode")%>(fmi2Component comp)
267 {
268 return fmi2OK;
269 }
270
271 static fmi2Status <%symbolName(modelNamePrefixStr,"functionODE")%>(fmi2Component comp)
272 {
273 <% match odeEquations
274 case {} then ""
275 case {eqs} then (eqs |> eq => equation_(eq); separator="\n")
276 else error(sourceInfo(), "TODO") // List.flatten(odeEquations) |> eq => equation_(eq); separator="\n"
277 %>
278 }
279
280 static fmi2Status <%symbolName(modelNamePrefixStr,"functionOutputs")%>(fmi2Component comp)
281 {
282 <% match allEquations
283 case {} then ""
284 case {eqs} then (eqs |> eq => equation_(eq); separator="\n")
285 else (allEquations |> eqs => (eqs |> eq => equation_(eq); separator="\n"); separator="\n")
286 %>
287 }
288
289 fmi2Status <%symbolName(modelNamePrefixStr,"fmi2DoStep")%>(fmi2Component comp, fmi2Real currentCommunicationPoint, fmi2Real communicationStepSize, fmi2Boolean noSetFMUStatePriorToCurrentPoint)
290 {
291 comp->currentTime = currentCommunicationPoint;
292 <%match varInfo.numStateVars
293 case 0 then ""
294 else
295 <<
296 int i=0;
297 for (i=0; i<<%varInfo.numStateVars%>; i++) {
298 comp->fmi2RealVars[i] += comp->fmi2RealVars[i+<%varInfo.numStateVars%>]*communicationStepSize;
299 }
300 >>
301 %>
302 /* TODO: Calculate time/state-dependent variables here... */
303 <%symbolName(modelNamePrefixStr,"functionOutputs")%>(comp);
304 return fmi2OK;
305 }
306
307 int main(int argc, char **argv)
308 {
309 int terminateSimulation = 0;
310 fmi2Status status = fmi2OK;
311 fmi2CallbackFunctions cbf = {
312 .logger = NULL,
313 .allocateMemory = NULL /*calloc*/,
314 .freeMemory = NULL /*free*/,
315 .stepFinished = NULL, //synchronous execution
316 .componentEnvironment = NULL
317 };
318
319 fmi2Component comp = <%symbolName(modelNamePrefixStr,"fmi2Instantiate")%>("", fmi2CoSimulation, "", "", &cbf, fmi2False, fmi2False);
320 if (comp==NULL) {
321 return 1;
322 }
323 <%symbolName(modelNamePrefixStr,"fmi2SetupExperiment")%>(comp, fmi2False, 0.0, <%settings.startTime%>, fmi2False, <%settings.stopTime%>);
324 <%symbolName(modelNamePrefixStr,"fmi2EnterInitializationMode")%>(comp);
325 // Set start-values? Nah...
326 <%symbolName(modelNamePrefixStr,"fmi2ExitInitializationMode")%>(comp);
327
328 double currentTime = <%settings.startTime%>;
329 double h = <%settings.stepSize%>;
330 uint32_t i = 0;
331
332 while (status == fmi2OK) {
333 //retrieve outputs
334 // fmi2GetReal(m, ..., 1, &y1);
335 //set inputs
336 // fmi2SetReal(m, ..., 1, &y2);
337
338 //call slave and check status
339 status = <%symbolName(modelNamePrefixStr,"fmi2DoStep")%>(comp, currentTime, h, fmi2True);
340 switch (status) {
341 case fmi2Discard:
342 case fmi2Error:
343 case fmi2Fatal:
344 case fmi2Pending /* Cannot happen */:
345 terminateSimulation = 1;
346 break;
347 case fmi2OK:
348 case fmi2Warning:
349 break;
350 }
351 if (terminateSimulation) {
352 break;
353 }
354 i++;
355 /* increment master time */
356 currentTime = <%settings.startTime%> + h*i;
357 }
358
359 #if 0
360 if ((status != fmi2Error) && (status != fmi2Fatal)) {
361 fmi2Terminate(m);
362 }
363 if (status != fmi2Fatal) {
364 fmi2FreeInstance(m);
365 }
366 #endif
367 }
368
369 >>
370 end mainFile;
371
372 ✗ template equation_(SimEqSystem eq)
373 ::=
374 match eq
375 case SES_SIMPLE_ASSIGN(__) then
376 <<
377 <%cref(cref)%> = <%daeExp(exp)%>; /* equation <%index%> */
378 >>
379 case SES_ALGORITHM(__) then
380 (statements |> stmt => statement(stmt) ; separator="\n")
381 else error(sourceInfo(), 'Unsupported equation: ...')
382 end equation_;
383
384 ✗ template statement(DAE.Statement stmt)
385 ::=
386 match stmt
387 case STMT_ASSIGN(type_=T_ARRAY(__))
388 then error(sourceInfo(), "Array assignments are not supported")
389 case STMT_ASSIGN(exp1=CREF(componentRef=cr))
390 then '<%cref(cr)%> = <%daeExp(exp)%>;'
391 case STMT_NORETCALL(__)
392 then '<%daeExp(exp)%>;'
393 case STMT_IF(__) then
394 <<
395 if (<%daeExp(exp)%>) {
396 <%statementLst |> stmt => statement(stmt) ; separator="\n"%>
397 }<%elseStatement(else_)%>
398 >>
399 else error(sourceInfo(), 'Unsupported statement: <%DAEDumpTpl.dumpStatement(stmt)%>')
400 end statement;
401
402 ✗ template elseStatement(Else else_)
403 ::=
404 match else_
405 case NOELSE(__) then ""
406 case ELSEIF(__) then
407 <<
408 else if (<%daeExp(exp)%>) {
409 <%statementLst |> stmt => statement(stmt) ; separator="\n"%>
410 }<%elseStatement(else_)%>
411 >>
412 case ELSE(__) then
413 <<
414 else {
415 <%statementLst |> stmt => statement(stmt) ; separator="\n"%>
416 }
417 >>
418 end elseStatement;
419
420 ✗ template cref(ComponentRef cr)
421 "Generates C equivalent name for component reference.
422 used in Compiler/Template/CodegenFMU.tpl"
423 ::=
424 match cr
425 case CREF_IDENT(ident = "time") then "comp->currentTime"
426 case WILD(__) then ''
427 else crefToCStr(cr, 0, false)
428 end cref;
429
430 ✗ template crefLocal(ComponentRef cr)
431 "Generates C equivalent name for component reference.
432 used in Compiler/Template/CodegenFMU.tpl"
433 ::=
434 match cr
435 case CREF_IDENT(__) then "om_"+ident
436 else error(sourceInfo(), "Only CREF_IDENT as local identifiers (for now)")
437 end crefLocal;
438
439 ✗ template crefToCStr(ComponentRef cr, Integer ix, Boolean isPre)
440 "Helper function to cref."
441 ::=
442 match cr
443 case CREF_QUAL(ident="$PRE", subscriptLst={}) then
444 (if isPre then error(sourceInfo(), 'Got $PRE for something that is already pre: <%CodegenUtil.crefStr(cr)%>')
445 else crefToCStr(componentRef, ix, true))
446 else match cref2simvar(cr, getSimCode())
447 case var as SIMVAR(index=-1) then error(sourceInfo(), 'crefToCStr got index=-1 for <%variabilityString(varKind)%> <%CodegenUtil.crefStr(name)%>')
448 case var as SIMVAR(__) then '<%varArrayNameValues(var, ix, isPre)%>[<%index%>] /* <%Util.escapeModelicaStringToCString(CodegenUtil.crefStr(name))%> <%variabilityString(varKind)%> */'
449 else "CREF_NOT_IDENT_OR_QUAL"
450 end crefToCStr;
451
452 ✗ template crefShortType(ComponentRef cr) "template crefType
453 Like cref but with cast if type is integer."
454 ::=
455 match cr
456 case CREF_IDENT(__) then expTypeShort(identType)
457 case CREF_QUAL(__) then crefShortType(componentRef)
458 else "crefType:ERROR"
459 end match
460 end crefShortType;
461
462 ✗ template expTypeShort(DAE.Type type)
463 "Generate type helper."
464 ::=
465 match type
466 case T_INTEGER(__) then "fmi2Integer"
467 case T_REAL(__) then "fmi2Real"
468 case T_STRING(__) then "fmi2String"
469 case T_BOOL(__) then "fmi2Boolean"
470 case T_ENUMERATION(__) then "fmi2Integer"
471 case T_SUBTYPE_BASIC(__) then expTypeShort(complexType)
472 case T_ARRAY(__) then expTypeShort(ty)
473 case T_COMPLEX(complexClassType=EXTERNAL_OBJ(__)) then "void*"
474 else error(sourceInfo(),'expTypeShort: <%unparseType(type)%>')
475 end expTypeShort;
476
477 ✗ template daeExp(Exp exp)
478 ::=
479 match exp
480 case ICONST(__) then integer
481 case RCONST(__) then real
482 case SCONST(__) then '"<%Util.escapeModelicaStringToCString(string)%>"'
483 case BCONST(__) then (if bool then "fmi2True" else "fmi2False")
484 case ENUM_LITERAL(__) then index
485 case LUNARY(operator=NOT(__)) then '!(<%daeExp(exp)%>)'
486 case UNARY(operator=UMINUS(__)) then '-(<%daeExp(exp)%>)'
487 case BINARY(__) then daeExpBinary(exp1,operator,exp2,exp)
488 case RELATION(__) then daeExpBinary(exp1,operator,exp2,exp)
489 case IFEXP(__) then '(<%daeExp(expCond)%>) ? (<%daeExp(expThen)%>) : (<%daeExp(expElse)%>)'
490 case CALL(attr=CALL_ATTR(builtin=true)) then daeExpCallBuiltin(exp)
491 case CALL(__) then daeExpCall(exp)
492 case CREF(ty=T_ARRAY(__)) then error(sourceInfo(), 'CREF array... <%ExpressionDumpTpl.dumpExp(exp,"\"")%>')
493 case CREF(__) then cref(componentRef)
494 case CAST(ty=T_REAL(__), exp=e) then daeExp(e)
495 else error(sourceInfo(), 'daeExp: Not supporting <%ExpressionDumpTpl.dumpExp(exp,"\"")%>')
496 end daeExp;
497
498 ✗ template daeExpBinary(Exp exp1, Operator op, Exp exp2, Exp origExp)
499 ::=
500 match op
501 case ADD(__) then '(<%daeExp(exp1)%>)+(<%daeExp(exp2)%>)'
502 case SUB(__) then '(<%daeExp(exp1)%>)-(<%daeExp(exp2)%>)'
503 case MUL(__) then '(<%daeExp(exp1)%>)*(<%daeExp(exp2)%>)'
504 case DIV(__) then '(<%daeExp(exp1)%>)/(<%daeExp(exp2)%>)' // TODO: some division by zero handling will be needed
505 case POW(__) then 'pow((<%daeExp(exp1)%>),(<%daeExp(exp2)%>))' // TODO: check sqrt of < 0
506
507 case GREATER(__) then '(<%daeExp(exp1)%>)>(<%daeExp(exp2)%>)'
508 case GREATEREQ(__) then '(<%daeExp(exp1)%>)>=(<%daeExp(exp2)%>)'
509 case LESS(__) then '(<%daeExp(exp1)%>)<(<%daeExp(exp2)%>)'
510
511 case EQUAL(__) then '(<%daeExp(exp1)%>)==(<%daeExp(exp2)%>)'
512 case NEQUAL(__) then '(<%daeExp(exp1)%>)!=(<%daeExp(exp2)%>)'
513
514 else error(sourceInfo(), 'daeExpBinary: Not supporting operator? <%ExpressionDumpTpl.dumpExp(origExp,"\"")%>')
515 end daeExpBinary;
516
517 ✗ template daeExpCallBuiltin(Exp exp)
518 ::=
519 match exp
520 case CALL(path=IDENT(name="DIVISION"),expLst=exp1::exp2::_) then '(<%daeExp(exp1)%>)/(<%daeExp(exp2)%>)'
521 case CALL(path=IDENT(name="smooth"),expLst={exp1,exp2}) then daeExp(exp2)
522 case CALL(path=IDENT(name="integer"),expLst=exp1::_) then '((int)<%daeExp(exp1)%>)'
523 case CALL(path=IDENT(name="abs"),expLst={exp1}) then 'fabs(<%daeExp(exp1)%>)'
524 case CALL(path=IDENT(name="min"),expLst={exp1,exp2},attr=CALL_ATTR(ty=T_REAL(__))) then 'fmin(<%daeExp(exp1)%>,<%daeExp(exp2)%>)'
525 case CALL(path=IDENT(name="max"),expLst={exp1,exp2},attr=CALL_ATTR(ty=T_REAL(__))) then 'fmax(<%daeExp(exp1)%>,<%daeExp(exp2)%>)'
526 case CALL(path=IDENT(name=name as "sin"),expLst={exp1})
527 case CALL(path=IDENT(name=name as "cos"),expLst={exp1})
528 case CALL(path=IDENT(name=name as "tan"),expLst={exp1})
529 case CALL(path=IDENT(name=name as "asin"),expLst={exp1})
530 case CALL(path=IDENT(name=name as "acos"),expLst={exp1})
531 case CALL(path=IDENT(name=name as "atan"),expLst={exp1})
532 case CALL(path=IDENT(name=name as "sinh"),expLst={exp1})
533 case CALL(path=IDENT(name=name as "cosh"),expLst={exp1})
534 case CALL(path=IDENT(name=name as "tanh"),expLst={exp1})
535 case CALL(path=IDENT(name=name as "exp"),expLst={exp1})
536 case CALL(path=IDENT(name=name as "log"),expLst={exp1})
537 case CALL(path=IDENT(name=name as "log10"),expLst={exp1})
538 then '<%name%>(<%daeExp(exp1)%>)'
539 case CALL(path=IDENT(name=name as "atan2"),expLst={exp1,exp2})
540 then '<%name%>(<%daeExp(exp1)%>,<%daeExp(exp2)%>)'
541 /* TODO: Generate used builtin functions before SimCode */
542 case CALL(path=IDENT(name="mod"),expLst=exp1::exp2::_) then 'om_mod(<%daeExp(exp1)%>,<%daeExp(exp2)%>)'
543 /* no events for foor and ceil */
544 case CALL(path=IDENT(name="floor"),expLst=exp1::exp2::_) then 'floor(<%daeExp(exp1)%>)'
545 case CALL(path=IDENT(name="ceil"),expLst=exp1::exp2::_) then 'ceil(<%daeExp(exp1)%>)'
546
547 /* TODO: pre needs to be handled in a special way */
548 case CALL(path=IDENT(name="pre"),expLst={exp1}) then daeExp(exp1)
549 case CALL(__) then error(sourceInfo(), 'daeExpCallBuiltin: Not supported: <%ExpressionDumpTpl.dumpExp(exp,"\"")%>')
550 end daeExpCallBuiltin;
551
552 ✗ template daeExpCall(Exp exp)
553 ::=
554 match exp
555 case CALL(path=path, attr=CALL_ATTR(__)) then '<%underscorePath(path)%>(comp<%expLst |> e => ', <%daeExp(e)%>'%>)'
556 case CALL(__) then error(sourceInfo(), 'daeExpCall: Not supported: <%ExpressionDumpTpl.dumpExp(exp,"\"")%>')
557 end daeExpCall;
558
559 ✗ template varArrayNameValues(SimVar var, Integer ix, Boolean isPre)
560 ::=
561 match ix case 0 then
562 (match var
563 case SIMVAR(varKind=PARAM())
564 case SIMVAR(varKind=OPT_TGRID())
565 then 'comp-><%crefShortType(name)%>Parameter'
566 case SIMVAR(varKind=EXTOBJ()) then 'comp->extObjs'
567 case SIMVAR(__) then 'comp<%if isPre then "XXXPreVars???" else ''%>-><%crefShortType(name)%>Vars<%if isPre then "Pre"%>')
568 else error(sourceInfo(), "varArrayNameValues ix>0")
569 end varArrayNameValues;
570
571 ✗ template constVal(Exp value, Type ty_)
572 "Returns initial value of ScalarVariable."
573 ::=
574 match value
575 case ICONST(__) then integer
576 case RCONST(__) then real
577 case SCONST(__) then '"<%Util.escapeModelicaStringToCString(string)%>"'
578 case BCONST(__) then (if bool then "fmi2True" else "fmi2False")
579 case ENUM_LITERAL(__) then index
580 else (match ty_
581 case T_REAL(__) then "0.0"
582 else error(sourceInfo(), 'No start value for variable... <%ExpressionDumpTpl.dumpExp(value,"\"")%>')
583 )
584 end constVal;
585
586 ✗ template startValue(SimVar var)
587 ::=
588 match var
589 case SIMVAR(initialValue=SOME(e), type_=ty) then '<%constVal(e,ty)%> /*<%CodegenUtil.crefStr(name)%>*/,<%\n%>'
590 case SIMVAR(type_=T_REAL(__)) then '0.0 /*<%CodegenUtil.crefStr(name)%>*/,<%\n%>'
591 case SIMVAR(type_=T_INTEGER(__)) then '0 /*<%CodegenUtil.crefStr(name)%>*/,<%\n%>'
592 case SIMVAR(type_=T_BOOL(__)) then 'fmi2False /*<%CodegenUtil.crefStr(name)%>*/,<%\n%>'
593 case SIMVAR(type_=T_STRING(__)) then '"" /*<%CodegenUtil.crefStr(name)%>*/,<%\n%>'
594 case SIMVAR(__) then error(sourceInfo(), 'No start value for variable <%CodegenUtil.crefStr(name)%>.')
595 end startValue;
596
597 ✗ template functionsFile(list<SimCodeFunction.Function> functions,
598 list<Exp> literals,
599 list<String> externalFunctionIncludes)
600 "Generates the contents of the main C file for the function case."
601 ::=
602 <<
603 <% /* Note: The literals may not be part of the header due to separate compilation */
604 literals |> literal hasindex i0 fromindex 0 => literalExpConst(literal,i0) ; separator="\n";empty
605 %>
606 <%externalFunctionIncludes |> inc => inc; separator="\n"%>
607
608 <%functions |> func => functionDeclaration(func) ; separator="\n" %>
609
610 <%functions |> func => functionBody(func) ; separator="\n" %>
611 >>
612 end functionsFile;
613
614 ✗ template functionBody(SimCodeFunction.Function fn)
615 "Generates the body for a function."
616 ::=
617 match fn
618 case fn as FUNCTION(__) then functionBodyRegularFunction(fn)
619 case fn as EXTERNAL_FUNCTION(__) then functionBodyExternalFunction(fn)
620 case fn as RECORD_CONSTRUCTOR(__) then error(sourceInfo(), "No records in embedded C yet") // functionBodyRecordConstructor(fn)
621 case fn as KERNEL_FUNCTION(__) then error(sourceInfo(), "No kernel functions in embedded C")
622 end functionBody;
623
624 ✗ template functionDeclaration(SimCodeFunction.Function fn)
625 "Generates the body for a function."
626 ::=
627 match fn
628 case fn as FUNCTION(__) then functionPrototype(underscorePath(name), functionArguments, outVars)+";"
629 case fn as EXTERNAL_FUNCTION(__) then "static inline "+functionPrototype(underscorePath(name), funArgs, outVars)+";"
630 case fn as RECORD_CONSTRUCTOR(__) then error(sourceInfo(), "No records in embedded C yet") // functionBodyRecordConstructor(fn)
631 case fn as KERNEL_FUNCTION(__) then error(sourceInfo(), "No kernel functions in embedded C")
632 end functionDeclaration;
633
634 ✗ template functionBodyRegularFunction(SimCodeFunction.Function fn)
635 "Generates the body for a function."
636 ::=
637 match fn
638 case fn as FUNCTION(__) then
639 let fname = underscorePath(name)
640 let prototype = functionPrototype(fname, functionArguments, outVars)
641 let bodyPart = body |> stmt => statement(stmt) ; separator="\n"
642
643 <<
644 <%prototype%>
645 {
646 <% /* No tail recursion in MISRA C? */ /* _tailrecursive: OMC_LABEL_UNUSED */%>
647 <% /* varInits */ %>
648 <%bodyPart%>
649 <% /* _return: OMC_LABEL_UNUSED */ /* No return label; avoid setjmp/longjmp in embedded C */ %>
650 <% /* outVarAssign */ %>
651 <% /* freeConstructedExternalObjects */ %>
652 <%match outVars
653 case v::_ then 'return <%varName(v)%>;'
654 else ""
655 %>
656 }
657 >>
658 end functionBodyRegularFunction;
659
660 ✗ template functionBodyExternalFunction(SimCodeFunction.Function fn)
661 "Generates the body for a function."
662 ::=
663 match fn
664 case fn as EXTERNAL_FUNCTION(language="C") then
665 let fname = underscorePath(name)
666 let prototype = functionPrototype(fname, funArgs, outVars)
667 let args = (extArgs |> arg => extArg(arg) ;separator=", ")
668 let varDecl = (outVars |> arg => '<%varType(arg)%> <%varName(arg)%>;' ;separator="\n")
669 let returnAssign = match extReturn case SIMEXTARG(cref=c) then '<%crefLocal(c)%> = '
670 let returnStatement = (match outVars
671 case {} then ""
672 case VARIABLE(name=cref)::_ then 'return <%crefLocal(cref)%>;'
673 else error(sourceInfo(), "Not variable return"))
674 let varAssign = if outVars then
675 (listRest(outVars) |> var => '*out<%varName(var)%> = <%varName(var)%>;')
676 <<
677 static inline <%prototype%>
678 {
679 <%varDecl%>
680 <%returnAssign%><%extName%>(<%args%>);
681 <%varAssign%>
682 <%returnStatement%>
683 }
684 >>
685 else error(sourceInfo(), "Unknown external language")
686 end functionBodyExternalFunction;
687
688 ✗ template extArg(SimExtArg extArg)
689 ::=
690 match extArg
691 case SIMEXTARG(isInput=true, isArray=false) then crefLocal(cref)
692 case SIMEXTARGEXP(type_=T_REAL())
693 case SIMEXTARGEXP(type_=T_INTEGER())
694 case SIMEXTARGEXP(type_=T_STRING())
695 case SIMEXTARGEXP(type_=T_BOOL()) then daeExp(exp)
696 else error(sourceInfo(), "Unknown extArg")
697 end extArg;
698
699 ✗ template functionPrototype(Text fname, list<Variable> fargs, list<Variable> outVars)
700 ::=
701 let fargsStr = (fargs |> var => ', <%varType(var)%> <%varName(var)%>')
702 let outarg = (match outVars
703 case var::_ then (match var
704 case VARIABLE(__) then varType(var)
705 else error(sourceInfo(), "modelica_fnptr"))
706 else "void")
707 let outargs = if outVars then (listRest(outVars) |> var => ', <%varType(var)%> *out<%varName(var)%>')
708 '<%outarg%> <%fname%>(fmi2Component comp<%fargsStr%><%outargs%>)'
709 end functionPrototype;
710
711 ✗ template varName(Variable var)
712 ::=
713 match var
714 case VARIABLE(__) then crefLocal(name)
715 else error(sourceInfo(), "Not VARIABLE(__)")
716 end varName;
717
718 ✗ template varType(Variable var)
719 ::=
720 match var
721 case VARIABLE(__) then expTypeShort(ty)
722 else error(sourceInfo(), "Not VARIABLE(__)")
723 end varType;
724
725 ✗ template literalExpConst(Exp e, Integer i0)
726 ::=
727 match e
728 case SCONST(__) then 'static const char * const OMCLIT<%i0%> = "<%Util.escapeModelicaStringToCString(string)%>";'
729 else error(sourceInfo(), 'Literal expression: <%ExpressionDumpTpl.dumpExp(e,"\"")%>')
730 end literalExpConst;
731
732 ✗ template callExternalObjectConstructors(ExtObjInfo extObjInfo)
733 "Generates function in simulation file."
734 ::=
735 match extObjInfo
736 case EXTOBJINFO(__) then
737 (vars |> var as SIMVAR(initialValue=SOME(exp)) =>
738 '<%cref(var.name)%> = <%daeExp(exp)%>;'
739 ;separator="\n")
740 end match
741 end callExternalObjectConstructors;
742
743 ✗ template callExternalObjectDestructors(ExtObjInfo extObjInfo)
744 "Generates function in simulation file."
745 ::=
746 match extObjInfo
747 case EXTOBJINFO(__) then
748 (vars |> var as SIMVAR(varKind=ext as EXTOBJ(__)) =>
749 'omc_<%underscorePath(ext.fullClassName)%>_destructor(threadData,<%cref(var.name)%>);'
750 ;separator="\n")
751 end match
752 end callExternalObjectDestructors;
753
754 annotation(__OpenModelica_Interface="codegen");
755 end CodegenEmbeddedC;
756
757 // vim: filetype=susan sw=2 sts=2
758