CompileDES  3.12
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 };
#define FAUDES_REGISTERCODEGENERATOR(ftype, ctype)
Class registration macro.
virtual void DoGenerateCyclicCode(void)
cut-and-paste template for code snippet assembly
Code-generator for ATmega microcontrollers.
std::string mATmegaPgmReadInteger
ATmega code options.
Definition: cgp_atmega.h:155
Abstract expression; see also Absstract_Addresses.
LineIterator LinesEnd()
Access to line records by iterator.
virtual std::ostream & Output(void)
Output stream.
virtual void DoGenerateResetCode(void)
cut-and-paste template for code snippet assembly
int mWordSize
compressed boolean capacity of target type word
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
Definition: cgp_atmega.cpp:59
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
Implementation of code primitives by generic C-code.
Definition: cgp_embeddedc.h:71
virtual void DecrementTimers(void)
re-implemented/additional code blocks
virtual void InitialisePorts(void)
reimplemented/additional code blocks
Definition: cgp_atmega.cpp:174
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
Definition: cgp_atmega.cpp:78
virtual void Clear(void)
Clear all data.
virtual void IndentInc()
Indentation (convenience support for derived classes)
bool mArrayForBitmasks
code option: use const array to represent bit-masks
virtual void DoGenerateDeclarations(void)
cut-and-paste template for code snippet assembly
void DoCompile(void)
add my preferences to DoCompile
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
std::string mIntegerType
target data type for integer
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 LiteralAppend(void)
Cosmetic: append literally from configuration.
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
virtual const std::string & Name(void) const
Get objects&#39;s name (reimplementing base faudes::Type)
int mIntegerSize
compressed boolean capacity of target type integer
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
std::string mWordType
target data type for word
virtual ~ATmegaCodeGenerator(void)
Definition: cgp_atmega.cpp:37
bool mEventNameLookup
code option: event name lookup
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
virtual std::string TargetAddress(const AA &address)
abstract address conversion
Definition: cgp_atmega.cpp:319
std::string mATmegaPgmReadWord
ATmega code options.
Definition: cgp_atmega.h:158
bool mATmegaProgmem
ATmega code options.
Definition: cgp_atmega.h:149
Abstract address; see also Absstract_Addresses.
bool mArrayForTransitions
code option: use const array to represent transitions
bool mStateNameLookup
code option: state name lookup
bool mATmegaPullups
ATmega code options.
Definition: cgp_atmega.h:152
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
void DoCompile(void)
add my preferences to DoCompile
Definition: cgp_atmega.cpp:99
std::string mPrefix
universal prefix (pseudo name space)
void DoGenerate(void)
protected version of generate
Definition: cgp_atmega.cpp:135
virtual void IndentDec()
Indentation (convenience support for derived classes)
virtual void Clear(void)
Definition: cgp_atmega.cpp:43
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
std::map< std::string, bitarray_rec > mBitarrays
Record of all declared bit-arrays.
LineIterator LinesBegin()
Access to line records by iterator.
virtual void LiteralPrepend(void)
Cosmetic: prepend literally from configuration data.
bool mBitAddressArithmetic
code option: compute bit and word address on target
virtual void Comment(const std::string &text)
Target comments (see EmbeddedcCodeGenerator for consistent reimplementation pattern) ...