CompileDES  3.13
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 
19 ATmegaCodeGenerator 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 
90 atmCodeGenerator 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) {
115  if((mATmegaPgmReadInteger=="") || (mATmegaPgmReadWord==""))
116  FCG_VERB0("ATmegaCodeGenerator::DoCompile(): target supports pgmread only for 8bit or 16bit data types --- ignoring option ATmegaProgmen ");
117  }
119  if(mATmegaPgmReadWord=="") mATmegaProgmem=false;
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
148  LiteralPrepend();
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
161  DecrementTimers();
162  // extra from atmCodeGenerator: initialise ports
163  InitialisePorts();
164  // snippets
165  LiteralAppend();
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;
202  LineIterator lit=LinesBegin();
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
257 void ATmegaCodeGenerator::RunActionSet(const std::string& address) {
258  Output() << "PORT" << address[1] << " |= ( 1 << " << address << " );";
259  LineFeed();
260 }
261 void ATmegaCodeGenerator::RunActionClr(const std::string& address) {
262  Output() << "PORT" << address[1] << " &= ~( 1 << " << address << " );";
263  LineFeed();
264 }
265 
266 // read inputs
267 ATmegaCodeGenerator::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 
291 atmCodeGenerator 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 
319 std::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
333 void 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
357 CodePrimitives::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
366 CodePrimitives::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
376 void 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
399 CodePrimitives::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
408 CodePrimitives::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
418 void 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
471 CodePrimitives::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 };
477 CodePrimitives::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
Definition: cgp_atmega.cpp:299
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
Definition: cgp_atmega.cpp:59
virtual std::string TargetAddress(const AA &address)
abstract address conversion
Definition: cgp_atmega.cpp:319
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
Definition: cgp_atmega.cpp:78
bool mATmegaProgmem
ATmega code options.
Definition: cgp_atmega.h:149
virtual void Clear(void)
Definition: cgp_atmega.cpp:43
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
Definition: cgp_atmega.cpp:99
virtual void InitialisePorts(void)
reimplemented/additional code blocks
Definition: cgp_atmega.cpp:174
std::string mATmegaPgmReadWord
ATmega code options.
Definition: cgp_atmega.h:158
void DoGenerate(void)
protected version of generate
Definition: cgp_atmega.cpp:135
virtual ~ATmegaCodeGenerator(void)
Definition: cgp_atmega.cpp:37
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
LineIterator LinesEnd()
Access to line records by iterator.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records 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.
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
virtual void IndentDec()
Indentation (convenience support for derived classes)
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record 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.
Definition: cgp_embeddedc.h:71
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