CompileDES  3.11
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 supported on this target");
131  mEventNameLookup = false;
132  mStateNameLookup = false;
133  }
134 }
135 
136 // DoGenerate()
138  FD_DCG("atmCodeGenerator(" << this << ")::DoGenerate()");
139  // cut and paste from base
140  mBitarrays.clear();
141  // say hello
142  Comment("************************************************");
143  Comment("CodeGenerator: Target ATmega Microcontroller ");
144  Comment("************************************************");
145  LineFeed(1);
146  Comment(std::string("CompileDES ") + VersionString());
147  Comment(std::string("Configuration: ") + Name());
148  LineFeed(2+1);
149  // snippets
150  LiteralPrepend();
151  // use base class for std semantics
153  LineFeed(2);
154  // use base class for std semantics
155  Output() << "void " << mPrefix <<"cyclic(void) { ";
156  LineFeed();
158  Output() << "}; /* end function " << mPrefix <<"cyclic() */";
159  LineFeed();
160  LineFeed(2+1);
161  // extra from ecCodeGenerator: provide timer decrement interface to host application
162  DecrementTimers();
163  // extra from atmCodeGenerator: initialise ports
164  InitialisePorts();
165  // snippets
166  LiteralAppend();
167  // done
168  Comment("************************************************");
169  Comment("CodeGenerator: Generated Code Ends Here ");
170  Comment("************************************************");
171 }
172 
173 
174 // code blocks: initialise ports
176  // figure output pins on ports A,B,C,D,E,F
177  bool outexists= false;
178  std::map<char, std::set< std::string > > outbits;
180  for(;ait!=ActionAddressesEnd();++ait) {
181  // strict syntax check for set/clr actions, otherwise we cannot handle bit operations
182  if(!ait->second.mSetClr) continue;
183  if(ait->second.mAddress.size()!=3) {
184  FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
185  }
186  if(ait->second.mAddress[0]!='P') {
187  FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
188  }
189  char port = ait->second.mAddress[1];
190  if((port < 'A') || (port > 'F')) {
191  FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
192  }
193  int pin = ait->second.mAddress[2] - '0';
194  if((pin < 0) || (pin > 7)) {
195  FCG_ERR("atmCodeGenerator::InitialisePorts(): unkown output port [" << ait->second.mAddress << "]");
196  }
197  outbits[port].insert(ait->second.mAddress);
198  outexists= true;
199  }
200  // figure input pins on ports A,B,C,D,E,F
201  bool inpexists= false;
202  std::map<char, std::set< std::string > > inpbits;
203  LineIterator lit=LinesBegin();
204  for(;lit!=LinesEnd();++lit) {
205  // weak syntax check for inputs, interpret as boolean expression if its not a port bit
206  if(lit->second.mAddress.size()!=3) continue;
207  if(lit->second.mAddress[0]!='P') continue;
208  char port = lit->second.mAddress[1];
209  if((port < 'A') || (port > 'F')) continue;
210  int pin = lit->second.mAddress[2] - '0';
211  if((pin < 0) || (pin > 7)) continue;
212  inpbits[port].insert(lit->second.mAddress);
213  inpexists= true;
214  }
215  // skip this section
216  if((!outexists) && (!(inpexists && mATmegaPullups))) return;
217  // configure ports
218  Comment("************************************************");
219  Comment("* initialise input/output pins *");
220  Comment("************************************************");
221  Output() << "void " << mPrefix <<"initpio(void) { ";
222  LineFeed();
223  IndentInc();
224  std::map<char, std::set< std::string > >::iterator oit = outbits.begin();
225  for(;oit!= outbits.end(); ++oit) {
226  Output() << "DDR" << oit->first << " |= ";
227  std::set< std::string >::iterator bit= oit->second.begin();
228  while(true) {
229  Output() << "( 1 << " << *bit << " )";
230  ++bit;
231  if(bit== oit->second.end()) break;
232  Output() << " | ";
233  }
234  Output() << ";";
235  LineFeed();
236  }
237  if(mATmegaPullups) {
238  std::map<char, std::set< std::string > >::iterator iit = inpbits.begin();
239  for(;iit!= inpbits.end(); ++iit) {
240  Output() << "PORT" << iit->first << " |= ";
241  std::set< std::string >::iterator bit= iit->second.begin();
242  while(true) {
243  Output() << "( 1 << " << *bit << " )";
244  ++bit;
245  if(bit== iit->second.end()) break;
246  Output() << " | ";
247  }
248  Output() << ";";
249  LineFeed();
250  }
251  }
252  IndentDec();
253  Output() << "};";
254  LineFeed(1+2);
255 }
256 
257 // output actions
258 void ATmegaCodeGenerator::RunActionSet(const std::string& address) {
259  Output() << "PORT" << address[1] << " |= ( 1 << " << address << " );";
260  LineFeed();
261 }
262 void ATmegaCodeGenerator::RunActionClr(const std::string& address) {
263  Output() << "PORT" << address[1] << " &= ~( 1 << " << address << " );";
264  LineFeed();
265 }
266 
267 // read inputs
268 ATmegaCodeGenerator::AX ATmegaCodeGenerator::ReadInputLine(const std::string& address) {
269  // if it is a port bit, convert to boolean expression
270  if(address.size()==3)
271  if(address[0]=='P')
272  if(address[1]>='A')
273  if(address[1]<='F')
274  if(address[2]>='0')
275  if(address[2]<='7') {
276  std::string res = "( PIN" + address.substr(1,1) + " & ( 1 << " + address + " ) )";
277  return AX(res);
278  }
279  // fallback to boolean expression
280  std::string res = address;
281  return AX(res);
282 }
283 
284 
285 
286 
287 /*
288 ******************************************************************
289 ******************************************************************
290 ******************************************************************
291 
292 atmCodeGenerator implementation --- atomic snippets
293 
294 ******************************************************************
295 ******************************************************************
296 ******************************************************************
297 */
298 
299 // implement pgm read for address-to-expression conversion
301  // test case
302  bool pgm_finteger = address.find("#PGM_FINTEGER# ")==0;
303  bool pgm_fword = address.find("#PGM_FWORD# ")==0;
304  // integer from pgm
305  if(pgm_finteger) {
306  size_t beg= address.find_first_of('#',1)+2;
307  std::string addr=address.substr(beg);
308  return AX( mATmegaPgmReadInteger + "( &( " + addr + " ) )");
309  }
310  // word from pgm
311  if(pgm_fword) {
312  size_t beg= address.find_first_of('#',1)+2;
313  std::string addr=address.substr(beg);
314  return AX( mATmegaPgmReadWord + "( &( " + addr + " ) )");
315  }
316  // base case: address matches expression
317  return AX(TargetAddress(address));
318 }
319 
320 std::string ATmegaCodeGenerator::TargetAddress(const AA& address) {
321  // test case
322  bool pgm_finteger = address.find("#PGM_FINTEGER# ")==0;
323  bool pgm_fword = address.find("#PGM_FWORD# ")==0;
324  // cannot deal with it
325  if(pgm_finteger || pgm_fword) {
326  FCG_ERR("ATmegaCodeGenerator: cannot convert pgm-address to target address")
327  }
328  std::string res=mPrefix+address;
329  return res;
330 }
331 
332 
333 // const-int-array
334 void ATmegaCodeGenerator::CintarrayDeclare(const AA& address, int offset, const std::vector<int>& val) {
335  if(val.size()==0) {
336  FCG_ERR("atmCodeGenerator::Cintarray(): ignoring empty const vector");
337  return;
338  }
339  if(val.size()+offset >= (1ULL << (mIntegerSize-1))) {
340  FCG_ERR("atmCodeGenerator::Cwordarray(): const vector exceeds addres range");
341  return;
342  }
343  if(mATmegaProgmem) {
344  Output() << "const " << mIntegerType << " " << TargetAddress(address) << "[] PROGMEM = ";
345  LineFeed();
346  } else {
347  Output() << "const " << mIntegerType << " " << TargetAddress(address) << "[] = ";
348  LineFeed();
349  }
350  IndentInc();
351  Output() << IntarrayConstant(offset,val) << ";";
352  LineFeed();
353  IndentDec();
354 }
355 
356 
357 // int array access by const
358 CodePrimitives::AA ATmegaCodeGenerator::CintarrayAccess(const AA& address, int index) {
359  if(mATmegaProgmem) {
360  return AA("#PGM_FINTEGER# " + TargetAddress(address) + "[" + ToStringInteger(index) + "]");
361  } else {
362  return AA(address + "[" + ToStringInteger(index) + "]");
363  }
364 };
365 
366 // int array access by expression
367 CodePrimitives::AA ATmegaCodeGenerator::CintarrayAccess(const AA& address, const AA &indexaddr){
368  if(mATmegaProgmem) {
369  return AA("#PGM_FINTEGER# " + TargetAddress(address) + "[" + TargetAddress(indexaddr) + "]");
370  } else {
371  return AA(address + "[" + TargetAddress(indexaddr) + "]");
372  }
373 };
374 
375 
376 // const-word-array
377 void ATmegaCodeGenerator::CwordarrayDeclare(const AA& address, int offset, const std::vector<word_t>& val) {
378  if(val.size()==0) {
379  FCG_ERR("ecCodeGenerator::Cwordarray(): ignoring empty const vector");
380  return;
381  }
382  if(val.size()+offset >= (1ULL << (mIntegerSize-1))) {
383  FCG_ERR("ecCodeGenerator::Cwordarray(): const vector exceeds addres range");
384  return;
385  }
386  if(mATmegaProgmem) {
387  Output() << "const " << mWordType << " " << TargetAddress(address) << "[] PROGMEM = ";
388  LineFeed();
389  } else {
390  Output() << "const " << mWordType << " " << TargetAddress(address) << "[] = ";
391  LineFeed();
392  }
393  IndentInc();
394  Output() << WordarrayConstant(offset,val) << ";";
395  LineFeed();
396  IndentDec();
397 }
398 
399 // word-array access by const
400 CodePrimitives::AA ATmegaCodeGenerator::CwordarrayAccess(const AA& address, int index) {
401  if(mATmegaProgmem) {
402  return AA("#PGM_FWORD# " + TargetAddress(address) + "[" + ToStringInteger(index) + "]");
403  } else {
404  return AA(address + "[" + ToStringInteger(index) + "]");
405  }
406 };
407 
408 // word array access by expression
409 CodePrimitives::AA ATmegaCodeGenerator::CwordarrayAccess(const AA& address, const AA& indexaddr){
410  if(mATmegaProgmem) {
411  return AA("#PGM_FWORD# " + TargetAddress(address) + "[" + TargetAddress(indexaddr) + "]");
412  } else {
413  return AA(address + "[" + TargetAddress(indexaddr) + "]");
414  }
415 };
416 
417 
418 
std::string mWordType
target data type for word
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
bool mBitAddressArithmetic
code option: compute bit and word address on target
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
LineIterator LinesEnd()
Access to line records by iterator.
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
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:320
std::string mIntegerType
target data type for integer
virtual void DecrementTimers(void)
re-implemented/additional code blocks
Code-generator for ATmega microcontrollers.
virtual void IndentDec()
Indentation (convenience support for derived classes)
Abstract expression; see also Absstract_Addresses.
virtual void DoGenerateDeclarations(void)
cut-and-paste template for code snippet assembly
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
virtual void LiteralAppend(void)
Cosmetic: append literally from configuration.
virtual AX TargetExpression(const AA &address)
abstract address conversion
Definition: cgp_atmega.cpp:300
Target ATmega micro-controller (AVR8)
Definition: cgp_atmega.h:116
bool mATmegaPullups
ATmega code options.
Definition: cgp_atmega.h:152
bool mEventNameLookup
code option: event name lookup
void DoGenerate(void)
protected version of generate
Definition: cgp_atmega.cpp:137
std::map< std::string, bitarray_rec > mBitarrays
Record of all declared bit-arrays.
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
std::string mATmegaPgmReadInteger
ATmega code options.
Definition: cgp_atmega.h:155
LineIterator LinesBegin()
Access to line records by iterator.
bool mArrayForBitmasks
code option: use const array to represent bit-masks
Implementation of code primitives by generic C-code.
Definition: cgp_embeddedc.h:71
Abstract address; see also Absstract_Addresses.
std::string mPrefix
universal prefix (pseudo name space)
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
virtual std::ostream & Output(void)
Output stream.
int mWordSize
compressed boolean capacity of target type word
void DoCompile(void)
add my preferences to DoCompile
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
Definition: cgp_atmega.cpp:78
virtual ~ATmegaCodeGenerator(void)
Definition: cgp_atmega.cpp:37
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
virtual void DoGenerateCyclicCode(void)
cut-and-paste template for code snippet assembly
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:175
bool mArrayForTransitions
code option: use const array to represent transitions
bool mStateNameLookup
code option: state name lookup
virtual void Clear(void)
Definition: cgp_atmega.cpp:43
virtual void LiteralPrepend(void)
Cosmetic: prepend literally from configuration data.
bool mATmegaProgmem
ATmega code options.
Definition: cgp_atmega.h:149
virtual void IndentInc()
Indentation (convenience support for derived classes)
#define FAUDES_REGISTERCODEGENERATOR(ftype, ctype)
Class registration macro.
std::string mATmegaPgmReadWord
ATmega code options.
Definition: cgp_atmega.h:158
virtual const std::string & Name(void) const
Get objects&#39;s name (reimplementing base faudes::Type)
virtual void Comment(const std::string &text)
Target comments (see EmbeddedcCodeGenerator for consistent reimplementation pattern) ...
int mIntegerSize
compressed boolean capacity of target type integer
virtual void Clear(void)
Clear all data.