CompileDES  3.09
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, 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()>= (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(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, 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()>= (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(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