CompileDES 3.14
Executable-Code Generation from Synchronised libFAUDES Automata
cgp_atmega.cpp
Go to the documentation of this file.
1
3/*
4 FAU Discrete Event Systems Library (libFAUDES)
5
6 Copyright (C) 2016 Thomas Moor
7
8*/
9
10// my includes
11#include "cgp_atmega.h"
12
13
14/*
15******************************************************************
16******************************************************************
17******************************************************************
18
19ATmegaCodeGenerator implementation --- class mainenance
20
21******************************************************************
22******************************************************************
23******************************************************************
24*/
25
26
27// Register derived class
29
30
31// ATmegaCodeGenerator(void)
33 FD_DCG("atmCodeGenerator(" << this << ")::atmCodeGenerator()");
34}
35
36// ATmegaCodeGenerator(void)
38 FD_DCG("atmCodeGenerator(" << this << ")::~atmCodeGenerator()");
39}
40
41
42// clear
44 FD_DCG("atmCodeGenerator::Clear()");
45 // call base
47 // my flavor of defaults
48 mPrefix="fcg_";
49 mWordType="unsigned char";
50 mWordSize=8;
51 mIntegerType="int";
52 mIntegerSize=16;
53 // my config parameter
54 mATmegaProgmem=false;
55 mATmegaPullups=false;
56}
57
58//DoReadTargetConfiguration(rTr)
60 FD_DCG("atmCodeGenerator::DoReadTargetConfiguration()");
61 // base
63 // avr options
64 Token token;
65 if(rTr.ExistsBegin("ATmegaProgmem")) {
66 rTr.ReadBegin("ATmegaProgmem",token);
67 mATmegaProgmem= token.AttributeIntegerValue("val");
68 rTr.ReadEnd("ATmegaProgmem");
69 }
70 if(rTr.ExistsBegin("ATmegaPullups")) {
71 rTr.ReadBegin("ATmegaPullups",token);
72 mATmegaPullups= token.AttributeIntegerValue("val");
73 rTr.ReadEnd("ATmegaPullups");
74 }
75}
76
77//DoWriteTargetConfiguration(rTw)
79 FD_DCG("atmCodeGenerator::DoWriteTargetConfiguration()");
80 // base
82}
83
84
85/*
86******************************************************************
87******************************************************************
88******************************************************************
89
90atmCodeGenerator implementation --- code organisation
91
92******************************************************************
93******************************************************************
94******************************************************************
95*/
96
97
98// DoCompile()
100 FD_DCG("atmCodeGenerator(" << this << ")::DoCompile()");
101 // call base
103 // fix my code options
106 switch(mIntegerSize) {
107 case 8: mATmegaPgmReadInteger="pgm_read_byte"; break;
108 case 16: mATmegaPgmReadInteger="pgm_read_word"; break;
109 }
110 switch(mWordSize) {
111 case 8: mATmegaPgmReadWord="pgm_read_byte"; break;
112 case 16: mATmegaPgmReadWord="pgm_read_word"; break;
113 }
114 if(mATmegaProgmem) {
116 FCG_VERB0("ATmegaCodeGenerator::DoCompile(): target supports pgmread only for 8bit or 16bit data types --- ignoring option ATmegaProgmen ");
117 }
120 if((mIntegerSize != 8) && (mIntegerSize != 16) && mArrayForTransitions) {
121 FCG_ERR("atmCodeGenerator::DoCompile(): target supports only 8bit or 16bit integers in compiled transition arrays");
122 }
123 // my preferences
125 FCG_VERB1("atmCodeGenerator::DoCompile(): with progmen we prefer bit-address maths over compiled bitmasks");
126 mArrayForBitmasks = false;
127 }
128 // my preferences
130 FCG_VERB1("atmCodeGenerator::DoCompile(): symbol tables not recommended on this target due to memory restrictions");
131 }
132}
133
134// DoGenerate()
136 FD_DCG("atmCodeGenerator(" << this << ")::DoGenerate()");
137 // cut and paste from base
138 mBitarrays.clear();
139 // say hello
140 Comment("************************************************");
141 Comment("CodeGenerator: Target ATmega Microcontroller ");
142 Comment("************************************************");
143 LineFeed(1);
144 Comment(std::string("CompileDES ") + VersionString());
145 Comment(std::string("Configuration: ") + Name());
146 LineFeed(2+1);
147 // snippets
149 // use base class for std semantics
151 LineFeed(2);
152 // use base class for std semantics
153 Output() << "void " << mPrefix <<"cyclic(void) { ";
154 LineFeed();
157 Output() << "}; /* end function " << mPrefix <<"cyclic() */";
158 LineFeed();
159 LineFeed(2+1);
160 // extra from ecCodeGenerator: provide timer decrement interface to host application
162 // extra from atmCodeGenerator: initialise ports
164 // snippets
166 // done
167 Comment("************************************************");
168 Comment("CodeGenerator: Generated Code Ends Here ");
169 Comment("************************************************");
170}
171
172
173// code blocks: initialise ports
175 // figure output pins on ports A,B,C,D,E,F
176 bool outexists= false;
177 std::map<char, std::set< std::string > > outbits;
179 for(;ait!=ActionAddressesEnd();++ait) {
180 // strict syntax check for set/clr actions, otherwise we cannot handle bit operations
181 if(!ait->second.mSetClr) continue;
182 if(ait->second.mAddress.size()!=3) {
183 FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
184 }
185 if(ait->second.mAddress[0]!='P') {
186 FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
187 }
188 char port = ait->second.mAddress[1];
189 if((port < 'A') || (port > 'F')) {
190 FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
191 }
192 int pin = ait->second.mAddress[2] - '0';
193 if((pin < 0) || (pin > 7)) {
194 FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
195 }
196 outbits[port].insert(ait->second.mAddress);
197 outexists= true;
198 }
199 // figure input pins on ports A,B,C,D,E,F
200 bool inpexists= false;
201 std::map<char, std::set< std::string > > inpbits;
203 for(;lit!=LinesEnd();++lit) {
204 // weak syntax check for inputs, interpret as boolean expression if its not a port bit
205 if(lit->second.mAddress.size()!=3) continue;
206 if(lit->second.mAddress[0]!='P') continue;
207 char port = lit->second.mAddress[1];
208 if((port < 'A') || (port > 'F')) continue;
209 int pin = lit->second.mAddress[2] - '0';
210 if((pin < 0) || (pin > 7)) continue;
211 inpbits[port].insert(lit->second.mAddress);
212 inpexists= true;
213 }
214 // skip this section
215 if((!outexists) && (!(inpexists && mATmegaPullups))) return;
216 // configure ports
217 Comment("************************************************");
218 Comment("* initialise input/output pins *");
219 Comment("************************************************");
220 Output() << "void " << mPrefix <<"initpio(void) { ";
221 LineFeed();
222 IndentInc();
223 std::map<char, std::set< std::string > >::iterator oit = outbits.begin();
224 for(;oit!= outbits.end(); ++oit) {
225 Output() << "DDR" << oit->first << " |= ";
226 std::set< std::string >::iterator bit= oit->second.begin();
227 while(true) {
228 Output() << "( 1 << " << *bit << " )";
229 ++bit;
230 if(bit== oit->second.end()) break;
231 Output() << " | ";
232 }
233 Output() << ";";
234 LineFeed();
235 }
236 if(mATmegaPullups) {
237 std::map<char, std::set< std::string > >::iterator iit = inpbits.begin();
238 for(;iit!= inpbits.end(); ++iit) {
239 Output() << "PORT" << iit->first << " |= ";
240 std::set< std::string >::iterator bit= iit->second.begin();
241 while(true) {
242 Output() << "( 1 << " << *bit << " )";
243 ++bit;
244 if(bit== iit->second.end()) break;
245 Output() << " | ";
246 }
247 Output() << ";";
248 LineFeed();
249 }
250 }
251 IndentDec();
252 Output() << "};";
253 LineFeed(1+2);
254}
255
256// output actions
257void ATmegaCodeGenerator::RunActionSet(const std::string& address) {
258 Output() << "PORT" << address[1] << " |= ( 1 << " << address << " );";
259 LineFeed();
260}
261void ATmegaCodeGenerator::RunActionClr(const std::string& address) {
262 Output() << "PORT" << address[1] << " &= ~( 1 << " << address << " );";
263 LineFeed();
264}
265
266// read inputs
267ATmegaCodeGenerator::AX ATmegaCodeGenerator::ReadInputLine(const std::string& address) {
268 // if it is a port bit, convert to boolean expression
269 if(address.size()==3)
270 if(address[0]=='P')
271 if(address[1]>='A')
272 if(address[1]<='F')
273 if(address[2]>='0')
274 if(address[2]<='7') {
275 std::string res = "( PIN" + address.substr(1,1) + " & ( 1 << " + address + " ) )";
276 return AX(res);
277 }
278 // fallback to boolean expression
279 std::string res = address;
280 return AX(res);
281}
282
283
284
285
286/*
287******************************************************************
288******************************************************************
289******************************************************************
290
291atmCodeGenerator implementation --- atomic snippets
292
293******************************************************************
294******************************************************************
295******************************************************************
296*/
297
298// implement pgm read for address-to-expression conversion
300 // test case
301 bool pgm_finteger = address.find("#PGM_FINTEGER# ")==0;
302 bool pgm_fword = address.find("#PGM_FWORD# ")==0;
303 // integer from pgm
304 if(pgm_finteger) {
305 size_t beg= address.find_first_of('#',1)+2;
306 std::string addr=address.substr(beg);
307 return AX( mATmegaPgmReadInteger + "( &( " + addr + " ) )");
308 }
309 // word from pgm
310 if(pgm_fword) {
311 size_t beg= address.find_first_of('#',1)+2;
312 std::string addr=address.substr(beg);
313 return AX( mATmegaPgmReadWord + "( &( " + addr + " ) )");
314 }
315 // base case: address matches expression
316 return AX(TargetAddress(address));
317}
318
319std::string ATmegaCodeGenerator::TargetAddress(const AA& address) {
320 // test case
321 bool pgm_finteger = address.find("#PGM_FINTEGER# ")==0;
322 bool pgm_fword = address.find("#PGM_FWORD# ")==0;
323 // cannot deal with it
324 if(pgm_finteger || pgm_fword) {
325 FCG_ERR("ATmegaCodeGenerator: cannot convert pgm-address to target address")
326 }
327 std::string res=mPrefix+address;
328 return res;
329}
330
331
332// const-int-array
333void ATmegaCodeGenerator::CintarrayDeclare(const AA& address, int offset, const std::vector<int>& val) {
334 if(val.size()==0) {
335 FCG_ERR("atmCodeGenerator::Cintarray(): ignoring empty const vector");
336 return;
337 }
338 if(val.size()+offset >= (1ULL << (mIntegerSize-1))) {
339 FCG_ERR("atmCodeGenerator::Cwordarray(): const vector exceeds addres range");
340 return;
341 }
342 if(mATmegaProgmem) {
343 Output() << "const " << mIntegerType << " " << TargetAddress(address) << "[] PROGMEM = ";
344 LineFeed();
345 } else {
346 Output() << "const " << mIntegerType << " " << TargetAddress(address) << "[] = ";
347 LineFeed();
348 }
349 IndentInc();
350 Output() << IntarrayConstant(offset,val) << ";";
351 LineFeed();
352 IndentDec();
353}
354
355
356// int array access by const
357CodePrimitives::AA ATmegaCodeGenerator::CintarrayAccess(const AA& address, int index) {
358 if(mATmegaProgmem) {
359 return AA("#PGM_FINTEGER# " + TargetAddress(address) + "[" + ToStringInteger(index) + "]");
360 } else {
361 return AA(address + "[" + ToStringInteger(index) + "]");
362 }
363};
364
365// int array access by expression
366CodePrimitives::AA ATmegaCodeGenerator::CintarrayAccess(const AA& address, const AA &indexaddr){
367 if(mATmegaProgmem) {
368 return AA("#PGM_FINTEGER# " + TargetAddress(address) + "[" + TargetAddress(indexaddr) + "]");
369 } else {
370 return AA(address + "[" + TargetAddress(indexaddr) + "]");
371 }
372};
373
374
375// const-word-array
376void ATmegaCodeGenerator::CwordarrayDeclare(const AA& address, int offset, const std::vector<word_t>& val) {
377 if(val.size()==0) {
378 FCG_ERR("ecCodeGenerator::Cwordarray(): ignoring empty const vector");
379 return;
380 }
381 if(val.size()+offset >= (1ULL << (mIntegerSize-1))) {
382 FCG_ERR("ecCodeGenerator::Cwordarray(): const vector exceeds addres range");
383 return;
384 }
385 if(mATmegaProgmem) {
386 Output() << "const " << mWordType << " " << TargetAddress(address) << "[] PROGMEM = ";
387 LineFeed();
388 } else {
389 Output() << "const " << mWordType << " " << TargetAddress(address) << "[] = ";
390 LineFeed();
391 }
392 IndentInc();
393 Output() << WordarrayConstant(offset,val) << ";";
394 LineFeed();
395 IndentDec();
396}
397
398// word-array access by const
399CodePrimitives::AA ATmegaCodeGenerator::CwordarrayAccess(const AA& address, int index) {
400 if(mATmegaProgmem) {
401 return AA("#PGM_FWORD# " + TargetAddress(address) + "[" + ToStringInteger(index) + "]");
402 } else {
403 return AA(address + "[" + ToStringInteger(index) + "]");
404 }
405};
406
407// word array access by expression
408CodePrimitives::AA ATmegaCodeGenerator::CwordarrayAccess(const AA& address, const AA& indexaddr){
409 if(mATmegaProgmem) {
410 return AA("#PGM_FWORD# " + TargetAddress(address) + "[" + TargetAddress(indexaddr) + "]");
411 } else {
412 return AA(address + "[" + TargetAddress(indexaddr) + "]");
413 }
414};
415
416
417// const string array
418void ATmegaCodeGenerator::CstrarrayDeclare(const AA& address, int offset, const std::vector<std::string>& val) {
419 if(val.size()==0) {
420 FCG_ERR("ATmegaCodeGenerator::Cstrarrayy(): ignoring empty string array");
421 return;
422 }
423 if(val.size()+offset >= (1ULL << (mIntegerSize-1))) {
424 FCG_ERR("ATmegaCodeGenerator::Cstrarray(): string array exceeds address range");
425 return;
426 }
427 if(!mATmegaProgmem) {
428 IndentInc();
429 Output() << StrarrayConstant(offset,val) << ";";
430 LineFeed();
431 IndentDec();
432 return;
433 }
434 // progmem: have individual strings first
435 size_t vit;
436 for(vit=offset; vit<val.size()+offset; ++vit) {
437 Output() << "const char" << " " << TargetAddress(address.Sub(vit)) << "[] PROGMEM = ";
438 Output() << StringConstant(val[vit-offset]) << ";";
439 LineFeed();
440 }
441 // progmen: have array of pointers to individual strings
442 Output() << "const char* const" << " " << TargetAddress(address) << "[] PROGMEM = ";
443 IndentInc();
444 std::stringstream strstr;
445 int newline=5;
446 strstr << "{" << std::endl;
447 vit=0;
448 while(true) {
449 if(vit==val.size()+offset) break;
450 if(vit < (size_t)offset)
451 strstr << "0x0000";
452 else
453 strstr << TargetAddress(address.Sub(vit));
454 ++vit;
455 if(vit==val.size()+offset) break;
456 strstr << ", ";
457 newline--;
458 if(newline==0) {
459 strstr << std::endl;
460 newline=5;
461 }
462 }
463 strstr << " }";
464 Output() << AX(strstr.str()) << ";";
465 LineFeed();
466 IndentDec();
467};
468
469
470// const string array access not defined
471CodePrimitives::AA ATmegaCodeGenerator::CstrarrayAccess(const AA& address, int index) {
472 (void) address;
473 (void) index;
474 FCG_ERR("ATmegaCodeGenerator::Cstrarray(): constant-str-arrays access not defined");
475 return AA();
476};
477CodePrimitives::AA ATmegaCodeGenerator::CstrarrayAccess(const AA& address, const AA& indexaddr){
478 (void) address;
479 (void) indexaddr;
480 FCG_ERR("ATmegaCodeGenerator::Cstrarray(): constant-str-arrays access not defined");
481 return AA();
482};
Code-generator for ATmega microcontrollers.
#define FAUDES_REGISTERCODEGENERATOR(ftype, ctype)
Class registration macro.
Target ATmega micro-controller (AVR8)
Definition cgp_atmega.h:116
virtual AX TargetExpression(const AA &address)
abstract address conversion
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
virtual std::string TargetAddress(const AA &address)
abstract address conversion
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
bool mATmegaProgmem
ATmega code options.
Definition cgp_atmega.h:149
virtual void Clear(void)
std::string mATmegaPgmReadInteger
ATmega code options.
Definition cgp_atmega.h:155
bool mATmegaPullups
ATmega code options.
Definition cgp_atmega.h:152
void DoCompile(void)
add my preferences to DoCompile
virtual void InitialisePorts(void)
reimplemented/additional code blocks
std::string mATmegaPgmReadWord
ATmega code options.
Definition cgp_atmega.h:158
void DoGenerate(void)
protected version of generate
virtual ~ATmegaCodeGenerator(void)
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
LineIterator LinesEnd()
Access to line records by iterator.
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
virtual void IndentInc()
Indentation (convenience support for derived classes)
int mWordSize
compressed boolean capacity of target type word
LineIterator LinesBegin()
Access to line records by iterator.
int mIntegerSize
compressed boolean capacity of target type integer
virtual std::ostream & Output(void)
Output stream.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
virtual void IndentDec()
Indentation (convenience support for derived classes)
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
Abstract address; see also Absstract_Addresses.
Abstract expression; see also Absstract_Addresses.
bool mBitAddressArithmetic
code option: compute bit and word address on target
virtual void DoGenerateDeclarations(void)
cut-and-paste template for code snippet assembly
virtual void DoGenerateResetCode(void)
cut-and-paste template for code snippet assembly
virtual void LiteralAppend(void)
Cosmetic: append literally from configuration.
bool mEventNameLookup
code option: event name lookup
std::map< std::string, bitarray_rec > mBitarrays
Record of all declared bit-arrays.
bool mStateNameLookup
code option: state name lookup
std::string mIntegerType
target data type for integer
virtual void DoGenerateCyclicCode(void)
cut-and-paste template for code snippet assembly
std::string mWordType
target data type for word
bool mArrayForTransitions
code option: use const array to represent transitions
bool mArrayForBitmasks
code option: use const array to represent bit-masks
virtual void LiteralPrepend(void)
Cosmetic: prepend literally from configuration data.
std::string mPrefix
universal prefix (pseudo name space)
Implementation of code primitives by generic C-code.
void DoCompile(void)
add my preferences to DoCompile
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
virtual void Comment(const std::string &text)
Target comments (see EmbeddedcCodeGenerator for consistent reimplementation pattern)
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
virtual void Clear(void)
Clear all data.
virtual void DecrementTimers(void)
re-implemented/additional code blocks