From 7c539d8e198e9113e21c6c13c41eb318842ec071 Mon Sep 17 00:00:00 2001 From: Serhii Sakhno Date: Wed, 13 Apr 2016 17:05:47 +0000 Subject: [PATCH] upload avra git-svn-id: svn://kolibrios.org@6400 a494cfbc-eb01-0410-851d-a64ba20cac60 --- contrib/toolchain/avra/.gitignore | 5 + contrib/toolchain/avra/doc/ChangeLog.html | 763 ++++++ contrib/toolchain/avra/doc/Makefile | 55 + contrib/toolchain/avra/doc/README.html | 759 ++++++ contrib/toolchain/avra/doc/README.txt | 679 ++++++ .../toolchain/avra/doc/asciidoc-xhtml11.js | 128 + contrib/toolchain/avra/doc/build-website.sh | 11 + contrib/toolchain/avra/doc/downloads.html | 75 + contrib/toolchain/avra/doc/downloads.txt | 6 + .../toolchain/avra/doc/images/highlighter.png | Bin 0 -> 72099 bytes .../toolchain/avra/doc/images/icons/README | 5 + .../avra/doc/images/icons/callouts/1.png | Bin 0 -> 329 bytes .../avra/doc/images/icons/callouts/10.png | Bin 0 -> 361 bytes .../avra/doc/images/icons/callouts/11.png | Bin 0 -> 565 bytes .../avra/doc/images/icons/callouts/12.png | Bin 0 -> 617 bytes .../avra/doc/images/icons/callouts/13.png | Bin 0 -> 623 bytes .../avra/doc/images/icons/callouts/14.png | Bin 0 -> 411 bytes .../avra/doc/images/icons/callouts/15.png | Bin 0 -> 640 bytes .../avra/doc/images/icons/callouts/2.png | Bin 0 -> 353 bytes .../avra/doc/images/icons/callouts/3.png | Bin 0 -> 350 bytes .../avra/doc/images/icons/callouts/4.png | Bin 0 -> 345 bytes .../avra/doc/images/icons/callouts/5.png | Bin 0 -> 348 bytes .../avra/doc/images/icons/callouts/6.png | Bin 0 -> 355 bytes .../avra/doc/images/icons/callouts/7.png | Bin 0 -> 344 bytes .../avra/doc/images/icons/callouts/8.png | Bin 0 -> 357 bytes .../avra/doc/images/icons/callouts/9.png | Bin 0 -> 357 bytes .../avra/doc/images/icons/caution.png | Bin 0 -> 2734 bytes .../avra/doc/images/icons/example.png | Bin 0 -> 2599 bytes .../toolchain/avra/doc/images/icons/home.png | Bin 0 -> 1340 bytes .../avra/doc/images/icons/important.png | Bin 0 -> 2980 bytes .../toolchain/avra/doc/images/icons/next.png | Bin 0 -> 1302 bytes .../toolchain/avra/doc/images/icons/note.png | Bin 0 -> 2494 bytes .../toolchain/avra/doc/images/icons/prev.png | Bin 0 -> 1348 bytes .../toolchain/avra/doc/images/icons/tip.png | Bin 0 -> 2718 bytes .../toolchain/avra/doc/images/icons/up.png | Bin 0 -> 1320 bytes .../avra/doc/images/icons/warning.png | Bin 0 -> 3214 bytes .../toolchain/avra/doc/images/smallnew.png | Bin 0 -> 292 bytes contrib/toolchain/avra/doc/images/tiger.png | Bin 0 -> 6515 bytes contrib/toolchain/avra/doc/index.html | 94 + contrib/toolchain/avra/doc/index.txt | 23 + contrib/toolchain/avra/doc/layout1.conf | 155 ++ contrib/toolchain/avra/doc/layout1.css | 65 + .../toolchain/avra/doc/xhtml11-manpage.css | 18 + contrib/toolchain/avra/doc/xhtml11-quirks.css | 41 + contrib/toolchain/avra/doc/xhtml11.css | 367 +++ .../avra/examples/testcode_avra-1_2_3.asm | 18 + .../avra/examples/testcode_avra-1_3_0.asm | 27 + contrib/toolchain/avra/examples/throttle.asm | 916 ++++++++ .../avra/examples/throttle_backemf.asm | 328 +++ .../avra/examples/throttle_dev_set.inc | 348 +++ .../avra/examples/throttle_divide.asm | 135 ++ .../avra/examples/throttle_momentum.asm | 314 +++ .../examples/throttle_momentum_lowpass.asm | 69 + .../avra/examples/throttle_multiply.asm | 74 + .../avra/examples/throttle_op_set.inc | 227 ++ .../avra/examples/throttle_pulse.asm | 140 ++ .../avra/examples/throttle_set_lowpass.asm | 69 + contrib/toolchain/avra/examples/tn15def.inc | 195 ++ contrib/toolchain/avra/includes/1200def.inc | 297 +++ contrib/toolchain/avra/includes/2313def.inc | 406 ++++ contrib/toolchain/avra/includes/2323def.inc | 248 ++ contrib/toolchain/avra/includes/2343def.inc | 256 ++ contrib/toolchain/avra/includes/4414def.inc | 528 +++++ contrib/toolchain/avra/includes/4433def.inc | 522 ++++ contrib/toolchain/avra/includes/4434def.inc | 613 +++++ contrib/toolchain/avra/includes/8515def.inc | 519 ++++ contrib/toolchain/avra/includes/8535def.inc | 613 +++++ contrib/toolchain/avra/includes/m103def.inc | 713 ++++++ contrib/toolchain/avra/includes/m128def.inc | 1175 +++++++++ contrib/toolchain/avra/includes/m161def.inc | 736 ++++++ contrib/toolchain/avra/includes/m162def.inc | 929 ++++++++ contrib/toolchain/avra/includes/m163def.inc | 743 ++++++ contrib/toolchain/avra/includes/m165def.inc | 1059 +++++++++ contrib/toolchain/avra/includes/m168def.inc | 958 ++++++++ contrib/toolchain/avra/includes/m169def.inc | 1248 ++++++++++ contrib/toolchain/avra/includes/m16def.inc | 863 +++++++ contrib/toolchain/avra/includes/m2560def.inc | 1760 ++++++++++++++ contrib/toolchain/avra/includes/m2561def.inc | 1516 ++++++++++++ contrib/toolchain/avra/includes/m323def.inc | 793 +++++++ contrib/toolchain/avra/includes/m3250def.inc | 1167 +++++++++ contrib/toolchain/avra/includes/m325def.inc | 1048 +++++++++ contrib/toolchain/avra/includes/m3290def.inc | 1427 +++++++++++ contrib/toolchain/avra/includes/m329def.inc | 1242 ++++++++++ contrib/toolchain/avra/includes/m32def.inc | 808 +++++++ contrib/toolchain/avra/includes/m406def.inc | 855 +++++++ contrib/toolchain/avra/includes/m48def.inc | 948 ++++++++ contrib/toolchain/avra/includes/m649def.inc | 1242 ++++++++++ contrib/toolchain/avra/includes/m64def.inc | 1178 ++++++++++ contrib/toolchain/avra/includes/m8515def.inc | 683 ++++++ contrib/toolchain/avra/includes/m8535def.inc | 841 +++++++ contrib/toolchain/avra/includes/m88def.inc | 958 ++++++++ contrib/toolchain/avra/includes/m8def.inc | 738 ++++++ contrib/toolchain/avra/includes/pwm2def.inc | 1245 ++++++++++ contrib/toolchain/avra/includes/pwm3def.inc | 1434 +++++++++++ contrib/toolchain/avra/includes/tn11def.inc | 233 ++ contrib/toolchain/avra/includes/tn12def.inc | 279 +++ contrib/toolchain/avra/includes/tn13def.inc | 468 ++++ contrib/toolchain/avra/includes/tn15def.inc | 388 +++ contrib/toolchain/avra/includes/tn22def.inc | 251 ++ contrib/toolchain/avra/includes/tn2313def.inc | 660 ++++++ contrib/toolchain/avra/includes/tn26def.inc | 542 +++++ contrib/toolchain/avra/includes/tn28def.inc | 188 ++ contrib/toolchain/avra/includes/tn45def.inc | 682 ++++++ contrib/toolchain/avra/src/Makefile | 40 + contrib/toolchain/avra/src/args.c | 222 ++ contrib/toolchain/avra/src/args.h | 67 + contrib/toolchain/avra/src/avra.c | 800 +++++++ contrib/toolchain/avra/src/avra.h | 370 +++ contrib/toolchain/avra/src/coff.c | 2089 +++++++++++++++++ contrib/toolchain/avra/src/coff.h | 403 ++++ contrib/toolchain/avra/src/device.c | 214 ++ contrib/toolchain/avra/src/device.h | 33 + contrib/toolchain/avra/src/directiv.c | 934 ++++++++ contrib/toolchain/avra/src/expr.c | 573 +++++ contrib/toolchain/avra/src/file.c | 317 +++ contrib/toolchain/avra/src/macro.c | 560 +++++ contrib/toolchain/avra/src/map.c | 76 + contrib/toolchain/avra/src/misc.h | 19 + contrib/toolchain/avra/src/mnemonic.c | 793 +++++++ contrib/toolchain/avra/src/parser.c | 412 ++++ contrib/toolchain/avra/src/stab.h | 114 + contrib/toolchain/avra/src/stdextra.c | 191 ++ 122 files changed, 50336 insertions(+) create mode 100644 contrib/toolchain/avra/.gitignore create mode 100644 contrib/toolchain/avra/doc/ChangeLog.html create mode 100644 contrib/toolchain/avra/doc/Makefile create mode 100644 contrib/toolchain/avra/doc/README.html create mode 100644 contrib/toolchain/avra/doc/README.txt create mode 100644 contrib/toolchain/avra/doc/asciidoc-xhtml11.js create mode 100755 contrib/toolchain/avra/doc/build-website.sh create mode 100644 contrib/toolchain/avra/doc/downloads.html create mode 100644 contrib/toolchain/avra/doc/downloads.txt create mode 100644 contrib/toolchain/avra/doc/images/highlighter.png create mode 100644 contrib/toolchain/avra/doc/images/icons/README create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/1.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/10.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/11.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/12.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/13.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/14.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/15.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/2.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/3.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/4.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/5.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/6.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/7.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/8.png create mode 100644 contrib/toolchain/avra/doc/images/icons/callouts/9.png create mode 100644 contrib/toolchain/avra/doc/images/icons/caution.png create mode 100644 contrib/toolchain/avra/doc/images/icons/example.png create mode 100644 contrib/toolchain/avra/doc/images/icons/home.png create mode 100644 contrib/toolchain/avra/doc/images/icons/important.png create mode 100644 contrib/toolchain/avra/doc/images/icons/next.png create mode 100644 contrib/toolchain/avra/doc/images/icons/note.png create mode 100644 contrib/toolchain/avra/doc/images/icons/prev.png create mode 100644 contrib/toolchain/avra/doc/images/icons/tip.png create mode 100644 contrib/toolchain/avra/doc/images/icons/up.png create mode 100644 contrib/toolchain/avra/doc/images/icons/warning.png create mode 100644 contrib/toolchain/avra/doc/images/smallnew.png create mode 100644 contrib/toolchain/avra/doc/images/tiger.png create mode 100644 contrib/toolchain/avra/doc/index.html create mode 100644 contrib/toolchain/avra/doc/index.txt create mode 100644 contrib/toolchain/avra/doc/layout1.conf create mode 100644 contrib/toolchain/avra/doc/layout1.css create mode 100644 contrib/toolchain/avra/doc/xhtml11-manpage.css create mode 100644 contrib/toolchain/avra/doc/xhtml11-quirks.css create mode 100644 contrib/toolchain/avra/doc/xhtml11.css create mode 100644 contrib/toolchain/avra/examples/testcode_avra-1_2_3.asm create mode 100644 contrib/toolchain/avra/examples/testcode_avra-1_3_0.asm create mode 100644 contrib/toolchain/avra/examples/throttle.asm create mode 100644 contrib/toolchain/avra/examples/throttle_backemf.asm create mode 100644 contrib/toolchain/avra/examples/throttle_dev_set.inc create mode 100644 contrib/toolchain/avra/examples/throttle_divide.asm create mode 100644 contrib/toolchain/avra/examples/throttle_momentum.asm create mode 100644 contrib/toolchain/avra/examples/throttle_momentum_lowpass.asm create mode 100644 contrib/toolchain/avra/examples/throttle_multiply.asm create mode 100644 contrib/toolchain/avra/examples/throttle_op_set.inc create mode 100644 contrib/toolchain/avra/examples/throttle_pulse.asm create mode 100644 contrib/toolchain/avra/examples/throttle_set_lowpass.asm create mode 100644 contrib/toolchain/avra/examples/tn15def.inc create mode 100644 contrib/toolchain/avra/includes/1200def.inc create mode 100644 contrib/toolchain/avra/includes/2313def.inc create mode 100644 contrib/toolchain/avra/includes/2323def.inc create mode 100644 contrib/toolchain/avra/includes/2343def.inc create mode 100644 contrib/toolchain/avra/includes/4414def.inc create mode 100644 contrib/toolchain/avra/includes/4433def.inc create mode 100644 contrib/toolchain/avra/includes/4434def.inc create mode 100644 contrib/toolchain/avra/includes/8515def.inc create mode 100644 contrib/toolchain/avra/includes/8535def.inc create mode 100644 contrib/toolchain/avra/includes/m103def.inc create mode 100644 contrib/toolchain/avra/includes/m128def.inc create mode 100644 contrib/toolchain/avra/includes/m161def.inc create mode 100644 contrib/toolchain/avra/includes/m162def.inc create mode 100644 contrib/toolchain/avra/includes/m163def.inc create mode 100644 contrib/toolchain/avra/includes/m165def.inc create mode 100644 contrib/toolchain/avra/includes/m168def.inc create mode 100644 contrib/toolchain/avra/includes/m169def.inc create mode 100644 contrib/toolchain/avra/includes/m16def.inc create mode 100644 contrib/toolchain/avra/includes/m2560def.inc create mode 100644 contrib/toolchain/avra/includes/m2561def.inc create mode 100644 contrib/toolchain/avra/includes/m323def.inc create mode 100644 contrib/toolchain/avra/includes/m3250def.inc create mode 100644 contrib/toolchain/avra/includes/m325def.inc create mode 100644 contrib/toolchain/avra/includes/m3290def.inc create mode 100644 contrib/toolchain/avra/includes/m329def.inc create mode 100644 contrib/toolchain/avra/includes/m32def.inc create mode 100644 contrib/toolchain/avra/includes/m406def.inc create mode 100644 contrib/toolchain/avra/includes/m48def.inc create mode 100644 contrib/toolchain/avra/includes/m649def.inc create mode 100644 contrib/toolchain/avra/includes/m64def.inc create mode 100644 contrib/toolchain/avra/includes/m8515def.inc create mode 100644 contrib/toolchain/avra/includes/m8535def.inc create mode 100644 contrib/toolchain/avra/includes/m88def.inc create mode 100644 contrib/toolchain/avra/includes/m8def.inc create mode 100644 contrib/toolchain/avra/includes/pwm2def.inc create mode 100644 contrib/toolchain/avra/includes/pwm3def.inc create mode 100644 contrib/toolchain/avra/includes/tn11def.inc create mode 100644 contrib/toolchain/avra/includes/tn12def.inc create mode 100644 contrib/toolchain/avra/includes/tn13def.inc create mode 100644 contrib/toolchain/avra/includes/tn15def.inc create mode 100644 contrib/toolchain/avra/includes/tn22def.inc create mode 100644 contrib/toolchain/avra/includes/tn2313def.inc create mode 100644 contrib/toolchain/avra/includes/tn26def.inc create mode 100644 contrib/toolchain/avra/includes/tn28def.inc create mode 100644 contrib/toolchain/avra/includes/tn45def.inc create mode 100644 contrib/toolchain/avra/src/Makefile create mode 100644 contrib/toolchain/avra/src/args.c create mode 100644 contrib/toolchain/avra/src/args.h create mode 100644 contrib/toolchain/avra/src/avra.c create mode 100644 contrib/toolchain/avra/src/avra.h create mode 100644 contrib/toolchain/avra/src/coff.c create mode 100644 contrib/toolchain/avra/src/coff.h create mode 100644 contrib/toolchain/avra/src/device.c create mode 100644 contrib/toolchain/avra/src/device.h create mode 100644 contrib/toolchain/avra/src/directiv.c create mode 100644 contrib/toolchain/avra/src/expr.c create mode 100644 contrib/toolchain/avra/src/file.c create mode 100644 contrib/toolchain/avra/src/macro.c create mode 100644 contrib/toolchain/avra/src/map.c create mode 100644 contrib/toolchain/avra/src/misc.h create mode 100644 contrib/toolchain/avra/src/mnemonic.c create mode 100644 contrib/toolchain/avra/src/parser.c create mode 100644 contrib/toolchain/avra/src/stab.h create mode 100644 contrib/toolchain/avra/src/stdextra.c diff --git a/contrib/toolchain/avra/.gitignore b/contrib/toolchain/avra/.gitignore new file mode 100644 index 000000000..a05b06ea9 --- /dev/null +++ b/contrib/toolchain/avra/.gitignore @@ -0,0 +1,5 @@ +archives +releases +patches +*.o +*.exe diff --git a/contrib/toolchain/avra/doc/ChangeLog.html b/contrib/toolchain/avra/doc/ChangeLog.html new file mode 100644 index 000000000..4ea249631 --- /dev/null +++ b/contrib/toolchain/avra/doc/ChangeLog.html @@ -0,0 +1,763 @@ + + + + + + + + + + +AVRA ChangeLog + + +
+
AVRA
+
Assember for the Atmel AVR microcontroller family
+
+ + + + + +
+ + + + + + + +
+ +
+

Version 1.3.0 (20100628)

+
+

by Jerry Jacobs

+
Additions and changes
    +
  • +

    +Added new targets, ATtiny13A, ATtiny24/A, ATtiny44/A, ATtiny84, ATtiny2313A, + ATtiny4313, ATmega328P +

    +
  • +
  • +

    +Added mingw32 support for building windows binairies from linux host +

    +
  • +
  • +

    +Removed obsolete Dev-C++ for windows building +

    +
  • +
  • +

    +Updated documentation and rewritten in asciidoc markup language +

    +
  • +
+
Bug fixes
    +
  • +

    +FIXED: 1934647: Handle also # directives because include files don’t use . directives. +

    +
  • +
  • +

    +FIXED: 1970530: Make whitespace character possible between function name and open bracket. +

    +
  • +
  • +

    +FIXED: 1970630: Make line continuation possible with backslash as the last character of a line. +

    +
  • +
  • +

    +FIXED: 2929406: Change incorrect argument --includedir to includepath. +

    +
  • +
+
+

Version 1.2.3 (20071115)

+
+

by Burkhard Arenfeld

+
    +
  • +

    +Fix bug 1697037 (Error with single character ;) +

    +
  • +
  • +

    +Better check for line termination. Now a single CR or a FF generates an warning message. Code with bad CR + termination could appear, if you edit CR-LF terminated files (WIN/DOS) with linux (LF only) editors. +

    +
  • +
  • +

    +Add patch 1604128 from Jim Galbraith (New devices ATtiny25/45/85, small fix for ATmega8 (no jmp, call instruction)) +

    +
  • +
  • +

    +Fix bug in handling of special tags (%HOUR% …). A % without a special tag was replaced by previous tag value. +

    +
  • +
  • +

    +Use a global timestamp for all functions which needs a time (pi→time). +

    +
  • +
  • +

    +Fix bug in handling of unknown args (E.g.: avra --abc → Segfault). +

    +
  • +
  • +

    +Fix segfault if .error directive without parameter is used. +

    +
  • +
  • +

    +Add a warning, if characters with code > 127 are used in .db strings and fix listing output. +

    +
  • +
  • +

    +Take a look at Testcode_avra-1_2_3.asm, which demonstrate some differences between 1.2.3 and previous releases +

    +
  • +
  • +

    +AVR000.zip contains some header files for different devices. +

    +
  • +
  • +

    +Included avra binary was created with ubuntu 7.10 linux +

    +
  • +
+
Bug fixes
    +
  • +

    +FIXED: 1462900: Segfault, if error in -D parameter. +

    +
  • +
  • +

    +FIXED: 1742436: Error in .dseg size check. +

    +
  • +
  • +

    +FIXED: 1742437: Error in EEPROM presence check +

    +
  • +
+
+

Version 1.2.2 (20070511)

+
+

by Burkhard Arenfeld

+
    +
  • +

    +Check in print_msg() if filename is NULL. Avoid printing a NULL-Pointer. +

    +
  • +
  • +

    +Warning, if no .DEVICE was found, because address range check doesn’t work without it +

    +
  • +
  • +

    +Error, if more than one .DEVICE was found. +

    +
  • +
  • +

    +Error, if .DEVICE is after any assembled code or .ORG directive, because .DEVICE resets the address + counters and the assembler builds wrong code. +

    +
  • +
  • +

    +Create a list of program segments (see orglist). Every .ORG, .DEVICE, .?SEG is stored, so the + assembler now can check for overlapping segments. Now overlapped segments in Flash, Data or EEPROM memory + are detected. Very usefull, if .ORG is used to build tables or bootloader code at specific addresses. +

    +
  • +
  • +

    +Better check for exceeding device space in RAM, Flash or EEPROM memory. Now not the total count of + assembled memory is used, instead every assembled address range is checked. +

    +
  • +
  • +

    +.DSEG and .ESEG now generates an error, if device has no RAM / EEPROM. +

    +
  • +
  • +

    +Now a warning appears, if a .DEF name is already used as constant or label. Atmel assembler generates this + warning, too. +

    +
  • +
  • +

    +Fix a small bug in the example program. +

    +
  • +
+
+

Version 1.2.1 (20061117)

+
+

by Roland Riegel

+
    +
  • +

    +Some of the high end AVRs use the SRAM adress range from 0x60 to 0x100 for IO extension. + Avra so far used to start with SRAM Usage at 0x60. This is now set from case by case. +

    +
  • +
+
+

Version 1.2.0 (20061015)

+
+

by Burkhard Arenfeld

+
    +
  • +

    +Patch segfault, if .error is given without parameter +

    +
  • +
  • +

    +Patch segfault, if .device is given with an invalid parameter +

    +
  • +
  • +

    +Check in predef_dev() if symbol is already defined. Can happens, if someone + tries to define the symbol with the -D parameter. E.g.: avra -D ATMEGA8 Test.asm + now generate error message, because ATMEGA8 is reserved +

    +
  • +
  • +

    +Add .elseif directive. It’s the same like .elif. (Original Atmel assembler use .elseif + and not .elif) +

    +
  • +
  • +

    +In .db lines strings can now contain , and ; characters. +

    +
  • +
  • +

    +Allow forward declaration of constants (.equ) except for .ifdef and .ifndef. + Invalid forward declarations are checked now. (In the first pass undefined Symbols in + .ifdef and .ifndef parameters are stored in a blacklist and checked in the second pass) +

    +
  • +
  • +

    +Extend the .message directive for better debugging. Now it accept not only a String. + You can use a list of expressions like in a .db directive as parameter. +

    +
  • +
  • +

    +The assembler pass variable moved into the pi struct. I deleted the pass variable from + a lot of functions. +

    +
  • +
  • +

    +New functions in avra.c. It was easier for me, to understand the code without the + for(label = first; …)-loops. Replaced a lot of for(label = …) -loops by one of this + functions. +

    +
  • +
+
+

Version 1.1.1 (20060906)

+
+
    +
  • +

    +right shift operator bug +

    +
  • +
  • +

    +LPM is supported on ATtiny26 but avra say it isn’t +

    +
  • +
  • +

    +bugfix for jmp/call opcode +

    +
  • +
  • +

    +crash due to a strcmp with null pointer when parsing the cmd line args +

    +
  • +
+
+

Version 1.1.0 (20051227)

+
+

by Tobias Weber

+
    +
  • +

    +.DW defines were missing in the listfile. +

    +
  • +
  • +

    +Support for mega8515. +

    +
  • +
  • +

    +Fix for generic register names and extended macro syntax. +

    +
  • +
  • +

    +Makefile for lcc-win32 Compiler. +

    +
  • +
  • +

    +Changed "global" keyword to ".global". +

    +
  • +
  • +

    +Added .includepath directive that allows setting include path. +

    +
  • +
  • +

    +segfault when not passing any sourcefiles. +

    +
  • +
  • +

    +--define FOO=2 does not work as claimed by the documentation. +

    +
  • +
  • +

    +Added return value, indicating whether avra failed or succeded. +

    +
  • +
  • +

    +Added support for automake utilities. See manual for more info. +

    +
  • +
  • +

    +if no code is present, eeprom hex file will be written anyway. +

    +
  • +
  • +

    +added -W NoRegDef for suppressing Register assignment warnings. +

    +
  • +
  • +

    +.db values were sometimes wrong printed in lst file with 6 leading F. +

    +
  • +
  • +

    +Added BYTE1() function equivalent to LOW(). +

    +
  • +
  • +

    +The character " (pharentesis) could not be use as single character like " +

    +
  • +
+
+

Version 1.0.1 (20040610)

+
+

by Tobias Weber

+
    +
  • +

    +Added meta tags for time and date. +

    +
  • +
  • +

    +Expression of .elif was cutted off in list file - fixed. +

    +
  • +
  • +

    +.equ, .org, .defines added to list file output. +

    +
  • +
  • +

    +Values and expressions of .db assignemts are now listed in listfile. +

    +
  • +
  • +

    +Added Support for ATmega48, ATmega88 and ATmega168. +

    +
  • +
  • +

    +Added .include error file name print out. +

    +
  • +
  • +

    +Fixed seg fault that could happen while using .LIST directive with no + listfile switched on. +

    +
  • +
  • +

    +Error when using comments within macros that made use of sign @ fixed. +

    +
  • +
  • +

    +Listfile lines are now prefixed with the current segment C,D,E for + code, data and eeprom. +

    +
  • +
+
+

Version 1.0.0 (20040214)

+
+

by Tobias Weber

+
    +
  • +

    +Added support for ATtiny13 and ATtiny2313 +

    +
  • +
  • +

    +List file command line syntax now AVRASM compatible +

    +
  • +
  • +

    +Map file command line syntax now AVRASM compatible +

    +
  • +
  • +

    +Fixed problem with limited macro label running numbers +

    +
  • +
  • +

    +Now multiple labels can be used within macros +

    +
  • +
  • +

    +Fixed error output line number for included files +

    +
  • +
  • +

    +code cleaned up +

    +
  • +
+
+

Version 0.9.1 (20030602)

+
+

by Tobias Weber

+
    +
  • +

    +fixed code for Linux compiler +

    +
  • +
  • +

    +fixed nested macro labels +

    +
  • +
  • +

    +code cleaned up +

    +
  • +
+
+

Version 0.9 (20030523)

+
+

by Tobias Weber

+
    +
  • +

    +Added labels to macros +

    +
  • +
  • +

    +Added special codes dst and src +

    +
  • +
  • +

    +Added directive .endmacro, only .endm was allowed so far +

    +
  • +
  • +

    +Added a return(0); at the end of main() to quiet the Borland C++ 5.5 + compiler (Jim Galbraith) +

    +
  • +
  • +

    +Fixed wrong flash size calculation (Jim Galbraith) +

    +
  • +
  • +

    +In device.c, added ATtiny26 to struct device device_list[] (Jim Galbraith) +

    +
  • +
+
+

Version 0.8 (20030307)

+
+

by Tobias Weber

+
    +
  • +

    +Added new macro assembler coding facilities +

    +
  • +
  • +

    +Added error description for .include directives +

    +
  • +
+
+

Version 0.7 (20000217)

+
+
    +
  • +

    +Added supported() function to check in a .if if a instruction is + supported (From Lesha Bogdanow <boga@inbox.ru>). +

    +
  • +
  • +

    +Added checking of which mnemonic that work on the different AVRs + (From Lesha Bogdanow <boga@inbox.ru>). +

    +
  • +
  • +

    +Added constants DEVICE, FLASH_SIZE, RAM_SIZE and + EEPROM_SIZE (From Lesha Bogdanow <boga@inbox.ru>). +

    +
  • +
  • +

    +Added tiny devices (From Lesha Bogdanow <boga@inbox.ru>). +

    +
  • +
  • +

    +Changed error on constant out of range into a warning. +

    +
  • +
  • +

    +Added support for instructions: (E)LPM Rd,Z(+), SPM, ESPM, BREAK, + MOVW, MULS, MULSU, FMUL, FMULS, FMULSU +

    +
  • +
  • +

    +Added support for new devices: ATmega8, ATmega16, ATmega32, + ATmega128, ATmega162, ATmega163, ATmega323, AT94K +

    +
  • +
  • +

    +Added --devices switch to list all supported devices. +

    +
  • +
  • +

    +Fixed bug in map file name when the name had more than one . (dot) +

    +
  • +
  • +

    +Added option --includedirs to add additional include dirs in + search path. +

    +
  • +
  • +

    +Added support for creation of intel hex 32 files to be able to + address memory above 64KB. Uses 02 records for addresses up to 1MB + and 04 record for addresses above 1MB. +

    +
  • +
+
+

Version 0.6 (20000124)

+
+
+
+

Version 0.5 (19990331)

+
+
    +
  • +

    +Bugfix: a inline string copy did not terminate string. +

    +
  • +
  • +

    +Fixed bug causing --define symbol=value not to work. +

    +
  • +
  • +

    +Added output of memory usage. +

    +
  • +
  • +

    +Fixed bug when there was a { in a comment. +

    +
  • +
  • +

    +Fixed count for data segment. +

    +
  • +
  • +

    +Fix to make a forward referenced label in .db/.dw work. +

    +
  • +
  • +

    +Added ATmega161 and ATtiny15 in list. +

    +
  • +
  • +

    +rjmp and rcall now wraps around with 4k word devices. +

    +
  • +
  • +

    +Fixed bug when branching backwards with BRBS or BRBC +

    +
  • +
+
+

Version 0.4 (19990202)

+
+
    +
  • +

    +Added support for global keyword to use on labels in macros. +

    +
  • +
  • +

    +Fixed get_next_token to handle commas inside ' ' +

    +
  • +
  • +

    +Fixed bug when searching for correct macro_call, so recursive + and nested macros will work. +

    +
  • +
  • +

    +Now handles commas in strings. +

    +
  • +
  • +

    +Added fix to handle semi colon in a string. +

    +
  • +
  • +

    +Improved mnemonic parsing for ld and st +

    +
  • +
+
+
+

+ +
+
+ + diff --git a/contrib/toolchain/avra/doc/Makefile b/contrib/toolchain/avra/doc/Makefile new file mode 100644 index 000000000..e79111bfa --- /dev/null +++ b/contrib/toolchain/avra/doc/Makefile @@ -0,0 +1,55 @@ +### +# Sourceforge helper Makefile +### +USER=jerryjacobs +HOSTNAME=shell.sourceforge.net +PROJECT=avra +HTDOCS=/home/groups/a/av/avra/htdocs + +all: help + +upload: htdocs_scp htdocs_chmod + +### +# Help message +### +help: + @echo "No command specified! Available commands:" + @echo + @echo "Current settings" + @echo "----------------" + @echo " User: ${USER}" + @echo " Hostname: ${HOSTNAME}" + @echo " Project: ${PROJECT}" + @echo " Remote htdoc: ${HTDOCS}" + @echo + @echo "Shell commands" + @echo "--------------" + @echo " * shell, open a shell" + @echo " * shell_create, create a shell" + @echo + @echo "htdocs commands" + @echo "---------------" + @echo " * htdocs_scp, copy all files from current dir to remote htdocs" + @echo " * htdocs_rm, remove all files from remote htdocs" + +### +# Shell +### +shell: + ssh ${USER},${PROJECT}@${HOSTNAME} + +shell_create: + ssh ${USER},${PROJECT}@${HOSTNAME} create + +### +# htdocs +### +htdocs_scp: + scp -r * ${USER}@${HOSTNAME}:${HTDOCS} + +htdocs_chmod: + ssh ${USER}@${HOSTNAME} chmod -Rv ug+rw ${HTDOCS}/* + +htdocs_rm: + ssh ${USER}@${HOSTNAME} rm -Rv ${HTDOCS}/* diff --git a/contrib/toolchain/avra/doc/README.html b/contrib/toolchain/avra/doc/README.html new file mode 100644 index 000000000..ac58a0c6e --- /dev/null +++ b/contrib/toolchain/avra/doc/README.html @@ -0,0 +1,759 @@ + + + + + + + + + + +README + + +
+
AVRA
+
Assember for the Atmel AVR microcontroller family
+
+ + + + + +
+ + + + + + + +
+ +
+

General and licensing information

+
+

AVRA v1.3.0 - Assember for the Atmel AVR microcontroller family

+

Licensing information

+

This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. Please read below for for information.

+

Disclaimer

+

This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details.

+

GNU General Public License

+

You should have received a copy of the GNU General Public License +along with this program; see the file "COPYING". If not, visit +http://www.gnu.org or write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You can +also contact the authors of AVRA to receive a copy of the COPYING file.

+
+

Atmel, AVR, AVR Studio, Intel, Windows are registered enterprises, brands +and registered trademarks. The mentioned companies have no relation to +AVRA and are therefore not responslible for any problems that occur when +using AVRA. Many thanks for your products, support and efforts.

+
+

Introducion

+
+

AVRA is an assembler for Atmel AVR microcontrollers, and it is almost +compatible with Atmel’s own assembler AVRASM32. The programming +principles and conceptions are based on the ANSI programming language "C".

+

The initial version of AVRA was written by John Anders Haugum. He released +all versions until v0.7. All later versions were released by Tobias Weber.

+

Differences between AVRA and AVRASM32

+

There are some differences between the original Atmel assembler AVRASM32 and AVRA. Basically AVRA is designed to replace AVRASM32 without special changes in your current Atmel AVR Studio enviroment. +Command line options have been adapted as far as it was possible until now. Jumping to fault containing line directly by double-clicking on the error message in the output window does work as with AVRASM32.

+

The differences in detail

+
    +
  • +

    +Support for some extra preprocessor directives. +

    +
    +
    +
    .define, .undef, .ifdef, .ifndef, .if, .else, .endif, .elif, .elseif, .warning
    +
    +
  • +
  • +

    +Not all command line options are supported. + Specifying an eeprom file (-e) is not supported. All eeprom data is + put out into a file called program.eep.hex and always Intel hex + format. Other hex file formats than Intel are currently not supported. +

    +
  • +
  • +

    +Forward references not supported for .ifdef and .ifndef directives. + This makes sure, that directives like .ifdef and .undef are working + properly. If you are familiar with the C programming language, you + should get easily into AVRA. See chapter "Programming techniques" for + more information about how to write proper code. +

    +
  • +
  • +

    +Enhanced macro support + AVRA has some new features for writing flexible macros. This should + increase the ability to reuse code e.g. build your own library. +

    +
  • +
  • +

    +Debugging support + AVRA creates a coff file everytime the assembly was sucessful. This + file allows AVR Studio or any coff compatible debugger to simulate + or emulate the program. +

    +
  • +
  • +

    +Meta tags for assembly time + This helps you tracking versions of your software and can also be + used to generate customer specific serial numbers. +

    +
  • +
+

Compatibility

+

Since AVRA is written in ANSI C, it should be possible to compile it on +most system platforms. If you have problems compiling AVRA, please leave +a message on the sourceforge message board or send a mail to the +authors of AVRA.

+
+

Installation

+
+

To install avra you should copy the avra-executable to an apropriate +location. To compile you should rename the appropriate makefile, and +perform a make (use smake for Amiga SAS/C, and nmake for Mickeysoft +visual c++).

+

Linux

+

To compile avra you need gcc and the automake utilities. These will create +a ./configure script that evaluates your system enviroment. To get the +AVRA executable, you have to issue the following commands:

+

aclocal +autoconf +automake -a +./configure +make && make install

+

AmigaOS

+

avra can be copied any apropriate directory. If you are using the source +distribution a make install will do the same.

+

Microsoft Windows

+

If you received the Windows binary package, look into the \bin +directory where you can find avra.exe. This should be copied to any +apropriate location. You can also overwrite AVRASM32.EXE in your +Atmel AVR Studio. If you want to compile it yourself you could download then +OpenWatcom C/C++ Toolchain for windows and create a new project and add the C +and H files to it and compile.

+

Apple OS X

+

If you recieved the Apple OS X binary package, look into the bin directory this +file is compiled universal and should run on intel 32 and 64 bit and powerpc. If +you want to compile it yourself go to the src directory and invoke make -f +makefiles/Makefiles.osx and then the executable should be created.

+
+

Synopsis

+
+

Command line usage

+
+
+
usage: AVRA [-f][O|M|I|G] output file type
+         [-o <filename>] output file name
+         [-l <filename>] generate list file
+         [-m <mapfile>] generate map file
+         [--define <symbol>[=<value>]]  [--includedir <dir>] [--listmac]
+         [--max_errors <number>] [--devices] [--version]
+         [-h] [--help] general help
+         [-W NoRegDef] supress register redefinition warnings
+         <file to assemble>
+
+

Parameter list

+
+
+
--listfile    -l : Create list file
+--mapfile     -m : Create map file
+--define      -D : Define symbol.
+--includedir  -I : Additional include dirs.
+--listmac        : List macro expansion in listfile.
+--max_errors     : Maximum number of errors before exit
+                   (default: 10)
+--devices        : List out supported devices.
+--version        : Version information.
+--help, -h       : This help text.
+
+

Warning supression

+

Since avra 1.1 there is a possibility to supress certain warnings. +Currently only register reassignment warnings can be supressed.

+

Example: avra -W NoRegDef

+
+

Programming techniques

+
+

Using directives

+

AVRA offers a number of directives that are not part of Atmel’s +assembler. These directives should help you creating versatile code that +can be designed more modular.

+

Directive .define

+

To define a constant, use ".define". This does the same thing as ".equ", +it is just a little more C style. Keep in mind that AVRA is not case +sensitive. Do not mix ".def" and ".define", because ".def" is used to +assign registers only. This is due to backward compatibility to Atmel’s +AVRASM32. Here is an example on how .define can be used.

+
+
+
.define network 1
+
+

Now "network" is set to the value 1. You may want to assemble a specific +part of your code depeding on a define or switch setting. You can test +your defined word on existence (.ifdef and .ifndef) as well as on the +value it represents. The following code shows a way to prevent error +messages due to testing undefined constants. Conditional directives must +always end with an .endif directive.

+
+
+
.ifndef network
+.define network 0
+.endif
+
+

Directive .if and .else

+

The three lines in the last example set the default value of "network". +In the next example, you see how we can use default values. If a constant +has not defined previously, it is set to zero. Now you can test wether +e.g. network support is included into the assemby process.

+
+
+
.if network = 1
+.include "include\tcpip.asm"
+.else
+.include "include\dummynet.asm"
+.endif
+
+

In the second part of the above listing you see the use of .else, which +defines the part of the condition that is being executed if the equation +of the preceding .if statement is not equal. You can also use the else +statement to test another equasion. For that purpose use .elif, which +means "else if". Always close this conditional part with ".endif"

+

Directive .error

+

This directive can be used to throw errors if a part in the code has reached +that should not be reached. The following example shows how we can stop +the assembly process if a particular value has not been previously set.

+
+
+
.ifndef network
+.error "network is not configured!" ;the assembler stops here
+
+

Directive .nolist and .list

+

The ouput to the list file can be paused by this two directives. After +avra discovers a .nolist while assembling, it stops output to the list file. +After a .list directive is detected, it continues the normal list file output.

+

Directive .includepath

+

By default, any file that is included from within the source file must +either be a single filename or a complete absolute path. With the directive +.includepath you can set an additional include path . Furthermore you can +set as many include paths as you want. Be sure not no use same filename +in separate includes, because then it is no longer clear which one avra +should take.

+
+

Using include files

+
+

To avoid multiple inclusions of include files, you may use some pre- +processor directives. See example file stack.asm that is being included +into the main programm file as well as in other include files.

+
+
+
.ifndef _STACK_ASM_
+.define _STACK_ASM_
+
+
+
+
.include "include/config.inc"
+
+
+
+
; *** stack macro ***
+
+
+
+
.dseg
+m_stack:    .byte __stack_size__
+.cseg
+
+
+
+
.macro      stack_setup
+    load    [v:w,m_stack + __stack_size__]
+    outp    [SPREG,v:w]
+.endm
+
+
+
+
.endif ; avoid multiple inclusion of stack.asm
+
+

Using build date meta tags

+

If you like to implement compiler build time and date into your +program, you can make use of some sepcial tags that avra supports.

+
+
+
%MINUTE%  is being replaced by the current minute (00-59)
+%HOUR%    is being replaced by the current hour (00-23)
+%DAY%     is being replaced by the current day of month (01-31)
+%MONTH%   is being replaced by the current month (01-12)
+%YEAR%    is being replaced by the current year (2004-9999)
+
+
+
+
buildtime: .db "Release date %DAY%.%MONTH%.%YEAR% %HOUR%:%MINUTE%"
+
+

This line will then assembled by avra into:

+
+
+
buildtime: .db "Release date 10.05.2004 19:54"
+
+

You may also create a self defined serial number with meta tags:

+
+
+
.define serialnumber %DAY% + %MONTH%*31 + (%YEAR% - 2000) *31*12
+
+

The %TAG% is translated before any other parsing happens. The real +output can be found in the list file.

+
+

Macro features

+
+

Sometimes you have to work with 16 bit or greater variables stored +in 8 bit registers. The enhanced macro support allows you to write short +and flexible macros that simplify access to big variables. The extended +mode is active, as soon as you use parenthesis like this "[ ]" to wrap +macro parameters.

+

Auto type conversion for macros

+

Values representing more than 8 Bits are usualy kept in a set of byte +wide registers. To simplify 16 Bit or greater operations, I added a new +language definitions. Words can be written as r16:r17, whereas register +r16 contains the higher part and register r17 the lower part of this +16 Bit value.

+

Macro data types

+

There are 3 data types that can be used. They will be added as character +separated by one underline character.

+
+
+
immediate values  _i
+registers         _8,_16,_24,_32,_40,_48,_56,_64
+void parameter    _v
+
+

16 Bit Source and Destionation registers dst and src

+
+
+
src = YH:YL
+dst = ZH:ZL
+
+

Within the parenthesis, the two words src and dst are interpreted as YH:YL +and ZH:ZL. Normal code outside of the macro parameter parenthesis can +still make use of these special key words "src" and "dst".

+

Examples for automatic type conversion

+

To simplify the parameters in the demonstration below, we need to +redefine some registers.

+
+
+
.def    a = r16   ; general purpose registers
+.def    b = r17
+.def    c = r18
+.def    d = r19
+
+
+
+
.def    w = r20   ; working register
+.def    v = r21   ; working register
+
+

If we substract 16 Bit values stored in a, higher byte and b, lower byte +with that in c:d, we usually have to use the following command sequence:

+
+
+
sub     b,d
+sbc     a,c
+
+

Now we can do the following steps to simplify 16 or more Bit manipulations

+
+
+
.macro  subs
+.message "no parameters specified"
+.endm
+
+
+
+
.macro  subs_16_16
+sub     @1,@3
+sbc     @0,@2
+.endm
+
+
+
+
.macro  subs_16_8
+sub     @1,@2
+sbci    @0,0
+.endm
+
+
+
+
;now we can write a 16 Bit subraction as:
+
+
+
+
subs    [a:b,c:d]
+
+
+
+
;or for calculating 16 minus 8 Bit
+
+
+
+
subs    [a:b,c]
+
+

Overloading macros

+

Like in you are used to C functions, you can write macros for different +parameter lists. If you would like to have a versatile macro, you can +specify a unique macro for each parameter situation. See the next sample.

+
+
+
.macro  load
+
+
+
+
; this message is shown if you use the macro within your code
+; specifying no parameters. If your macro allows the case where
+; no parameters are given, exchange .message with your code.
+
+
+
+
.message "no parameters specified"
+.endm
+
+
+
+
; Here we define the macro "load" for the case it is being used
+; with two registers as first parameter and a immediate (constant)
+; value as second parameter.
+
+
+
+
.macro  load_16_i
+ldi     @0,high(@2)
+ldi     @1,low(@2)
+.endm
+
+
+
+
; the same case, but now with a 32 bit register value as first
+; parameter
+
+
+
+
.macro  load_32_i
+ldi     @0,BYTE4(@4)
+ldi     @1,BYTE3(@4)
+ldi     @2,high(@4)
+ldi     @3,low(@4)
+.endm
+
+
+
+
; Now let's see how these macros are being used in the code
+
+
+
+
load    [a:b,15]     ;uses macro load_16_i to load immediate
+
+
+
+
load    [a:b:c:d,15] ;uses macro load_32_i to load immediate
+
+

More examples

+
+
+
.dseg
+counter  .byte 2
+.cseg
+
+
+
+
.macro   poke
+.message "no parameters"
+.endm
+
+
+
+
.macro   poke_i_16_i
+ldi      @1,high(@3)
+sts      @0+0,@1
+ldi      @2,low(@3)
+sts      @0+1,@2
+.endm
+
+
+
+
.macro   poke_i_i
+ldi      w,@1
+sts      @0+0,w
+.endm
+
+
+
+
.macro   poke_i_v_i
+ldi      w,high(@3)
+sts      @0+0,w
+ldi      w,low(@3)
+sts      @0+1,w
+.endm
+
+
+
+
.macro   poke_i_v_v_v_i
+ldi      w,high(@3)
+sts      @0+0,w
+ldi      w,low(@3)
+sts      @0+1,w
+ldi      w,BYTE3(@3)
+sts      @0+2,w
+ldi      w,BYTE4(@3)
+sts      @0+3,w
+.endm
+
+
+
+
; this writes '9999' into the memory at 'counter'
+; uses only the working register for transfering the values.
+
+
+
+
poke     [counter,w:w,9999]
+
+
+
+
; works same as above, but the transferred value '9999' is also
+; kept in the pair of register a:b
+
+
+
+
poke     [counter,a:b,9999]
+
+
+
+
; in my design 'w' is always working reg. which implies that
+; it cannot be used for normal variables. The following example
+; uses poke_i_i because the parameter contains two immediate values.
+
+
+
+
poke     [counter,9999] ;uses poke_i_i
+
+
+
+
; to be able to choose between a 8,16 or 32 Bit operation, you just
+; add a void parameter.
+
+
+
+
poke     [counter,,9999] ;uses poke_i_v_i
+
+
+
+
; and the same for 32 Bit pokes
+
+
+
+
poke     [counter,,,,9999] ;uses poke_i_v_v_v_i
+
+

Loops within macros

+

One problem you may have experienced, is that labels defined within macros +are defined twice if you call the macro for example two times. Now you can +use labels for macro loops. Loops within macros must end with _%. the +"%" symbol is replaced by a running number.

+

Loop example

+
+
+
; Definition of the macro
+
+
+
+
.macro   write_8_8
+write_%:
+     st      Z+,@0
+     dec     @1
+     brne    write_%
+.endm
+
+
+
+
; Use in user code
+
+
+
+
write   [a,b]
+write   [c,d]
+
+
+
+
; After assembling this code, the result looks like this
+
+
+
+
write_1:
+     st          Z+,a
+     dec         b
+     brne        write_1
+write_2:
+     st          Z+,c
+     dec         d
+     brne        write_2
+
+
+

Warnings and Errors

+
+

Some errors and warnings may confuse you a little bit so we will try to +clear some frequently asked questions about such cases.

+

Constant out of range

+

This warning occurs if a value exceeds the byte or word value of a assignment. +Read the comment posted by Jim Galbraith:

+

The expression (~0x80) is a Bitwise Not operation. This +operator returns the input expression with all its bits +inverted. If 0x80 represents -128, then 0x7f, or +127 +should be ok. If this is considered as a 32-bit expression +(AVRA internal representation), then it appears to be more +like oxffffffff-0x80 or 0xffffffff0x80. The result would then +be 0xffffff7f. The assembler would then have to be told or it +would have to decide, based on context, how much +significance to assign to the higher bits. I have also +encountered such conditions with various assemblers, +including AVRA. To make sure the assembler does what I +really want, I use a construct like 0xff-0x80 or 0xff0x80. +This way the bit significance cannot extend beyond bit-7 and +there cannot be any misunderstanding.

+

Can’t use .DB directive in data segment

+
DB and .DW is only used to assign constant data in eeprom or code space.

The reason why using it within data segment is forbidden is, that you +cannot set ram content at assembly time. The values must be programmed into +ROM area and at boot read from ROM into RAM. This is up to the user code. +You can only allocate memory for your variables using labels and the .byte +directive.

+
+
+
.dseg
+my_string: .byte 15
+
+

BYTE directive

+
BYTE directive can only be used in data segment (.DSEG)

This directive cannot be used in code or eeprom region because this only +allocates memory without assgning distinct values to it. Please use .db +or .dw instead.

+

Internal assembler error

+

If you get an "Internal assembler error" please contact the project maintainer +by sending him a code example and a description of your working enviroment.

+
+

AVRA internals

+
+

This section provides thoughts of the avra internal design. I have to admit +that the code of avra is anything else than clean and optimized. To increase +the code readability I will try to give you some standards that should improve +quality. The following standards are similar to what GNU proposes.

+

Coding standards

+

Tab space is always 2 spaces. The Tab character (ascii 9) is not used. +if,while,for are always opened on the same line but closed on the next line. +The closing bracket is in the same column as the first letter of the loop +directive.

+
+
+
Example:
+
+
+
+
    while(i > 0) {
+     do_something();
+    }
+
+
+

Credits

+
+

We would like to thank the following people for giving contributions, +patches and bug reports, as well as suggestions and new ideas.

+
+
+
      Jon Anders Haugum (project founder)
+      Burkhard Arenfeld (release 1.2.0)
+      Tobias Weber (old maintainer)
+      Jerry Jacobs (release 1.3.0)
+      Bernt Hembre
+      Nils Strøm
+      Roberto Biancardi
+      Qwerty Jones
+      Ben Hitchcock (Maker of the mac port)
+      Daniel Drotos
+      Laurence Boyd II
+      Varuzhan Danielyan
+      Laurence Turner
+      Eugene R. O'Bryan
+      Dmitry Dicky
+      Bob Harris (Maker of coff support)
+      Tobias Weber (enhanced macro support)
+      Lesha Bogdanow
+      Jim Galbraith
+      Mark Brinicombe
+      Igor Nikolayenko
+      Peter Hettkamp
+      Herb Poppe
+      David Burke
+      Alexey Pavluchenko
+      Alan Probandt
+      Mariusz Matuszek
+      Arne Rossius
+      Marti Tichacek
+      Patrick Parity
+      Johannes Overmann
+      Roland Riegel
+      Peter Katzmann
+      Donald D. Davis
+
+

And all the anonymous people who submitted patches!

+

Thank you for your work and support.

+
+

References

+
+
+
+
http://www.suprafluid.com/avra
+http://www.avrfreaks.de
+http://www.atmel.com
+
+
+
+

+ +
+
+ + diff --git a/contrib/toolchain/avra/doc/README.txt b/contrib/toolchain/avra/doc/README.txt new file mode 100644 index 000000000..9c34bdbb8 --- /dev/null +++ b/contrib/toolchain/avra/doc/README.txt @@ -0,0 +1,679 @@ +README +====== + +General and licensing information +--------------------------------- +AVRA v1.3.0 - Assember for the Atmel AVR microcontroller family + +Licensing information +~~~~~~~~~~~~~~~~~~~~~ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. Please read below for for information. + +Disclaimer +~~~~~~~~~~ + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +GNU General Public License +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You should have received a copy of the GNU General Public License +along with this program; see the file "COPYING". If not, visit +http://www.gnu.org or write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You can +also contact the authors of AVRA to receive a copy of the COPYING file. + +Trademarks and copyright +~~~~~~~~~~~~~~~~~~~~~~~~ + +Atmel, AVR, AVR Studio, Intel, Windows are registered enterprises, brands +and registered trademarks. The mentioned companies have no relation to +AVRA and are therefore not responslible for any problems that occur when +using AVRA. Many thanks for your products, support and efforts. + + +Introducion +----------- + +AVRA is an assembler for Atmel AVR microcontrollers, and it is almost +compatible with Atmel's own assembler AVRASM32. The programming +principles and conceptions are based on the ANSI programming language "C". + +The initial version of AVRA was written by John Anders Haugum. He released +all versions until v0.7. All later versions were released by Tobias Weber. + + +Differences between AVRA and AVRASM32 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are some differences between the original Atmel assembler AVRASM32 and AVRA. Basically AVRA is designed to replace AVRASM32 without special changes in your current Atmel AVR Studio enviroment. +Command line options have been adapted as far as it was possible until now. Jumping to fault containing line directly by double-clicking on the error message in the output window does work as with AVRASM32. + +The differences in detail +~~~~~~~~~~~~~~~~~~~~~~~~~ + + - Support for some extra preprocessor directives. + + .define, .undef, .ifdef, .ifndef, .if, .else, .endif, .elif, .elseif, .warning + + - Not all command line options are supported. + Specifying an eeprom file (-e) is not supported. All eeprom data is + put out into a file called program.eep.hex and always Intel hex + format. Other hex file formats than Intel are currently not supported. + + - Forward references not supported for .ifdef and .ifndef directives. + This makes sure, that directives like .ifdef and .undef are working + properly. If you are familiar with the C programming language, you + should get easily into AVRA. See chapter "Programming techniques" for + more information about how to write proper code. + + - Enhanced macro support + AVRA has some new features for writing flexible macros. This should + increase the ability to reuse code e.g. build your own library. + + - Debugging support + AVRA creates a coff file everytime the assembly was sucessful. This + file allows AVR Studio or any coff compatible debugger to simulate + or emulate the program. + + - Meta tags for assembly time + This helps you tracking versions of your software and can also be + used to generate customer specific serial numbers. + + +Compatibility +~~~~~~~~~~~~~ + +Since AVRA is written in ANSI C, it should be possible to compile it on +most system platforms. If you have problems compiling AVRA, please leave +a message on the sourceforge message board or send a mail to the +authors of AVRA. + + +Installation +------------ + +To install avra you should copy the avra-executable to an apropriate +location. To compile you should rename the appropriate makefile, and +perform a make (use smake for Amiga SAS/C, and nmake for Mickeysoft +visual c++). + + +Linux +~~~~~ + +To compile avra you need gcc and the automake utilities. These will create +a ./configure script that evaluates your system enviroment. To get the +AVRA executable, you have to issue the following commands: + +aclocal +autoconf +automake -a +./configure +make && make install + +AmigaOS +~~~~~~~ + +avra can be copied any apropriate directory. If you are using the source +distribution a 'make install' will do the same. + + +Microsoft Windows +~~~~~~~~~~~~~~~~~ + +If you received the Windows binary package, look into the \bin +directory where you can find avra.exe. This should be copied to any +apropriate location. You can also overwrite AVRASM32.EXE in your +Atmel AVR Studio. If you want to compile it yourself you could download then +OpenWatcom C/C++ Toolchain for windows and create a new project and add the C +and H files to it and compile. + +Apple OS X +~~~~~~~~~~ + +If you recieved the Apple OS X binary package, look into the bin directory this +file is compiled universal and should run on intel 32 and 64 bit and powerpc. If +you want to compile it yourself go to the src directory and invoke `make -f +makefiles/Makefiles.osx` and then the executable should be created. + + +Synopsis +-------- + +Command line usage +~~~~~~~~~~~~~~~~~~ + + usage: AVRA [-f][O|M|I|G] output file type + [-o ] output file name + [-l ] generate list file + [-m ] generate map file + [--define [=]] [--includedir ] [--listmac] + [--max_errors ] [--devices] [--version] + [-h] [--help] general help + [-W NoRegDef] supress register redefinition warnings + + + +Parameter list +~~~~~~~~~~~~~~ + + --listfile -l : Create list file + --mapfile -m : Create map file + --define -D : Define symbol. + --includedir -I : Additional include dirs. + --listmac : List macro expansion in listfile. + --max_errors : Maximum number of errors before exit + (default: 10) + --devices : List out supported devices. + --version : Version information. + --help, -h : This help text. + + +Warning supression +~~~~~~~~~~~~~~~~~~ + +Since avra 1.1 there is a possibility to supress certain warnings. +Currently only register reassignment warnings can be supressed. + +Example: avra -W NoRegDef + + +Programming techniques +---------------------- + + +Using directives +~~~~~~~~~~~~~~~~ + +AVRA offers a number of directives that are not part of Atmel's +assembler. These directives should help you creating versatile code that +can be designed more modular. + +Directive .define +^^^^^^^^^^^^^^^^^ + +To define a constant, use ".define". This does the same thing as ".equ", +it is just a little more C style. Keep in mind that AVRA is not case +sensitive. Do not mix ".def" and ".define", because ".def" is used to +assign registers only. This is due to backward compatibility to Atmel's +AVRASM32. Here is an example on how .define can be used. + + .define network 1 + +Now "network" is set to the value 1. You may want to assemble a specific +part of your code depeding on a define or switch setting. You can test +your defined word on existence (.ifdef and .ifndef) as well as on the +value it represents. The following code shows a way to prevent error +messages due to testing undefined constants. Conditional directives must +always end with an .endif directive. + + .ifndef network + .define network 0 + .endif + +Directive .if and .else +^^^^^^^^^^^^^^^^^^^^^^^ + +The three lines in the last example set the default value of "network". +In the next example, you see how we can use default values. If a constant +has not defined previously, it is set to zero. Now you can test wether +e.g. network support is included into the assemby process. + + .if network = 1 + .include "include\tcpip.asm" + .else + .include "include\dummynet.asm" + .endif + +In the second part of the above listing you see the use of .else, which +defines the part of the condition that is being executed if the equation +of the preceding .if statement is not equal. You can also use the else +statement to test another equasion. For that purpose use .elif, which +means "else if". Always close this conditional part with ".endif" + +Directive .error +^^^^^^^^^^^^^^^^ + +This directive can be used to throw errors if a part in the code has reached +that should not be reached. The following example shows how we can stop +the assembly process if a particular value has not been previously set. + + .ifndef network + .error "network is not configured!" ;the assembler stops here + +Directive .nolist and .list +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ouput to the list file can be paused by this two directives. After +avra discovers a .nolist while assembling, it stops output to the list file. +After a .list directive is detected, it continues the normal list file output. + +Directive .includepath +^^^^^^^^^^^^^^^^^^^^^^ + +By default, any file that is included from within the source file must +either be a single filename or a complete absolute path. With the directive +.includepath you can set an additional include path . Furthermore you can +set as many include paths as you want. Be sure not no use same filename +in separate includes, because then it is no longer clear which one avra +should take. + +Using include files +------------------- + +To avoid multiple inclusions of include files, you may use some pre- +processor directives. See example file stack.asm that is being included +into the main programm file as well as in other include files. + + .ifndef _STACK_ASM_ + .define _STACK_ASM_ + + .include "include/config.inc" + + ; *** stack macro *** + + .dseg + m_stack: .byte __stack_size__ + .cseg + + .macro stack_setup + load [v:w,m_stack + __stack_size__] + outp [SPREG,v:w] + .endm + + .endif ; avoid multiple inclusion of stack.asm + + +Using build date meta tags +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you like to implement compiler build time and date into your +program, you can make use of some sepcial tags that avra supports. + + %MINUTE% is being replaced by the current minute (00-59) + %HOUR% is being replaced by the current hour (00-23) + %DAY% is being replaced by the current day of month (01-31) + %MONTH% is being replaced by the current month (01-12) + %YEAR% is being replaced by the current year (2004-9999) + + buildtime: .db "Release date %DAY%.%MONTH%.%YEAR% %HOUR%:%MINUTE%" + +This line will then assembled by avra into: + + buildtime: .db "Release date 10.05.2004 19:54" + +You may also create a self defined serial number with meta tags: + + .define serialnumber %DAY% + %MONTH%*31 + (%YEAR% - 2000) *31*12 + +The %TAG% is translated before any other parsing happens. The real +output can be found in the list file. + +Macro features +-------------- + +Sometimes you have to work with 16 bit or greater variables stored +in 8 bit registers. The enhanced macro support allows you to write short +and flexible macros that simplify access to big variables. The extended +mode is active, as soon as you use parenthesis like this "[ ]" to wrap +macro parameters. + +Auto type conversion for macros +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Values representing more than 8 Bits are usualy kept in a set of byte +wide registers. To simplify 16 Bit or greater operations, I added a new +language definitions. Words can be written as r16:r17, whereas register +r16 contains the higher part and register r17 the lower part of this +16 Bit value. + +Macro data types +^^^^^^^^^^^^^^^^ + +There are 3 data types that can be used. They will be added as character +separated by one underline character. + + immediate values _i + registers _8,_16,_24,_32,_40,_48,_56,_64 + void parameter _v + +16 Bit Source and Destionation registers 'dst' and 'src' + + src = YH:YL + dst = ZH:ZL + +Within the parenthesis, the two words src and dst are interpreted as YH:YL +and ZH:ZL. Normal code outside of the macro parameter parenthesis can +still make use of these special key words "src" and "dst". + +Examples for automatic type conversion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To simplify the parameters in the demonstration below, we need to +redefine some registers. + + .def a = r16 ; general purpose registers + .def b = r17 + .def c = r18 + .def d = r19 + + .def w = r20 ; working register + .def v = r21 ; working register + +If we substract 16 Bit values stored in a, higher byte and b, lower byte +with that in c:d, we usually have to use the following command sequence: + + sub b,d + sbc a,c + +Now we can do the following steps to simplify 16 or more Bit manipulations + + .macro subs + .message "no parameters specified" + .endm + + .macro subs_16_16 + sub @1,@3 + sbc @0,@2 + .endm + + .macro subs_16_8 + sub @1,@2 + sbci @0,0 + .endm + + ;now we can write a 16 Bit subraction as: + + subs [a:b,c:d] + + ;or for calculating 16 minus 8 Bit + + subs [a:b,c] + + +Overloading macros +~~~~~~~~~~~~~~~~~~ + +Like in you are used to C functions, you can write macros for different +parameter lists. If you would like to have a versatile macro, you can +specify a unique macro for each parameter situation. See the next sample. + + .macro load + + ; this message is shown if you use the macro within your code + ; specifying no parameters. If your macro allows the case where + ; no parameters are given, exchange .message with your code. + + .message "no parameters specified" + .endm + + ; Here we define the macro "load" for the case it is being used + ; with two registers as first parameter and a immediate (constant) + ; value as second parameter. + + .macro load_16_i + ldi @0,high(@2) + ldi @1,low(@2) + .endm + + ; the same case, but now with a 32 bit register value as first + ; parameter + + .macro load_32_i + ldi @0,BYTE4(@4) + ldi @1,BYTE3(@4) + ldi @2,high(@4) + ldi @3,low(@4) + .endm + + ; Now let's see how these macros are being used in the code + + load [a:b,15] ;uses macro load_16_i to load immediate + + load [a:b:c:d,15] ;uses macro load_32_i to load immediate + + +More examples +~~~~~~~~~~~~~ + + .dseg + counter .byte 2 + .cseg + + .macro poke + .message "no parameters" + .endm + + .macro poke_i_16_i + ldi @1,high(@3) + sts @0+0,@1 + ldi @2,low(@3) + sts @0+1,@2 + .endm + + .macro poke_i_i + ldi w,@1 + sts @0+0,w + .endm + + .macro poke_i_v_i + ldi w,high(@3) + sts @0+0,w + ldi w,low(@3) + sts @0+1,w + .endm + + .macro poke_i_v_v_v_i + ldi w,high(@3) + sts @0+0,w + ldi w,low(@3) + sts @0+1,w + ldi w,BYTE3(@3) + sts @0+2,w + ldi w,BYTE4(@3) + sts @0+3,w + .endm + + + ; this writes '9999' into the memory at 'counter' + ; uses only the working register for transfering the values. + + poke [counter,w:w,9999] + + ; works same as above, but the transferred value '9999' is also + ; kept in the pair of register a:b + + poke [counter,a:b,9999] + + ; in my design 'w' is always working reg. which implies that + ; it cannot be used for normal variables. The following example + ; uses poke_i_i because the parameter contains two immediate values. + + poke [counter,9999] ;uses poke_i_i + + ; to be able to choose between a 8,16 or 32 Bit operation, you just + ; add a void parameter. + + poke [counter,,9999] ;uses poke_i_v_i + + ; and the same for 32 Bit pokes + + poke [counter,,,,9999] ;uses poke_i_v_v_v_i + +Loops within macros +~~~~~~~~~~~~~~~~~~~ + +One problem you may have experienced, is that labels defined within macros +are defined twice if you call the macro for example two times. Now you can +use labels for macro loops. Loops within macros must end with '_%'. the +"%" symbol is replaced by a running number. + +Loop example +^^^^^^^^^^^^ + + ; Definition of the macro + + .macro write_8_8 + write_%: + st Z+,@0 + dec @1 + brne write_% + .endm + + ; Use in user code + + write [a,b] + write [c,d] + + ; After assembling this code, the result looks like this + + write_1: + st Z+,a + dec b + brne write_1 + write_2: + st Z+,c + dec d + brne write_2 + +Warnings and Errors +------------------- + +Some errors and warnings may confuse you a little bit so we will try to +clear some frequently asked questions about such cases. + +Constant out of range +~~~~~~~~~~~~~~~~~~~~~ + +This warning occurs if a value exceeds the byte or word value of a assignment. +Read the comment posted by Jim Galbraith: + +The expression (~0x80) is a Bitwise Not operation. This +operator returns the input expression with all its bits +inverted. If 0x80 represents -128, then 0x7f, or +127 +should be ok. If this is considered as a 32-bit expression +(AVRA internal representation), then it appears to be more +like oxffffffff-0x80 or 0xffffffff^0x80. The result would then +be 0xffffff7f. The assembler would then have to be told or it +would have to decide, based on context, how much +significance to assign to the higher bits. I have also +encountered such conditions with various assemblers, +including AVRA. To make sure the assembler does what I +really want, I use a construct like 0xff-0x80 or 0xff^0x80. +This way the bit significance cannot extend beyond bit-7 and +there cannot be any misunderstanding. + +Can't use .DB directive in data segment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.DB and .DW is only used to assign constant data in eeprom or code space. +The reason why using it within data segment is forbidden is, that you +cannot set ram content at assembly time. The values must be programmed into +ROM area and at boot read from ROM into RAM. This is up to the user code. +You can only allocate memory for your variables using labels and the .byte +directive. + + .dseg + my_string: .byte 15 + +BYTE directive +~~~~~~~~~~~~~~ + +.BYTE directive can only be used in data segment (.DSEG) + +This directive cannot be used in code or eeprom region because this only +allocates memory without assgning distinct values to it. Please use .db +or .dw instead. + +Internal assembler error +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you get an "Internal assembler error" please contact the project maintainer +by sending him a code example and a description of your working enviroment. + + +AVRA internals +-------------- + +This section provides thoughts of the avra internal design. I have to admit +that the code of avra is anything else than clean and optimized. To increase +the code readability I will try to give you some standards that should improve +quality. The following standards are similar to what GNU proposes. + +Coding standards +~~~~~~~~~~~~~~~~ + +Tab space is always 2 spaces. The Tab character (ascii 9) is not used. +if,while,for are always opened on the same line but closed on the next line. +The closing bracket is in the same column as the first letter of the loop +directive. + + Example: +---- + while(i > 0) { + do_something(); + } +---- + + +Credits +------- + +We would like to thank the following people for giving contributions, +patches and bug reports, as well as suggestions and new ideas. + +---- + Jon Anders Haugum (project founder) + Burkhard Arenfeld (release 1.2.0) + Tobias Weber (old maintainer) + Jerry Jacobs (release 1.3.0) + Bernt Hembre + Nils Strøm + Roberto Biancardi + Qwerty Jones + Ben Hitchcock (Maker of the mac port) + Daniel Drotos + Laurence Boyd II + Varuzhan Danielyan + Laurence Turner + Eugene R. O'Bryan + Dmitry Dicky + Bob Harris (Maker of coff support) + Tobias Weber (enhanced macro support) + Lesha Bogdanow + Jim Galbraith + Mark Brinicombe + Igor Nikolayenko + Peter Hettkamp + Herb Poppe + David Burke + Alexey Pavluchenko + Alan Probandt + Mariusz Matuszek + Arne Rossius + Marti Tichacek + Patrick Parity + Johannes Overmann + Roland Riegel + Peter Katzmann + Donald D. Davis +---- + +And all the anonymous people who submitted patches! + +Thank you for your work and support. + +References +---------- + + http://www.suprafluid.com/avra + http://www.avrfreaks.de + http://www.atmel.com diff --git a/contrib/toolchain/avra/doc/asciidoc-xhtml11.js b/contrib/toolchain/avra/doc/asciidoc-xhtml11.js new file mode 100644 index 000000000..30d738ab0 --- /dev/null +++ b/contrib/toolchain/avra/doc/asciidoc-xhtml11.js @@ -0,0 +1,128 @@ +var asciidoc = { // Namespace. + +///////////////////////////////////////////////////////////////////// +// Table Of Contents generator +///////////////////////////////////////////////////////////////////// + +/* Author: Mihai Bazon, September 2002 + * http://students.infoiasi.ro/~mishoo + * + * Table Of Content generator + * Version: 0.4 + * + * Feel free to use this script under the terms of the GNU General Public + * License, as long as you do not remove or alter this notice. + */ + + /* modified by Troy D. Hanson, September 2006. License: GPL */ + /* modified by Stuart Rackham, 2006, 2009. License: GPL */ + +// toclevels = 1..4. +toc: function (toclevels) { + + function getText(el) { + var text = ""; + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants. + text += i.data; + else if (i.firstChild != null) + text += getText(i); + } + return text; + } + + function TocEntry(el, text, toclevel) { + this.element = el; + this.text = text; + this.toclevel = toclevel; + } + + function tocEntries(el, toclevels) { + var result = new Array; + var re = new RegExp('[hH]([2-'+(toclevels+1)+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i" + + "" + + n + ". " + note + ""; + spans[i].innerHTML = + "[" + n + "]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i" + n + "]"; + } + } + } +} + +} diff --git a/contrib/toolchain/avra/doc/build-website.sh b/contrib/toolchain/avra/doc/build-website.sh new file mode 100755 index 000000000..9c7c25e79 --- /dev/null +++ b/contrib/toolchain/avra/doc/build-website.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +VERS="1.3.0" +DATE="2010-06-28" + +ASCIIDOC_HTML="asciidoc --unsafe --backend=xhtml11 --conf-file=layout1.conf --attribute icons --attribute iconsdir=./images/icons --attribute=badges --attribute=revision=$VERS --attribute=date=$DATE" + +$ASCIIDOC_HTML -a index-only index.txt +$ASCIIDOC_HTML ChangeLog.txt +$ASCIIDOC_HTML downloads.txt +$ASCIIDOC_HTML README.txt diff --git a/contrib/toolchain/avra/doc/downloads.html b/contrib/toolchain/avra/doc/downloads.html new file mode 100644 index 000000000..be8f1fb72 --- /dev/null +++ b/contrib/toolchain/avra/doc/downloads.html @@ -0,0 +1,75 @@ + + + + + + + + + + +Downloads + + +
+
AVRA
+
Assember for the Atmel AVR microcontroller family
+
+ + + + + +
+ + + + + + + +
+ +
+
+
+

The latest release can always be downloaded from sourceforge.

+ +
+
+
+

+ +
+
+ + diff --git a/contrib/toolchain/avra/doc/downloads.txt b/contrib/toolchain/avra/doc/downloads.txt new file mode 100644 index 000000000..2c1c77b61 --- /dev/null +++ b/contrib/toolchain/avra/doc/downloads.txt @@ -0,0 +1,6 @@ +Downloads +========= + +The latest release can always be downloaded from sourceforge. + +http://sourceforge.net/projects/avra/files diff --git a/contrib/toolchain/avra/doc/images/highlighter.png b/contrib/toolchain/avra/doc/images/highlighter.png new file mode 100644 index 0000000000000000000000000000000000000000..ad1090b380d71a639e25a1f14d4c90a6f35962a1 GIT binary patch literal 72099 zcmeFZbySpH*glGYl1g_BDBY-p)Bu8{bceuD(%mHjl7dQugfv5UGt__*B8}1@HMDfi zoQL=IeP6%d`PTXG{Bzb>Yu17po_Y3u?tSmQuj{(6O{AKN++AF1Tr@Pay9)9$8fa)3 zZ_&`u+p*DsPa-SqzXLyRxoOBrqm_T9-2~oXT1!2bLPM*H!@DxO4ZLSCm)CfXhUUwH zhW08H4ebK>=+y=qng<^m8p0F}O(X>kjl%h3v$_}>8Y)&nMoP>3#daIctQI`+6m$|` zlJGpK;}x}qdV;JcDbYJw2K)+Y6BL3^9sPdJt=EGw_wOr7lPbUF>W__#z16+nj)4%x zRu_D4d{T*9?Nq&r3VE&QlPoe3&~mvMm}wFevAKTIq+Qs)t~F;eRc4s6B{%h=!NdPq zTj$oEF3;Af|5J1($^TyL4DUF-=#2+@!<>wR7P3z(GCwwM>+U%Pu6CE@B3pNkZ(qs% zcQx=$c4jm(Ty9)hTw`1h-vE}n>jAvx>kB31gImN5|Gt9V8PGg@j~&6tDa-9&jw`T5 z@E?D@MJ$hnu2wkZVS8#4)EV?=cbMKuU>0eze^YpcDgV!F^nHg%#>IXGj1T2OiOf1} zdn{BCMDW%C!5$j)0S)Kfzc0yI%vzP}t!@~y50*7Mb}^xA5-@ar9Bp!yDDQj*rVZP_z zAL`3yZ*8d3pG{;nx5xVJp;E}&0-cXo$t%jY#xr5(T~||x&Tx~!^VKTzzE~O|$F5Ku z*!7OnCz*xTgNx(3sWZEZDU+b<_j2^-Q$g2LAfc_@-_Idwi_Lbuj!N$Mp?|jMMjy~g&_16S;O%~P6tL13kdb_FJ z-Il%GnFd}DTlDx>vhUGw8cDugsBX$1k~I_@P0<@$KI84oz~R0b6$S;&GztEG@HF(n z8C&IOEN_so?GF>v%7DEFf|IOo=V0<>(EOq*ZI2uup*upA)!z)+?T_HBXnjp{satOJ zB;exc;&_VyB++U$lvZaqwG7*9zvR)fFI36MR-4#@sIH6GF z*J8wN?n~9C)6@pTqoDQ9WbnnNQ#pYrM^Se05tzsL8iGXHG#ned#F3uj{94r&q_W9?hP-0(yFQH%Y|w@s)Am z9i6G`x2hsn%R-8YFXExFPVhCW1ma1ceoEHVx+dy;h<7Nc477a!LLGo+8l2=J2aF<7IB112kGmS5&tdK z0sebPpYH|r7)U$p=Qms(K`t3fb9m;(yjDsf2SU+a9ncJg#h zz3>?UzY?(8e0D`2Lc;7sj!~DvOn1dLTR`KkI7621=|6M) zJifwQuRCbyAqIgj$Bx7=UV^*+W8=kVBv?D`##6;{%0`yR5Eb|#(t8@Ddi1m`mg>>KRm`eJsA3~In8;BE>L9P zXFF94#T+Z`qsbC`vxBi zWVhlvf8fxm_!8-NFR*a$a)m*nTFcA05V^fGu?7>Q^TP*8(EcJd)Vxb4QtL2N5Axr? zMgQ?fvj-J*f9fZ%aSI2V27uFA0?-@iCYwnv2 zg9jqxTAR>)-PhZ@D?5W)?)l=OjlWT-7DCp`SUn!aA zMXUExR~Rs#SMKg!?#(n**iDrOi%k46ck?Z#bdkTd&QT%!2e9_(AA#QzPKIHRyhn2c zW(XF9ypw<)N9SmY7dD*1f0`G5&6&@NyCjS@S?4+DP%A7T#`}8`@}ZZ#cIN=PdOI`c zPID!RU(A*Fb_`rG&(qIrSyc`Ny6UE3);=J@@3L(z*F?d<{+39)vEuc2j87S~`Lm!e zN^~oFgHSsQ$TDDy2_9CTu=zgrM>khl5IcMp^IJ6%bM<>Icoe)@5~tVeTV4eITPyP` z62~c>52I9$KhFDY7h)_JHC`_A2aJLLNB|OpOLn zpUuoWap?%QEu4W<6yP_TO(k{3);Q~ezBSVBRE>9g2?aw=p%88>$Fpw3o2N)2JsM}b zk{6lMXRJ4iY+lN%=B5hH9e!Jvnf1bj%k3FpI()k3UB5c40BeGL2F2tCRgLHUR8Z>& zS#|Wn&$;C%P+f@U{2-mbV2Hl-;z1;*Z(BVfO297Ys_az={VA~V78d$DAWLSNt=s$z zCR;(9kuem01Dvd z*7Gwx|2L3Qt1@>LooaX%_dg)TXmH1)J%{#kO^~1U;VXT^tn{J(`>nq@ITh7B1frHffIYjOE7Qqo>%;+li5ZT<=K`l)^p19uAULt$Lp_+6}s18&FE!u z4_k{9u79xCP23nhb~GoV4%5}23Rai|tPOrSTvy2w^+U|2##^gq3Hu?=QZ@U&eiZXu zo?fcZ4LsS+d!IgaJ&^z%FIMLKqffz1#NOAdNITeB));GCrdZ(5o{^`0v9!V$I}#fs z53oEz^RUC20MUEMo%HLLhO5&o>(;}q@M>G5K}`he>e zm#4*=sbYWPNcQ`DkbRg@qw@>k5--QAx#>oCMEc$NE5Bjb3TQsB==lg#eSSHsFr{*3 z#I_~Svk85bMew6{?Z619c)8K0&#H7BUXa7()TL81m@#ZiT7v|SNGm&7B0?zH&q(6O z@kWfF)m7t09Ep-7SDDpF8c6VZ-~P158KX*gZs+K=AH`$tF)gtXCp8AI;1RDFiTUHk z@3q4HI0M}%$MXe5E;Dy>#30-^H<>|43gdT>A`)Mj6b5>|+$#_mxVN`pIe!{wQt0>+ zCS{C1)nEcDanpxn`DPe2$jt3E`&&a(nIhke_ei?~kN9KpG90$2^+~gTbdi-g&=opU zEOQ&;e|><=$!U;H_9?$?dhLTt-mkfF)x9pe25B2nA}qY+0v2TFwN0H-#*Fveuh+nt+`w%9G9ZmnvH($>Rx`m*l!!!P|#VzT0^Rq3A zd)hlX+_vp(!9%KtdM~$Sf05hh)PK*~yRH#&ZJlxP&Xl~Dlq2DYtb)1^1=vw1I)+M$ z861yP?4l5;`YV`=uygj|Ep6(YR9>%kVMS~)*$|PDot^-pxp0M3O=HxjvXydXxDBWw zOYHq$(~Uunh|dFYuy+r6Ja!wk4qh;Z`F=-TZ?q+%YBs*j?;xH)g*_0eC0FC)#cj|d z#h^y^c2ltawSx8vg#+w!I;YdGvpgTJtLb&Y%#wTenmpuxRi-en@W7x|8lMzL?0PQl zY8#Y;R-;~|@koXIIO-^v+ViGU!mD?mCKk8JO@7xQSk3l((9|%MGcHyO@sb0@F1ZAA zMO+tw6b9Z{PoS=JnKCX;GMv&yJT$r$kOMoVepbfYE<_X_vp=uhYQVbOM%v#uNV@S& zLzrK6JJAGge0r)#k{ud0L@~*x(XH7PU1!qTepJ(!*iAsUt6P)hnQQRgR_|2=NfjlL zw+#HTp+!R9%#}$_fU8^UcUY5f$Sw4q>C7Dd}cjK z!es7r;(T{%k0GSDs=N<5ex&+#;IYmNvuFEZKX|Xo#uh5QNgWqqTR$qcjH+tD*=8y~ z6fTClls}0?94AAQ`olP$wq|Yy-oaX0N_Dh;M?;3EJuVTU@&m^%BkDGqSyIXtytbsi z^=u!0d|I)m-&7bD^4*!=X3ovjt8XsF-6UWEA)ayKy%Cw+Q`>OLHKIWMo4rX&W2cCC ztS42JM~!!5jkjxIodg~>WTeLhwg@55$GHiv%nPuRM~4XP$$8f=MfZ3OvrCIL#V?-G zNGAA?UXZ{pp3JURj`ASmj)-Q5!){G7(r)|n4JtR;>gpEog;`|;p1NDY4uapFeP))v z6xq=%)M7W1t&PjksI{eB(qh8@SXM#T!8e0@;SVq8yH(l=EVu-u&OT8v; zywlPlsngV`%>|*V72vhmvd8X5fWRGlZPw?+8Ay})lD`gH>uVX@$>S3N%{3vuMUuDT ztjGjCp15d4`saygE#41>pXr!)DP1lj=m>W8=B=KzzQ)$n?*3&Gc*U#7hpQ89$kn@D zuwXs%MG^xgg{F=bj9s_U_d%<2-$^c8^B$W+0+_D zq>4-sa|x(|;^WPjs*-A-p9`ia!)x0z3uR)`5^RXQajk|D|+60?)(q za=;MJQ*m$F18IIKs1hfiwm=&T4*cLPDaTDQNzyBONKO_YpP+I)d)k1h#H_5W5>@s} zs`x6O@c9I7+cR=SI#D!JsTxpn;h^L_$Y@mTCZt6dQ9j?z{J(bpolHj58<#jD!ObzosQ~tjpC<546cZECch&QtiG8 z&IGMkYZzE=f-WDn&SX@0p~>^@i)3r8ei>!}X$E2=@4<^SK+L#VV_s#Txg%h(ql${F zU+We30@mtGj{O48c;_kkO$TA(Lc8EQ$cqUnl4tGvGwQtU#}`WR^JkX!FuAbrQm8N^ zy3Qf5vpn!b!?DYuF|>Y>@0k$5O-fOKBlk zTky=1{j~OS3WO>V;qWlxtrwHua&i`(@yXXN>*}(>Q662!?lCB<2*yU(u+MQ$aB@~ZC&|WuiBV%Tw z=H$Y)gg)L@54tpoRbD|34`JZBgJFADEo@Q3K0IACpPn2fBkjT3u1S=Lk9_rMFgjV)WRhBSF(H;kZUJAM`j^kU~?IsB{ky`C~w*p zztvrn+Dr6HkPj{qv#Du5gsZYlyq@mN z2&twFVyoOYWJqmdkH9B(3tV^06OKBY-vTrI6!IJ?UcMtvE|kF2NwQ#2Z0e_8w(d+= zLSu}MmfoT`cUypb`US=2gGpj9u0>)Qn*P4r)2#Z7@m({$*4kG!G?;<5NJragPbIy@ zlEC#rxPoX2AHh;@o8=z7Nsoe2P*azPjSZehmdlRN`d=27cU&3GB`Z80QgEo;s$9s2 zyW>Q|-Dg3zzgSD(^w3@5iSw97eT69nrQGW8!Po>>oVyKvh8`zOU($&loBG{4cCYuA z4ZrK?Y%av9br(wwoBrtJqvaIyh1V?!yKDVjqoxA_r*U@g>V9Ul{yUe?+Qv5MlwaiF z2vZzZbIz3YC_6~ILn-k>t$cGg!$m+EerGG7BtA$ui#-FBZr|xsoC8&}4g!&E8N5I> z=sXS6GJ0!1%-PpWo9;8Lto$w=vl3$QV#ViT?Q+6cg=ScDKz>}weUzSP+d}~Mhr3vI@0DUl!P|4`S2pGyNW~Gf0(ON`5osBmZ+}`7&Az znF~%fJmeaYEd6&@{Uwj5D!mdBa5I-1{!fZ#5GBc08TvY6IrA@_lxJ|mQ7g1^+}?Qd z8%zU>jfFM3et~AqBdz+kf3QP_hqn;ppRx7-m8*eYB#E)r3R!M(MBm7R|GXlUftDXi zlmDU8Grhw^A1_vT)qnrL-n_!R4|L~k%)8saG1Ol-W(r30uqDo}mjCa548flPP5r?G zi(7v(Bn1Y^j5N$5t`Gk&cTv7v{V7-0pS^4$28N;hy=BWE!%%ZG44zjT;(rW- zE)cWt0@d~ue|#ng48mY6sEzfXXfp(FD+2Lud6u+uBa!}Yc#s8%&i8}d)Bi&D&iJN@ zsn6AaiB5kH&b#kGWFLtJ9{o{SsOAKk*rwL6|4Y*QyNeIgfl;yQi<^)Ccl0GanSmyZ z9}IZ@-l1;N!RjW#w$DcV{^whiQ$l36)s`+Y!hbb{7$;S7s9Ns= zQP2b}%207o%M8v}j;+|KeE4WqWtJM>@rj{?fmL+O+hrK~d9BtrzC_chd6Ol8pUtG* zzqxZ_u2KH|{kt@R9|aw#V`)V_@g1!rOMsTF3`Ia2rMAVREsDGTO*MI`yNSJbnRZEP zI^kdFDqf~;ZyC)}YaNNP)MdQ3>iwyzT$bz7g_9=?BHj(M#r+8v7x<`;hs~s0h&(C; zPl(j%R=n7JHVdX7$`GZ%3dg7Vz+BFvV4UgzC;+{quZ{Fad!{+w(#X%UY7`despm_Q zL}*9csj@7y$XG@&d7U*Sqhb8~K+@XSqL%Yq`sTjv*C#U@hnFWi-9fC+(|#T_s%A+< zlXHtWFLs3CQGCr14JXT~w3%(J5(K2ig^pkhK<@WJjI+(hm}5Tzup5m{~Evi=12%hSE^_?Mr5eu?MQDSfHKB(h0g$mijqlx4VkiD=(l zZ{ZA~*Y$N5pRC)=N=vdadPer5UjO?VNNCTqIsKvc*>d-31q|jo+}~`AY6~2`&?+@- zb2xJ#p!1c-`5q1nYCP{+leHyvaet9KxuexUPvKW<_`Q6$sF^LVZUUH4x5Rb+bPW8vC}6;@$Iw8Xn?Y5A%6 z5*OHv74*e{`Z{mpk&|-isR{Hjui{ehTmi+W%qMPZ8zZ@Awpw+z+VM5hyhc5>ZMc3q zercx2;u0RUY_#^TOT7!{hwCFzK8I@)Me0w3pekPyIj0soL%eopBim~LkvZ`C!UrFn z6SwA|p;^Disu8Q&dN?zhg0~CHeI`>JW70Fa`oZAh057aZE>7a2sJt1Fc!jGycMSRh zZ`IgNKpA_S36?VX&F?tQc|&U&q?sZ)9Gh0jwSsA+iXfAv`pk+6`&woMNvRFqU`S8I zUU^$)5Yng5jE^vT-L$9l4J!l(@@U7rPU**tpU_A5P5q?6rBP-6Q=>NwEd&rUzD4+4 z7_kGfG((e!$3PPI#-m}0OD<%K&!N@W3cq=8=v%ygt{~)9d(!?&0wj4zs+eQ2&Qo5OT z7lM#idb%xgmPvI=%4U*1hExfxQSlQcV>3i!?#@2!+_ED^*Zua)O9MYNC4Mcx;d#2C z_tiZ)h7srMv9OlB+3oK&&ma9v`N}qeRYeB1P$GlqL{r$;QkYPSTZP}F8#P%Pmjfz` zN7FBdSapJ}dVjPeiYHWIy{D>^^fkMqDt3S=VbJd1B(c>^0PcBz3*%0N`Zo;h_T{v@ zsgJB<3!5cLo5}8fd1%>hD)SI86&%#AA4bWw3KfxkJ8`ipjDH9HF~PH8+bYbe)aBdE zzA7RoTuLy)^vw_6C$SH#5|qd)m*8_mq(eC*@;NGSSv+H)q(gF+=J)HTLTiQEr`IQX z#w$QK4e}KeTYV0@3RE&g0xnM`bZ^Iu^L2>zJctw1fNHVFJk*npvI$8ke@uVO@S;Nv zj{{EnzM2*sD2D8LYI>LYafjU5Uhi8P7mMxbs(uC*)|Kd_OlG*-g)Effizbt5q^RPo z#PSK2m)NwG4~@1}Nq*T6rWigw!9oiHo=`wFQ*8H1v0}$#rVmuQlR%;M zL5uUxw?gx3VG$A$WrQV!H9zL<_BXSoLevHj6D2ePwxK%Nc$^M-d#P-oddImRP;E|k zT6g~$~^~QhXsgyK^l6{maN1N~QWSOD04&xmq zpBxn_LC6o{`1WiOmt~pb_bGhAXhR_*H3nQ#_63)EbV&qOFK+)3eqDWpSCtAmrN|(C z)Sr+0V%C^#ghd_mLy;!`{3oTwBsPEJMrX$Pm538RAQZx{`F+<0Qz>n;{C1l>cYdTM z`_CGM1g}7KTr7y>G*&5jnk&ae$S`n`_9HoAo-|X&v?Ffa{7AhwwOV zLGY4zH-ZR?=ghV|0R2$*iMDBz&T6f2Zx%U5N+&~eJmhK5M=kx(^nq`j-XRY9&X-)J zdP@C_(MS5+hV`M$`ctdWX7O zyWz{&?RCCa6n^DA&+UbiM6zpv`W4(D435S8xatR%C4`!64}7ulV1&eh@D259DA}@2 zm^^VRMmiArEp+}DsocaNmTv})(i!We2||*zRJC-XuciMAxtB_mxKd2PwDRdJ-j;9< z0gv|n@~(8GVB~#(;a`MZbGhr%%}(kNazn=YMYyc&!G0-KNEK6X)_Ahp$YcWj8FMJ!E z|CU++w=a(N$+B1Ps{2^4gs&uSx9P>v<{57$Pgk1A9r1zN#cjYUziVFSEr2sHBP@9y9d)mNJ_sJ;8hM*{ zmnY$6JR3T|)by&!y{Wo)V0=?R0W?-KTPHF2(t$d;B*T2&A9a0d7O7p+k0r1&)9T~4 zQ`5W`H(}}`oLZD(mIxhv?d?f#iHLkQyQ`~BT4Kzl7Pp+cc!@08>o!NGhz#j2gN8BS zKg)_Vj~%Y7hbq9YPvS0-hV+ugdekMjBX?E}lZB$&c&p?2>*T5YTs165cmofj(**3G z%u{;mbULNXtApvk5IkjH*@A57K|MM}zTDao`eh{@M(k0)cst3#kpCl~4p$tNe7LUi{ikIn+R+9SaqGltb?4)F zI%V)B3xAhpr=ft16AvhA>p~ChU4^&AHra$T{i{l3m1K3Q}@uh;wq;>%|;oll}yQeru?jr_-QmMM`dDIU8*vvy~cgB zMRCQ4-Ge+cTl$N4n&P$3T(Gtm81@HQ*(!p6;$JPVqbmKAV9MLtE&se?Z(C9MoT9@hkbwc2{K z30^mpFP%y+?MDPg17!alvlZci#mvdh3^GvrZdx~a56n(%h?ra$KkoM;OsW_CPxOMingcrXaCr!MH<*5w zdFq`_A7(E83f`;f2QbY-;8dwy5yAgL56>jPjyuh=eX zKPtujXvg}*ewr^Xcz(A}lee7)t6n-i@(z^8UYEk#aF&=T`(#^b_4{K*ds&9ZhuJ|U z9QH$Y)W8Dz=uss%q)QBWwnE=k(S8Ble411J!z6Y$9r9?d5Ak<|9*MA3tpJ$j0Y2~U z{rl8RNkD!h%8gsTfhu=mJt^F9gmbd6d$Xpau}nZNxu8=*m*U>9XvWR%{ON`Dmc8~^ z_Ixg3&mEizzCNxr`9kZ*g)4R5cn}q!=M0|erobcn#=Vs3O1vkoL?Ofa;7+MU$cMKD zLJ0q&N14wwTnX*OX9B*LLz1_^LV$geXE4C?$q!l8>UqKKi#KYqhsFDZEm-4MKF{rM z=aa);%!Q-0gtnVa3ceg?5mz<L`)?_cu}KZu zYU5=>KJuA$0Z{GzRc5_;5|JJKH|7IuuqRkDs89DBU{KSOQC++}su7mK#I&Ns+ZK9& zNuX}lPGaZb%v6cnc=R(~b$Kf^aJGN=o8x{zXGOM!y**FYDUE3X)m948%TOA>bW+|I zv+f%9VbRczA+|gcN6g{?B!6dV@8g{qaUi`niF-mj3rtgnpJg(T@VOP!r*|tQ5{j1? zD+176Sf?)|9x_avy9tmY9OE|(s*GlItd%@3X5ob27^*No=5=Mjh2Y0!orQR((xY61Nwk1?Y$&AcAlh6L3R}8 ztIzN5^YNYyJ{m@24}A1wG9Afow_KPN7$qK1g@$$*re}=;d~F>|fC*FF@?Pcr8>K~_ z9*}H)R#|>wT4a8QPL%qZ!&SxTm|Lq2OP;!ZE+~s)2A<4gEOOU4U+G2Ucz6Gn-sa@6tsmLC};OfoVbyD zBufF^$ej7vA36`<4kXN0d4Ah+QtA(@!+%Zvp>>e~U)GdL_4rfw>$wrJbRf0==~}>J z-3Iy@st&N{4!erBH|q}9;Q3rc#Kiw}wjxWvjd%lYO=^`FCLV}**<8!KO!!knHv2jHEtbln#`JhcRx2Kods3T8N>m5}58Ezu zuho7sccrUu5P#<1x2pN;Rz;d~D~VD`ILa}l4jw&>Y>w+B*nGjV@VSrfqWo^DfFH_` z$Fc~lFkTEeR`qLN616X{=xPA^O#`4}D8#b}IL_+DLyek#0Y=)By#)e{EB}+%$;%U-$V| z9|7C(2==7@;ErUDzC(4rrKC=IcMTZ_r}xliKoZ+)JDtDb&vc@KfKmWZxUHJ@t6xf# zViy~^7xGi(#x52+Kk9Z%w`s=<)y@Ie=6sVItHup)xV|_({22n5l;IW}tHM+&rBkYG zSWYr@OcnLw$$6zWm?lsn6G_Z(TtrJUx*L+>3YpzuR!$eZ8)LyV*9&w zqXGH!w9I_ND52oofF2ztiv*GiVaVeW?UFaUactR_!zuh2-PNq|@Ib~p#z#^zJFZeh z6_H=)U(4Kk{F(Fy{h9a1RFw!_RWHo9`H2fsvH|)@$#i5g)!6oT>#XCruV=+i@f!n$ z-0k@aB%6Hk@6m}^^jq@3Tb}q@J}f3OXp*s!7xAMC$8Bwp-xz)x4tTzc-Lkxwar|rj z&s~kj!$E-&4>0cF6XKmdR?{W&CZm1gnunE44(vB@$@Q2vT%|`qz+zyr%z6gu1H(r`d%&e_S#HwR zO8(yjoLa9(2k*<7&5fzza99k*DE;$c7u*1*~;75QXon0GB zYHKrH$=D7>jA7lS#tfM#(G{{C$EL$5=Xn0gXF(Xk6@}9xHC>n!f8Vx>8)~ckGB}PZ z+GVA;*bR@212d*lDrKMbh;vPp|Co4TIKmLK2cVpWb+)%bgmQxp-LBuOEv+Q<@UQfV zQpA$1qL^P|@K5??6C8DpMvdgk`V1Cj@>atVm<)iKQPHVC~KHU%nQNi9TXn9Xt{)L3P(I)abVD{!adEaleud$<#)RK zRwbELm40yHbZ-H4v>))rC65e?(2Ldh&X8x$`dyhp0;7}Q==Bo z9X@PZw$JL6wJ%4cLBW!p?}yTb3^iuKQN<6|?m~NwY2$AcRnqs;B~wNfiz-=9!ZC8ot3 z2YmT`IN_1E_{p@nRTUso?$zg|_61S21`Ec9q?nK1(I6`UuEbATK&$!jau0CBUWH-B z*0OKuLvtiSISuH{GPJ8bA4zkmtX}Dq+=;rD#&5U@j!4eElEtH-s zb8p_53uv@5AHlFTcg(KW7W$xQd=M)-*t^ryrhtd3-So+YsZAKngnjcAph*$18$>6H7O#$=%DN#XON)p+SiPkVS~5SdiaFocP7>` zOk8ACNJ$P9KoqPyMezDiW2+;tJKE^w7L{5`I0voNyNc1wSkyhN470=1`Q+vUx(`m3 z+9~Z?2STw zA{hxD+H-UGQF{>QlBBNMiWibtoFW4EEe-8aASLm{5b!sxA6-$VRq<7eF4K%X2h8O3 zwLay(y(Vq*zFXW?(|j1}teYgyl}>BA%EMxZ+?&!MCv^F#TY6V-J-nuCwN9^xMB%`r zlX33zvC8%>%Qu~UAjj+Uc(!S|3cZo9y+rRZ6mjmpj0#DKFo-GE3)7eO_sRKLd@lY8 z5D1YuTw#U3M^^S>KO5^>9_4c`zo#_7dXR*cT1I{;oAZ#P-RReNX4unrpM&pE-K@PH zLumrMt^4ToEu9HCJnM~f743WU;6S4h^^&H880)FI#J2rmrnLip(Wc zZF|}?1ei^oXasxRBsHER3Pg3&!7cGn_DM#}3o1G6ZV^vPTvf8^ zS6|GF@nu+L$03GVIEX5{>xZZLqs;g;g7|l^2`f0b&@iN0fydBORR_uYw= z$en?Y*hj+TRjJ5;;(1_)IV-0!Q;A}NCy+c+JX>RoU$%*3LYD5t@L z|B)?ZCYTG}D|eNTm!5%l%U1j*Uf;$8j%+}3Ix*&^CuuQ-7g)s$l6WPWWNp-OM;blRo*SRavgaq|W)+CI0{X*(RUr9v#=q!IB=aOzjk z-co1z|56yF+LEKHCGcc5R%>CCFAeJ07I4fm3-{T^3EL^Swr=~?&-wBzpli|zfm$Mt zNbT->H2rLODdYEuE+j1ckVQGA((lxf$r|FpfxWnf;i=l4fmJsQ&ZB{T!?T+G68>aU z`k^nZGCA8btfvhBI1CE~_oJ1%BT~?&wC71BsirbJ($jPzHF&#@QqAS#ICD=SHySEG z`9&8CE2WQfH)cA{vb^$xvWF_3!_`~k8)e@pb7NeW$>d^Kb~nw=;0!UJC|g!-853UCt}Pj=x6lkYmL_w zWBQL-fMZD^XmU-$*$1S=@*DsS%3B_i2s3|pnQEOGY}z&SUD)x$8btWT>B|i@G%4#r zM;jb6&E4Z|KSQ4ej^`c!oEoH-XOJUVWJ}KN9_}r?p?vOdmDA4iog!B1P1Bl^=4KBn z#5+`Lag zssker;=&0)I(P*^mop2!r)W&;K5ab`qAjDk~{z-^b%T7Un*lLqwTvHsqFPx{(1_@ zdp8eSh8_S=xec1D3zI0rL`n6;jvNjAPEF$;Jqwz9`ZTvE|L)McksB?2M<{!uP)+MM z{|WT9{+j?jvVmv-h4^4j-EuJx1Zg0?&E{x+hN#!c%Dt8x!`%{uG$3Htyd1f&9MBmI z91sIGEt}Cig|{?9lXsRKj`|ZhRZ|~YqL9~YW((~B@vN%ldQ~~=?tYKpnAN($W8x}l zK~Z6xA;8H-pqlD1oGGq1?R&H_0+1k6jY+riwI}~ojV*H}I5hG;`|Y)P0o5wtAkR=1 z80LG7u)^UvC!8h>ViaCJ1y<7=awohGU_b;lfH9*U02OPGo(*C={#@m};A6<@7H}#^ z(0M`p^FWB=6~|t`dUPf?uLAx z6V>_w1wUE^5k&_}@{OmISf@H-2R$TgKuKlw$2tM{icszjJ|zP>zMT~%XMkAg&&tx? zWFddE!$lGIjdw`TpC2Z6hdwd?&QS}-U?zmtaN^9EyvL`xW)Hg(oiYXmPOYL>HjICj zA*(}MJF-%Ee1E=|Q%vNzoerF~1c z@Ka`@J}fXGN!JKUb_cyGM#8qTK^;5e2(^A9( z#gNavv`<)44zwBX<(Wy3WvVY102W4X-@D-~KpI7%Xwd8C6HdcB_l}p6S7zdGp^@L!xBAu0|}*m=FZTnRI^i z>&#vvu1s|~NI&8%t+(d44#gmVS*=$H!PRUai57Ngf{(ExuyvxBhjV13qZokH0`gy* z2zV_1@^J_Z#*T4I@JKCo~(N4hiH`ERj6tFqNtI#Ue zpri$33Gc~kq&ERf8KfrNqmvzKP-n}CQPop#@#TXe(GC8OQO}n8u%=n1W*89GvGr?p z0Aa)3%C}cC8^K<(Vn;pv+s_p|PWTy;fw0N*vC#zt)MQ!0T@fRcnGZM}*zQ_P6*sx9drlP_RJ4e0 z=4fIB0Ayg5=}5#sMIt~18Ep-(jFB4b7~j%TOe}rpPx3GEPR9EpHi7CAWt7>MC zi`#A)5GGHmP`Pn4v^qqQ=7hWb;o4ALTk~GUo|oKIF@$WFn2#$zK@4u}>Y&!*=>S_N zcSk%x1q5wpEds$YizSqW*Ir0x(6o_3X^&%IzJL?V(B<^0U%@B67AZX)b4!i_m8v(> zbNos=Efms9|D>IG@X6`Sl10FB#9d_h6G=6=bdO2C&8g3mA>+ z)uMap{V@B7@J^uM^}>7Uw%FqkeM9UAKrPM96|nPoY3U*u3jwm;DWs(i%r`EY4x;NT zHTMjTzYr5Q9$#+E`b4GUCt!^Oj!efrEnI%W(ed~R16wRpUFr{d)MjCppf1sdD)$c_ zUrsIV&zNG81so4`>HB^>d4L$NEY&Ho0$*;|0Ev5l>EH@vv7xCdUI&5Wu9_W{#@6Nk zBY6fh5dk!0B3>g?2+ExEs{2|8g%lMYAV4?NzpZm{wi4$T3%fv+ShbnaOIP`XzF*Lw z!gQp*-IE>aM2lBHhwJ$K&5Rrb*G?QE=)bABp+BEo&$<1bA>r z76C$eRVdAY-ev@MiLYjj6pd4uST1On359eV)%>#gO z5d6u1+LXl!m^wi1;vl+)F9TP}UK2R|r1h~xvBQtHY75P!U})@_A6cx%=m$MDbKbTi zVtPs}No8h8E)VU2sEvzZKxq0%N?Y%>*Y;tYaW7Q6gq%ddGKO{iH`3dW`4SGGu=#cX z7ZzRYG%Uo9(sVmNL1<~wB~7Fpz;|sn?oHETh*~o?94L`IPkXFB-)te^VVm&zm(gDd z6`XJr`RDpHdPF!(@6e8Tm_)}dwkFF+^tht`^;AYA0;s06=Vev~j%n}p4Gfcqt1dok z+RVzJs&e=ZYu<4H=%x7nknh9bSMBU^aDvoD-hkiU*x>COU#zHHvO{zt8en9fYCrrc z>f)46ZTI${6u3o<{XjCKfA+VF^Dnd`F9+OmlalO0<_}pNxQO=uzv%zNApmNn7hYR< zvlHu7q_2JhS^z&admlh9M6<*Q;&olC^XaC_MOwZ{d1lm8?1>Je8XxR6GBD$6vI1D84 zc%?5+b(C@mA;snSWy|~v=aZxpxH+e9X5LxUu~n_ga}AhtoUF3<%9nJ?VFjTeh&!0x z?bH;m>6-+lLX0;)UGs({ohFlpPZQw{Dc{hX<$R%mnn#mj!p@6m{=466tlRz1A>u;E zCsg4=wbx%Xo1B#blA_&+|rKH#U69a+hAr8!)p{@EA?kI~c+OuLoJoHfR0?tLM3LabMGgDxSTi=C5n|+alYQ zK+q2cyqpEk(}7auc%zHCu{^Ld0dMQAhv`d2WXS*{Y-dcdewgBNNAknyjXaJf;GdZ+ z0Bk;rj1vHc$G--Ev+e;GTNSW!?UE#D4j}St7ASv*1%VB!oEF-@#Ix#_>W#Qp16v&c z?!!>lUq7bun?HMhUsf!DHz(egVT|@lolreGxJI-XTF)9Io(9G2@BvCLXo%@5bD%^6 z;DzP|{(&Oy52WTxuEw>(=c~ykU2Srp0IlS)Iy+rj{T9zMc|Dp4m8c=o%P=J_v3ppM z1`}B>y0Ne~(eWnmHSfm@}~^{UAjqf5w(BUfX~1q zA)^WiFg9rD`lXt3v9y~Cqye{j_un$k9Bu-&0x{wtV)%{Q)cEZ>eY=QDSWm@wgu2o(u{7*y&5PEa1izfRCFRz5Q^ z92=yKB6(aYD>={fkh0*8ESAwrO!8%y(GRX8-5KDZK!2f=7RLJVIfeHj!d;E-{}*|G z9aZHPxBtQjNOw!4G)PD{h&0kIT~g8|jYz`+>5!1_MmnS=M7pJvpdXj)SuXPJfwqHN~0 zsWr!?Wh||f+?{v^RRlt@YAkvFw~_e%9|#e#KxQiceNrr^5_HE3Rmg#sMpObVFSb-n zdw}8=_Y&;ZJ2L+4)^W1HRAR(tr`jeG9F*xMVJ{IbeL?`C933*^KHn*v8S)M{J%u=wYjGLzRxQZIBzfMXu9)?%cGzMODAj#T? znxCQPsl49E=cj=vg?3zh@No$5BDG!T(fwwzP!%OR;7?I|wdxHqnG7;O^sb_wI)Y{` zE11L)_x4d{l;BUK{anh&@7^cTJn;t3f+YMEq}97ZCF=%eN=fC2p`AI zh@3;sB_os*zU*{-0w%0D5+M&xn~yd#j=;W|JvCmeX$MNQL-hMbFGK%Kv`i#WV1gp1 z6av35M8%=-tB4V%y?t9Xj!;j%ibR0SivTsLR`k}hIjzg*oHz{&flj5srt-iR@Wl5p zfadzoIe2p?XFBytiEx4mo}ClVW7m5B0cteRAo!s7rm7cO-4s7ELa30zlZln24CYnx zL<*-?Z%KH27(9skTpf1vwX|_XbwtCuR937pbJw_wgNmL~xdZHgw*GhMI+s)~VapRPW zVx+@BbO5TA=QuFg z>C1IwdU>QNEG7$cv)h8QHARQ{5kJEvB?P({O&B9$^^Sg?wYVEejJB;MT?FHt!xu?HD$2Q9Wlw_DfW>BLHDUM81rr^0Mp)5${&@G zMU5r`m4#c~XjfF#m1{8@LmCzjI6CYqpgT6ve zlC;XP*p}M79CCHUe$FOzIqB_Y!ONlsi;1!9EcKQe9?4k2R&OgV}}(j6-sQ%v^8H1myr)mG-5{*|9P7y38~)YbF)Ip$xF zsE>oG%{&DcCFQ0vUT7s-5AB5j3!lMaDabEI-P;dJ>ISa+-IiOT*Gl1HcxiaS9PHph z1FE|Dr$6iS5yS>HJRso;VU<{Xy!?gfhnnSe-#p})Cpodw@KPDp1Bk+b@YHbxR;jHl zpikivtyE}j;yTRTqnn*Ng8zw~1{8g2h8~IL0}!MhL3DVF&9}+8`zb62+~*+-mT<{k zctaHfZ}Y!vffhW6#Q4MDq?89p{Vhk^V~-Qz&UT+Xp78c{dJbu1UZJ6F?xnPW!6w61 z?%hV->qN>aS5QYi5dK|`K}~a*PpPIdJhmBZzI`Y9!eu?#{G$WaeI9-czdmBwwJqg6 zug`ToqnMCXRH268CqFwA&^euN_4d>%LnH^Wc<7IP5(h^RYGO<@96M2NKp{tH|4ig2 z0I^6Ou4d|pRNa|QLhoS~fjBKc1BBQZOm9E9XS6bcY1>m3iVw; zc5L6voBHAgS8Zkr1h5EjbbDc$9A0c>WaomXY|o>Jkozf_EP}TK@>A(ee zWLt=e2qx4TnENE4B0krL$J<<=HkHaC`u{n2qO>b)n?ysL6xm&0m>jXd6J~83)Y9|r z5R{fY@POH7%J7B3J`w=~=M5%ImK}KXfa?Eg(h5RLKmPClySx9!3gz2EMx*HpBXW`! z>>x1rOPw|wlJ1Wp=VnI=H zPugoW06YL3AIh+^XjLpPdJi{Gg86tXMr!m7qY;H&%K`d`1$TugEz1ZR$>!j_dAn7g zZtPUhi{-25982dg-f(Fkt&cvgH(LMTYf$92=*`2X+--Bth44u=d|W?2Th;lZBls9( zg09);qNp`-cR%EE7iD2btyX;LFc#sU~n*Qm1 z43}M>*0s6Z?OCV{GJ^s=8K2eT7jyBq5Wp7*!~%s-&bi-hgI{6GWC>9ISFcFe{TqR$ z%mJ|50DEDWdb)wtPxdnmEON`v@bMv0HI&*tIpu7WvM zA1%N7H5u`UXz;+o6A033FI6I|!9HIlNYaQ0p=mcb=C)Y94>52G%~o-dy?tWFPr*OF zcf8g3NUBFqI`4f_lc>LdWYoULwfk_}o!*_3v#^xEqbY24(q-Vw0V2=G?D4z%_Kn)> z(dKz1u9pD38NCIpdo9@V-`2hZ=M|stt)LI=oNDf>1e6E)X$z>>p#mF>uKV+=9f83> zezF)!aUhJrrkkV?`KDH|-O{wdhZrXi3qIdOws_Wrab{szO{bCbQ#WnAa5W25jOjyy zoq3i|8}0Iwg$|caq3dI!gje0dp{m^@$%uLoP25ulB^gnE8_)@riRUb~#}z;mss)wc z83Xmr@SfL_-)Nq?$Jv)ORs&Lu4J@U7)0G{&o~;J`lRoJ${98&q-xk9C}v+V5SbcY$RMI7>J|GX{jQ ztVynI4?qc3X@4|csG20J`#U%}gwr(_o+VamH32*osArjX=7UN8pB08_^8c*^-**ic z0!KmvXtL*FX2tds)mc=BW%SQWhgJbUz}>kCbEP^0ra`m&-Q`Jq zWX{jUowE|f?#79^AWYxQuT(UqmGD^?9f1;7=e5Xa!1Sm|J1Mq*LdiLCI=ox z@Ymli|0Er|zJY>Tjk24c zwA(#>I(zvF2gFi1tg$l9@u9}K@)EY`Cb#llMEV0zHZ=+qGCLHC^Oe4+gJh{5$~n-( zOXR*NYS>Y0i!1SX^~tt{-GrG@wU%cv^E5K2YDbM3#^UBPolh!DFec&UvRf4JTgxz+ z$H{U_KRiJ&`0jkU?1@K;i(V5+XXi4d+6ygR*}pR7cl#`Vq03UJ@%I>??#`G$Cc<()iz-tk^RBSBkGlVxQi_XAt(?EYI0_bP6nsWt%*+So#+$3N z-U^I&`D{jENWQ=!h=+-=Hk3-J`pA8^1?U5p4(_@d6Zc8Rf|JzWz*+zw+&Tv=!wZ(+ ze&Mf%^YsqAtsr2EfKFWSlby#z2LkR%PQRId!huCvZglFOPxCXoG?rwT*AyFbQ<@aI zx2J#Z&EmJNC74rq=X|lMwt0|}{Zi)ez0bSti6cA)l@*A9Ed~3^Co+NA`Dv;T6Qj9% zJT?U*b#@>6v zfz$!3oTfiho#g}b3Xp+y32TbgYV?aiC1AF&giMElI``8$_~lsSRV-J_R0rx_6_W-` zs=ag(a)9-H8dW4h!S7yi(-ZkPk-5QXG$-|-O(gLhPCCIFgYNkyia&`=E;{T@gWaBv zOS4uQe}9!|gX4BzfPfnmI{!?Er4Z;gKepu zA{oQVks^8*U}9n^300dP$Wn&#T@Ts^KSBz`sYt`Yc$xA~1)+4Mdn`Wkf? zH5xWW(F^J;h>Gw@kX{rHZhxpx^5CpxZbtIhW6v$#LTgItkud2ek&t z9lC=eG69@hS{Q!TRQOQ*&ZV|y*^+c}-gEZH+vQoH#}{ZbhEJauE>9Vn5zUzYN` zeVFv^W3)|&L*tTq*u7sfW&=j0`$)fAkMq|o!Ldga=MkH5S<|6pwk*F2d~)RcO_b7D zHudonIjppVqp#WPV#1wl;O1ZK{{%dnJ zq1ySkSm+vsML3NHa>%7m9GVOs5ESbPDBb?fqG_(O`^u-SGbulmSx}ePVb6wA6GHS9 z$6%QvInC?V}D<)}_zX@{-10y&(UE z>3n_e(B0=neSeBiu-EVN6o}E^$H7C~7ljkV2wVk%hxliDiZAfOQn~2I0eJ3TsWs>p zJr9J&H^ScN4V*?oL zg1EBjNr#PB!uLV*FmR}ubipYi5O9ki0{fy%N(>6eYW_nf_Sc{l`H@)^(#r`}XfW_{ZdVv}j%OAccv$04xDV%FDoVdF^P_urbM>Wt(3DUkWTRu9M-}1r z#%=sjXJbOUo=GO0{rrNAndOX#x=o-h#G_~CZlG8@U2%fkSI}lFALreQx9`B#^dTON zp^#q-3hq-wmxiC~EoZAyohUL$;_Q~)5jbWA7E9A7%%f7!l}K$im9@8(AxslVwFDbw zSK!wgBo{NNLn#A=X8>!QDP`;LThUk0*+zH>+N`I11oh>vgk~h_dms;gTVX)ll?c4a zALkI&fi?b#GuLFOfzNa4aEFn7_s5i`qWU7wL>7Ttt0K_bsnK;WMKmoeiw!a0`D-w9 zf|_!tUuU`>uB4+D7f8Q(2%P_H6Kk+wT{AdXuOdr8RrV(dMD~i2OLZbj|NXc z`o|Oo)Jt&)TL4c#AySWT-R&;=Jzi5k^n`g9;9c8~RWzXs-48@6u}d_}d3`wZ`YUef}V-vbhU{(r1w;BPdO0>0uS1}n*bP91mvMKPI( zOZEPz%6kDNA^p#5{~sGXN+uVpp)4*D zo6F^y{g-#&jt(?Ebou^LYB@2I?mH3^dG~Iv>P2PK->^a)Rh(omJ(Gwr9HyT7Ib^Sf z{+TJ!V(?Y+`L{V;iV7|QX8ry2D<;1Xv!mQ-$~q|@BUK=|d6wALq3#|j!G8OH=7Z=* zs%SI*lht(!riP03R<1}{p2miyp(qXSrhSngB%HHBHA4P)zFx!1PMQC+tWyWF;o-;#5^C^oQh` zy^Z~>@H9d3PqTkZk#fg{kpSkck(I{B2YGt6SuOvroD_JA99hxWrug*1cnQ-l-bldsx2tfe|L-;ctJj`Qf%=!PPIX4ts!y)uuvsS ztAxh(1_9btomov;Q@K={tE8!0`y4M23TVxaeaIgg#uj+}bdT_Ma?8#h4X~;I;8jmQ z?dP0sbkDMq?>XZ6tSl}EW1JPwC?OFY_Ydd^51~gmVj#oX(AdndgT+Vsuzm|Nk>VpF#o>C4tZ(lwCrrCJU!%RQ+wH~7@ zLqc6rzKl_avHjjB@&#NA)^apFGaf^$VZHqSG$!vxi zC-Iq$clyFmi%-^A()o$+{&hwTiUlpB`g7d08cy7BcBPIa4-;l?hfOs_%To)T4zdE( zo3bK}5Po$Va{!`2{p&ilr-sf1Kos_#*_Tu0HzdIF*n!}vKvSL+E>jbV&bB1l`D(ZI!k2oq zm3DI9Tu**PtXt5#w7s4iF$%tP1~}3JV}L`QiY$LHuezSThiN+{0mX1cI~0k^3*HSx z-Q71-9#|m=XCEk@rROia`4nN(^mEUa!D~QjNLU3iu~s_>=Qxg=TfIO($K#!#1QzXJ z=)Svs?@#UlxNc)g{pzecy&K;K5xuaBS-5yrU*Lj)R?dSE>90} z`kthrwEcq$U08hGrf=wRyL|M#pA*?eeOWLtzN3D8H6~m^&vQ}7%phNj%*>!nl+VR< zBS1i}-BL`o)$sM5XJ1Mw*~g;Q$NjZR_dhaD$%dO;TeAB-Km#(d+@^Z2reXFoI+wB8 z1UujkB7}4K@oWnB9M?nb=Jk&c0VH#Fx}%Pta|GxXe2;EkJFYn(zcrvtVM6JE#kQ{R z);M4Ip|F@c!wEjVtuBGC;U8tc-_d12FSV5gw*(% zyt-YTKN=yb)N`=JKr$Cfgu^Nu|BqM zs_WR#NoF(}ieOE1C;0m-$U|+@aQC|m=5F!BpB>8MoaQp7*SQZ=JwEJ7D!j1bU!^$#g`H8I_uLZhKM_au`w2OMii&qiLLFGu}_aW_)#V# zM`Vl{Pm&uvsKUXyY2WkdO~|Bo8Tw1 zV$kv^6n+wv8^m6a&0-m>a5nC zMp-hgi_Kdf<0eSk#@Td^V`ril=?@M|H9&%a~%Yps_DyPQG9zi$HD zS7&OlErTe3Q2ck7CklPje-Z%y@4hK|pTG8h2=1fr7P&H1mP}EKunzMAfY_QPCRy|F z(R)1Qv0r~@urfZxk#5{%&@;N7_2_YOOixOZ#H=hH3X9W1Jhe=I}6)9{uWA!F8!V%1OX*#v^v(v;Z@w;f3b7i1UbSYKvykiVm(Q`N8U@k93O!vM#Sz_K znc!~v8AVjJ?I>}v)fk23>l%&UJR;7gTzf__8p(D;1-+;B^0NZ*K@!_xxubK@*PzCH zXcHY$2rmU<6?E0n0YM2E!b#W>cH>_$+jGiEe_}Gcv2Gr6?(>{9uoHwim5TC zC&7*^eRGwvTR=stk^iWG{{nmDZajlrHT>BsUe5bX@$Cmyk~q@b{%BtdMZf+lxl@x! zX`jHaMC%sXuV>OnyD!Ki&HW%$Yiv_z@4W^-p zJ{o)s>!PseE0D~q(ES8to5XyOavPzvUBuCHgbfdC;tLgG&m(9cX?oE!`~G`8X)#?5 z9WZJ3p{1ofAysy^N)SkfBkM!RcCF-hiBs@CzrLVY>yICML*xd(py*sDPY$>e|2IC) zCM^YYK>kSEB}Yvjxu7w*j!H;Ss4Tv0-R9Gx0)r3G_fkJ3$r|o<$|v6a(a1}DTgvbO zTgmt4vR}y419s_2MoLxE1yf_LV#XEVeOz4}^$(LzX$WycwRKKgv{hFFpF)VH_p!2z zZEl&~#Jj7>GIgn48tNQNpt^&k#caBeC-eZ9-&u=ePTt}}9$;+y9sk$>9+Qu+<|fMx zM5?!e8y$*z+yKBq^PY$Y5@C2U=LKmVF|SbwCuh`ibZXybLU{>)jcTu#Qh4n2BT3R= z*B+rP1t|j8LWIbnL38iBLe>23**%(eW&o^&L&N~G;2L=8OS(`K=!=1P!p<1nsxi6R z0h~c2R^nSRjOMd%o_)dp20eWI5~x8_HK?;&Mvg;|w;gfeE%qZxFSorDfQRw4*vS$U zE?y;2LPk!IuKLT6glRnePb*{!fxb5pbvp-x@}Z39ZLuOW)?(Hl2W0MmPGD35=X>c^ z8cW2A$_o|$MlS}N0CAOGt0EIsW+DtUTPVXdO0<-V)Cv>9iDe*64w6qUr8>20$iR1T zrWrULtMNU0_pO72%AghDQcb7=Wq^y-zSo70@6S-*PX>vd!KivW7j+n9MZzsFd(b4d z(~~(S-n|G$Qa{m&XM*j0(qPy^Y}4{PQ$I^=i4{={Em z+4vFT*q`KpA1d7$T@I%*nZ@#8#Wc%#yLwpInqck2tEoZ)rI7%d7*Y;%c}jRvXMYUi%(f#ceBuH4k?LkSnzULnsX68YPb z3+x`w|3@1kj!j~&iBuqOR=r9r0Cufk$ZNS{!g4B{5H*e!6Rz^@=IbCFN^g&|eZ3D) z1A%`nj$S#-_wJU6f?YCowflEiKhOcooXE?l!e-`)8Jq1q?=>>t1Rx0zaoS8P4Z-#} z7gqB;`yOo{lO($LbHQyY)^(-ptvxxX1y)iC@JE8U1d&y-TH%{eNzzZp@ho@H$UZ4G zMk`nx&RNS`ftjWFR*m_dv9jJa`Rni4gS`dzhDCFF`LmBF@>!4rNJS^?VYDkjUdKI9 z@X!$L*DtkPApoE;9Cw{oYR^S~n#3S;WN(t;22|02{CDR4xV4gJ@6;TvfK{)r2hbjk zQ;I+f7vLWCd{$GPoX3msWynOI#TeIvxPl#qF~21+qZNN~InV}fl&%_1+0Iv35d|zT zL-L+KX60%NfX{DluCAA4zQb|LBP-Ti!e55TQCh4cM1j`S%RUPA@niTWTKOyKwT&RB5=kwceePQbFS(4t@};5q zmPDM_ait5{1zwZ#dL~N(^%aZ+39Z=5(PW@FtPDY!&dDderZV5D*%}7BO5?+ZJw9uI z0%?aO%ZxG!!8QD$8TQHBTt1mLiAtsjrJ)ai5()T7i3raE{JRlo(Hz@jF<*SN zIebr^KyA#iiWJ-{qxUAMz!mPK@a2PuMIlrpRQj{}uIG+m0C@>hd_Zyy7I!3&0feQ&RJ+#DTnu)aA}fiJEQymwh8yzj zuem#+3Pn$u|BkPTR|ta&=Olbgv8wl6l*g2}WGMXU-PF&KBLt4XBGb~(DLy~Ip#?W7_%pCmfn(F(*5V{5C}CX;y8PxU>QBoo6h%1usU74~?t+>lfY&_}==~jC^=o zAB#o@0d~FBC2*jm+6Iroy8CirNAsIJ(fqs!>W|qSI(Yby^>BhUChaFEFNPa@I#NDb zhR(zRo*@Foa+`-)(Gx5=B|^qHto4rumrEoeP2`S>L~Ryd6TS9c7`Cts;RQT2uiXsD z_P2VvKi{y&qK))xfRfmzf(mp&gR*n*=EriU$oUdn?XKwucF~zs+AM-U3E;u2uScxIKegwc2#Aat3BX;bqT${|_jW&4|?zo<#MuXb$MEruh&(f*=99lPoY zaIo`pUBYA)g~T{osmzdejjzzOXi4m9_XitXuMh&4o|=E>69cKByeHMoz_6uoiF)Qv z@A#vRei``@{{tzFUOXh?Cfq*5w4#Hp)t;LnGXC#O>L?;wE<3Egq3S{FDC5M6BCoc= zKZSC)40~NplozJ-nbbZ!%>~y>!HZR(I#;Tb3*kv(quO_Q3n3&qTVfcvnk?C>u`{?a zxFfDBJ;G;&NOch_yf0|p^SG{OK_5^bTD!Lv5tt64>Do@REKhgrRzm@7g&Pk+_zJL+ zCpj~cbNSr>bO9SvKySbgq^BJj*^b|_0>6t0oxRub^N;9A%%Yd>{6fZN2qWqZ!m0oz z!>mz4ME>Fv*4?pMa#QO0QVwwX{th z5!r~0-cv0OGIY{ljBt%=zc6y6Gk0S(is8u^8XfN+qBCANf{3Lq z5f`UAjJYKyPgm-5uDGjh&T*(jcH6aU4qVn`>>bQD;}g9S)5UU4DNaJc?()3yaWsP4af)Th*V9|($Q8X`vV8`UzOJ4kBEa4e ze@a3@=KRQcFLfX#fAiE;*qtrW0du6~ZG8(g_eP9(B4;ON_JDPeYNCxb-XnsnyuRh< z`^_&@wlN8eKa@YE+Cjb%AgRtPoP6aLi)Yaz22OUQ9JnG?O)}C?nn>zRTCnNmXLh<~ z2rGxZ6lc6Ywu{RV0C!=M3!M~Ka!)hU0BTvZ=7{2efCMhpKT}v}7|x`$^Mi0Lbimk+ zIt052HGfTF#D}uGFb`wKUm?piwBICUqB`iNF`Y6ia#Y?hLYCw*&9EWC72rTXPi(N= zGLzP%2>rX=%3}dsXfS`ndQ8lV|7jyh(4N-yR*76UTP4#zm*?coI`-d4)ci2Pb{CeR zF;yK^_n?0QuI@5cF{QecoQg>jR)8-1pyl>*C(En^VcM$bck@bx$)UXe@Mxp5&bOOI zPf+3p^lsulrP;N;^7*d+w4~M2v+o$%X^VQliVOofZDdw)_Gh}!AB!^zcQjK@nk;YK zn@{ct=!a^m<5QGtzA~Llu!%&9c zJclRbL7IE-Oin(>?G4GX8!merLSK-1Fb61&78xsZ0n> zdzTf!F*R0+`6W{yQk7i!ROLrS<9Od~Y zG{k+tk2MWKfY|s zJtKU(>_S!FidR+|{PFKxVofE3A{G984lVec!3dHTz>)Y96ZGE&m;#bb}Z!N%x)@I7Nf zPxo(WG_+|ya-L~?{mZ76N!XlxLtOJlkK`xo`%-WM~$sLzt}R7k^FNQppn;92#IyWg5CT0l%#_f*AdFlE*uV<0XcR)sst-fxic@ z*wX<83#6D!LH+wCsaWX)?D`X`bl~d9OX2akcBerh;k1B(`&G*yuMcNLJ&L7$KB_+NI`=9mpzG7wqA$gr5MT%bR9TS-zFfNv`woz3oH>B~ zmo)17hN zoI%gqq7w0l%A3(b`cHcKPn&u<_ z7T9AQ_(Jzs`d|mHX9I*ISQjfT4hf11l@9SL@Z!T$p& zJWNbJXhvaJZ5b&Y<>wMKmkANMIUZYoc#qH&zysSu0ZmvNkO{-_nG!%|3|NQ$0ENHi zi~MMZtGKwmIyj`nyA3}B1?E&n7){c!ay+v(4!W4r;0YWwbKl?92rDQPq*zJr22OVI zfB2*%ISbSM=OA?`-6-?0vT|FaDaOA|rC$#@;(AtmV6u0>By?)!piRDS)Chc41A14$ zj%Tu{K?F@?6sUzNkba82>PM`E7hF16tVaplr2PfhMb!5`nP}H|%LPC?;Hf`5+3qZU zg^Sz1iQJF#cdQ+mp~DdJz!jz)a+xI6web3y5Loaj^i4)z&1ZV0m75j z_&~SC+vMn9~~M2PRaIlTyuJpBD2+|Kok|=cI~m z<>z`1GlKrlVhvVpe`cs%f@WHq;h!c7z^?j<`tipzJpE4)JQ@OBGT9lAL;snXP;Ht& zp6{3C{Le)AfBq)Q1sAK;2B)SBp*hQgZ_N^6Y&z7@;z*`ZHN)hkeN+s+=6Mk?R}%e7 z)meaf3*P)cOy(XTb$S3Vvv>#bH6!LB2>8H!s8|#6S(Gq!`X}xS9r?#Nkxqp4_Pv`U zdQlWSbGGUDn_e-Zq2J8o{qtMMd3G~8rejXEC$hAB`-Z-uxayPj8oO+dQ;3iobdP2f%p9 zOv6cH8>r5yScaS{L+2*mW+eT9UNxO0XvCb_`XYV~`L_2Bec`bQ8PmVt3Ka7;XG=k| z`)lKCn$rSNE`1xNHoAtJv&qX{k5zu@FgCu z_Bz-DtOkfxIzIr4H!v%ogM*0v7d_m1l}-Ot3=P4RPMvCY0%-J^EX~k!fA&7~ead}Y zBXiGxaIz4_d1KD5c;uqj`|9#FU}v;xPe@U;6zTljusiuo=Z`aVNDN>muxkTupzM;r zuYW>i&^jq5?9As?{}mIFP&F(t7qTX+k!8Ekl&^T;x*k#WDOSbpdAjZjortmo&5Qi7 zp&H)IH)al1r%RuVarcwi#gFd=`i<%xG>@HhA+KTDF9^L#$;+t>5Bo%;<#6UZOw4sc zr&h@43LLnjCa0U|5o-g9y)f+KNe^4yAT3$C&+aa(GC z$>S(H6`Kpt0Qj-DSN>zqRdVIq>x;voNs*wO{u`?MkU&iOX=@R(*!BGexf})<11hjWd2~zZr-8+_tjK* z63gSoGQH&&ww9+OQvFp!Rc4u(-cEXu_rf=;z88sacox*w(>-;V^&=uBNXyx?6iNYv zsp_@;+{aP3#mJu&^Q{Yl#iyBK+r$5dE&lTe`c-b(diAjDe6>{k#gB`lq1z*ofsYp0 z2&!s^t^pN_-R9f4oo@oUf%ycl_y(x#;V1n`WyMD;;oHnLU&aIL+ODfu(2tn5y@OxP zJ)^i46VNPkeEj0u)reGkZZV9co6I}4w6KdP5CzvPP@)3c4sbry=3<*jkfmx9#TM+bLS##7&pyp{#wvg0-LgcL$KFo zAFtoRp9n)NZyCP=B6zLcBDtNtom9LDMb|UBp-K#KXt0J2IkM6g9GJBI=v{!PlSQ%( z?1OUEdj%I+5>_E?7ygJH?lULG7aw0ugns4e$H6r}KWeSDp2$%5IH{6)xC@=h7%%D= zQyrs&ru5fzYM%^`3LD-Ln<-`L@|pbrQaJKwOg*wZgl=!ENBYk@6$rs9gNB+waX;Zr zLA8f&<6A`+k>M#AqejdCHm7ov*Kk?=)5 zs=o_-L|3*Zs2^Q%Ufmt}whNnn)^t-XZtzPn+(rzCLk@~350Yu>x6($c%j_@k6FhY` zGb^7XD= z?OB2WNt-!*ldlQ5W~BIrsPYI#cnhIow4IGkQE>kb(|z1I>ONKVdu6YUXy#5HYS8G5 zuxpm>BtY%=XHFaA8Lz_$YOhG^6ee&TU)z@KepW4r)}EcXU+)8v_0eli!iuRyK-;Xb z%P6{k%XzaDP&JgA?=GxvlNW?Vz?|7Wgt8jykvfU+@ky)SmkSDiF&5GW$HyCo{2*X<%bA!0 zNYC^#{PAf#dGABB+p66R$QY~T4m1|NF7k}LBm-OEgPy?xMzQDbp7I9Kr2Z6(e5^$o zF2G%xmrE``-WNb9t8@VBxf0oG=zU#;rS1;p_mYQ^8o$EZiZxAx%yYZtp+O6t6Lr0 zbtdgm=ghg!vHg`#d0I!~?Z$eVDUBuyFORnI)@wB{CQF|OTxpaC-S&)IwobQw?D<47 zjHA9klD$W0;GTZw)|N8MT4$6Aq+5P!S=7dEWYP;C8pvtz&{a&142 zQN@zd*-Z;UVtgGoXL>mg%DLVgRfi4K(;+)*>V8Y02~L}_Vqgm8R~#`?%Jd_~a(mX9 zQ4WQGssG`w^$xI71Q%qtMq)&o$v;UhoPjmt<(i+noZiKcaD(eCz$Ju&$F5q%Fxg*7 zA}HqrAns;Pp(>mZHs3Rf8Lg*TNT#@HD3)&`b2B$6HGaTEWq{R!St1O2Hk_SAcn=ogQVXLJD9={FkCo*#Jot!~^I)V& zT}smTS^2ZY5`#8ja-5EL0FUA>nFBZ>g{$2WJJ>ekN8*icJ2=O&TI-KwqZZuu~qx2wZmqd;oK{2(*^>DsT~ zs&cj7t1>hlJXly7_Bv*|dvaN#BDaH}XtSA5aNy0{PU#M!`1th{xXx4%COE;RsF!;} z8!L)?p)cv%Pm6iqAnOgN__u4E2S3uQ;tdH^(COiq!f<#NoKGDpdOA|*u10a@%*JoH z_^{=wvB`eKOK3IRH{%YG`&9?R!L7TR?@t*gSVij@otrB+KF4RT(kD(fm2FfH3bXoZ zOY=N*>+Mf&Z*%3IuMZs&eeaLW2VyPcrsxNQaL4dH!+eixPEjD%K2gZ;SY}f?1-B2E z=Kg$=c`JXZkICKC9NOA;!(gzbhTHfl#+GBeV`XUeoC*6R^k@_G>%&aA(=1|sXL`un z=Z0_fJS&`d6VjHckmvnUf%yY$PGgHyog6oY6!_y?1a|pxq@*weC0xV>8#z5sZH}KG zD;=v|GfHJ10!$n7MFB5Cyv+(iECh=%7*N`hG?h5z4T!2M60S!|QSu zgg^h{Klmlp$vAE6vCCEi3wQDt|JzsqZZ%~B2S+)WaPglL+U5n(0)(qXJBQ5rC*wQL zmrqPLhLRnIyELlZUK)>YI<4dMX@E0}J4J`9AKcUbT%|2KLyGeie!3|cjXGKuxW5W> zh8q7C_26H0fmYcVlSTHQ5?PcHyp|Wkz4I5`1_V%hAUbZ#hPnPLi~#s7RQr^j{cFyK zer`KpycIDq%>Ek%fI-fQ5jEc&{};j4aqtrUmIbnwd3#f*W^ATM0K4C2^WF9V(~s}* zB|;A69Sct;%@Jnv>l@#mzrPL4=_HEp?+coUm!%jLVcMhuK?rBq zP=toR$(e~twG3Td`5XN=Cy^LdzPI@^G(~#&D#iafA-6!ZBK{d#F+p7>Q8yoE1msE0<4B4nk-NtN@f zSfmo;v}gGVRGBQ~VW~5bb7~b%=IeRxID@IZ1)0kd-k}!v|8K{DunlaD@Y}$^? z9fALYN9#IBrS1|%F4PM0z4%NTag6HQ07V7hSI6LB8$HmLs!*O-tyn;Ory^h0;ocR3 z{ez%<16Ua|NXX)P727lcJR=o)@P|EU;XmLo2T|0nPO)P#o5BUe6NXldKlrYY^WOq7 zp{lUyYrxa6w={n?UKG|5h}s6eH-y$WtPk*OCa7mX?;ALb_GYRP!@n3+n105YXFGhR zL?=qh2Z%fHG1r zsN(~&2zS~{lbanl*DO=QN<sG0n_}_j>-sX;c^u%F5#P1~PZ!=sytMrN0-Yv!mvK<;Kaj z1_`zNnkjZ}@jJBJagqs8FaS>0i#?dc$RY2wG7Plvm29XFCZ_PW4~8q4QNT_8%^0CH@+$cIywvrxf9|K60$?1KkZdTPc3(XNcc)$FteSxmTuM~B6^j87bk-%y zN1v#jVBjl06KhtPUC_w)v~?<0#X)8Ks@O+MY6m?+6vud^2G83bGmOj=Xd1uK=uOl4Q;e*RlY`$%{r`eW zV9%2w85MX1gF`@EX?H13prsavE$Ofc=v31~ozg+I#-QwmFd%Z!%v2h}9I!`*olyYC z&?XK#Sb(#z`bPNi!{3kRVnf|2#dK6ZIy6nYfgF=(<;-DlF1fF5`4ZWWoU?L!J zX%LW(B^@H&h=imFC?ZHV0+Iq!(jZ+bD2;R}f=WrFfI)}S`Cd!hTc7`P&KT#MFX#R6 zj^Xx$d&OLH-uIl>b^R(d(Tz>vUBmN>$FqJ{v6XeCp)LPo1dBISm-Yc>9r%4Nf5K6Ww94 zNXHg>9mAA}V%@Tb_t*_#YDIRoYSAO2NEaps*fc+vya9(;ju7m{RQoX7k(|UTcHJD7 zSGjBL!Kuucw+iI@l~L`Os!@|$Dn1ohgT=+SVUvY9#6%nETTJhCM-b4$?I#i^BCfD@ z-G-@Hdh5Lw_AtrEkxKPJU3?z(A~G9wpIc%&!P zx3x*HxjaLWdl{(&QD=PVy13<7)pYU`{oDbLr&_|9V9wRgm=u=Ry$>;Jn-Je(i*y{LE>aym7b9aaDsmRHU1%3T=aCxOM;IUP?NvhqBte%KPVcK3SL7yH+ z+YbmlK6i(>sswe(T8)~BNOa029^sC(htl%8#HZB%%efADk4Of_q1uaX4)Cx8Pe#RX zUsCpZp+Tmp4%^x7dVfM$NwMV2P({JJW?VjIKO~+yI_Zq$yg(X5C4D`^`!%d0_Y4$! zSb#4_xJm7OiBB#Z(!4!CI`@`;JEg5l-lKpfEoynZ3YSJ!)NVk5%G`kP(t^1hs_1@& z917()a#p%9&?)Jv0D|ChWWRSs%yN!~HvyVxoU8H;g*3m?=%n7A2C&`qGI!0Gk2_|B+6%HLT- z@RL&L?x_=01x7uKO=0;KP4q5ZWL!LNUuBT<8x9B3ZzaiuP#|`3^eaEkBgZ8^C{Pv5 zRUoA=0h8s8sQzrv6ZhfZ`uZ|+xkm>o2Do@nUZPUE4ohL@gO$E#=*h!l!Y^)9{%QqeEU^K3?=ve<`z{|^pCM)H{^g41 z+lgm}{Xf_IyPE|b(nM>XBir)(J4s#> zkKKc{$d6@q5Asyjrd3FPVO9EbV=pCj!V&tx6t-IahaL^{c^bldj2o!@4{o^n$SO~~ zoNW>dXD>+9aNQKKOpbf1+i9S%X_g@cpuhKWk*+MKa77rsmb>&6Pp)?-$qOo^jDvCd zkBlRE^WN9K$e<7ClDyZszZ|64Xr|L6d<=_27d53)3h&MgDe+ebW{30euu*3a(rQ)B zdCLKX-V#CCb#30W>{*vX40`Ft=3q%aq3?l%p?KgmI`{kqPs>S4_8rnGp7_u!o3cV- z6E)~b=`A_jed2&Qb1fphfJc>L@JQ}DVd`ZhL$0TbK*8Wkvq(#OsfW40(5;VcNOWsR zW=cDEnapdtb}H+F`zpt)St-$qeeR0#J)11~M53 z(xDs5W;#T%gVfH4@f&+dEiYe~3BnPPoV!DDgWY^_=p=ow;N(-_l=05W}eKp}^+W_EKS5 zxHt%BUj?L?a**V!jz2dJZK$Uw$U&3-a9`Sl+c?iixR=%HYr8%s@AVD@rly^tpx4Cu z3?UsNPl1Iy?V^cc-er7$ZiSSvYl|x22z#x`L>TjA^MU>BcCz`Feb{`dD;(hv&*1-kvYicAp)YF_N! z%Jr%PjNOaVbFX2B@A?q%@dtI!{xE2E&txLIA`u;iniu}sqOZkKV5g#?MTr~M^1 z(V7RbNn|z&N!dJ$A{l*9`3D7T_f!9^VC*RmET=eMs$y3Z(=-q=vGQA~Uu_qF*h4H8JcHj5pWnlGm#n(*T&xLc z`!Tzd2DsUY_+0JH8I*5jL|{$rZBM8W9o9O2Di8R|X}Dhhs@CO=)f|Y4ZSGM49$^xlMp7uV_ag&r_~XN``o4br+%=Zalz@R(uOdg)wWmN~s@`L@a3V#p zgja&o6{z*Bem_XJ>|VH*jN(M1aZymP--5t2k(o>?K?Me~{Dx^y%=cF~{R5U(?FNNd z`*tD%*T|@V3rZnIDU&=Q}F{S)~;jOc2qLH6`gSQ7Tv*-sL@yFUCBxAD=&T zp}lW1ekCnkp7G_{0W-`s8uitgsz258uWPt~a*WTRfK2{iYpGq1M(iM;(6YYLr@<}6 zu`Yj1iJ>^iA&Ey`n@DD4t7lvi?iQ5*JA$oaI|RmnpfJ5c)pLaXaheTD4+i`NX~jen0sb zew!4z@%b)Pf=Z+M%A*JP!u#8uUN?HHe(72$j6wkxLV|97F`l+tP3_eVIfN$xDHpER zCGo5s%`<-<&_~HtrpYXdiS@hErtpvx$-X*k{<{liErc#O*|vkY7jJ>p@1KUQ1dzRZI2H8WZQOj0CY!1;&X8NyRawyvsSl)$iKVd3fN-9 zwdRxbSjnH9hn)|(Ya2GuM2@$_Wvxn$l3sQ(%%D%!4nIpi&yFZAp_?*zNWYjwaJ}aq z#M%W4L6sqJ(A12h|5GtCfw2~lJBijo=PxDiCMt558+RTkjy$78`etbaqv#|hYqw|Z zJT)yn24kqll8$YgDUH_?#w?Z$Zs-z>Z;Y3klp1`yHXaHb5e}qsh%*S&ebwcSjVbjn zATK@-e$TvDyXA}{Clbcvs|x>b6faOM_VyKVK{Qj#^W%_hPth*PTQN?e8zuJQXK2MS zl8DBO_iqYiPxe(06{W{g$2OMrl%3b>ox0`q`@yEnA$&&+W(gGU>nyIiRHQJ0&cT7P z1g9ZzzcQ;LmE(gbt{ZOAe5(rgo8a;vKZ!FYE37a}x+r6i$wc&$`*q(lff7sC#9UVx z_~X^@7M}1-gtNlXs#I9Q@*QIVF63ZivflMVbWN>O>;2M_pR@Us6wtxr@Z3WU{4%}M zT+#c3fpW3cRR1;cg4n>(r1;j&=^Vus z^+@BwMXF1_2V$B}B`H)^kqMpg2P65Y6V9NwRZS$IEB}6jWIFZyqG5)*@+l z`QO*;efC~>ah<(b_G7cd3r1#QQnx;GzjvxY=bq9XnJfQ7{JfhNl>h-YJ-?jCsB>_H zBK6mBsa4s2G58GQmNvMSBX~sy^KXr2xY!lEsCY}TWe2d{GVirtx)cMsD{M)L3<>kr zaNke#6EI8uS!z^OqRN&m+aYhBTH+Oxd5+>nd~*Zgb}%trwY8q5?AiTr4eC)(CoNCj zeMXU34DkpV=e2{v%Y}0Gp9@a(W$%Jr^O-|NzdC2~GQ)~D2WuDV?yj|kSoBvd>HREY zuvK`fo1gX8d8GJ*MS&ApMuhX^%R1|${hi*_{HpQct>WerUl8B!BoKWha#dIy(u!^zelmx>+u+(>y*od>{csb zHPCzW)*P3fE%0gD`$j|C?Z4Hd_mjzj6YQZAh>|3Z7w=LIn-V@5MW+57zkbBL7;&RX z&EorGv-Q5YMAO2EY;HOzwkpOi)Kroyt0DA*fVJ))C8WPI!&*@`yF~dR0d7d`DV>s*T zcd}dKi z)jo1rwb&huG#mKsTD&EAVf6Mod2zV+FLg>q_TY7vq|(K=0XHjh4ext=IssZR$7K4+ zEm#wu6Ul$7iLEv_l<+1M1Uxfss6H8AYtDFhvr-cODrIM!^s+%Y$XmM_&&Ufmx?MKK7&z0lO~uI9>~fkxR(TJ>3ZvT|#Rl z0UCmqU{-G1$5q2~Mi9u(|L8%uvL??8NHz3@K#~IDxP4vUTeV1!GV!OU9%VHPYK;|E z!&!z!5pAlFcsvsdX_;;>1p*@K>rUOrLL17v*(sD}3vWo?3FFe8$mOXyTD)4DfzNY? zf+@*d6l;#LS`LrMO+;Vhx0Ttbsp<*K8G=+Vq2N1=sPe7HCMhgK!T7PKl?xvPo~ z20@wgE~+gaK*B(0y^81EZt}V9q=JZ77;*-sNRRRVs9t z_&^O#u|!v7cg42oa}grSPvh#&(dEg`!MuP_CaoHUG^xp%>%bDjg`(S~?IEgXuyGKuMK>M`z`Z(kpctQ;|I|y zGS=-J>4xik+V1>za_rUK5ihmsKc_8NulBO2^gzdV-_HCzJwv&>jyX9PrA@8|0ll?) z{nbtv&$kvXOPv(U*R#yUk@(2dJyaYUv)YfBev{mnXoiKt)!db+pjNl|nSAEs7Z*+I zH$elvPW-HAR~Oi?flPWBme?K&Bh6dnIQ_tj*qzHPF+-AHRddCk-lB&1&|cj(*ziXP zncrF!Bh)W{i*8K2!z|GPKH&Dmk^OYvv;Ki;S!(s zp|-_Eu4Rf~W>}10@$b^?e5!aa?e`8PEfllO^T!)@{wJkb-Oi2$bfD?^4_V3+a?7?b z1M>ZKxGZ4IB9uCi&QiTE42JfRoFq)9Nco(IOWPbR>@m+ajcI-*`QIK1cZ7BWpI z3kpe-m@l8No_{rJ{sf+h^p8oBwO5JrZag4)ErlRI^FewjI4g6fL;hkU*^X(?2bqDD zN~VB(Iu#15^D0K-mv17$P2@;7=pQ_mmEdqmV2d}e_R?)$!oF;+{$aKA0q6}!pN`e@ znfx9J>rNJA{lgxqpGEG?xCneB;_Cv$tJru(Rv;g{bCROisglWK6?w@IYOgz zde`Ib^^0i3x8!v-(}isuQAb=C6E6@#d?V0&_eZE+xR;J0e)F8KU<9V;=*G83--rWp z^FM!BVqj$SWAugf-)!hz7&djikG}c;@r3|)>K#14#S$FtO}?7M>BfD2_-mz{4sBm= z=dBZ}C%q1olBaC!D>q@3HIh5`>?+J>a3ox1)M`m?r03bP^)zyPWvRBaOUnv(up#>_ z@%Z$F&Y%m(7qYz?)5cL7aOHP!l_4`&@V^t6lR|*6d3zA(xTt%1Ppz6l)|W>CtEbYjtIjgWx+&<8G4C%M^-8lDBx041i{?X9q57 z#tv-&v+=)DiPT;KWD3;9d9ah--JGnu2eWv{)761&ma2!1ILSZ(L5ftsqFEBS=TTIG z5oDaRb-WaR3t}XCzn#iqc6@$_eRh1VD#*N#;;5+ghnFhr{0F(jv@#Fq4Wgb3BW7-D z*!DW!`(7mrxlR}aw6#bL4&=s2db^#bl8R`?OsnyyZrij`HN*#|zL6-J-kI-5b1(x_ zhhm-l>wbG*0d#<{+7allbskoULbeHiu1OpKu5PqLmV`Cu)G3Do9}eS_<=VMJHd3>~ zUX0X!5id~lpNYM2TQQ=1fW%7y;1APaoO4}-o1f$em#-<{!D^$z6WWEK;-T;9<+cXK zXu)zzKACfm?pweX)$nf;#uafT1m>so`x40pwgUrF@)-nF72Y0uQR12-CD@kvMZIUw2~+oi+RH1I}= zCR#g>$RM$+xmBW|rBG+O&ulom)-mWzT$iK{*X3!c_{;-d$6}oBFYNQN9}&a3Y?Al} zkBfc-l2@ys$~EUDRYJ;lxcSvXq(celjG($j_Fl&@4Mutc2w#-g=7Mf6lmwhXK7qf1 zUVpiTd~aH+ku?%sz4yDX%%>!WWL5?xzFRc6JWyGqDbNAh+>u2WhWTJTn(gh$T4JTH zXu4b1m(kFy>Gd4YHPt>@+EAZQ6LZQDXvq_kx*y;Txutw>i)^jfjI-z)Q{X4rL}*}O z^uzU(hQ@E&9a0V8fINa4&e)cXs`0O^aIVB9F>&~-p+!~&8{aMnGXiu#UCA_h2 zfbl-g9MYiqr{$X6i)O{eu$vAK5UN!sMCFfUF+v#sG!p?wYfG zt#R5VII2=%s2aU$#CmFoVUjyQ+aH2Z4%^gXnt2wy1nX`t%2(Y&T+{xW{Yp$S$RRxZ zVTk~muwHMRJ%wRu1TKls@b6D^0Y(P)(IPwX=EP7oYy~>vWVfMfyqre2lOlEIgFlAt?-HU$qRJt$1EQ(r*H^4gn1mCwU!tFs?O06_x!s*ikj& zD%g^#(Fk&R%<5{b(Z2je`lvuB;(uJMS~M7+x|U>it-q=;F+W7Km|=ZHvE|t2I;7bw z>fYPXVUcE&2)eSe)MP)*)q(q#G?1*uL_IC6PeJ?i z{x>cjh9K7%PXj!vU7&{*&i3|24_*?jD7f1VTiU@T;i+9wyYBgwymANfS*nw@3+um- z|B}8j8lc)e)wOcKTS1~-ASL7rjd1wJC|@BWS;6}9)Q$JdBj5~#g&~)ncmm2DTnWfQ zAu8T|YW`OJgjOZA52@@8`~oJj>QYu8;f%$mpl|-bI4m=@sSdb~Q~}G_ART6xcl*7O zFC-4o=xp0`pY{x$C}1NLQ2iwg#yzvBSAhAa@`{x~AT5Bqi$1XbReQmUzWr01A@6bj zPhWJ!EW`fzGrr&V1xNn_8o!kz@T$IYA%bdyS*Sll$jWJ9fc21m7$%(lBc|>PhUmw$ zw=9{-8_C1B*c0<_#8lsmF~}2G{msu~6m%&`k_F(w@nhMw#dZp}@V+orM;CT9e-=_R zdf45$ma-YCL+MfUt$Fp|4L!DPL;f*yXNe_3f`*jR=zX$wa_nfbhy;&=Dp^bfPKv}T@u{6j2^LKx2XKOT-_ufzA9fT;ql3&oA5w}$=r8G=ZHCGmx(o1?AhWjG*76w3CFjHvErs#~{(L|eP%fPI`Po-H zlp*D7|}rP?^njnww1 z_Hf;yef2fT7>Fg_%cJ~Z9%ZvUkQz>_VdNF^DHO`L8OG#>B|UFJZ33G<%zrDo8KruRxS&$nxT%;{uHX_vG zBAgR`kGStQQSbey)gaZ&$&0Xt^?`&JG;WEa3Z_<1!?1CYXf^Z|&WwS* zABy2~I(_}IDBt^@$k1WGDMA$oxi#OD1>4U>zv3Y)eBc4xXRVWkjP)u=5#TUuIz(1< zh4P+{d5jIH!VpzzDFWr9s>#y+O=g7=8b&WZapUhCoqq)vFDPhNQu+P0!0CD+(q`50 z=Tv^5={NF@JL(O6OauA#7>Ax(37OW{Naps2pmpg4~`;}5H`y31YDEg<9;sb^((82 zu9wz8(9Yqid-DazljuZ>tW$Q~0*&};c3v~b05KB>-wqiivUhlXezbzQpvyu6(wjR> zX~JgQ7QSys2{4nK>jQpWYXvBbVf2J$Nf2JxBxp|YDc@~0ibnKZFQ!b((CuW6hjH2* z6d|RFpExk}Uu|^J*r4%XSPIe^&%6${Ijx1E-+@ML@?$r?QxS#9HJ&GJ87d}sDxBh8 zjKPfjIQU1h_&v6c$={(Ix?^D&(TFP80OKSzCfc0V>1KudBWNucKZv(^j4D5D$G#GK z0c9W54xM=A$g+X=O#Ys0$-K21f}FUOX8{5_K@`uT0)c~P#s~X zs&m)yJ)Fv2n4XZNx^bC>FSUex7m-)0h09XT)=@FQr^UfiK@}o2coxZt`^x;N7sKfE z(m%rPJMD=*(C9E41ISH8Qe)&mqVZ*x&KOXiFU% zNv&hXCnI|8)!j>oMqZ?wYn_nd%w-|Ld6SC%EUO`;ru0QsWQ z0<%J$7(^)5qRY%@TzmHk=Y$HK1eX^b9uFP0bDhy%sZCYR)oGJTTHl) zgj*1mg2eTgP-py%X!^}O(`2(qA|N3J=2$bwcI94|O zC-i)6@tVmWg&FKy<2g#U-%Fp+VtDLQYnrv9#K~dn^2iV0)6>F$2tN$a`s=4&R7Q~h z4D*n{O1t^QN8-oV1rgv>w>d3WYLyxO+T!4d8(U|K6<{92V;VNbBoX~U+9`|r;V=da zB$pN;UWSwh;o1^#W_J_p1=}MuiCPA|KlDK9It1cW+HOh->6_osUX1*p)i;Me<7=~@ z8cwrf8U3rlQZa>J7mLUfA(#6rlq6QhjTO#-E6~9f@0XZ)EwTRG|6b9W6Xk_{p;oZG|!JV~E3ok_r9Kuv79 zCZyQXryk4%dM}kIRjJ{J7F*ta5a4N9^&l1}{E%jKzc+#^U@{~z;h|zV+4SgeTc9s*IG1f0)rLd{h)=P-e`EEHt zEgrZI*yZe8pVGBC5xuT1wN6NktZ{MWS!!>=O*!UA^5 z6@^}BcMa&D?#3u&hC=^L!|EZd*@%aV6(}gWaif+X3vUV-@__lyOZkb>2MVM_kOmTK z8)HcSyXHhkmZ$_N7SoS`6uaOHQ=|Wz7XlIN6K#uz{-_7T+sniEUw;DO{XT!$@`P%@Gn~`DJTDlgiYk0BN&c#A1J5C+ida$KPMr{v-L3 z0QCo9EHX|fcV)&s-<)@18F+dfU&-_xEf7M z&*n@U+Az~SW@bX0Z6~Ua`a};d=vQ@|WBzM-%4o2}3M0q`G&rjZZuBG%r6ux|MxRtU z82kFjA8apv-rru~LFnW5{Uns0{9;tG|2i>KvXqi@mbid_K~EKXOEoE2ZtJayZVX1m zR(kTC+k$`AsTk>%3=Lt^RM+>CD)o{ERVAK>H-}4#=LFa4l<1m^&1H4Jr2KsTt=IN= zvThAL(H0Hp4$E9`=@wev|CyL|$f5-%!ID4A=;z8waK65I*(i_cx?1?uSd`0@n&1Sg z)x?$YqkPYMnq;V@ccaPh|Dtc+Bz{euvF}*(>6yZW|72`T1Y#%;AvL=_F-&YLrCYdN zqSKkfT~#DG(b!O|``%@(sYbU@qRu%5(^Mhv8KNw>(0)iuxUY?mG=6q<2Isq4h`BLEFL*7j${qiR(PGfe(3qJ25bd}isPw8D(8n@h$huo z9+h$`LlWHuy)fg#2Z`nD)84~M1px$+Sg!V!CSS+?{bcb-nUC{&WeoZ`D{tLa3?^%@ zHJ7QU>933z&pmW3GoJdxk0b=ZOyh#-WbFcFuWgftYPub}X+9Y3-id~vyOG5o!iX+!4H^pSH6{bR4qmc}ho zQTi+Q&zO`M7R3&@iTS-S7Ts!+YrWs&t=qh~!+~?lIPy#1EozAq&6D6C6?q!v zB~gNe%aq#AsT))M@l3rywc9OjTRh z^NVMz-D-YgsQ7utZlsuxfcwmyQqq|qUOqO?^z`xwFm080^KcU-Q>8AZ-*yi zWht3y9qsxNOVu>SQYnJZKe^0jOKrWD*MgtJwocI) zHr|&XuHw4-3=E)+ri=SdHq2bVyx*BF<(qqmxbN^344bA+>ekJhUQoF$J*969Q#Y=7A-VRekA2q;p~&eY2>xbV!a{z5^rMLGv~>@^{#TwG zmlx!=tV(oggmwI-b~I1&cJU4i{dJTIgzU+Rbe)Leu8x`0oQdfvGswg8J07~nce{t8 z`$!)>Y27>ohtkpGPSW=Dl)G-Bjj82Jn}5!JU=%yVoaj3eS8X>PkSV^>Mra<1Ek28; z8_t3ojUEQRN|K(Eo7Ap(vPP%Vvg%juEQCs=ab;MJu68sy%Dl=|2tTp!NA=c|#hhah z(LWktI2k>e)3ea6qsmga{nsRkB~T`5VTh%Ybt*DXLwyIUU;5ueaAAr?WR&O`A*v)@ zn}Yk+3f`f8{MRN<1~ug}z-Z*exf<$cZ+wJ2*WWYaMl2T7LYs>wxBrd*K#r>-kk4r> zq0;|&PKU#DTCEl-XFPo`a)QQ$d`_eG+5g9LnhBoMq`cJsQA&itnM6*fxL)p$Wme^hyTwl`v27-z8NT%l$5r6Fa6iTGbXz7 z=(3ft^ggIJHC62Y9M)ZSnKLN@sPG=nTPPR)R>Zze0($?;8-`;Xe_jon4qmw$|Gn~G zQ#r;!Jf_%<#f$f-WiooUKr;K!`65CK?0w`(1$c^!eOHhL+TZ8wMFO0kq}iKa|GZoV z^*nrE3iaRrvH(6+!gRTES%1G5UWE3)+l%7zbx-d21~%+V1fl+>^gDpPCFRBIYX0Bj zzgzrJ(Rgot<+^wLRcBh3!JZVc!|$Bf=UasCb|f#q1=rE0aKq2d(Z?M(*&bZ_AY(QG zX84UT)dL^#rEckCCm(`!Zj!rDbuP*+l=SUx%t?+LMqnts+jz6|5ZVgOueTq^Pa=vDRh;Knq1N0QW$5C$>8@ z{IqTvB^SfMz;FfFnUi@Y1zB27 zWR4EZ+G;>j_VbjDjKoxmx{yJKHu-ZdA|24!v#F^xxNgs_VVAm>9BwQ#Q_k zj8dNc4EY8FefsG^M>&hev4Vj)Mr)1debCRUzZ?EyjnSb}>l4slK% z{SKI}LgUpBv*V1`-VT=Cv&7y`cTpDi9#{HK#BtYZg%Xs3aKh4%dh{x{o0qDnqd}1d>Cq`i|Tfsgil- z82)*0DM^?4Sf!k6a>6jHE#K((J0Ixc_G&=EUB@%*ZMhek{!`xvv%xgAYcJi`u4~FO zmH}(0G(GqXOPL)X5YO+S$E@awRn}#@^|L1V5Q!@^Q(R_WXlwPu=g=*{yMJpO1jwKK zC8GzNfZf!d6=sB&Wc5qRyd-YMXRbw)CurC?$!K=3XG06dOK zs4DP$%M(kE#5gvbgh9R-OyFgGm0y^>G)Z@{R(zQ*!x-th_&b51>?s&<7N|a2g5RY( ziHT1gEDdNg_=qrXp1@$Q2)Fv=;D%v3-v#Ugq}X{93GCbF{UKFLoz z>?W){xy4pipEo|h7`V%hzHz@MdB>GjQUR-{Me1@mHggi=_8tDOlY>&+77Ap6>|H|_ zP11XRygegk&V;c79+&96hDd`KZ|kaW%++m@?AitA2#6b;@lps?C%0Xez4#$G1_S?v zWFYs)V%X@zVNSVPTbi!czzEnS?a`qD2@ru&`IQ!au1jvq0g?|O&*P@0kpHQ_Kc=L; zINc7FQx7OnXrBWJrH3Yqbn@@>I--{+nGA3Vl8vO`sZ`b47RzbA8A{c{rp?lM;Tmm` zWH31BCK6T|4VnR`Th$2?>>KQ&5k z1Ow*n9mMM!H*;?`#tPisInQm;G5r+J#DJ(PBi>IclV3&cTm^cCd!+B69RX&ve}noD%?^9A~W{Ulq4oXx^?EV!-u@?~nzd*E7oa_|SwL9V1tjJT4(j3teC{Q0?Z#eApN~_8%#$ZkoAw5mWZK&0t2YPhcR%c^ZmR=e1 zM54Ia#NM-2lJ+Gl$Za{=ZSXifTtk43Adu?o&Y34WW-+-gw1DB1C8+$@>roNGuBr zMuZf@f480C18?uwxyID~lcP2N=bB{3Gnw&8$F~?%k1EzDcPJaKt7+8B^I4 zI#WB{B$r*$aZw~NYH!`9pqWzMQ27?~2(#*(!iEut^9Ox%dg}Z!N)Pn?c)U0Yfgg#yk&<6~e>`#~V?dhGXOAIdKrKCLd-BY3Eu;c4LHAP)w2g&TetGV%@ zyHED%kP!PjaM~l)Z6?ZyB0&D%n={%tF;~D-N!w(!E|a)Rl6_^Wd!YGnZyla0bBy$7 zwQq)-USwlev=w^2jXrR-kl-92O7Y3q%`6L3qYBH;bw)D8mtXnEX|%a7eh<$H=`GsO zO3uRYT=W~b%$1T135F-zcM1|E#{yh6x4kma{>&$^JNFWm$k5{4q7#vXT2Q#f&p;9h z{9L0z%n~)U%8{S6`Y!C97gFFklH$QbCO*$KL@}u;eN^c=V(7wnp2cdGXw-Vk5HF7< zGgqz_ptI60mshmUX)S9zgPkn$Z?|bRU|uNW9kxEA9j0@ie3Hp7|He{;3k{qpjLydi zF<^3Dd%-drq7m`5bmcq*3BRoF@TTpb_#F21?t5iDVz-LHstNfRPI?J3F$fNF)$g40??&Dan1raU zy-^oRb9<>w0gKFb(f%w>U8W79M~4Ts%MpT@y{M51t&vbK@nf!@(2)??0TzD<6Q=1|x8U_%=8ws#mT300s{2rXK=cvk5exmj?X`@;#Q3qw+Iu>*xgEj8s&|*C zGOz628^{{<%6m91`mfsD9=5@98gKS8ss?hQsAnL^{bnDTIfPGnI-wujOdG+%wSSym zNhlk=XHGG@H>FpxR42yyB1iTe(ma=(zlDXP`cWGUh|y7uC)a@aF;xYqdGt(cFOyqE zE2Y-td^ZWI$(MDa8(^ZjxnTHldqDM~1=<-2g^5ptqNP>F40Aj82twvO0G9n>@*J@vBzQ~XI=didb7|N7v6eYt@%fDXELT4EcK zzpUd0qM;-03W*~4)5gn0Gs2fKxAk8BLn)T&LaNYfWBV=sYKn=`UxaJ$K&0BO=Zz0S zbKCvyb9hTgr4u|2Bdof)l)kxaToAt-E^xRx@|((%UszMT!PS&N+Rj6rSKwM)rnoE? z_%07c&*!`bE8-&%dt>9V!KMxY1k8hg%wwyH$WUI9H}AgfY88HVrfHlBY^Dh7ds4op zx!ERI8N92bfmdT2`=plpP9$9@Lipfp1`l-dz<5oY*HiPIflQQ*R?S_7&^T7s4t6Y^ zHG74jg-NwR(Zf-9Xg>@J1BlC@0loypPq1fFN#K}~o+8CNDSs9N{mwsBm#pDG)=jr=o)T$D zdJnu(sYYY@X#Aa_uVOQS1TCDmip03Pr!G|(^Kt>dQt_yT)w)6X3qCnay{hM_po9F2 zZsRiD-?C;5E7Ifi_W=yFlpd^Xla4XySCE^)~R<8EIqT zW@tM6q3W|apBuAyufc64f*JS)PqN{wrtb(1LF zrOjI8wPUbb>2skfozj)NO@{QtaV872UKoP2FCV+tZHrGSeYOtTrI<5aU^M$S^}fxQ z*N^CFeh!dpOC)mYUVb>YFAVVpwXUaua5t{z5PhT41T-kqw&u1$pn|-&Ds{&Clrz|nwzgtXdfth zJ-`zDx~zuEqe!;9`jGTw%j{&>YOKc5jJCUQT>kBq3nIFEHVmbmVUZ3`z}o`}mUCxB zRM0b1vUx+i+9N0%XHt>OX0=1xp2gz(Kzb3i{eS{K`!u3=IvxQ5kc&om+X2`e&iX+OW-2>5tPQuI~g8xN|@*~+dwV!G=J zR*8G#87IPKgu zEz`-5*nby5rTcXNtj;#Re|RFlp*{V|lfM=CJ9H*@)H#_Ej-pykDbN3+*dVlBbX;V( z!7;^|@a4OCEfjt5t7f5(Msi}JH6nZmS$Rkkhb{KBp!ANS-z8&4J8bO`Ve5BNLjBaE z@VciZAGwe=@9?KGDR&cJjtPx+7_pH)*?X_u395NX_9oEJi$!a?zDasyaJ#@>F{f+M zaN-J*2Dq%wcnv{b^PSHb%Ek+L3>d=akmP9^nV8wvpaB>r7TyLrjRDQ)Rgq{J#O_6kVg+udNtG&MzA!8pc`HNB%lP`q*d- z#dKOblNDd&=}vh&VoW_+36t95QGK4h-sF_t}w(%l?HPM4HgnjKnMb{nxo^yiD}uTn9ncYOn-3-agm6;kv|^f>uy z7(c=Y@DRA2a%o(u-IjD|DR2^Y;IY6fvg}f3-lZfHJOZB8!}9DNvYaJIWkv~E-Cmns z&P}_5`R2}+P2iy2`dGFHLqKqpvwHfDB!lc0r7BTcak|i@XceO=rw+KW*i|!eUk~rG zS4F_R2G=e?xE4v_)+t6(xGfw$52!shF!ZVkGh$hgA`3g>jl~-{7rExd+w=v-jC76I zk%o62F_qRs7_#c4Dq%-EMq5>Rquc$$_ZeeNG9uDGTO`m8Cw|{7Z#AOrK*LWU^s2^l z<$N0TxMakiqRa9`)>Q$2KXar=J9oVw#ymrYj!m>_Y}Xe_RCSigH=ca#e2}sFJ@?we zy$!{)f---#TO8*`fjzFZIR^L9wA8`Qc;gauO7<1kx&(8_0_TC}x?2V4mgFie*Y*pN zow0lEy%96G^mvTr>t+&}VV&a9PYzEeE|J<6N8EET`?kSHY8`9GgWBA)iz{Fv^T186w>3a%7r;h$CYDP^WfG*t`stF)erByS zQGeB+a7*8PZT02*g&IoBmkn;iJCbJlD>b+5SxBcUH`_kcD-JO!zoqZ0x%fh10|*$| zWZcSf!kJRO2)8mz2KHy>s+L+8zjJB042p(XDp}Y`#{=siPaN*kdQJoC4) z-+@(C(Tz1uDYOoB`{_^Oruny9RHwZ6e%yHFPLMGB+THQw*8C%V%9v}~4r*YE>pN&g zL_E?*I@TomKvm~9;p|*@x=gWsRBRniTaO;zw)xRB+W-x%QUf0AvsL!~k>dFy&aS-V z2A4}{=J*6$L=zvq^YpJWR1~G{zf$24f#2O^fEi*;X`zw5y<0kh4EDpRoG-|ye6Y`* zL!oT6&G%Y~g$f<>rfthv?xpU!3q|h@QJ#u$BW(g-6p~MEDzdnd@hirM1IRFtB=f?h zNAiprTN4vNgt-q~xv7kM?* z2vH(b(^ihcHa)Q@_hpogGg{0`_OE2v1#C#)W@|ThfJZway~O-PP^nc5h&z{Px$X_C zexhk-<*Y{E*s#(l2MIk(%d_pMD7>53?9a?XbXxg134=u;nYAr=dx+ebEQ*5}kOPEf zj_L;m$`pC3?UZhmBXe9FC?0OQ4ti2v?yj)FjbwHrzI3SP)qmwtW^&Mcfq>3hZX2pX z)t=@>4WdY*iGtC)%eP#$YF&xHp<`7_J!-E@GW`;To|Bez{oG<4Y%II6c1DIr)_Uf@MBB*@i%kTf_b`QAgT2jNZ%v4G6%_vz?8qEW^CFu-1vg6qs>9j8r_2Qp%MqKgjIyw2l5=GmJ9~xQ-h4*6 zI6}x2b~(af(B$j#E#X6aoEk$0z5B?tK|UKOLq%?z+V$Qs^0IiQ%4B~p^ns>>*SW;- zD*{-=mmMmY)qUgZ)|w91r}uPQM7Rc*3)BgiLd9m^8bb*;5GX_9YJaB#lRsFBGQOm) z-(x(T0DU(8b6oGmJ$?va847(w zN=k}T_7@(OSX9)7TwQ+m4d`E6&2DSQxDH644Kyb{1ukIuhEHN_Of4~a9HtA<|ho!;{Ad^waeG7 zK%x9T(Cu>D{uwR@{%MRD9}%RT_w@XWw*nYQqz-6ie-!T1KiFcR3p+GctHJ@te>Gb| zK(x9n$Xgllhg3C?0Xrel6#T~w3;X2y9^dG=fAs*f; zG$&X32RUR!#+DU$<7c1zK@b1W!TtYo=8)^X(Ti%ZKo}mGgICR5ulmb{9_hDSD7$Ym z7Mkcl@GV!OM;1-X1@OYI7>2CG#4T|C-5Nor!mA%P4WtEleEqf#(d(UI0?2%daR#aq`&5;?| zD-kIoMMt-&GY9ZDB3TR#-+o}enZ3PSj_kT*_+kvXA@rxQZt z_pF}I0W5uEdCYr#UgJ|G=n}&3G##&bhMQmW61(Kvu%V?iwBbRChYTUkZ`F=vNKu~V z_28N4`cfpT7KZ1H%^@Ylm<=6tP~Q7uG?!fw(XS4h+vKIrePwhBzVq8u0UIsPRfY?` zmAoxb0mcx36ZvtVDwF_1L2uH8ilDQC%cYLz_V1?>_Noa`FS)JeCuiZvg~^J`R8x42 zXYPx`X$6jQq35>b(}{&fAZT^x%7?B!LzGSzmp`$n(LBcZ&5#Q?^d2-x^_n8o+RzdV z-Z_$SJFCyhJhMPvLCSAyWpeUM#h&B$PcP-2#7{{Q?Wz8L^tsp*x4jq1TK%~E2El_K z^3y4j$TLqhyR;lZvWpqXAmX&K`}xuA5MX-7i)a?bNah15y+A}Ai}==dbo1;K|BHEQ zX0?tJ6j&>B-~fU` zQM7)MlTasPAHhtkxzaK*y%SEP=H>gG*i(@G8ZcS&pDwrq1=bK=qe^Dnj<3Uyp#;`O z!YG)Ji)gE(dKIi^y@HxO9KIoNLsVJK;q2jmc=#P+~#SGl^x?h7%?0D;Nm#T<^L#YI=M|Ro#z6gUOWV512(YhVlPk^0GB;Je2}ezGY9i-LR3tHxU$;RKaiu&r1?_~)KId;a%)BpMvQTddpCmcfvJaTYcvLSM@i2JMg0 z?@b*@wIsmW(L)~xfiuUgd^VWBE7O(r*O+D!u`Su23fExInTBthac7D%){zo54k9$1 zjkI{YLNPO=U4&~KErNwcT^)9PYy5M)hoH$}>itETI7V&OSV^n8Q9Av)dszYtADhGq z+o~*k&sOu7N8XEZQ==B0nqAs1EiHu-e4XQ9ht4^+v>;OZtXSO>Kn!q)8XS+Z8~s(j zg|OK6Q5H_?DXpyaJ4_mK57+u`a1`rWTWj&$U&AG}N9SsGsdD%8JTK-(;MoQi7=wfW zaBzY?IE_onh@5{^@QdZ0D7QgyM!QI5(vLf)-sX50uD_8W#SPNtq`z^;Yrvvsjjhun zpE^OU3^u}U9IVnSU2j;gkJS)>E~$_ZiS~fq-%|muv_SJ|$<>MEW8xdFfR7r82~qrw zMLNM&H5pR#cQw~WT;KqJeOCXPn?rx*Zq`a*_o62IKao*AJ}BoW#L>C_{TcQjbyfO5 z>l$8EK_6y9GTqSM5DE^QP>6cCIjf2P8ykjpW`tp|tHpo$%LW6CULH`M&FQFDyvE;q z-dCG{n^?a6NV(-kMSzb_o!|PQ>s+t0qSveM4@75q1r{7sXZ!iPUE`OoFn*FoUyAka zWJ@KkVEgJJnAx}P_ky;MdV_3@KIQYQGTtTTZVYImkg<2z;Fj|>j4XxlmGhz=$EA#$ z@7Ohr24lD$QD2BcKIzUBKS9^m#>*JXH|GE-}#imh(T(pOnz)(ccFuzM{BJf`07hIqYgAzo`4%PS zDwE7-*%N;6qvO4-Tb$w$4&)X!bi`59UCL6+;ucL2R!?j$e9)YEkD~DJ`z5nXnticb zD6{SRD5qJsoNE?mK%6KDoWy`I1R#~q#=;)K`jYmDpU)9z75ECLdR{`a`i}AAttZ zOk85RDQ*Sh1^*KT?h?h{1TogPj}7rMmzJ&v!n$W3T7Y%y zI_MmfTee{ungB$XimQ!@XdrrWT^#pTpT($GSS|@`RCf8L3};-sA=zjOF~&6CS30;0 zk^J_r=`Q&Hj8IxKL{-uQ0tAe5laNnowS}+=!d02QB{!pFOUu20ka7jsQ2a_vnPvTH zWlpbs@0W;akv00wzARZWd14z={hmq6rxg16TGjfm3GGo|NHc4B0f_7-n{mxE!6*oM z8q~gk1bwxs@V41}RQMiR3uDI1;-8roxHBCEEc!u>HHkCx`(gkO3F!#`>^ zt(wd%N4&1$_ma;|%FW27?X6Y19vv1oa(yy*QSICo87tnPYKG)hn|!q)K$#to4-Vuv zpS@MJ6w;$eIr+jW-^f}C4F}LPrD~F97uMqLx_L5)sx)1ymr4B@B%$oz{|%Bh&FKi8 z-{upf-vB^b=4jtDP!c-cFK0>G_K@dKHhN>E&XS%VY)@7kM??-}rng&#*^$CA6aYQ5 zgK_%MC#+b@iG=efMaBP7daKy42uW=mOb$RT%SsXCUO|0p8hsWi2Uy4F#MH1S91hwx zHK#=}q%)Bmt7oBfqaYh$(RT9yn1{@)PvQ$bhRm2&KYoF_y|O-+RyLMOtL4pIyK$T} zN8@nN9Y*OUu`pbQb*jxY5I7K>xoHjk+x^E?x4LL8r=SH}H*>k8&>-$bryf~WLyU-8 zJi8vXTDRCV(A!QAi4dNMOv@@rwaJMW!%Q$M(_mbubLBL%=&G%u$zV^VNlGtX*|EI4 zsSa{NnbHBZK9fs@j``7pPde!0sn5k5&7}q(?>L)Cm}QcuvR2B&*;S#u`0e8rTifsp zsZQ@u0Is6%-QAN;&ut~zyCMVt(|HE|d8hM_7CzLuUi5dQ$Z7>K`T9@-|Ih2An7PCV zAn@V{m2l30deiT)2`iKmV^^G|4-qQzEgrxrN9X3VmtGp9p?5fx#Fx4SAbRp`Xw`L^ zY?barA`(RLD;iyNnY?mR4PKnT@ohXNuVcrAG$@8x8*ih?QAsl_jB@FHb@zK-2njPR9}i=7&uqvXlr!-^4zRhx?ObA zD~-XP&L5W?j%|qOl=35!ZEz^@AIQD+UQ{GYh90swN>sqs1&VLGsCkvgQc65wo-J(w z+vV?2%5gUX^3P4MolQAuA~RUUs=tpgJ_-bKMAOOTMNWt*lX(5C3W(%JU)r1~00r%@mFc5S%FszidO z*H@AD3$qlK4HR60jx?oHUrXJ{;siIG~`tN@Xj1 z)$*FNM(TSFJvmB{aSDuUZ;S@(0BdxyHZU0kYU!WN!$uez&GR^u4kI4M+y@-f=GW)r z$TdhV7eykkgh~!;!&=)SKzd1VUKZ%Rf$FLoQr>^S~V6|oc41CD`kzf1U&sv_b61MYm%?cjANs^xU==m z`<0zmL)xr+E>4n+L;~jbhr=46`@Q@tI5_0!@_=n^#LsZF;a*2DZ!G^C!MLC*R|*V9 zefewp=ac6O77F`W-een`#>B!4*#^o=<;Ud*so9E8>!n^n(?ixZvdx=8ID1XBa3u-T zl)hPHL^Z>sK*B9WRZN&?nz9ffU0&Z(S#fWS&QQ3^*hGK^NlP7-#47oKHs%Af2l)>t ziuEoD@OM)qmk>|bD2rv~thz-m5v>wA{Dk;a-U4i9qq0T@bYV%z z2#P$e7oh~0o&q55%eQ5eluzE6th=nxM&Wt1pER7RKEkafBJuf^4qJ&Szr@#O+B+?v zFVMjAj0LV2bY0X&t_9P$^?z&M4pNs$eY7BM+dk5hDz{5BE&YIyqo2WF(iNdBwt2pR z;i;=eyK?ahqpv<%!d*pQKxxa|eu1jnOq7m0{=LacgI>93Z{VAP4n>9$#SxTy0L!~e z0_meuE7B>NbwR$|FBFzSmDsxc&-y3TlK`?zL@6J05Y{6vELfUiw?L;Xrp)#+7f1B7t{O9)KzW7B-*2iRS z3%}{@?O2!bXc;vtQ()x~bAH03)JcE$X; z&r-$OcO4xC9mU1Rv-MCq<*aVpUBK3qlXGtmFcUDGN^RX;D5YHMFynB}MQPe~pTT0i z-4(Hb2P?ABnaU=|O!S8Q7D>05Q!Z`JsMS2^K2 zzcw#43aMce>V^rwBd^)r^@v+(NIhfYVOYEHN{(zjx#87ylgl_stmF~AoP?rE+?>MD zbHc0xsgARukqY;9l$bq+BD<^snDR&v!oKzD5c`D*K_MYsSAxrDLM|vW6EX-8ihfE9 zeoFya#Q+$+7<2t4z0Gl|C;Y0==1c1Mm{7)gEIYWZgqJ~P}PG|HeX&%DV8 zqq-QdRcaCjbPe?uju(qJF`3UQd32~sd?-ojug;IGUdca+HM~g7z|Y_Gb#fu3c0LQq z%&))Tl??c?J$6yk--IafGIZC>-<2Cw|L?aTZxVuUze?lQ_>Z$hLpao`oWgJmKKBLe zbjI}GSh;zSQM~<4I_NNP#JD~&ILT;=F zqPnsMd4ahc0nVqq_Q#|gr$)*s@q(1Gu;`;MDaq@t4jHh#3)izxHqA|AUW~3!%cez@ z(z!o4c>+B>M(*O`9yXT%^V*PwDe67AoXp*IU$ez$c~UWd>$T7u$E+~`?Z`bz#m;Sw zrDG0xIW}kvnWogVb7?r6PLO*$I)lJJsW+D5hOxHXsdAF(c^WaJ34rkuKM;Hh)|9?c zek~de>N0VpYtYED69B?{<(UG=?cQ@0*C(2H0g(gT$+FsB1KfVIu67Zb!o?=N&+^A4at~f z;va=cx=n#f!LdvWJ&+2Uvv+WK9tny%!19xP7Zu))Bk<0BGCkoADA#_-~6;F=FW zVGB4<6xV3a7|>-nHs;b?Tc>T3PYPRz&}czode1mQ^cK)}&l3488Tq|=$bt5CvbPT- zx2Xh*keABAkL~VB7@+$+SX5ds5WDh~4n-3TILnVUdH`XxCdF|v4`N;MA;ho5sUI(X z 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 k$icl>bq%jWwc?6- zvu{|G*&`M0{f;lwgaEled;!< zA0H+UY5Hf5}{$woesSXyg~aiP9=o6#^lk3SA?K;5$fZ&0&=8E%euh zNRmaS@g}0Ly4x#<0bzS&(v$1-5J!$Mjs22fmBUG5XYLhu4Fv$NDbiekI!arA`7@Ad z%n353>bwLI@e#KE&w{D$*^%Ntkw5l4iBx6jMZ?)BxefCC<8%Tl zZ-Ov#(`{W5#yK=^{ z$z$4V^_ijn06SlkeFs~AX}i0eE0DgOPf9MQb!+U}DBs+xG7yPRETPlyaxW2IXVR{{ z%38jO`uqlQtNe3y{aORlmUz$-^Y)Jq{I-AO#X@>0Fs#+W9N?rvSjw}}i*#)SXAYl1ydVsCCa;}G2VZke<$WPQm)>8|_OW&fA! zKp;!bf+Hn*^k&1oVtIV;eZ+cE;4QJu&cPrlu?kahhw+D}Zb3+`^~v#{5B}tgllah7 zwDfRzLyWyy#%llTF~N%mpYsKdaU2B>pv5fGWPEz!-4z|K1UkQz(!Jrb8>gE;6ExM_ zcJ9>CFP++-IRiw$AW)XIw`}rJ&%?p^-(cAOXQArfpJ<<1Ez?{U4H8oRZ|nJWvM7aP zp})w!De(Wqaqr>&9L<8k;lH|Z%psX)vCIj*_kf#BbTrHKU#RjcCnCjmL?4|vEu@4S T`QB~<3;tYE)>JB2unPTu-l{@M literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/README b/contrib/toolchain/avra/doc/images/icons/README new file mode 100644 index 000000000..f12b2a730 --- /dev/null +++ b/contrib/toolchain/avra/doc/images/icons/README @@ -0,0 +1,5 @@ +Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook +icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency +from the Jimmac icons to get round MS IE and FOP PNG incompatibilies. + +Stuart Rackham diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/1.png b/contrib/toolchain/avra/doc/images/icons/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..7d473430b7bec514f7de12f5769fe7c5859e8c5d GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQC}X^4DKU-G|w_t}fLBA)Suv#nrW z!^h2QnY_`l!BOq-UXEX{m2up>JTQkX)2m zTvF+fTUlI^nXH#utd~++ke^qgmzgTe~DWM4ffP81J literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/10.png b/contrib/toolchain/avra/doc/images/icons/callouts/10.png new file mode 100644 index 0000000000000000000000000000000000000000..997bbc8246a316e040e0804174ba260e219d7d33 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQWtZ~+OvdJMW|Y+^UT?O-M{rKJsmzxdayJ{ zDCQA!%%@7Jj$q%-wf8e0_jRx8Dqi$}^?K=?6FriQFLv>>oc^CE+aVHhW3=nZ+fQ4!M=ZC7H>3sl|FJr3LwU zC3?yExf6FO?f@F61vV}-Juk7O6lk8Yg;}bFaZ-|HQc7Azopr01?u8M*si- literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/11.png b/contrib/toolchain/avra/doc/images/icons/callouts/11.png new file mode 100644 index 0000000000000000000000000000000000000000..ce47dac3f52ac49017749a3fea53db57d006993c GIT binary patch literal 565 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZI14-?iy0V%N{XE z)7O>#600DeuDZ?5tOl@ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=9KoYUDZ+`aP)jU z&ny=ErrK^#Gw!AcR}pdfMERuV^@&0$@(#^6b8c@rn^6RWX3pUb z4*6@PZ+H0#u=rjsXzS?6n6*sBGbHqGTU%mCsH?n#%j;eD^2}qe=iX*J@VQ3BRpz+u z{PX#N(^9X${`$90+;!pWs>o@z_n8G)7Uo7PJz`jrS+)QE@=PWHmc~UIw=WmUe73o7 z>^bR(M752aYoNg~ozu7U7&{(U>{s!;bn#f?ItjL^o`e{*EOQHqO;ccnz9hLK5@2cAyw@AaPFL~Cp#02|E|4xeQteNtB7waMs QVCXP-y85}Sb4q9e0GRUFb^rhX literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/12.png b/contrib/toolchain/avra/doc/images/icons/callouts/12.png new file mode 100644 index 0000000000000000000000000000000000000000..31daf4e2f25b6712499ee32de9c2e3b050b691ca GIT binary patch literal 617 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZI14-?iy0V%N{XE z)7O>#600De9$%>2LVd81Yeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=Cn>wTzx1(qV@bS z0hYvspf(--lM>otrqbK$7p{3DzJ|+KN8%5ows)AI?zWk_n>jwEHXrTJecpEW_0xL= z?}N`*R`T~d2{AN${y8T#GEn4hUb&52^}Op@TW4{oc)A6)%$5=G}h# z?O{QLj@aRcAIf&y&OiUN=H2gq=_}V|pWfuReDV|{jwXw~>#w)I|9${XE z)7O>#600Dep5bGK9wD%hYeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=Cn>w>~AWNX^a2R zbkveVY|45D7UnZ&JtjPwvdCCscZp0EA*0()#GOw)UH4-^&)y^E*4%UC)*|J}q_Ss;tN`nd8$>x9$_Xb^O2EpX&@C ZI46EzbLxq-voTO7gQu&X%Q~loCIF_C`w;*D literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/14.png b/contrib/toolchain/avra/doc/images/icons/callouts/14.png new file mode 100644 index 0000000000000000000000000000000000000000..64014b75fe2e84d45ed861974c72462727979360 GIT binary patch literal 411 zcmV;M0c8G(P)!ax*-PXaQ9e~6^e1gu=a6a&KSz}bR`+prYG9ayB$BDjWGfIE;t#wl!+ zR3S(jA%y#i_@eOOedXoc%RQe%L;wH~k+s%ZI~)!<=dD%?4MaplaU9QPGski2q3`>r z(}{j@0a$CLl+)={2vLWml*i-oa5#J}DW$gCZB~Z!(!M#)2St|1_V^0qpmCrBof=Y&NUas@LmfSw=)4B4f;8Fu)(eFsv24 zJzXxBrayquXcR?J{XE z)7O>#600De0j~t#c`vY#Yeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=9Eq_Jl&Ka(%QdX zh{H8O%#_7)Tc@t$mM`p4(Ne7omR*~(>gd8_8AZH{=3ms$Fmzm^yL@_+(#aQQ5>7QW z>3g2fIsH(ugM)!V$x4Rr_+!J_XU%4xbz0aE;^N{m@42Z|@0S@TQ=WbP`TMV5Ok;<| z^Ihv+@6tQ{sciRF9dD7Nr=KobwJJ68zJK$<1Pd9rz%4O)*;}Jzj&~nTGMecz>B%lV zK|`fmIc8mp-h8iSXiGFW=C(L+XH4DRxZQX87^-dLuD>odo6YLT@Sw)dfBEIG)v2@6 zR)%mL7GRj1x-&v&+2q@A%a&h0`Lw7|#(w_!tgT!PoJ|+re`lxaY7e*=hH)_rZeB4|imU1$R#1`!P>&$poQl;nzm}mD5ZFopaX|GsS%q*{P~< z;WtmO%lhToBL0i}yfkaOt?EN=nkLNGuU`ywhI5H)L`iUdT1k0gQ7VIjhO(w-Zen_> zZ(@38a<+nro{^q~f~BRtfrY+-p+a&|W^qZSLvCepNoKNMYO!8QX+eHoiC%Jk?!;Y+ zJAlS%fsM;d&r2*R1)67JkeZlkYGj#gX_9E3W@4U_nw*@Ln38B@k(iuhnUeN2eF0kK0(Y1u|9Rc(19XFPiEBhjaDG}zd16s2gM)^$re|(qda7?? zdS-IAf{C7yo`r&?rM`iMzJZ}aa#3b+Nu@(>WpPPnvR-PjUP@^}eqM=Qa(?c_U5Yz^ z#%Y0#%S_KpEGY$=XJL?(l#*ybuErX#^g`ttQfwn3r>K)tuC)r#2`iJ>Prt42#Ndx#Uc~1)>aw z3jE@Q4|!9Z%lVv}- zc=48cF7H)t`(Ck`^+mtha~Np7bBSw2NpOBzNqJ&XDuaWDvZiNlVtT4?VtQtBwt|VC zk)DNurKP@sg}#BILUK`NaY>~^Ze?*vX0l#tv0h4PL4IC|UUGi!#9fLzfW~Qojmu2W zODrh`nrE42VU(7fm~5G9U~HM3l#*m_WNcxOXkuzEX4g z+-vfUhb0A>b04=Im{6XiQd1v%r%>h0$G8U7E1If8OQ!N~xOYY5h0NDT$p9(iZ?Q&e z18-(+l~J8O`)kc}e&uL$eW&>P-#`~Qm$*ih1m~xflqVLYGB{``YkKA;rl!p+yCFkc(+@-h!Xq*<< zxXkpt#FA2=d1VEBsYynrsitN|Y01eJ$;p;U#>wWX2KP5v&I9V=1L+C? fTFYQ)RAFeOZJ=$?lDoSWD8u0C>gTe~DWM4f^}upZ literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/6.png b/contrib/toolchain/avra/doc/images/icons/callouts/6.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba694af6c07d947d219b45a629bd32c60a0f5fe GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQ*)Bra@SU# zmiz#bR~{$s2si{S(aY|Z}Vd7tb ouUmn-_&~Y>fYve?8dVq?X&Y!8wB+ut1u%w%U~xZhnMEEs6JbBSw2NpOBzNqJ&XDuaWDvZiNlVtT4?VtQtBwt|VC zk)DNurKP@sg}#BILUK`NaY>~^Ze?*vX0l#tv0h4PL4IC|UUGi!#9fLzfW~Qojmu2W zODrh`nrCEbVQgk$XkwI@Y+{_8nv`N>YGIaQkz#0QY@Te9lBQ<)awbq0A4pdK&{_sV bqY6VKZ3AtCmfYR7Kp6&4S3j3^P6u&S`V$cAh@R~F=4@V4jxkzlaQrcFYWK{)(`o5XZnut z=nE4SU2g1ZW%;@@I$>_e3F8a=8WK~|CVXt1DqisQxtIX|`YW_n&?Nh#1gQ}d)$LrYTw(_{nVG)tp2V+#}WG*e^KRLdkoLz7g? qn(IA84Qgo42`r6v<+Hvch>@C7(8A5T-G@yGywn*$#_oy literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/callouts/9.png b/contrib/toolchain/avra/doc/images/icons/callouts/9.png new file mode 100644 index 0000000000000000000000000000000000000000..a0676d26cc2ff1de12c4ecdeefb44a0d71bc6bde GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQNRqa;^5&H%t0&v*|C|wdb9$wI zR@+N9#RIowg@Uqn&z-__Tzhhz!sG|vTxA7?=O|Y?u(d4T{!RM9c7chr6d%1?R=i16 z?@Ic{f32YJFJnVhX)qGzOMplv!L->5yAlT#}irms+fsQd*FoSE84k zpF44v;trs3T43Wc)AJHbN`dAXo0u6Hr<$gkq?lM38ycjV7+5A5Sr{ayr5c%-n;95g pF*H#D>f!_G3IJNmU}#ifXryhRZP1dtyA~+J;OXk;vd$@?2>@J{cB%jX literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/caution.png b/contrib/toolchain/avra/doc/images/icons/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..9a8c515a109faf9159777ac9e6861c2b8e7df383 GIT binary patch literal 2734 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 literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/example.png b/contrib/toolchain/avra/doc/images/icons/example.png new file mode 100644 index 0000000000000000000000000000000000000000..1199e864f8502a57c3b8def7c2e1d90c5f760a73 GIT binary patch literal 2599 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 JPDHLkV1oa#`7Hnd literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/home.png b/contrib/toolchain/avra/doc/images/icons/home.png new file mode 100644 index 0000000000000000000000000000000000000000..37a5231bacc905886c9351a291e0d5eed68dd60e GIT binary patch literal 1340 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 M07*qoM6N<$g4<+Y4gdfE literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/note.png b/contrib/toolchain/avra/doc/images/icons/note.png new file mode 100644 index 0000000000000000000000000000000000000000..7c1f3e2fa7ef8897bb55ee0e0dda088dc49d6408 GIT binary patch literal 2494 zcmV;v2|@OWP)Dn;hlg!sWaK|u z738H>q0O5&+vt7wuzAz%lqL_6pE$;`=_$TGUSZXTKE{?UTV#Q4eNlNy5f~X6vC;eP zVar?IL^}QqvwNN<9++V9)D&M@mNI(ZJ=}l){r{0jyrc*W4-ebj%iAbbjxqbUooH}4 zuZUNi7mlaxe8H{Yp@$wSHWB%^MdKw!V8@OfbY&U!zwaWH1ECZMSs=**Axr2VTE>nY zJBTp?U=3MN%Nye7^JNh+5usEnkslf-lmqG&b&3m$`XUlKILOS*6L|lEeL0JH(vmpIP@3Z^}f3}I(e8SSttw+1qk&H*S&}e3GMAA ze*25>uxL>y9qlEuEJammu}RJZ5CH{IL<&-v!LqCF#LVnM6r2|T?>)7XyLk5G&`*lKvIwdGy#_(nzjI3(5CqS2q6%0s89LCN8ZARpWMe?PmD9V?HShd%D^46n-da~Q0bB!|EBq>kbB>Eu-+5C=y+<^lE)vp=*IvDh z&wTt&rcO=q;MU#j89PizM@H}-Rga;VI;Lj~b&!c7sK&G4*;xL@AYv=42@Ky5Lkv(r``>09+Sn36l=6 z84v~GqWqsXfEXi~07CEyNgBxW6tgmEaLm=~L<2=p=SYIbsghVP_0%`Ra6A$gv2LUnu6t|!IS4XAcz)5gy2b%K$<2%qgy+N3n``vNcr^Q zmN%H6A>=IzEhvB(BZ#2Rkw+mU4vPUNDKQ4}7*SQ6I$|_XE%HVk!F!HZs!SX_&UNe8 zV*mzw_wDD{i7DQ&ZY_yR5m5{S?2-V?s}HCuqD8fE!Q(XHcTbKIP5Il?2N)Zlp}ni0 za%UfZ+;xO+eeXBy-2EKRC+t6XlI=Ujd1TvD?EA+dL=(RI{a^Cj{$q4^cJkf(9z?V- zy=Zh7FQM}W(AiN&)T2Jd`+%zF=0aLf|5ja=Oj3vEYJhk@_ zcieg%Z{4_#y<_|N!;^pK%{N|)i16Nb-pC`5Zs*$9E@RE=6|KR{@N{=|@#U}mkozBa zj9YHH9ytHdc0QR`4!oEwUD8c=cYEu3QFjMp&rY!6`ZX<(dEW4(%~6}32H?SmA7lON zR&w3Ct9g3QKbfn~0`2E6ziF8+3;xuMO6%lbHX&cK1 zdW%z5qc3DxiJNa&2Ph%Hrs124#YGz`7*fm{3t91PH2%;Sh14O&014#tFeAXyE|BL>6|K8yg#=x3{Y}v$mQ|(ef=8&(R{e zL9_a)N)Z7RXqL$0RL7Y$UOcE4&XC3=YFzLj)09gtqt8D33|9;d6d^{yIQ_RMW=f2X zJSurEg~sANv%)wU9tJ56E=`rjI*mptS^!FtWMKeo-MZDbZTmI1-F7=51=pLSuF;4{ zF{zqqL#5?pYt9WczAK7ZY-vG5hcpI7K^jBj#pRMHG%+#32i|iVi98n4YW;xYr_3{riW@h)^doN%7{9V+h zk6;!#cyN-uUgNL3_Aq(mIDg$ehQ&xndmCL{ZLD10&oygSAp(N~y+srn0E~zbkyt-# zpQs+SIn0db4jg3nt}!Z=%7OqWPF0rk)D zr>8l2s>1lB@$ff)#?*sGJVnVz0zW@d(3twxNo#p`CGHJ_WD_uk{2YrQse z#LSqPnK|p?*UYHb>#ak)bB-iQNRot7sf73b^6y4fwdLW$YlU&m+vcV=Lw@G-xp$l1 z`?IJaBE%S5qeD}ZB)L2a{V&M>_pg-y4e|OV literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/icons/prev.png b/contrib/toolchain/avra/doc/images/icons/prev.png new file mode 100644 index 0000000000000000000000000000000000000000..3e8f12fe24c6e042bc7ef4badb15449f71529ace GIT binary patch literal 1348 zcmV-K1-tr*P)4zN}O#(F4Jyqw_mKoxsZ-I`F8^(@$jCw?lX&Z*cU6RDktP#MR}H zlhq+#oL?sxw7*T*#_N0K!;^R6&X1hFlgZ`&eE8s)di4)Ja|MTlarpRjgN5sT7OwZ1 znM&el#YE0!-%i8S7Q?lgOtgpU@w&`b50(9;YPBkx;KCEH9mmVQ^vrMb>bbJPGnyb0 zKC3o)?sr@H{r)lLrjvYhs?N48hEXJl2-8~)*_2Tim*VkZAZD6#pO(wz(AjW%_MmbS z#~<63OCBm2w1yzGeEq);PnGi&#yzxBBs@(N3!_j7Ld!4|f=Jk!(ewhB#no_THQq5l z#kbeo(raf7A}?mr$y{ldM{F&vo^WGj$dh|>%uFRWXHaW~w0idifY=JV3o-w_lE^md zndfWa%vUZj2^`4f#&kXz(e7!Q-H6g$hPmzj#=u0lRS!6Oxl0hq|ADcv)QCC1oToiV z(IKNP%{^^ZEV@7erHd0;#UQW@0?Xdn6y>?hJ&xey*Xs|=`={X zDt>8Yl8T*^pwyj^0}87($N)R)uk?JbwQ~IH8;5pZeld8Z1z%j+04oII;ZR95auK@> z+-&vjY^;3FF2djcA-wqlY|C#r9|UmheOO$(9~=vWF&GWq!3ZR-Y1>=Y#yKwF851%bhFn^Tcx=|i_Y_;w@TcEczP#9FOEO?A8IbitvR+8qgapGL zo%PkOAKo~z-C3A-0G=)BrSI53t0XEHCtY%hh_n|Gg&~Wzkhy6OKcPt&#p#76X)h$> zZD`Ua!c`$RZ`T?1)<4;&K7J3VIRMpaRen`^y6f#@%X}ty!!3}(Aiu<&y-BPF2ysgfxD;Ok7lwd z!`7_3xs1+T8BlLWc&@^86~=+JR>=9QEtXf?XC|X_$BVl9A7HIgsl=P$YPBkd%BegzoguJ`Sw#ZI@`Y=1HyUpR3GTB}ql;R7$o zkt0VmkUq~}{}}1a^A@v5YgNeljt|fo#6ug~n#=HVGG6&~xBl!jumUt6dO_}iE5NJ8 zGx@eE7ID0yf~>-7CDBOR-f~`U+#Yk*8bAjaR4NsFFXMY?uTl@~Xu}==0000nf>Ig{1EaU9&jkXs-GLC9WnUJFu8^E@0$2HhAO}e_e z=XQsH#dN5}~1?frSef(%RZeTU#57qGUyqBxe%nia~@cod?_} zZki^2eSPfQxs%x^*-*HlnI39*+lEmbp@oToHh6+m2;f7=}SdM+e)sZR4KRk1+qH#Z(0S#FA-Z z@f3+vhKz1tm=-t=q9~$z6ntI}p@1Jn5jp?KDc*SH53FCmo-JFp5C{bD`FyTN%JxRt z0Jd#ArfG8I$PpfY{Be|;W|rK3H-4X&{=rcOMxtbNBQM_b1oGbdydJ7Tem*&Vn6Y!m z*}8QrEiEks0s&N2b-ghoL|J9jHGbc|eJoqHjO&)H;I4b`Bbm{8?^G}6`iIbT15pqV zivft@giOBIbd!ORI5mxnXu9ow)~s2>o;`brMx&(DX-w0^w(S|8?u<#CYy2-BdYGR- z_6)OU*U)?6G6N&g&x|YZl(QwXghzD4LhyuH@z7?TdU_MKZL@0CDgb;wAF?bvr94qG zgdE3lOw;7>;lnIjwv088b`Ytl=A$#85>2EE8;e7Hbd+QwhGRRZUN2SEv+?@gvdFkY`0S(b|?c1ZxsvK&p*xbx0CXhE({j;&Ll{D@EjM9@8{K5U!}UbnouZ&s;Wqm zR1lzO4!EJy(b0iY(@bMiGiNSbCYns=#j=Dsx|0J8T_%mV}>^YG1?&-U%xiN#_w=0iaMx7PRd^|5W+HkRCR4?|-y2Hlu1 zkd%TTAc+#8V1OUq_5Eo&J&MAE_y3@Hm6{Zf>ZPXs20A-C>FMbqnM|VVI<{?Rmn-D} zU|AMBckblg_H_jOJ}z7up0T=!qKFy{lF{^nUTv2+!iBzr0lt;Lry>*>EWZqNrXfYwGCg>LQUy zkWQyD45K^%H+)`y{dHztdjl20AcLc^qH#YBNEF$(|0qvxeU1Z%P7qC`h$d1zw|76! z?>&&OV>0dwJrva!p!!=k(%s#i1t=6o)8+v;e7d{4X5!H%)^~GKpar zSf+_(TUzX-w^eD@hFQ3qDSxAyZZbdB! zVB0pwjveFr+aD-e@7*5+7{1g`ZOts&+FEG7u8wQwM3^0^B2?kW@AIO_GO=WeCx6pP zB9)mj2L!<5@#6DWaQgHIWHOoDM9#Cf;7n{;7QMZ_+_F5xX#a55#RX?nK|qpZ{`lKX z)Yr`|qz-^kz>i0n!2>xWdproDNPmAnx~^lICYEJQ(_1J9a2$t`krBMAil&=0#=bWY zAeG6lJm>p|*wOiCPJGl0z}rVpG9FLm#eLC&AP9(}1dc;A8pSkCcP=Q;1Ga6WX&RCw zV_5b?0#kUMBM1VKn%SH@bCH@zCC5HI%l<>n#RUQ+7SeS^OuGg8jY2ez^+*4 zgy$7S!M5$GQQ`=bnOqbg5{aPeI+7^j6f(MmN8-^ai*IV?*6+**;L^}o*|G2HwG16u zk_m-Eh+=-EyT%s<5Ji!Oh6WOe1gb}#Sn}q&w*-h|+oY07e)hmUS$*gFhbJa4n0|i| z(X|u~P+MD@&70ivnYDH52d;vJ3l}nQ`6515ot|L1i9BUiO{dcY{a)_9V{umJSUfrL z_sQ>;oCqgH%cRJp5;Qe6A+^K_yq?0}FQPXU9YvNE2KxR>OG`_(Yf+X51Yx52q$mojSFh$=&nf&~Pr-00Bmmc5 zQnRaSE5+@(By^JZ5S^xjmUM0A8yY@DHseYCf?Q(s?CFc{1NlvRat!$?(CwrttL zaPRw=$&r#F;DUHnm3NPQjA5EteRHeBpRI$6crTNRGd^$;$FUgh{SRx`t|b%-5ex?1 zJ@FL*2%;$B@puRX0&Ly7mA}96J4Ca@$~4EgXv$#6%WrUbcpTj@*?;&Xrezn6`%Eg% z(8aTelEi^MJK3;d1L1I(a5zjL5Xep7X#{0;C1SA{d-m+%>0fPP#Y3A=D-+v)7=hMt&{flcGj+4OE?^+s;Y|0%1SCKD#|jxY=B${ zP18swlf+^%dU|@;wQCn$U0u}FFJMmne0=^21X0AXZG?%~L6YQ&bAoh&{=N^neC9Yy zmo8=H%9YgD*Aohb2#3RjLZK_}PJiz6fpj`eGMOZiNRUV*=uah}zm(nwpwev}h46EiL$bKKy<^!C;VJF!<%454a=ughtnOG)*I&PLocj z$xLo!G)>Ff0=nxfS(fp5Jb1m{>=MD}^L=$EG`S=9jLa~MthgI+7r-4ZfD19@jLe1zYw%4)aycz=34IrN7Q8_?WBoG2YRoWs12q8e+irO1DxN$-1 zg)8b|5m$tW;J~4XB7`Ub0mW7NptQ6peTXD>;&}bqwRd-hgWI%$wv04~nfc~7|M|X| z?-SghmG;akFk_%6FvbM~m;j>}lx|dh_MYioZ?CukbPMnbm`w4f{4cn)XZ8*dZ)2&~2C{D9rqR3{A4zlfXp@XeI8z(ouZm`=TGcf_2y`6G zDARiXLG#H^p6A8a1ef;AZUC_lC%FT<^WDgAIDpWpiYmO=66lNs)uut+J3D1q;e_?(#!IWr$JIi6-T zZ}Y$g#rTloY{iT=LhG#3Q@+;^bc4{%Aq$oKiSS(u)n<$ne{r zEnawRg!?D6+_OHz*X25cSsP;vHxDavt`fgrOh&?!6!?>iy5Z-dKsM|@J34j&$nw0kz^tI=dNSwB0@iL+K| z_aOzmoy+B(czRP-3=KdxGK7(#>PPI@JWSe=|9Lfc-J0Q-lT8GIFw!_ykGVzdw8J>E zV*j8Gi~*bS`9WDo$28iPmBIE$hpq_)ur0yMkB>5aaEULE4A2N%nhZ!yePcruixQYX z$l_>D5cD+lR*Vp^b*exn)ek`w>ow3gF&JY2*s*zpoe#EH?xeuZg0LpAoT3C=WGd^b zhLD#29=X*aCxqldk`UN-{%3IcJSXZNPN|kXxM_bpzJtqgA_p{^+5@m3AgsJTPc2)g(a4d_1G$ z;In4E%AnI>%ncaJ28_7@?gcgt^n1ez8= zxm-54mR_IhM%=4)vf-8yOSmaPN*PkhU`xZfN|#okIdV4O%zW5ivkiiXQ|B9cx#k}l zNsjL;h`*1of&sRd)bg?^9`XZwW1|yK=3K>a&c;y^#}@Qr!+b5G-cE3AfwEx9k2pH# zvrugu8jBC_Ez0t*z>?>A$tt*9E}LyrZf)629`*yvt@_bqvlBaMI~LiDjV&cofH4Wn zD{YSb)zN>PZ?@|7##bZB@qL$|70>gcYgUk5yLL$+dz6=+isitI8nsbMF_Fty8GvSx zggVg`oA6XRSv+vbr;9-Sx)tOqxB#3=GFfPdViC(J3djkx6ejLU-Cih|bMu4NQVnPV ef#-Q^63Rc48$x8f$~3$H0000`P)d5JJSZ-4p;tQ2(;H4XU?3FZEbBMB9Srp8#ivqs;a6%@Ub8@O_QNeC{BaH;Gi0YAq~Sw2|iX=u3R}{ z63TGCE2We@Jw3ee!V4Tbb}Y`{bzLVA2+-NtiD4Ln-?&^Z?DqKZQdO0loSZ?w&(F_C z2!X1qgJV1%56?gUJgZl)X71d%j2kx&hr=;sU=K+^N+~@a4}13P;n=Zbae*2Ng=lYY z=i0A+g|>O~kVZ%)rM0z8udPkBCL1?yWbN9u%$YN1SQ2Wg##r$C_wP>v9}EWR?Cj*? zd+!n2ycr3DnyEDH-OHcr>XN_%96x@XqeqYO_19n1-QA607|1l1PPqe7@O5={yz#~x zNtW;E=->}O`x*8G001LO;y~%{-OQ-2PT9A1?ON8aU(a24-IaDHk_bpCrQ7Z1z<~oC zIdUYfFBA&V)YL@7haVz$?i?Z1)S>{TJ9aSh#TQfduUN5yZQHgnW5$e>B;p82DdpwM zm#MF>=hatVjhiSK4AR!t#y2NVVx+McKr`^#z+VYG3@ijnfUF^i+*VV=tX;d}+M?K= zeDX;uD=Sm)L~N?Oe*L=Kx^-((E)N6(^2(Jf@}ph5DaEQ$%QrSQa`^CJ z4jnoaXN9QSTsmaxn`iRg#%1d1IUEt#jzvcE>bNSwcTNv-sDV=f$g+;|^eI7c#Z9>P%-9MO5 z-l)<1VD4Y>n+u=fZR+LLsH?d|WP9 zWCvEQT9wlB4Gj%kJ9!d+bu|(Y2^x(aS9Tu4)Cv2#7(Zq-iWNc#1IyGZcKkop$05@PI%zO2~0WQ|m#Kl519$tCn73%8hXl`yM5C}vFOrAVB4!o}G zw6wHviyrWTG(k!b0##8^L}a8M^zx?*XPI%&LK@p| zaP*T?90A&53=-9bpZ=7K)zwK=?t}>w$j!~g?RMky`H~MZ(==&lXrS@^_vx*zO>&u3 zYEu;u7E)M95k?9t#yKp6X&{9FX<>Kea_2Lh+uy={oeMBjg*KHVs2!K9f==8`Z7US5-k)!pfYjNRBVbJPje%t?x)`u!lv30 zmWhxGrfEh1}VLtGgRZwIh&VnFuKmLPtrlUZzE1#sq!`EP8Pla@-g?y1TjX z*)KW!<$vM^^pGE67JwPT=5T?{fvP%CRTZ1fh27!6<;ub5?P6llZG?P%xLgi|jI5HX z6wkCYPa-gQT}x;`4eTjj&iJBYq?Gtqt>&wL`#HO|*YeH(oMrZ3&m${48)wdF6uT3f z%|f+1QEdt~RRyP${4wLX|G~wC`a21F`!K>9L2oB{DGZjW#1V+~v&0E+1=?DgDVR73 zhuzMoafK{gy^cGlP2tU>Yk<8>x#RncxuqCaZUIu2Sf+(U!KOG-RU3-aN%rV5I2<;# zKo5O=y+A1LR3AbAs%_6l2HX?dHd*Y&VTvu^m}^{!a_q@#s{=)vp5X1sLZ zQxX`wCnQYf0OkUpeeeNBD2Qd~NXrDF<8Wm&wrD!@7L~DbO%)|mr{VW@6ZHF{ca6y5 zWg1A!z|_O&S_mx^1Z((1b0|q7;B-1sRW;>A(|~tgIl}qheuWkaV3}d0FhLkNoen0H zexLD^ZYL*qG+{5GJZ3$QxJ0sL^8wu6>ahuuL5h4qzBMdMJn%4AAfO z67u<&pg`^r*1x-|Dsuu+KPxCG;J!ECq;S!qBx~dW3xExet-^in3gKY?fRzofbX1|? z%y!{)Wnr_aAPl7LN7wx5p#WOYM|Vd%-kx@(9zeg6p1_=Eo?+ghLxjWOB#dzcVlNC3 zc||KMEaZpBj#0R9Vba8tfYrbgKQ8A_e>{)w_hN%Lww}v46qni4aIM)a{Qx%0u<_#J-|LF~+{;*#Y|d`%`Yuc(>#nSlT zpAVxq!|i;RMx%1~x^+DK_S;A)(RDq}xQe0-K1r&o8rgy4$B$E9UYs5%<>D zGwHzxlTvE|@Dy-I4=lLvF;2bzuXwvV2>E^V_jJbqHqdieCEODX^OV}uasx}F67kw+e(yu6%g)21=QeJn=_W~}DwAg{S;F#9J^?_}w79;;#zxk!U!M}Z&1O>u!&y~TB`+_J zl9Cek?c2xl<;(GSJaOOwii?Z6@2$5eo;PoZD`t949DnEH#c9DeG&E3IS(z3*B%A}W zBwl*yCAMtY!i5VLl47Eyq=X0FeV5zj&CBT4mQJTX{4h^^`e|D58#ZiU*|KG6!9$wo z^+b0{7ZZJbeSB74&NpYzCiM*`(|`0MRu3eEMDXX%onyz29h8-o4GBIifkYBJckZOB zs)`35cwn$U_PbQi9+^lqRmRHs^XJ*Rbt@}YtQZ#jkOUG*)YR1Q?6c1@fByVoL1h9w zm7G6+p68x>j^)djGiAz@VZjeeAdy5}T^)}<{x}sC6*mQbsQ%NZPjm3#!HnEyLC^LFIoa=8#f zux8B~N=r*e1b##W;5!m6EiGKTc8$KizQH%j|BFO_H=Z(O3X>;K&KNw5kN`wT1cO2P z`ufl`EvXd08BtZ0tgI~Z^Yh8c$w5`sjDPI>U*&+9vOrPmY5)KL07*qoM6N<$f*8*h AfdBvi literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/smallnew.png b/contrib/toolchain/avra/doc/images/smallnew.png new file mode 100644 index 0000000000000000000000000000000000000000..411c2e178de59fa4f713ae2146618c6a434ce0ab GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^(m*W8!3HFC{I44WDaPU;cPEB*=VV?2Ic!PZ?k)`f zL2$v|<&%LToCO|{#S9F5hd`K7RKu$QD9B#o>FdgVlSPu%lwZ`)B@QUG#M8ww#Nzbb z(A!)M3Ou&c4*vU}%`W&Y#pia3P=txVGrin&ac)i3GmBV-U+zBGm+Y+@>&?&L_&W0K zmUYz^Qr5C8vHKjpAuh~cgFQNnkwIYUv7de+a%ZniVszMY%9X|7zO2bi_RwO78E@CP zKT+GXD?iGCcjlIfdt9DM{f)c1Y2MB!Tc0dWZ`To-_iwM+uZz1^Z2G6{eZSW6Rex6B hCY!kVA8yB=;e2tUtlsf$nlI4344$rjF6*2UngByNY}Nn( literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/images/tiger.png b/contrib/toolchain/avra/doc/images/tiger.png new file mode 100644 index 0000000000000000000000000000000000000000..332b11f3aaa6be10622937f08103127a39a58fc5 GIT binary patch literal 6515 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 Nrbd=Gstq26{|}G`IpqKV literal 0 HcmV?d00001 diff --git a/contrib/toolchain/avra/doc/index.html b/contrib/toolchain/avra/doc/index.html new file mode 100644 index 000000000..c5fa0d80a --- /dev/null +++ b/contrib/toolchain/avra/doc/index.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + +AVRA Home Page + + +
+
AVRA
+
Assember for the Atmel AVR microcontroller family
+
+ + + + + +
+ + + + + + + +
+ +
+
+
+
+
+
+
+

Introduction

+
+

AVRA is an assembler for Atmel AVR microcontrollers, and it is almost +compatible with Atmel’s own assembler AVRASM32. The programming +principles and conceptions are based on the ANSI programming language "C".

+

The initial version of AVRA was written by John Anders Haugum in 1999. He +released all versions until v0.7. All later versions were released by Tobias +Weber. And version 1.3.0 is released by Jerry Jacobs.

+
+
+

+ +
+
+ + diff --git a/contrib/toolchain/avra/doc/index.txt b/contrib/toolchain/avra/doc/index.txt new file mode 100644 index 000000000..9956c0aaf --- /dev/null +++ b/contrib/toolchain/avra/doc/index.txt @@ -0,0 +1,23 @@ +AVRA Home Page +============== + +.{revdate}: AVRA {revnumber} Released +************************************************************************ +This release contains a few improvements, a couple of bug fixes and +documentation updates. + +Read the link:ChangeLog.html[ChangeLog] for a full list of all +additions, changes and bug fixes. Changes are documented in the +updated link:README.html[Readme]. See the +link:downloads.html[Downloads] page for sourcecode and binary releases. +************************************************************************ + +Introduction +------------ +AVRA is an assembler for Atmel AVR microcontrollers, and it is almost +compatible with Atmel's own assembler AVRASM32. The programming +principles and conceptions are based on the ANSI programming language "C". + +The initial version of AVRA was written by John Anders Haugum in 1999. He +released all versions until v0.7. All later versions were released by Tobias +Weber. And version 1.3.0 is released by Jerry Jacobs. diff --git a/contrib/toolchain/avra/doc/layout1.conf b/contrib/toolchain/avra/doc/layout1.conf new file mode 100644 index 000000000..a78db2b24 --- /dev/null +++ b/contrib/toolchain/avra/doc/layout1.conf @@ -0,0 +1,155 @@ +# +# AsciiDoc website. +# Three division table based layout (layout1). +# +# +-----------------------------------------------------+ +# | #layout-banner | +# +--------------+--------------------------------------+ +# | | | +# | | | +# | #layout-menu | #layout-content | +# | | | +# | | | +# | | | +# +--------------+--------------------------------------+ +# +# - The #layout-menu and #layout-content divisions are contained in a +# two cell table. +# I would be nice to use pure CSS for the layout but the table is better for +# this layout because: +# +# * The column widths automatically size to fit column width (specifically +# the #layout-menu) +# * The column heights automatically size to the tallest. +# +# - The #layout-content division is a container for AsciiDoc page documents. +# - Documents rendered in the #layout-content use the standard AsciiDoc +# xhtml11 backend stylesheets. + +[specialwords] +monospacedwords=(?u)\\?\basciidoc\(1\) (?u)\\?\ba2x\(1\) + +[header] + + + + + +ifdef::index-only[] + + +endif::index-only[] + +{doctype-manpage} + + + + +ifdef::asciimath[] + +endif::asciimath[] +ifdef::latexmath[] + +endif::latexmath[] +{doctitle} + + +
+
AVRA
+
Assember for the Atmel AVR microcontroller family
+
+ + + + + +
+ + + + + + + +
+# Article, book header. +ifndef::doctype-manpage[] + +endif::doctype-manpage[] +# Man page header. +ifdef::doctype-manpage[] + +endif::doctype-manpage[] +
+ +[footer] +
+{disable-javascript%

} + +
+
+ + diff --git a/contrib/toolchain/avra/doc/layout1.css b/contrib/toolchain/avra/doc/layout1.css new file mode 100644 index 000000000..8ae10e991 --- /dev/null +++ b/contrib/toolchain/avra/doc/layout1.css @@ -0,0 +1,65 @@ +body { + background-color: white; + margin: 1%; +} + +h1 { + margin-top: 0.5em; +} + +#layout-banner { + background-color: #73a0c5; + color: white; + font-family: sans-serif; + text-align: left; + padding: 0.8em 20px; +} + +#layout-title { + font-family: monospace; + font-size: 3.5em; + font-weight: bold; + letter-spacing: 0.2em; + margin: 0; +} + +#layout-description { + font-size: 1.2em; + letter-spacing: 0.1em; +} + +#layout-menu { + background-color: #f4f4f4; + border-right: 3px solid #eeeeee; + padding-top: 0.8em; + padding-left: 20px; + padding-right: 0.8em; + font-size: 1.1em; + font-family: sans-serif; + font-weight: bold; +} +#layout-menu a { + line-height: 2em; + margin-left: 0.5em; +} +#layout-menu a:link, #layout-menu a:visited, #layout-menu a:hover { + color: #527bbd; + text-decoration: none; +} +#layout-menu a:hover { + color: navy; + text-decoration: none; +} +#layout-menu #page-source { + border-top: 2px solid silver; + margin-top: 0.2em; +} + +#layout-content { + margin-left: 1.0em; +} + +@media print { + #layout-banner { display: none; } + #layout-menu { display: none; } +} diff --git a/contrib/toolchain/avra/doc/xhtml11-manpage.css b/contrib/toolchain/avra/doc/xhtml11-manpage.css new file mode 100644 index 000000000..3ea378a1b --- /dev/null +++ b/contrib/toolchain/avra/doc/xhtml11-manpage.css @@ -0,0 +1,18 @@ +/* Overrides for manpage documents */ +h1 { + padding-top: 0.5em; + padding-bottom: 0.5em; + border-top: 2px solid silver; + border-bottom: 2px solid silver; +} +h2 { + border-style: none; +} +div.sectionbody { + margin-left: 5%; +} + +@media print { + div#toc { display: none; } +} + diff --git a/contrib/toolchain/avra/doc/xhtml11-quirks.css b/contrib/toolchain/avra/doc/xhtml11-quirks.css new file mode 100644 index 000000000..b807a95a9 --- /dev/null +++ b/contrib/toolchain/avra/doc/xhtml11-quirks.css @@ -0,0 +1,41 @@ +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +pre.verseblock-content { + font-family: inherit; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } diff --git a/contrib/toolchain/avra/doc/xhtml11.css b/contrib/toolchain/avra/doc/xhtml11.css new file mode 100644 index 000000000..2f93ba1d3 --- /dev/null +++ b/contrib/toolchain/avra/doc/xhtml11.css @@ -0,0 +1,367 @@ +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > pre.content { + font-family: inherit; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} diff --git a/contrib/toolchain/avra/examples/testcode_avra-1_2_3.asm b/contrib/toolchain/avra/examples/testcode_avra-1_2_3.asm new file mode 100644 index 000000000..275f94db9 --- /dev/null +++ b/contrib/toolchain/avra/examples/testcode_avra-1_2_3.asm @@ -0,0 +1,18 @@ + .device ATmega8 + .org 0 .db 1,2 + .message "The previous line is ignored with avra-1.2.2 because .org 0 is terminated with CR only. " + .message "This is line 5 but avra-1.2.2 shows line 4" + .db "X%MINUTE%YEAR%" ; Take a look at this percent chars too : % % % % + .db "%YEAR%HELLO%" ; Strange replacement, if one percent char is missing + .db "%HOUR%:%MINUTE%%" + .db "øC" ; Look at the special char. (Error in listing only. HEX-file was ok) + ; Additional warning : Don't use linux editors with UTF charset ! A single special char + ; (Code > 127 in codepage 850 e.g. german umlauts) could be an unvisible TWO bytes sequence + ; in UTF coding. To be on the save side never use chars with code > 127. + ; It's better to replace them by the code e.g. .db "M",129,"nchen" (german town 'Munich') + ldi R16, ';' ; This is wrong with avra-1.2.2. + ldi R16, 0x3b ; Should generate same code like above + +; TODO : +; ldi R16,high (11111) ; "high(" is OK, "high (" isn't. Same with other functions... + diff --git a/contrib/toolchain/avra/examples/testcode_avra-1_3_0.asm b/contrib/toolchain/avra/examples/testcode_avra-1_3_0.asm new file mode 100644 index 000000000..5b3a418ef --- /dev/null +++ b/contrib/toolchain/avra/examples/testcode_avra-1_3_0.asm @@ -0,0 +1,27 @@ +; Test new device +.device ATmega328P + +; Test number sign labels +#define TEST +.define DOTTEST + + +; Test whitespace between function name and value +ldi r16, high(0) +ldi r17, high (0) + +;--- +; Test data segment start with a number sign instead of a dot +;--- +#DSEG +Buffer: .BYTE 8 ; Reserve 64 bits + +;--- +; EEPROM segment +;--- +.ESEG + +; Test line continuation +AVERAGE: .db 0xF0, 0xFF, \ + 0x55, 0xFF, \ + 0x55, 0x0F diff --git a/contrib/toolchain/avra/examples/throttle.asm b/contrib/toolchain/avra/examples/throttle.asm new file mode 100644 index 000000000..330ddb6b7 --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle.asm @@ -0,0 +1,916 @@ +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * "throttle.asm" * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** +; *************************************************************************************** +; * Fixed Version for avra >= 1.2.2 because .DSEG cannot be used, if device has no SRAM * +; * B.Arenfeld, 10.05.2007 * +; *************************************************************************************** +; *************************************************************************************** +; *For Attiny 15 * +; * * +; *For compilation with: Avra 0.70 or later * +; * * +; * Atmel avrasm32.exe will not work becaue of the * +; * use of preprocessor directives #ifdef, #ifndef * +; * , and #endif, which Atmel doesn't support! * +; * * +; *Compiling requires the following files: * +; * "tn15def.inc" Labels and identifiers for tiny15 * +; * "throttle_dev_set.inc" Tiny 15 device settings * +; * "throttle_op_set.inc" Operation settings (THIS IS THE ONE TO EDIT THE * +; * COMPLIE-TIME OPTIONS ON THE WAY THE THROTTLE * +; * PERFORMS * +; * * +; *Depending on the compile time options, the following files are also required: * +; * "throttle_divide.asm" Two division routines. (one from atmel) * +; * "throttle_set_lowpass.asm" Lowpass filter on throttle handle * +; * "throttle_momentum.asm" Compute speed according to momentum * +; * "throttle_momentum_lowpass.asm" Lowpass filter on momentum handle * +; * "throttle_backemf.asm" Adjust pwm based on motor speed * +; * "throttle_pulse.asm" Provide pulse assist at low motor speeds * +; * "throttle_multiply.asm" atmel multiplication routine * +; * * +; *Subroutine Categories and Stack * +; * * +; * The Tiny 15 has a three level stack which handles return addresses for * +; * subroutine calls and for interrupt service routines. The categories below * +; * ensure that the stack does not overflow. The four (4) categories are: * +; * * +; * -- Top Level Routines: These routines are never called, and never * +; * return ("ret") and so the stack is, "empty" * +; * These routines may call any subroutine. * +; * Register Variables: Temp, Temp1, ... * +; * * +; * -- First Level Subroutines: Stack has 1 entry. These routines may call * +; * Second Level Subroutines only. * +; * Register Variables: A_Temp, A_Temp1, ... * +; * * +; * -- Second Level Subroutines: Stack has 2 entries. These routines may NOT * +; * call any subroutines. * +; * Register Variables: B_Temp, B_Temp1, ... * +; * * +; * -- Interrupt Service These occur assynchronously, and therefor may * +; * occur during Second Level Subroutines. If so, * +; * the stack has 3 entries and IS FULL. These routines * +; * may NOT call any subroutines. * +; * Register Variables: I_Temp, I_Temp1, ... * +; * * +; * Register variables are reserved for each level of routine. Each level may freely * +; * use the register variables for it's own level. Some sharing of variables may * +; * occur subject to these guidelines: * +; * -- No category execpt Interrupt Service may use Interrupt Service variables. This * +; * is because ISRs occur asynchronously. * +; * -- A category may NOT use variables reserved for higher level categories. * +; * -- A category may use lower level routine variables as long as their use does not * +; * span any subroutine calls. * +; * * +; *Other settings * +; * There is no way to put these settings into this file, but these must also be * +; * done: * +; * * +; * BODLEVEL: 0 4.0V * +; * BOODEN: 0 ENABLED (brown out detection) * +; * SPIEN: 0 ENABLED (in circuit programming) * +; * RSTDISBL 0 DISABLED (reset on PB5) * +; * CKSEL 11 (very quickly rising power) * +; * LB1 1 (LB1 & LB2: No lock) * +; * LB2 1 * +; * * +; * Calibration byte into flash byte address as specified in * +; * osccal_location. * +; * * +; * Notes regarding these settings: * +; * --Brown out detection. The datasheet warns against using the EEPROM without * +; * brownout detection because of the possibility of errant execution at very low * +; * voltage levels. * +; * * +; ************************************************************************************** + + + +;***************************************************************************************** +;***************************************************************************************** +;* Included files * +;***************************************************************************************** +;***************************************************************************************** +.INCLUDE "tn15def.inc" ; Labels and identifiers for tiny15 +.INCLUDE "throttle_op_set.inc" ; Operation settings +.INCLUDE "throttle_dev_set.inc" ; Tiny 15 device settings + +;***************************************************************************************** +;***************************************************************************************** +;* DATA TABLE * +;***************************************************************************************** +;***************************************************************************************** +;.CSEG +;.ORG 0x01E0 ; Program .ORG 0x01E0 actually means byte + ; location 0x03C0. + +;***************************************************************************************** +;***************************************************************************************** +;* Data: reserved for OSCCAL byte * +;***************************************************************************************** +;***************************************************************************************** + +; Fix : The Tiny15 has NO SRAM. Use of .DSEG is invalid ! +;.DSEG +; +;.SET osccal_location = 0x3FF ;Place in the last byte of program memory. +; ;High byte of program memory 1FF +; +;.ORG osccal_location ;reserve this byte for oscillator +;.BYTE 1 ;calibration value + + +; Fixed Version for avra >= 1.2.2 +.CSEG +.EQU osccal_location = 0x3FF ; The last flash byte is used for the calibration + ; value and is replaced by the programmer + +; Now reserve the last word in flash memory. If you are sure, that the program doesn't use +; the last flash word, you can disable the following lines. If not, it's better to enable +; them to check for overlapping code segments. + +.ORG 0x01FF ; Last word in flash memory +.DB 0xff,0xff ; Fill with dummy values. Only last byte is used + ; but flash is organized in words. + ; 0xff is the value of unprogrammed flash + + +;***************************************************************************************** +;***************************************************************************************** +;* Reset and Interrupt Vectors * +;***************************************************************************************** +;***************************************************************************************** +.CSEG +.ORG 0x000 + rjmp ST_RESET + +.ifdef OVERLOAD_ENABLED + rjmp ST_PWM_LEVEL_OFF ; INT0 interrupt handler +.else + reti ; Not used. +.endif ;OVERLOAD_ENABLED + + reti ; Not used. rjmp PIN_CHANGE + reti ; Not used. rjmp TIM1_CMP + reti ; Not used. rjmp TIM1_OVF + reti ; Not used. rjmp TIM0_OVF + reti ; Not used. rjmp EE_RDY + reti ; Not used. rjmp ANA_COMP + reti ; Not used. rjmp ADC + + +;***************************************************************************************** +;***************************************************************************************** +;* Top level routines. The basic program is a state machine, with states all being * +;* top level routines. These routines are never used as subroutines * +;* and therefore can call any subroutine. * +;***************************************************************************************** +;***************************************************************************************** + +;******************************************************************************** +;* ST_RESET * +;* This is power on reset. The reset vector points here. * +;* * +;* Inputs: none * +;* Returns: none * +;* Changed: B_Temp * +;* Calls: * +;* Goto: ST_MOTOR_OFF * +;******************************************************************************** +ST_RESET: + cli ; Disable interrupts + + ldi B_Temp,(dir_out_port_bit | pwm_port_bit | dir_in_port_bit | momentum_port_bit) + out DDRB,B_Temp ; Assign output port directions. + ; Inclusion in the above list makes the + ; port an output port + + ldi B_Temp,0x00 ; A "1" makes output logic level high + out PORTB,B_Temp ; A "1" assigns pullups on inputs + ; Therefore all outputs are at logic low, and + ; all inputs do not have a pullup assigned + + ldi B_Temp,acsr_val ; Disable comparator and interrupt + out ACSR,B_Temp ; Using port for PWM + ; (comparator defaults to powered up) + + ldi B_Temp,0b01000010 ; Disable pullups. + out MCUCR,B_Temp ; Set sleep mode (moot) + ; INT0 interrupt on falling edge + + ldi ZL,low(osccal_location) ; r30 + ldi ZH,high(osccal_location) ; r31 + lpm + out OSCCAL,Implicit ; Place calibration byte + + ldi B_Temp,0b00001010 ; Enable watchdog + out WDTCR,B_Temp ; timout 64mS (nom) + + ldi B_Temp1,pwm_period ; Set pwm oscillator period + out OCR1B,B_Temp1 + + ldi B_Temp1,tccr1_enable_t1 ; Turn on the PWM oscillator + out TCCR1,B_Temp1 + + ldi Flags_1,(0b00000000 | F_stop) ; Set emergency stop flag so that + ; throttle doesn't start on powerup +.ifdef TRADITIONAL_ENABLED + .ifdef MOMENTUM_LOWPASS_ENABLED + clr momentum_lo_prev ; MOMENTUM LOWPASS + clr momentum_hi_prev ; Clear the history + .endif ;MOMENTUM_LOWPASS_ENABLED +.endif ;TRADITIONAL_ENABLED + +; rjmp ST_EMERGENCY_STOP ; ***EXIT STATE*** + +;******************************************************************************** +;* ST_EMERGENCY_STOP * +;* * +;* Reset to "off" state. * +;* Clear global variables associated with momentum and lowpass filters. * +;* * +;* Inputs: none * +;* Returns: none * +;* Changed: Global variables cleared * +;* Calls: None * +;* Goto: ST_PWM_LEVEL_OFF If throttle is zero * +;******************************************************************************** +ST_EMERGENCY_STOP: + +.ifdef BACKEMF_ENABLED + .ifdef LOWPASS_ENABLED ; BACKEMF LOWPASS + clr error_hi_prev ; Clear the history + clr error_lo_prev + .endif ;LOWPASS_ENABLED +.endif ;BACKEMF_ENABLED + +.ifdef MOMENTUM_ENABLED ; MOMENTUM + clr speed_lo_prev ; Clear the history + clr speed_hi_prev +.endif ;MOMENTUM_ENABLED + +.ifdef TRADITIONAL_ENABLED + .ifdef WALKAROUND_ENABLED + clr throttle_hold ; Clear the history + .endif ;WALKAROUND_ENABLED + + .ifdef THROTTLE_LOWPASS_ENABLED + clr throttle_lo_prev ; THROTTLE LOWPASS + clr throttle_hi_prev ; Clear the history + .endif ;THROTTLE_LOWPASS_ENABLED + +.endif ;TRADITIONAL_ENABLED + +; rjmp ST_PWM_LEVEL_OFF ; ***EXIT STATE*** + + +;******************************************************************************** +;* ST_PWM_LEVEL_OFF * +;* ST_MEASUREMENT_SETTLE * +;* 1. If entered at ST_PWM_LEVEL_OFF turn pwm off * +;* 2. Set the ADC ports to input * +;* 3. Pause to let ADC inputs (including back-emf) settle. * +;* 4. Read the throttle controller. * +;* 5. Set LED ports and overload ports (also ADC inputs) to output * +;* 6. If throttle_set is not zero, or if motor is still running by momentum * +;* continue running motor (jump to ST_SET_NEW_PWM) * +;* 7. If throttle set is zero and motor is not running, then set the direction * +;* relay and test backemf input to determine backemf mode. * +;* 8. Turn of motor (jump to ST_PWM_LEVEL_OFF) * +;* * +;* Inputs: none * +;* Returns: none * +;* Changed: B_Temp, B_Temp1 * +;* Calls: READ_THROTTLE * +;* Goto: ST_PWM_LEVEL_OFF If throttle is zero * +;* ST_SET_NEW_PWM After delay * +;******************************************************************************** +ST_PWM_LEVEL_OFF: + clr B_Temp ; Set PWM duty = 0. + rcall SET_PWM_DUTY ; i.e. turn off the power + +ST_MEASUREMENT_SETTLE: + ;******************************************** + ;* Set all measurement ports for input and pause. + ;* During the pause: + ;* 1. inductive current in the locomotive falls to zero, and + ;* the backemf voltage appears on the backemf port + ;* 2. the momentum, direction, and throttle voltages stabilize + ;******************************************** +.ifdef TRADITIONAL_ENABLED + .ifdef LEDS_ENABLED + cbi DDRB,momentum_port ; Make input port (pullup must be disabled) + cbi DDRB,dir_in_port ; Make input port (pullup must be disabled) + .endif ;LEDS_ENABLED + + .ifdef OVERLOAD_ENABLED + in B_Temp,GIMSK ; disable INT0 interrupt + andi B_Temp,0b10111111 + out GIMSK,B_Temp + + cbi DDRB,throttle_port ; Make input port (pullup must be disabled) + .endif ;OVERLOAD_ENABLED +.endif ;TRADITIONAL_ENABLED + + sei ; Enable interrupts + wdr ; Reset watchdog timer + + ldi B_Temp1,pwm_full_count ; Pause for inputs to settle + rcall COUNT_PWM_CYCLES + clr Cycle_count + + ;******************************************** + ;* Read the input ports and make some + ;* mode decisions based on those inputs. + ;******************************************** + + rcall READ_THROTTLE ; Find throttle handle position in throttle_set + +.ifdef TRADITIONAL_ENABLED + .ifdef MOMENTUM_ENABLED + .ifdef MOMENTUM_LOWPASS_ENABLED + .include "throttle_momentum_lowpass.asm" + .endif;MOMENTUM_LOWPASS_ENABLED + .endif; MOMENTUM_ENABLED +.endif ;TRADITIONAL_ENABLED + +.ifdef DIRECTION_ENABLED ; Check Stop, and Adjust Direction +CHECKING_STOP: + sbrs Flags_1,BF_stop ; Check stop flag is set + rjmp DONE_CHECKING_STOP + + cpi throttle_set,0x00 ; If throttle handle is at zero + brne ST_EMERGENCY_STOP ; reset the emergency stop flag + cbr Flags_1,F_stop ; reset emergency stop flag. + rjmp ST_EMERGENCY_STOP ; ALWAYS STOP +DONE_CHECKING_STOP: + +CHECKING_DIRECTION: + + .ifdef MOMENTUM_ENABLED + mov B_Temp,speed_hi_prev ; Don't set direction unless the actual + cpi B_Temp,direction_threshold ; speed is less than direction_threshold + brsh DONE_CHECKING_DIRECTION + .else + cpi throttle_set,0x00 ; Don't set direction unless the throttle + brne DONE_CHECKING_DIRECTION ; handle is at zero + .endif ;MOMENTUM_ENABLED + + sbic PORTB,dir_out_port ; Find port direction + rjmp PORT_REVERSE + ;rjmp PORT_FORWARD + + PORT_FORWARD: + sbrs Flags_1,BF_reverse ; If port says forward + rjmp DONE_CHECKING_DIRECTION + sbi PORTB,dir_out_port ; But flag says reverse, then reverse + rjmp ST_EMERGENCY_STOP + + PORT_REVERSE: + sbrc Flags_1,BF_reverse ; If port says reverse + rjmp DONE_CHECKING_DIRECTION + cbi PORTB,dir_out_port ; But flag says foreward, then forward + rjmp ST_EMERGENCY_STOP + +DONE_CHECKING_DIRECTION: +.endif ;DIRECTION_ENABLED + +.ifdef TRADITIONAL_ENABLED + .ifdef THROTTLE_LOWPASS_ENABLED + .include "throttle_set_lowpass.asm" + .endif ;THROTTLE_LOWPASS_ENABLED +.endif ;TRADITIONAL_ENABLED + + cpi throttle_set,0x00 ; Run the pwm unless the throttle + brne ST_SET_NEW_PWM ; is zero + +.ifdef MOMENTUM_ENABLED + mov B_Temp,speed_hi_prev ; In momentum mode, run the pwm unless + cpi B_Temp,0x00 ; the actual throttle setting reaches zero + brne ST_SET_NEW_PWM +.endif ;MOMENTUM_ENABLED + + ;******************************************** + ;* Only arrive here if the throttle is set for 0 speed + ;* and the locomotive is actually stopped (momentum) + ;******************************************** + +.ifdef BACKEMF_ENABLED + ;******************************************** + ;* The backemf measurement should be at or near zero, + ;* since the locomotive is stopped. If it isn't, + ;* do not use backemf speed control. + ;******************************************** + sbr Flags_1,F_use_backemf ; Default to use backemf + + rcall ADC_SETUP_EMF ; 4 lines read the backemf +WAIT_FOR_VALID: + sbis ADCSR,ADIF + rjmp WAIT_FOR_VALID + + in B_Temp,ADCH ; Read the measurement + + + cpi B_Temp,0x40 ; Test measurement + brlo END_CHECK_BACKEMF_MODE ; If small, use backemf adjustment. + + cbr Flags_1,F_use_backemf ; Otherwise, don't use backemf +END_CHECK_BACKEMF_MODE: +.endif ;BACKEMF_ENABLED + +.ifdef TRADITIONAL_ENABLED + .ifdef LOCO_LIGHT_ENABLED + ldi throttle_set,light_pwm + rjmp STABLE_PWM_SET + .else + rjmp ST_PWM_LEVEL_OFF + .endif ;LOCO_LIGHT_ON +.else + rjmp ST_PWM_LEVEL_OFF +.endif ;TRADITIONAL_ENABLED + + +;******************************************************************************** +;* ST_SET_NEW_PWM * +;* Compute the pwm setting based upon momentum, backemf, and throttle setting * +;* Inputs: throttle_set * +;* Returns: none * +;* Changed: throttle_set, other variables in included files * +;* Calls: various in included files * +;* Goto: ST_PWM_LEVEL_ON * +;******************************************************************************** +ST_SET_NEW_PWM: + +.ifdef TRADITIONAL_ENABLED + .ifdef LEDS_ENABLED + cbi PORTB,dir_in_port ; logic low out (turn off LED) + sbi DDRB,dir_in_port ; Assign output to drive led (output is low) + + cbi PORTB,momentum_port ; logic low out (turn off LED) + sbi DDRB,momentum_port ; Assign output to drive led (output is low) + .endif ;LEDS_ENABLED + + .ifdef OVERLOAD_ENABLED + ;******************************************** + ;* The thottle port is driven to logic high. If this port gets pulled + ;* low (overload), this triggers the INT0 interrupt, which will shut off + ;* the pwm. + ;******************************************** + sbi PORTB,throttle_port ; Logic hi out. + sbi DDRB,throttle_port ; Make output port. + .endif ;OVERLOAD_ENABLED +.endif ;TRADITIONAL_ENABLED + +.ifdef MOMENTUM_ENABLED + .include "throttle_momentum.asm" ; momentum adjustment +.endif ;MOMENTUM_ENABLED + +.ifdef TRADITIONAL_ENABLED + .ifdef WALKAROUND_ENABLED + mov throttle_hold,throttle_set + .endif ;WALKAROUND_ENABLED +.endif ;TRADITIONAL_ENABLED + +.ifdef BACKEMF_ENABLED ;******************************************** + ; Adjust throttle_set according to + ; measured backemf. + ;******************************************** + + sbrs Flags_1,BF_use_backemf ; If the flag is set, use backemf + rjmp DONT_BACKEMF ; Otherwise, don't + + .include "throttle_backemf.asm" + ; If using backemf, don't use throttle_scale + rjmp ST_PWM_LEVEL_ON ; ***EXIT STATE*** + + DONT_BACKEMF: +.endif ;BACKEMF + + + ;***************************************************************** + ;* Scale the throttle_set between 0 and pwm_period * + ;* multiply pwm_period and throttle_set and divide by 256 * + ;* read answer from hi byte of return. * + ;***************************************************************** + + + HILOCAL1 _main_scale_multiplicand + B_TEMPLOCAL _main_scale_multiplier + B_TEMPLOCAL1 _main_scale_result_hi + + ldi _main_scale_multiplicand,pwm_period - pwm_min + mov _main_scale_multiplier,throttle_set + rcall mpy8u ; multiply + mov throttle_set,_main_scale_result_hi ; read result + +; rjmp ST_PWM_LEVEL_ON ; ***EXIT STATE*** + + +;******************************************************************************** +;* ST_PWM_LEVEL_ON * +;* 1. Enable overload testing * +;* 2. Produce pulse if required * +;* 3. Run pwm at throttle_set * +;* 4. Wait for a while * +;* * +;* Inputs: throttle_set * +;* Returns: none * +;* Changed: B_Temp, B_Temp1, various * +;* Calls: SET_PWM_DUTY * +;* COUNT_PWM_CYCLES * +;* Goto: ST_PWM_LEVEL_OFF After PWM goes to off state * +;******************************************************************************** +ST_PWM_LEVEL_ON: + +.ifdef TRADITIONAL_ENABLED + .ifdef OVERLOAD_ENABLED + ldi B_Temp,0b01000000 ; clear INT0 interrupt + out GIFR,B_Temp + + in B_Temp,GIMSK ; enable INT0 interrupt + ori B_Temp,0b01000000 + out GIMSK,B_Temp + .endif ;OVERLOAD_ENABLED +.endif ;TRADITIONAL_ENABLED + + cpi throttle_set,light_pwm ; never run pwm lower than light_pwm level + brsh DONE_CHECKING_MINIMUM + ldi throttle_set,light_pwm + rjmp STABLE_PWM_SET + +DONE_CHECKING_MINIMUM: + +.ifdef PULSE_ENABLED ; Produce pulses during output + .ifdef BACKEMF_ENABLED + sbrc Flags_1,BF_use_backemf ; If the flag is set to use backemf + rjmp STABLE_PWM_SET ; don't pulse + .endif ;BACKEMF_ENABLED + + ; Pass in: throttle_set + .include "throttle_pulse.asm" +.endif ;PULSE_ENABLED + + +STABLE_PWM_SET: + mov B_Temp,throttle_set ; Stabilize at throttle_set + rcall SET_PWM_DUTY + + ldi B_Temp1,pwm_full_count-pwm_settle_count + rcall COUNT_PWM_CYCLES ; Wait for end of interval + +.ifdef BACKEMF_ENABLED + sbrc Flags_1,BF_use_backemf ; If the flag is set to use backemf + rjmp ST_PWM_LEVEL_OFF ; ***EXIT STATE*** +.endif ;BACKEMF_ENABLED + rjmp ST_MEASUREMENT_SETTLE ; ***EXIT STATE*** + +;***************************************************************************************** +;***************************************************************************************** +;* First Level Subroutines. * +;* These routines include the routines which are called by other code and also call * +;* Second Level Subroutines. * +;***************************************************************************************** +;***************************************************************************************** + +;******************************************************************************** +;* READ_THROTTLE * +;* First Level Subroutine * +;* * +;* Read the throttle controls, which are: * +;* Momentum level (analog): Returned in "momentum_set" * +;* Returns and 8 bit number, with '0' meaning minimum momentum. * +;* * +;* Direction, brake, and stop switch. * +;* Returns value in flags: F_brake, F_reverse, and F_stop * +;* * +;* Throttle setting (analog: Returned in "throttle_set" * +;* Returns an 8 bit number (0x00 to 0xFF; 0 to 255), * +;* where '0' means "motor off" and 0xFF (255) means full speed. * +;* * +;* If a speed table is implemented, it will be in this routine * +;* * +;* Just now, this value comes from the analog input and is converted by the * +;* ADC. The raw 8 bit number is returned. * +;* * +;* Inputs: None * +;* Returns: Momentum setting in "momentum_set" * +;* Switch positions in F_brake, F_reverse, and F_stop * +;* Throttle setting in "throttle_set" * +;* Changed: Cycle_count incremented by up to 5 * +;* Calls: ADC_SETUP_MOMENTUM * +;* ADC_SETUP_DIRECTION * +;* ADC_SETUP_THROTTLE * +;******************************************************************************** +READ_THROTTLE: +.ifdef TRADITIONAL_ENABLED + .ifdef DIRECTION_ENABLED + ;******************************************** + ;* Measure the direction, brake, and stop switches and + ;* set the flags appropriately + ;******************************************** + rcall ADC_SETUP_DIRECTION ; Setup to read + WAIT_FOR_VALID_DIRECTION: + sbis ADCSR,ADIF ; Check for ADC completion + rjmp WAIT_FOR_VALID_DIRECTION + + in B_Temp,ADCH ; Read value + + .ifdef WALKAROUND_ENABLED + cpi B_Temp,0x90 ; Above this threshold + ; deactivates handheld controller +; brsh HOLD_THROTTLE + + brlo HOLD_THROTTLE_NOT + rjmp HOLD_THROTTLE +HOLD_THROTTLE_NOT: + .endif ;WALKAROUND_ENABLED + + cpi B_Temp,0x1B ; Below this threshold (0.53V) sets 'stop' flag + brsh TEST_BRAKE_LEVEL ; Typical stop voltage is 0.30V + +.ifdef SWITCH_LOWPASS_ENABLED + sbrs Flags_2,BF_stop_count ; If the stop count flag is not set, then + clr Flags_2 ; set the counter to zero + + cbr Flags_2,F_stop_count ; clear the stop count flag + inc Flags_2 ; increment the counter + + cpi Flags_2,stop_count_max ; compare the count to the maximum + sbr Flags_2,F_stop_count ; set the stop count flag + + brlo END_READ_DIRECTION ; if the count is lower, don't change status flag + + dec Flags_2,F_stop_count ; decrement stop count flag +.endif;SWITCH_LOWPASS_ENABLED + + sbr Flags_1,F_stop + rjmp END_READ_DIRECTION + + TEST_BRAKE_LEVEL: + cpi B_Temp,0x37 ; Below this threshold (1.07V) sets 'brake' flag + brsh TEST_REVERSE_LEVEL ; Typical brake voltage 0.87V + +.ifdef SWITCH_LOWPASS_ENABLED + sbrs Flags_2,BF_brake_count ; If the brake count flag is not set, then + clr Flags_2 ; set the counter to zero + + cbr Flags_2,F_brake_count ; clear the break count flag + inc Flags_2 ; increment the counter + + cpi Flags_2,brake_count_max ; compare the count to the maximum + sbr Flags_2,F_brake_count ; set the break count flag + + brlo END_READ_DIRECTION ; if the count is lower, don't change status flag + + dec Flags_2,F_brake_count ; decrement break count flag +.endif;SWITCH_LOWPASS_ENABLED + + sbr Flags_1,F_brake + rjmp END_READ_DIRECTION + + TEST_REVERSE_LEVEL: + cpi B_Temp,0x53 ; Below this threshold (1.62V) sets 'reverse' flag + brsh TEST_FOREWARD_LEVEL ; Typical reverse level 1.40V + +.ifdef SWITCH_LOWPASS_ENABLED + sbrs Flags_2,BF_reverse_count ; If the reverse count flag is not set, then + clr Flags_2 ; set the counter to zero + + cbr Flags_2,F_reverse_count ; clear the reverse count flag + inc Flags_2 ; increment the counter + + cpi Flags_2,reverse_count_max ; compare the count to the maximum + sbr Flags_2,F_reverse_count ; set the reverse count flag + + brlo END_READ_DIRECTION ; if the count is lower, don't change status flag + + dec Flags_2,F_reverse_count ; decrement reverse count flag +.endif;SWITCH_LOWPASS_ENABLED + + cbr Flags_1,F_brake ; Clear brake flag + sbr Flags_1,F_reverse ; Set brake flag + rjmp END_READ_DIRECTION + + TEST_FOREWARD_LEVEL: ; Typical "nothing" 1.95V + ;no test required + +.ifdef SWITCH_LOWPASS_ENABLED + sbrs Flags_2,BF_foreward_count ; If the foreward count flag is not set, then + clr Flags_2 ; set the counter to zero + + cbr Flags_2,F_foreward_count ; clear the foreward count flag + inc Flags_2 ; increment the counter + + cpi Flags_2,foreward_count_max ; compare the count to the maximum + sbr Flags_2,F_foreward_count ; set the foreward count flag + + brlo END_READ_DIRECTION ; if the count is lower, don't change status flag + + dec Flags_2,F_foreward_count ; decrement forward count flag +.endif;SWITCH_LOWPASS_ENABLED + + cbr Flags_1,F_brake ; Clear brake flag + cbr Flags_1,F_reverse ; Clear reverse flag (i.e., foreward) + + END_READ_DIRECTION: + .endif ;DIRECTION_ENABLED + + .ifdef MOMENTUM_ENABLED + ;******************************************** + ;* Measure and adjust the momentum input + ;******************************************** + rcall ADC_SETUP_MOMENTUM ; Setup to read + WAIT_FOR_VALID_MOMENTUM: + sbis ADCSR,ADIF ; Wait for ADC completion + rjmp WAIT_FOR_VALID_MOMENTUM + + in momentum_set,ADCH ; Read value + + .ifdef WALKAROUND_ENABLED + ldi B_Temp,0x90 + cp momentum_set,B_Temp ; Above this threshold + ; deactivates handheld controller + brsh HOLD_THROTTLE + .endif ;WALKAROUND_ENABLED + + ldi B_Temp,0x40 + sub momentum_set,B_Temp ; Subtract offset (1/4 of 0xFF) + + brsh END_READ_MOMENTUM + sub momentum_set,momentum_set ; If smaller than offset, make zero + + END_READ_MOMENTUM: + .endif ;MOMENTUM_ENABLED + + ;******************************************** + ;* Read the throttle level + ;******************************************** + rcall ADC_SETUP_THROTTLE +WAIT_FOR_VALID_THROTTLE: + sbis ADCSR,ADIF ; Check for ADC completion + rjmp WAIT_FOR_VALID_THROTTLE + + in throttle_set,ADCH ; Read throttle value + + subi throttle_set,0x08 ; Subtract offset (force zero) + brcc DONE_READ_THROTTLE ; If new throttle is negative, + + clr throttle_set ; make throttle zero. +DONE_READ_THROTTLE: + + subi Cycle_count,256-3 ; Normal arrival here occurs after 3 adc + ret ; conversions, which take 195uS, or 4.875 + ; pwm cycles +.ifdef WALKAROUND_ENABLED + HOLD_THROTTLE: ; Normal arrival here occurs after 1 adc + ; conversion, which takes 65uS, or 1.625 + ; pwm cycles + + cbr Flags_1,F_brake ; Clear brake flag + mov throttle_set,throttle_hold ; Use previous value. + + .ifdef SWITCH_LOWPASS_ENABLED + clr Flags_2 + .endif;SWITCH_LOWPASS_ENABLED + + .ifdef MOMENTUM_ENABLED + ldi B_Temp,0x40 + mov momentum_set,B_Temp ; 'long' momentum + .endif ;MOMENTUM_ENABLED + ret +.endif ;WALKAROUND_ENABLED + +.else ;NOT TRADITIONAL_THROTTLE + sbr Flags_1,F_stop + ret +.endif ;TRADITIONAL_THROTTLE + + +;******************************************************************************** +;* COUNT_PWM_CYCLES * +;* First evel Subroutine * +;* * +;* Increment Cycle_count timer each PWM cycle. * +;* Return when Cycle_count = B_Temp1 * +;* * +;* Inputs: B_Temp1 Exit when count reaches this number * +;* Returns: None * +;* Changed: B_Temp,Cycle_count * +;* Calls: None * +;******************************************************************************** +COUNT_PWM_CYCLES: + in B_Temp,TIFR ; Wait for pwm timer to reset + sbrs B_Temp,OCF1A + rjmp COUNT_PWM_CYCLES + + ldi B_Temp,0b01000000 ; reset interrupt flag + out TIFR,B_Temp + + inc Cycle_count ; increment counter and repeat + cp Cycle_count,B_Temp1 + brne COUNT_PWM_CYCLES + ret + +;***************************************************************************************** +;***************************************************************************************** +;* Second Level Subroutines. * +;* These routines make no further subroutine calls. * +;***************************************************************************************** +;***************************************************************************************** + +.include "throttle_divide.asm" + +.include "throttle_multiply.asm" + +;******************************************************************************** +;* SET_PWM_DUTY * +;* Second Level Subroutine * +;* * +;* Inputs: B_Temp PWM on count * +;* Returns: None * +;* Changed: None * +;* Calls: Not allowed * +;******************************************************************************** +SET_PWM_DUTY: + + out OCR1A,B_Temp ; Set the PWM equal to the input B_Temp + ret + +;******************************************************************************** +;* ADC_SETUP_DIRECTION * +;* ADC_SETUP_MOMENTUM * +;* ADC_SETUP_THROTTLE * +;* ADC_SETUP_BACK_EMF * +;* Second Level Subroutine * +;* * +;* The ADC is switched off, and restarted on the selected port. * +;* * +;* Inputs: None * +;* Returns: None * +;* Changed: Various B_Temp variables * +;* Calls: Not allowed * +;******************************************************************************** +.ifdef DIRECTION_ENABLED +ADC_SETUP_DIRECTION: + ldi B_Temp,admux_direction ; Setup MUX for direction/brake measurement + rjmp ADC_SETUP +.endif ;DIRECTION_ENABLED + +.ifdef MOMENTUM_ENABLED +ADC_SETUP_MOMENTUM: + ldi B_Temp,admux_momentum ; Setup MUX for momentum set measurement + rjmp ADC_SETUP +.endif ;MOMENUTM_ENABLED + +.ifdef BACKEMF_ENABLED +ADC_SETUP_EMF: + ldi B_Temp,admux_emf ; Setup MUX for back_emf measurement + rjmp ADC_SETUP +.endif ;BACKEMF_ENABLED + +.ifdef TRADITIONAL_ENABLED +ADC_SETUP_THROTTLE: + ldi B_Temp,admux_throttle ; Setup MUX for analog measure +; rjmp ADC_SETUP ; of throttle. +.endif ;TRADITIONAL_ENABLED + +ADC_SETUP: + ldi B_Temp1,adcsr_off ; Turn off the ADC + out ADCSR,B_Temp1 ; + out ADMUX,B_Temp ; Setup MUX as per entry point + ldi B_Temp,adcsr_enable ; enable ADC, disable interrupt, clear + out ADCSR,B_Temp ; interrupt flag, free-running. + + ret + + +;***************************************************************************************** +;***************************************************************************************** +;* Interrupt Service routines. * +;* These routines can occur assynchronously. Therfore, they might occur during a second * +;* level routine. Therefore THEY MAY NOT CALL ANY SUBROUTINES. * +;***************************************************************************************** +;***************************************************************************************** diff --git a/contrib/toolchain/avra/examples/throttle_backemf.asm b/contrib/toolchain/avra/examples/throttle_backemf.asm new file mode 100644 index 000000000..522274691 --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_backemf.asm @@ -0,0 +1,328 @@ +;throttle_backemf.asm + +.NOLIST +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** +.LIST + +.ifdef BACKEMF_ENABLED +;******************************************************************************** +;* BACKEMF_ADJUST * +;* Top level routine * +;* * +;* The throttle_set is compared against the back emf generated by the motor * +;* and adjusted to reduce the error * +;* * +;* Inputs: throttle_set Target speed * +;* Returns: throttle_set Adjusted target speed * +;* Changed: error_hi Adjusted throttle, upper 8 bits (local) * +;* error_lo Adjusted throttle, lower 8 bits (local) * +;* error_hi_prev Previous throttle, for filter (global) * +;* error_lo_prev Previous throttle, for filter (global) * +;* emf_hi Measured emf, upper 8 bits (local) * +;* emf_lo Measured emf, lower 8 bits (local) * +;* B_Temp,B_Temp1 * +;* Calls: ADC_SETUP_EMF * +;* div16u * +;* DIVIDE_16_SIMPLE * +;* Goto: none * +;******************************************************************************** + + HILOCAL1 error_lo ; assign local variables + HILOCAL2 error_hi + + ;***************************************************************** + ;*Convert throttle setting into 2 byte 2's compl. * + ;* * + ;* This is a 7 bit number plus 1 more bits after the radix * + ;* It is in (error_hi) -radix- (error_lo) * + ;***************************************************************** + mov error_hi,throttle_set ; Put throttle into 16 bit form + clr error_lo + + lsr error_hi ; Convert to 2's compliment + ror error_lo + + ;******************************************************************************** + ;* READ_BACKEMF * + ;* Returns a 2 byte 2's compliment measurement of the motor backemf. * + ;* * + ;* 1. Add together 8 samples of the (8 bit) pwm value in the two byte * + ;* emf_hi--emf_lo register. * + ;* 2. Multiply by 16. * + ;* 3. Result: Minimum value = 0x000 (decimal 0) * + ;* Maximum value = 0x7F8 (decimal 2040) * + ;* * + ;* Time required: * + ;* 1. 1st Sample: 125uS * + ;* 2. next 7 Samples: 455uS * + ;* 3. balance of Subroutine: 10's of uS * + ;* TOTAL 580uS min * + ;* * + ;* Each cycle of the 25kHz PWM takes 40uS, therefore, this routine takes * + ;* at least 14.5 cycles of the 25kHz pwm. * + ;* * + ;* Inputs: None * + ;* Returns: emf_hi--emf_lo: 2 Byte 2's compl (but always positive) * + ;* measure of motor backemf. * + ;* Changed: B_Temp,B_Temp1 * + ;* Calls: ADC_SETUP_EMF * + ;******************************************************************************** +LOWLOCAL1 emf_hi ; Names of local registers +LOWLOCAL2 emf_lo + +;READ_BACKEMF: + rcall ADC_SETUP_EMF ; Setup ADC to measure back_emf. + clr emf_lo ; Clear the value of emf. + clr emf_hi + + ldi B_Temp,8 ; Add 8 samples +WAIT_FOR_EMF_MEASURE: ; Wait for a measurement of the EMF + sbis ADCSR,ADIF + rjmp WAIT_FOR_EMF_MEASURE + + in B_Temp1,ADCH ; Read the measurement + + sbi ADCSR,4 ; Clear the interrupt + + add emf_lo,B_Temp1 ; Add to low byte (no carry) + + clr B_Temp1 + adc emf_hi,B_Temp1 ; Add carry to high byte. + + dec B_Temp + brne WAIT_FOR_EMF_MEASURE ; Measure for complete set + ; Sum of 8 samples. + + ldi B_Temp,4 ; Convert 11 bit number into a 15 bit +COMPUTE_EMF_AVERAGE: ; number (only 11 significant figures + lsl emf_lo ; though) + rol emf_hi + dec B_Temp + brne COMPUTE_EMF_AVERAGE + + ;***************************************************************** + ;* Compute the error. That is, throttle = throttle - emf * + ;* * + ;* The result is a two byte number (signed two's compl) in * + ;* error_hi -radix- error_lo * + ;***************************************************************** + sub error_lo,emf_lo ; subtract low bytes (after radix) + sbc error_hi,emf_hi ; subtract high bytes (before radix) + +.ifdef BACKEMF_SCALE_ENABLED + ;***************************************************************** + ;* Error multiplier (complex) * + ;* * + ;* Error gain is equal to: * + ;* * + ;* Error err_scale err_mult * + ;* ------------------------ * 2 * 2 * + ;* err_scale * + ;* 2 + throttle_set * + ;* * + ;* The maximum gain when throttle_set = 0 is 2^err_mult * + ;* is cut in half when throttle_set = 2^err_scale * + ;* * + ;* Result is signed two's compliment in * + ;* error_hi--error_lo -radix- * + ;***************************************************************** + cbr Flags_1,F_negative_err ; Assume error is positive + + sbrs error_hi,7 ; Test algebraic sign + rjmp POSITIVE_ERR + + sbr Flags_1,F_negative_err ; If error is negative, set flag. + com error_lo ; Convert to positive + com error_hi + subi error_lo,0xFF + sbci error_hi,0xFF + +POSITIVE_ERR: + + B_TEMPLOCAL _bemf_lo_byte + B_TEMPLOCAL1 _bemf_hi_byte + + mov _bemf_lo_byte,throttle_set ; Divisor = throttle_set+2^err_scale + clr _bemf_hi_byte + ldi B_Temp2,EXP2(err_scale) + add _bemf_lo_byte,B_Temp2 + adc _bemf_hi_byte,_bemf_hi_byte + +; mov dd16uL,error_lo ; Dividend = error (same register) +; mov dd16uH,error_hi + + rcall div16u ; Divide error by (throttle+offset) + ; (almost 4 pwm cycles) + ; adds 3 to Cycle_count + +; mov error_lo,dres16uL ; Same register +; mov error_hi,dres16uH + + sbrs Flags_1,BF_negative_err ; Check sign flag + rjmp POSITIVE_ERR_1 + + com error_lo ; Convert back to negative + com error_hi ; if necessary + subi error_lo,0xFF + sbci error_hi,0xFF + +POSITIVE_ERR_1: ; Scale for maximum + ldi _bemf_lo_byte, 7 - error_mult - err_scale + rcall DIVIDE_16_SIMPLE + +.else ;case BACKEMF_SCALE_ENABLED is NOT enabled + ;***************************************************************** + ;* Error multiplier (simple) * + ;* * + ;* The error multiplier setting (error_mult) can range * + ;* from -8 to +7, and the actual error multiplier is * + ;* 2^(error_mult), which therefore ranges from 1/256 to 128. * + ;* * + ;* Step 1. Multiply by 2^8. * + ;* Equivalent to moving the radix point to after * + ;* error_lo. THIS STEP REQUIRES NO CODE * + ;* * + ;* Step 2. Divide by 2^(error_mult - 8) * + ;* * + ;* Result is signed two's compliment in * + ;* error_hi--error_lo -radix- * + ;***************************************************************** + + ldi _bemf_lo_byte, 7 - error_mult + rcall DIVIDE_16_SIMPLE + +.endif ;BACKEMF_SCALE_ENABLED + + +COMPUTE_NEW_PWM: + ;***************************************************************** + ;* Add in the original throttle * + ;***************************************************************** + add error_lo,throttle_set + clr B_Temp + adc error_hi,B_Temp + + ;***************************************************************** + ;* Clamp to between 0 and +255 * + ;***************************************************************** + brmi SET_ZERO_PWM ; If result is NEGATIVE, set to zero. + + cpi error_hi,0x00 ; If hi byte is zero, result is ok. + breq LOWPASS + ldi error_lo,0xFF ; otherwise, clamp + rjmp LOWPASS + +SET_ZERO_PWM: + clr error_lo + +LOWPASS: + +.ifdef LOWPASS_ENABLED + ;***************************************************************** + ;* A transversal low pass filter * + ;* Lowpass on the emf-adjusted pwm * + ;* * + ;* gain input "emf_lowpass_gain", range = 0 to 8 * + ;* * + ;* The actual filter time constant "tau" is equal to * + ;* tau = 2^emf_lowpass_gain * sample_interval * + ;* * + ;* The sample interval is nominally 10mS, so the time * + ;* constant values are: * + ;* 0 1 2 3 4 5 6 7 8 * + ;* 10mS,20mS,40mS,80mS,160mS,320mS,640mS,1.28S,2.56S * + ;* * + ;* The current sample is added to an attenuated sum of previous * + ;* samples as follows: * + ;* * + ;* Adjusted Value = 1/(2^gain) x * + ;* ( 1x sample number (i) * + ;* + gain x sample number (i-1) * + ;* + gain^2 x sample number (i-2) * + ;* + gain^3 x sample number (i-3) * + ;* + .... * + ;* ) * + ;* Where: * + ;* Gain values: gain = (2^emf_lowpass_gain - 1) / 2^n * + ;* 0,1/2,3/4,7/8,15/16 ... 255/256 * + ;* * + ;* Algorithm: * + ;* * + ;* -Input (current sample) in error_lo (error_hi=0) * + ;* 0x00FF max * + ;* * + ;* -Input (scaled sum of previous samples) in * + ;* error_hi_prev--error_lo_prev. * + ;* 0x00FF * (2^emf_lowpass_gain - 1 ) max * + ;* * + ;* 1. The error_hi_prev--error_lo_prev is added to * + ;* error_hi--error_lo * + ;* 0x00FF * (2^emf_lowpass_gain) max * + ;* * + ;* 2. This value is also stored in * + ;* error_hi_prev--error_lo_prev * + ;* * + ;* 3. The value (error_hi--error_lo) is divided by * + ;* 2^emf_lowpass_gain (resulting in lowpass value, * + ;* max 0x00FF) * + ;* * + ;* 4. The value (error_hi--error_lo) is subtracted from * + ;* error_hi_prev--error_lo_prev. This is the new * + ;* stored value. * + ;***************************************************************** + clr error_hi + + ;**** + ;* 1. Add in cumulative previous error + ;**** + add error_lo,error_lo_prev ; Add in scaled previous samples + adc error_hi,error_hi_prev ; + + ;**** + ;* 2. Store + ;**** + mov error_lo_prev,error_lo ; Store new value + mov error_hi_prev,error_hi ; Store new value + + ;**** + ;* 3. Divide new value + ;**** + ldi _bemf_lo_byte,emf_lowpass_gain + rcall DIVIDE_16_SIMPLE + + ;**** + ;* 4. New value in error_prev + ;**** +ADJUST_STORED: + sub error_lo_prev,error_lo + sbc error_hi_prev,error_hi + +.endif ;LOWPASS_FILTER + + mov throttle_set,error_lo + subi Cycle_count,256-15 ; Normal arrival here occurs after 3.5 + 14.5 + + ; pwm cycles. Add 15 counts here, also 3 added in + ; div16u + +.endif BACKEMF_ENABLED diff --git a/contrib/toolchain/avra/examples/throttle_dev_set.inc b/contrib/toolchain/avra/examples/throttle_dev_set.inc new file mode 100644 index 000000000..d954df0c8 --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_dev_set.inc @@ -0,0 +1,348 @@ +;throttle_dev_set.inc + +.NOLIST + +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** + +;********************************************************* +;* Hardware Settings * +;********************************************************* + +; +; REGISTER ASSGINMENTS +; Note that registes 16 - 31 are acessed by a larger instruction +; set than registers 0 - 15. +; + + +;********************************************************* +; REGISTER ASSIGNMENTS +; GLOBAL VISIBILITY ;all functions have access to this NAME of the register +; GLOBAL DURATION ;the register always MEANS the same thing. +;********************************************************* + .DEF Flags_1= r16 ; Global. Status flags + .DEF Cycle_count= r17 ; Global. Count PWM cycles + .DEF throttle_set= r18 ; Global. Current Throttle Setting + +.ifdef SWITCH_LOWPASS ENABLED + .DEF Flags_2= r19 ; Global. Switch "status" flags +.endif SWITCH_LOWPASS_ENABLED + +.ifdef MOMENTUM_ENABLED + .DEF momentum_set= r4 ; Global. Input control +.endif ;MOMENTUM_ENABLED + +.ifdef TRADITIONAL_ENABLED + .ifdef WALKAROUND_ENABLED + .DEF throttle_hold= r14 ; Global. Previous throttle setting + .DEF Flags_2= r19 ; Global. Switch "status" flags + .endif ;WALKAROUND_ENABLED +.endif ;TRADITIONAL_ENABLED + +;********************************************************* +; REGISTER ASSIGNMENTS +; LOCAL VISIBILITY ;only the translation unit has (should have) +; access to any NAME of the register +; GLOBAL DURATION ;the register always MEANS the same thing. +;********************************************************* +.ifdef MOMENTUM_ENABLED + .ifdef LOWPASS_ENABLED + .DEF error_hi_prev= r2 ; Global. History of error + .DEF error_lo_prev= r3 ; Global. History of error + .endif ;LOWPASS_ENABLED +.endif ;MOMENTUM_ENABLED + +.ifdef TRADITIONAL_ENABLED + + .ifdef THROTTLE_LOWPASS_ENABLED + .DEF throttle_hi_prev= r9 ; Global. History of throttle handle + .DEF throttle_lo_prev= r10 ; Global. History of throttle handle + .endif ;THROTTLE_LOWPASS_ENABLED + + .ifdef MOMENTUM_LOWPASS_ENABLED + .DEF momentum_hi_prev= r11 ; Global. History of momentum handle + .DEF momentum_lo_prev= r12 ; Global. History of momentum handle + .endif ;THROTTLE_LOWPASS_ENABLED + +.endif ;TRADITIONAL_ENABLED + +.ifdef MOMENTUM_ENABLED + .DEF speed_hi_prev= r5 ; Global. Speed at last sample time + .DEF speed_lo_prev= r6 ; Global. Speed at last sample time +.endif ;MOMENTUM_ENABLED + + +;********************************************************* +; REGISTER ASSIGNMENTS +; LOCAL VISIBILITY ;only the translation unit has (should have) +; access to any NAME of the register +; LOCAL DURATION ;the register has different meanings in different contexts +;********************************************************* + .DEF Implicit= r0 ; Local. Used for implicit lpm + .DEF Sreg_stack= r1 ; Local. "stack" for SREG during interrupts + +; .DEF ZL= r30 ; Local. Used for Z pointer (low byte) +; .DEF ZH= r31 ; Local. Used for Z pointer (high byte) + +.MACRO LOWLOCAL1 + .DEF @0 = r7 ; Local. General Use +.ENDMACRO + +.MACRO LOWLOCAL2 + .DEF @0 = r8 ; Local. General Use +.ENDMACRO + +.MACRO HILOCAL1 + .DEF @0 = r26 ; Local. General Use +.ENDMACRO + +.MACRO HILOCAL2 + .DEF @0 = r27 ; Local. General Use +.ENDMACRO + +;********************************************************* +; REGISTER ASSIGNMENTS +; GLOBAL VISIBILITY ;all functions have access to this NAME of the register +; LOCAL DURATION ;the register has different meanings in different contexts +;********************************************************* +.MACRO B_TEMPLOCAL + .DEF @0 = r23 ; Local. Second Level Routine Safe +.ENDMACRO + +.MACRO B_TEMPLOCAL1 + .DEF @0 = r24 ; Local. Second Level Routine Safe +.ENDMACRO + +.MACRO B_TEMPLOCAL2 + .DEF @0 = r25 ; Local. Second Level Routine Safe +.ENDMACRO + + B_TEMPLOCAL B_Temp ; General use names + B_TEMPLOCAL1 B_Temp1 + B_TEMPLOCAL2 b_Temp2 + +;ISR LOCALS + +; UNUSED + +;.DEF Not_used= r29 + +; GLOBALS + + +;FLAGS_1 flag data + +;.SET F_Flags_1= 0b11111111 ; All flags + +.SET F_accel= 0b00000001 ; Accelerating if 1, decel if 0 +.SET BF_accel= 0x00 ; Flag bit location +.SET F_brake= 0b00000010 ; Brake set if 1 +.SET BF_brake= 0x01 ; +.SET F_stop= 0b00000100 +.SET BF_stop= 0x02 +.SET F_reverse= 0b00001000 +.SET BF_reverse= 0x03 +.SET F_negative_err= 0b00010000 +.SET BF_negative_err= 0x04 +.SET F_use_backemf= 0b00100000 +.SET BF_use_backemf= 0x05 +;.SET F_= 0b01000000 +;.SET BF_= 0x06 +;.SET F_= 0b10000000 +;.SET BF_= 0x07 + +.ifdef SWITCH_LOWPASS_ENABLED +;FLAGS_2 flag data - count and status for forward/reverse/brake/stop + +.SET F_Flags_2= 0b00001111 ; All flags + +.SET F_stop_count= 0b00010000 +.SET BF_stop_count= 0x04 +.SET F_brake_count= 0b00100000 +.SET BF_brake_count= 0x05 +.SET F_reverse_count= 0b01000000 +.SET BF_reverse_count= 0x06 +.SET F_foreward_count= 0b10000000 +.SET BF_foreward_count= 0x07 + +;bits 0-3 the count- from 0-16 + +.endif SWITCH_LOWPASS_ENABLED + +;PORT SETUP STUFF +.SET emf_port= 0x05 ;PB5 - INPUT -- Back EMF input +.SET emf_port_bit= 0b00100000 ;PIN1 ADC0 + +.SET momentum_port= 0x04 ;PB4 - INPUT -- Momentum Level input +.SET momentum_port_bit= 0b00010000 ;PIN2 ADC3 Acceleration-indicator output + +.SET dir_in_port= 0x03 ;PB3 - INPUT -- Direction/Brake +.SET dir_in_port_bit= 0b00001000 ;PIN3 ADC2 Deceleration-indicator output + +.SET throttle_port= 0x02 ;PB2 - INPUT -- Throttle Handle MAY USE INT0 +.SET throttle_port_bit= 0b00000100 ;PIN7 ADC1 (Could also use INTO + ; INT0 as DCC input.) + +.SET pwm_port= 0x01 ;PB1 - OUTPUT -- PWM (off L) +.SET pwm_port_bit= 0b00000010 ;PIN6 NO ADC + ; ONLY PWM PIN. + +.SET dir_out_port= 0x00 ;PB0 - OUTPUT -- '1' = forward +.SET dir_out_port_bit= 0b00000001 ;PIN5 NO ADC '0' = reverse + + + + +.SET acsr_val= 0b10000000 ; bit 7 --AC0 1 --comparator disabled + +.SET eecr_read_enable= 0b00000001 ; bit 4,5,6,7 --unused + ; bit 3 --EERIE 0 --interrupt disabled + ; bit 2 --EEMWE 0 --master write disabled + ; bit 1 --EEWE 0 --write disabled + ; bit 0 --EERE 1 --read ENABLED + +.SET eecr_mwrite_enable= 0b00000100 ; bit 4,5,6,7 --unused + ; bit 3 --EERIE 0 --interrupt disabled + ; bit 2 --EEMWE 1 --master write ENABLED + ; bit 1 --EEWE 0 --write disabled + ; bit 0 --EERE 0 --read disabled + +.SET eecr_write_enable= 0b00000110 ; bit 4,5,6,7 --unused + ; bit 3 --EERIE 0 --interrupt disabled + ; bit 2 --EEMWE 1 --master write ENABLED + ; bit 1 --EEWE 1 --write ENABLED + ; bit 0 --EERE 0 --read disabled + +.SET admux_emf= 0b00100000 ; bit 4,3 --unused + ; bit 7 --REFS1 0 Two bits: + ; bit 6 --REFS0 0 Select VCC volt reference + ; bit 5 --ADLAR 1 left adjust, 8 bit data in ADCH + ; bit 2 --MUX2 0 Three bits: + ; bit 1 --MUX1 0 + ; bit 0 --MUX0 0 Select ADC0 from PB5 + +.SET admux_throttle= 0b00100001 ; bit 4,3 --unused + ; bit 7 --REFS1 0 Two bits: + ; bit 6 --REFS0 0 Select VCC volt reference + ; bit 5 --ADLAR 1 left adjust, 8 bit data in ADCH + ; bit 2 --MUX2 0 Three bits: + ; bit 1 --MUX1 0 + ; bit 0 --MUX0 1 Select ADC1 from PB2 + +.SET admux_direction= 0b00100010 ; bit 4,3 --unused + ; bit 7 --REFS1 0 Two bits: + ; bit 6 --REFS0 0 Select VCC volt reference + ; bit 5 --ADLAR 1 left adjust, 8 bit data in ADCH + ; bit 2 --MUX2 0 Three bits: + ; bit 1 --MUX1 1 + ; bit 0 --MUX0 0 Select ADC2 from PB3 + +.SET admux_momentum= 0b00100011 ; bit 4,3 --unused + ; bit 7 --REFS1 0 Two bits: + ; bit 6 --REFS0 0 Select VCC volt reference + ; bit 5 --ADLAR 1 left adjust, 8 bit data in ADCH + ; bit 2 --MUX2 0 Three bits: + ; bit 1 --MUX1 1 + ; bit 0 --MUX0 1 Select ADC3 from PB4 + +.SET admux_off= 0b00000000 ; bit 4,3 --unused + ; bit 7 --REFS1 0 Two bits: + ; bit 6 --REFS0 0 Select VCC volt reference + ; bit 5 --ADLAR 0 right adjust + ; bit 2 --MUX2 0 Three bits: + ; bit 1 --MUX1 0 + ; bit 0 --MUX0 0 Select ADC0 from PB5 + +.SET adcsr_off= 0b00010011 ; bit 7 --ADCEN 0 ADC enable disable + ; bit 6 --ADSC 0 Start conversion no + ; bit 5 --ADFR 0 Free running mode disable + ; bit 4 --ADIF 1 Interrupt flag clear + ; bit 3 --ADIE 0 Interrupt enable disabled + ; bit 2 --ADPS2 0 Three bits: + ; bit 1 --ADPS1 1 + ; bit 0 --ADPS0 1 Prescaler div 8 (200kHz) + +.SET adcsr_enable= 0b11110011 ; bit 7 --ADCEN 1 ADC enable ENABLED + ; bit 6 --ADSC 1 Start conversion yes + ; bit 5 --ADFR 1 Free running mode ENABLED + ; bit 4 --ADIF 1 Interrupt flag clear + ; bit 3 --ADIE 0 Interrupt enable disabled + ; bit 2 --ADPS2 0 Three bits: + ; bit 1 --ADPS1 1 + ; bit 0 --ADPS0 1 Prescaler div 8 (200kHz) + +.SET mcucr_power_down_mode= 0b00110000 + ; bit 7 --unused + ; bit 6 --PUD 0 pullups ENABLED + ; bit 5 --SE 1 sleep ENABLED + ; bit 4 --SM1 1 Two bits: + ; bit 3 --SM0 0 Sleep in power down mode + ; bit 2 --unused + ; bit 1 --ISC01 0 Two bits: + ; bit 0 --ISC00 0 INTO interrupt on logic + ; low input + + +.SET wdtcr_off_enable= 0b00011000 ; enable watchdog turn off +.SET wdtcr_off= 0b00010000 ; watchdog turn off + +.SET gimsk_val_off= 0b00000000 ; bit 7,4,3,2,1,0 --unused + ; bit 6 --INTO 0 INTO interrupt disabled + ; bit 5 --PCIE 0 pin change interrupt disabled + +.SET gimsk_val_pcie= 0b00100000 ; bit 7,4,3,2,1,0 --unused + ; bit 6 --INTO 0 INTO interrupt disabled + ; bit 5 --PCIE 1 pin change interrupt ENABLED + +.SET gifr_clear= 0b01100000 ; bit 7,4,3,2,1,0 --unused + ; bit 6 --INTF0 1 INTO interrupt flag cleared + ; bit 5 --PCIF 1 pin ch. interrupt flag cleared + +.SET timsk_val_off= 0b00000000 ; bit 7,5,4,3,0 --unused + ; bit 6 --OCIE1A 0 TC1 compare interrupt disabled + ; bit 2 --TOIE1 0 TC1 overflow interrupt disabled + ; bit 1 --TOIE0 0 TC0 overflow interrupt disabled + +.SET timsk_enable_t1= 0b01000000 ; bit 7,5,4,3,0 --unused + ; bit 6 --OCIE1A 0 TC1 compare interrupt disabled + ; bit 2 --TOIE1 0 TC1 overflow interrupt disabled + ; bit 1 --TOIE0 0 TC0 overflow interrupt disabled + +.SET tifr_clear_tov0= 0b00000010 ; bit 7,5,4,3,0 --unused + ; bit 6 --OCF1A 0 OCF1A flag not cleared + ; bit 2 --TOV1 0 TOV1 flag not cleared + ; bit 1 --TOV0 1 TOV0 flag CLEARED + +.SET tccr1_enable_t1= 0b01100011 + ; bit 7 --CTC1 0 Clear on compare match no + ; bit 6 --PWM1 1 PWM mode ENABLED + ; bit 5 --COM1A1 1 Two bits: + ; bit 4 --COM1A0 0 Clear output on OCR1A match + ; Set output when TCNT1 = 0 + ; bit 3 --CS13 0 Four bits: + ; bit 2 --CS12 0 + ; bit 3 --CS11 1 + ; bit 4 --CS10 1 CK*4: 156.25nS + ; 256cnt = 25kHz +.LIST diff --git a/contrib/toolchain/avra/examples/throttle_divide.asm b/contrib/toolchain/avra/examples/throttle_divide.asm new file mode 100644 index 000000000..ba6cb030b --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_divide.asm @@ -0,0 +1,135 @@ +;throttle_divide.asm +; +;******************************************************************************** +;* div16u * +;* Second Level Subroutine * +;* * +;* Program from Atmel file avr200.asm * +;* * +;* Since the 25kHz pwm cycle is 64 clock cycles long, this subroutine * +;* requires 3.67 to 3.92 25kHz clock cycles. * +;* * +;* A single line was added which adds 3 to Cycle_count * +;* * +;* Inputs: HILOCAL2:HILOCAL1 and B_TEMPLOCAL1:B_TEMPLOCAL * +;* Returns: HILOCAL2:HILOCAL1 = HILOCAL2:HILOCAL1 / B_TEMPLOCAL1:B_TEMPLOCAL * +;* LOLOCAL2:LOLOCAL1 = remainder * +;* Changed: B_TEMPLOCAL2 * +;* * +;* Calls: Not allowed * +;******************************************************************************** + + + B_TEMPLOCAL2 dcnt16u ; Local counter + + HILOCAL1 dd16uL ; 16 bit Innput + HILOCAL2 dd16uH + + B_TEMPLOCAL dv16uL ; 16 bit Input + B_TEMPLOCAL1 dv16uH + + HILOCAL1 dres16uL ; 16 bit Output + HILOCAL2 dres16uH + + LOWLOCAL1 drem16uL ; 16 bit Remainder + LOWLOCAL2 drem16uH ; + + + +; +;*************************************************************************** +;* +;* "div16u" - 16/16 Bit Unsigned Division +;* +;* This subroutine divides the two 16-bit numbers +;* "dd16uH:dd16uL" (dividend) and "dv16uH:dv16uL" (divisor). +;* The result is placed in "dres16uH:dres16uL" and the remainder in +;* "drem16uH:drem16uL". +;* +;* Number of words :19 +;* Number of cycles :235/251 (Min/Max) +;* Low registers used :2 (drem16uL,drem16uH) +;* High registers used :5 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH, +;* dcnt16u) +;* +;*************************************************************************** + +;***** Subroutine Register Variables + +;.def drem16uL= r14 ; Reassigned +;.def drem16uH= r15 +;.def dres16uL= r16 +;.def dres16uH= r17 +;.def dd16uL= r16 +;.def dd16uH= r17 +;.def dv16uL= r18 +;.def dv16uH= r19 +;.def dcnt16u= r20 + +;***** Code + +div16u: + clr drem16uL ; clear remainder Low byte + sub drem16uH,drem16uH ; clear remainder High byte and carry + ldi dcnt16u,17 ; init loop counter + +d16u_1: + rol dd16uL ; shift left dividend + rol dd16uH + dec dcnt16u ; decrement counter + brne d16u_2 ; if done + + subi Cycle_count,256-3 ; Add 3 to Cycle_count + + ret ; return + +d16u_2: + rol drem16uL ; shift dividend into remainder + rol drem16uH + + sub drem16uL,dv16uL ; remainder = remainder - divisor + sbc drem16uH,dv16uH ; + + brcc d16u_3 ; + + add drem16uL,dv16uL ; if result negative + adc drem16uH,dv16uH ; restore remainder + clc ; clear carry to be shifted into result + rjmp d16u_1 ; + +d16u_3: ; if result NOT negative + sec ; set carry to be shifted into result + rjmp d16u_1 + +; + +;******************************************************************************** +;* DIVIDE_16_SIMPLE * +;* Second Level Subroutine * +;* * +;* Inputs: dd16uH:dd16ul and dv16uL * +;* Returns: dres16uH:dres16uL = dd8uH:dd8uL / 2^dv16uL * +;* * +;* Changed: nothing else * +;* N.B that dd16uH, dd16uL, dv16uH and dv16uL are aliases for: * +;* dd16uH=error_hi * +;* dd16uL=error_lo * +;* dv16uH=B_TempX * +;* dv16uL=B_TempX * +;* dcnt16u=B_TempX * +;* Calls: Not allowed * +;******************************************************************************** + + +DIVIDE_16_SIMPLE: + inc dv16uL +DIVIDE_16_SIMPLE_LOOP: + dec dv16uL ; decrement counter + brne DIVIDE_BY_2 + ret + +DIVIDE_BY_2: + asr dd16uH ; divide by two + ror dd16uL + rjmp DIVIDE_16_SIMPLE_LOOP + diff --git a/contrib/toolchain/avra/examples/throttle_momentum.asm b/contrib/toolchain/avra/examples/throttle_momentum.asm new file mode 100644 index 000000000..087a04789 --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_momentum.asm @@ -0,0 +1,314 @@ +;throttle_momentum.asm + +.NOLIST + +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; ***************************************************************************************: +.LIST + +.ifdef MOMENTUM_ENABLED +;******************************************************************************** +;* MOMENTUM_ADJUST * +;* Top level routine * +;* * +;* Momentum simulates the mass of the train. Since model trains have little * +;* mass, the locomotive speed can directly follow the throttle setting; in * +;* other words, a model train can accelerate and decelerate instantly. * +;* Real trains are very massive, and therefore they do not accelerate or * +;* decelerate quickly. * +;* * +;* According to Newtons law, the acceleration is proportional to the force, * +;* and inversely proportional to the mass. Therefore, the more massive the * +;* train, the more slowly the train will accelerate or decelerate. Also, the * +;* more force the locomotive can provide, the faster the train will accelerate. * +;* Deceler depends on the braking capability of the overall train. * +;* * +;* If force were constant, Newtons law states that acceleration would be * +;* constant too. This subroutine assumes that somewhat more force is * +;* available at low speeds than at high speeds, so that acceleration will be * +;* greater at low speeds. The subroutine also assumes that opposing forces * +;* (friction, wind resistance, etc) are stronger at higher speeds. This * +;* assumption also means that acceleration will be greater at low speeds. * +;* * +;* This subroutine calculates acceleration/deceleration by this simple * +;* Method: * +;* * +;* The rate of speed change (accleration and deceleration) depends on the * +;* current speed as * +;* {Speed_Max (0xFF) - Current_Speed} / {Tau*Rate} * +;* * +;* Where T = index of sample time * +;* t = real time * +;* Tau = time constant * +;* Rate = Update rate (nominally 100Hz) * +;* * +;* That is, the acceleration/deceleration is maximum at zero speed, and * +;* approaches zero at maximum speed. * +;* * +;* When accelerating, the speed at the next sample period is * +;* Speed(T) = Speed(T-1) + {0xFF - Speed(T-1)} / {Tau*Rate} * +;* * +;* Giving an acceleration curve that looks like a normal exponential. * +;* Speed(t) = 0xFF { 1 - exp( - t / Tau) } * +;* * +;* * * * +;* * * +;* * * +;* * * +;* * * +;* * * +;* * * +;* * * +;* * +;* * +;* When decelerating, the change rate equation is the same, but the change * +;* is subtracted, as * +;* Speed(T) = Speed(T) - {0xFF - Speed(T-1)} / {Tau*Rate} * +;* * +;* Giving a deceleration curve that looks like * +;* Speed(t) = 0xFF { 1 - exp( -(T1 - t) / Tau) } * +;* which is a mirror image of the acceleration, NOT a normal exponential. * +;* * +;* * * * +;* * * +;* * * +;* * * +;* * * +;* * * +;* * * +;* * +;* * +;* In each case, the acceleration or deceleration is "clipped" at the current * +;* throttle setting so that the speed doesn't overshoot or undershoot. * +;* * +;* Three different values of Tau are used, that is * +;* Tau_accel Corresponding to acceleration under power * +;* Tau_coast Corresponding to deceleration when coasting * +;* Tau_brake Corresponding to deceleration when braking * +;* * +;* To permit finer control of momentum, the throttle setting is converted to a * +;* 16 bit number, where the 8 msb's correspond to the throttle setting from * +;* the throttle handle and sent forward. * +;* * +;* Inputs: throttle_set Throttle handle position ( 0x00 to 0xFF ) * +;* speed_hi_prev Hi byte of (T-1) throttle setting (stored) * +;* speed_lo_prev Lo byte of (T-1) throttle setting (stored) * +;* Returns: throttle_set Adjusted throttle setting (T) * +;* speed_hi_prev Hi byte of (T) throttle setting (stored) * +;* speed_lo_prev Lo byte of (T) throttle setting (stored) * +;* Changed: B_Temp * +;* B_Temp1 * +;* B_Temp2 * +;* B_Temp3 * +;* Calls: NONE * +;* Goto: MOMENTUM_ADJUST_RETURN * +;******************************************************************************** + B_TEMPLOCAL2 _time_constant_adj + + +.ifdef TRADITIONAL_ENABLED + .ifdef LEDS_ENABLED + sbrc Flags_1,BF_brake ; If the brake flag is set, + sbi PORTB,dir_in_port ; Port Output: Indicate deceleration + .endif ;LEDS_ENABLED +.endif ;TRADITIONAL_ENABLED + + ;******************************************************************* + ;* Adjust the value of "momentum_set". + ;* This adjustment makes it easier to fine adjust low momentum settings + ;* while still permitting large momentum settings. + ;* + ;* The ammount of momentum to apply comes in in "momentum_set" + ;* which is read in READ_THROTTLE. The nominal range is + ;* 0x00 to 0x40. This value is multiplied by two and squared, + ;* giving a new range from 0x00 to 0x4000. The update rate is 100Hz, + ;* and so the new range corresponds to a time constant from + ;* 0(decimal) to 164(decimal) seconds. Since the adjustment was + ;* done by performing a square, the adjusted value is non-linear + ;* with the input value. + ;******************************************************************* + lsl momentum_set ; multiply by two + + HILOCAL1 _mset_multiplier ; supply to mpy8u + B_TEMPLOCAL _mset_multiplicand ; supply to mpy8u + + mov _mset_multiplier,momentum_set ; + mov _mset_multiplicand,momentum_set ; + rcall mpy8u ; square + + B_TEMPLOCAL1 _mset_hi_byte ; return from mpy8u + B_TEMPLOCAL _mset_lo_byte ; return from mpy8u + + ;******************************************************************* + ;* Compute the difference between the maximum throttle and + ;* the current throttle + ;******************************************************************* + HILOCAL2 _mset_diff_hi_byte + HILOCAL1 _mset_diff_lo_byte + + ldi _mset_diff_hi_byte,0xFF ; Maximum possible speed + ldi _mset_diff_lo_byte,0xFF ; + + sub _mset_diff_lo_byte,speed_lo_prev ; Difference between max speed + sbc _mset_diff_hi_byte,speed_hi_prev ; and current speed + + ;******************************************************************* + ;* Determine whether to accelerate, decelerate, or remain unchanged. + ;* Compare the throttle handle setting with the actual speed + ;******************************************************************* + cp throttle_set,speed_hi_prev ; Test if throttle position is larger + ; or smaller than the speed. + + breq EVEN_SPEED ; If the throttle position is the same + ; as the speed. + + brlo SETUP_DECELERATE ; If the throttle position is smaller + ; than the speed, then need to decelerate. + +; brsh SETUP_ACCELERATE ; If the throttle position is larger + ; than the speed, then need to accelerate. + +SETUP_ACCELERATE: +.ifdef TRADITIONAL_ENABLED + .ifdef LEDS_ENABLED + cpi throttle_set,accel_led_threshold ; If the throttle is less than minimum + brlo END_SET_ACCEL_LED ; don't light led + + mov B_Temp2,throttle_set ; If the throttle is closer than led_threshold + subi B_Temp2,accel_led_threshold ; don't light led + cp B_Temp2,speed_hi_prev + brlo END_SET_ACCEL_LED + + sbi PORTB,momentum_port ; Port Output: Indicate acceleration + END_SET_ACCEL_LED: + .endif LEDS_ENABLED +.endif TRADITIONAL_ENABLED + + sbr Flags_1,F_accel ; Set accelerating flag + ; Indicate acceleration + + ldi _time_constant_adj,accel_offset+1 ; Acceleration time constant adjust + + rjmp CHECK_BRAKE + +EVEN_SPEED: ; Arrive here if throttle_set=current speed + + sbrc Flags_1,BF_brake ; If the brake flag is set, decelerate + rjmp CHECK_BRAKE ; + + rjmp DONE_WITH_MOMENTUM ; Otherwise adjustment is necessary + + +SETUP_DECELERATE: + cbr Flags_1,F_accel ; Clear accelerating flag + +.ifdef TRADITIONAL_ENABLED + .ifdef LEDS_ENABLED + + cpi throttle_set,0xff-decel_led_threshold ; If the throttle is more than maximum + brsh END_SET_DECEL_LED ; don't light led + + mov B_Temp2,throttle_set + subi B_Temp2,0x00-decel_led_threshold ; If the throttle is closer than the led + cp B_Temp2,speed_hi_prev ; threshold, don't light the led + brsh END_SET_DECEL_LED + + sbi PORTB,dir_in_port ; Port Output: Indicate deceleration + END_SET_DECEL_LED: + .endif LEDS_ENABLED +.endif TRADITIONAL_ENABLED + + ldi _time_constant_adj,0+1 ; Coasting deceleration time const. adjust. +; rjmp CHECK_BRAKE + +CHECK_BRAKE: ; Always check for the brake. + + sbrs Flags_1,BF_brake ; If brake flag is not set, + rjmp ADJUST_TAU ; proceed. + + ; Brake overrides acceleration + ; or coasting. + cbr Flags_1,F_accel ; clear accelerating flag + ; Indicate deceleration + + ldi _time_constant_adj,brake_offset+1 ; Braking deceleration time const. adjust. + +; rjmp ADJUST_TAU + +ADJUST_TAU: + ;B_TEMP2=B_TEMPLOCAL2 + dec _time_constant_adj ; Divide tau_base by 2^_time_constant_adj + breq DIVIDE_TAU ; to produce adjusted tau. + + lsr _mset_hi_byte + ror _mset_lo_byte + rjmp ADJUST_TAU + +DIVIDE_TAU: + sbr _mset_lo_byte,0b00000001 ; Force last bit 1. Prevent divide by zero. + + rcall div16u ; Divide _mset_diff_hi_byte:_mset_diff_lo_byte + ; (difference) + ; by _mset_hi_byte:_mset_lo_byte (dividor) + + sbrs Flags_1,BF_accel ; add or subtract change depending + rjmp SUBTRACT_CHANGE ; on F_accel flag + ;rjmp ADD_CHANGE + +ADD_CHANGE: ; Case accelerating + +; HILOCAL2 _mset_diff_hi_byte +; HILOCAL1 _mset_diff_lo_byte + + add speed_lo_prev,_mset_diff_lo_byte ; Add in the change + adc speed_hi_prev,_mset_diff_hi_byte + + cp throttle_set,speed_hi_prev ; If larger than the throttle_set value + brlo USE_SET_SPEED ; clamp at throttle_set value + + rjmp DONE_WITH_MOMENTUM + +SUBTRACT_CHANGE: ; Case decelerating + + sbrc Flags_1,BF_brake ; If the brake flag is set, + clr throttle_set ; decelerate all the way to zero + + sub speed_lo_prev,_mset_diff_lo_byte ; Subtract the change + sbc speed_hi_prev,_mset_diff_hi_byte ; + + brlo USE_SET_SPEED ; If less than zero + ; clamp at throttle_set value + + cp speed_hi_prev,throttle_set ; If less than the throttle_set value + brlo USE_SET_SPEED ; clamp at throttle_set value + + rjmp DONE_WITH_MOMENTUM + +USE_SET_SPEED: ; Use the throttle_set value directly + mov speed_hi_prev,throttle_set + clr speed_lo_prev + +DONE_WITH_MOMENTUM: + mov throttle_set,speed_hi_prev ; Put the new value into throttle_set. + +.endif ;MOMENTUM_ENABLED diff --git a/contrib/toolchain/avra/examples/throttle_momentum_lowpass.asm b/contrib/toolchain/avra/examples/throttle_momentum_lowpass.asm new file mode 100644 index 000000000..33574775e --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_momentum_lowpass.asm @@ -0,0 +1,69 @@ +;throttle_momentum_lowpass.asm + +.NOLIST + +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** +.LIST + +.ifdef MOMENTUM_LOWPASS_ENABLED + ;***************************************************************** + ;* A transversal low pass filter * + ;* * + ;* This is copied from throttle_backemf.asm. * + ;* See the documentation there. * + ;***************************************************************** + HILOCAL1 _momentum_lo ; assign local variables + HILOCAL2 _momentum_hi + + mov _momentum_lo,momentum_set + clr _momentum_hi + + ;**** + ;* 1. Add in cumulative previous throttle + ;**** + add _momentum_lo,momentum_lo_prev ; Add in scaled previous samples + adc _momentum_hi,momentum_hi_prev ; + + ;**** + ;* 2. + ;**** + mov momentum_lo_prev,_momentum_lo ; Store new value + mov momentum_hi_prev,_momentum_hi ; Store new value + + ;**** + ;* 3. + ;**** + + B_TEMPLOCAL _lowpass_lo_byte + ldi _lowpass_lo_byte, momentum_lowpass_gain + rcall DIVIDE_16_SIMPLE + + ;**** + ;* 4. + ;**** + sub momentum_lo_prev,_momentum_lo + sbc momentum_hi_prev,_momentum_hi + + mov momentum_set,_momentum_lo +.endif ;MOMENTUM_LOWPASS_ENABLED diff --git a/contrib/toolchain/avra/examples/throttle_multiply.asm b/contrib/toolchain/avra/examples/throttle_multiply.asm new file mode 100644 index 000000000..23a32654a --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_multiply.asm @@ -0,0 +1,74 @@ +;throttle_multiply.asm +; +;******************************************************************************** +;* mpy8u * +;* Second Level Subroutine * +;* * +;* Program from Atmel file avr200.asm * +;* * +;* Since the 25kHz pwm cycle is 64 clock cycles long, this subroutine * +;* requires just under 1 25kHz clock cycles. * +;* * +;* A single line was added which adds 3 to Cycle_count * +;* * +;* Inputs: HILOCAL1 and B_TEMPLOCAL * +;* * +;* Returns: HILOCAL1 x B_TEMPLOCAL = B_TEMPLOCAL1:B_TEMPLOCAL * +;* * +;* Changed: B_TEMPLOCAL2 * +;* * +;* Calls: Not allowed * +;******************************************************************************** + + HILOCAL1 mc8u ; multiplicand + B_TEMPLOCAL mp8u ; multiplier + B_TEMPLOCAL m8uL ; result Low byte + B_TEMPLOCAL1 m8uH ; result High byte + B_TEMPLOCAL2 mcnt8u ; loop counter + + +; +;*************************************************************************** +;* +;* "mpy8u" - 8x8 Bit Unsigned Multiplication +;* +;* This subroutine multiplies the two register variables mp8u and mc8u. +;* The result is placed in registers m8uH, m8uL +;* +;* Number of words :9 + return +;* Number of cycles :58 + return +;* Low registers used :None +;* High registers used :4 (mp8u,mc8u/m8uL,m8uH,mcnt8u) +;* +;* Note: Result Low byte and the multiplier share the same register. +;* This causes the multiplier to be overwritten by the result. +;* +;*************************************************************************** + +;***** Subroutine Register Variables + +;.def mc8u =r16 ;multiplicand +;.def mp8u =r17 ;multiplier +;.def m8uL =r17 ;result Low byte +;.def m8uH =r18 ;result High byte +;.def mcnt8u =r19 ;loop counter + +;***** Code + + +mpy8u: + clr m8uH ;clear result High byte + ldi mcnt8u,8 ;init loop counter + lsr mp8u ;rotate multiplier + +m8u_1: + brcc m8u_2 ;carry set + add m8uH,mc8u ;add multiplicand to result High byte +m8u_2: + ror m8uH ;rotate right result High byte + ror m8uL ;rotate right result L byte and multiplier + dec mcnt8u ;decrement loop counter + brne m8u_1 ;if not done, loop more + ret + +; diff --git a/contrib/toolchain/avra/examples/throttle_op_set.inc b/contrib/toolchain/avra/examples/throttle_op_set.inc new file mode 100644 index 000000000..a46fd6397 --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_op_set.inc @@ -0,0 +1,227 @@ +;throttle_op_set.inc + +.NOLIST + +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** + +;********************************************************* +;* Operation Settings * +;********************************************************* + + + +;********************************************************* +;* Compile time options +;********************************************************* +.define TRADITIONAL_ENABLED ; A traditional throttle. NOT + ; a dcc decoder + + .define WALKAROUND_ENABLED ; Removable, walkaround throttle + ; (Does nothing unless the + ; TRADITIONAL_ENABLED is also defined) + + .define THROTTLE_LOWPASS_ENABLED ; Lowpass filter on throttle handle + ; (Does nothing unless the + ; TRADITIONAL_ENABLED is also defined) + + .define MOMENTUM_LOWPASS_ENABLED ; Lowpass filter on momentum handle + ; (Does nothing unless the + ; TRADITIONAL_ENABLED and + ; MOMENTUM_ENABLED are defined) + + .define SWITCH_LOWPASS_ENABLED ; Lowpass filter on direction switches + + .define LEDS_ENABLED ; Acceleration/Deceleration indicators + ; (Does nothing unless the + ; TRADITIONAL_ENABLED is also defined) + + .define LOCO_LIGHT_ENABLED ; Keep pwm on at low level so light + ; remains on. + ; (Does nothing unless the + ; TRADITIONAL_ENABLED is also defined) + +.define BACKEMF_ENABLED ; If enabled, speed is compensated + ; according to motor back emf + + .define BACKEMF_SCALE_ENABLED ; If enabled, the speed compensation + ; is reduced as the throttle setting + ; is increased. + ; (Does nothing unless the + ; BACKEMF_ENABLED is also defined) + + + .define LOWPASS_ENABLED ; Provide a lowpass filter on the + ; the back-emf error amplifier + ; (Does nothing unless the + ; BACKEMF_ENABLED is also defined) + +.define OVERLOAD_ENABLED ; Enable overload protection + +.define PULSE_ENABLED ; Pulse power at low throttle + + ;.define PULSE_AMPLITUDE_SCALE ; Increase pulse size at lowest throttle + ; (Does nothing unless the + ; PULSE_ENABLED is also defined) + + .define PULSE_WIDTH_SCALE ; Increase pulse width at higher throttle + ; (Does nothing unless the + ; PULSE_ENABLED is also defined) + +.define MOMENTUM_ENABLED ; Simulate momentum + +.define DIRECTION_ENABLED ; Direction/brake/STOP input +;********************************************************* + +;********************************************************* +;* Variables for all compilations +;********************************************************* + + ;******************* + ;* High frequency pwm settings + ;******************* +.SET pwm_period= 0xFF ; The pwm clock ticks at 156.25nS per tick + ; The pwm runs at pwm_period * 156.25nS + ; The pwm frequency is 1/ (156.25nS * pwm_period) + ; Maximum is 255 (0xFF) + +.SET pwm_max= 0xFF ; Maximum pwm "duty cycle" is equal to + ; pwm_max / pwm_period + +.SET pwm_min= 0x08 ; Minimum PWM "duty cycle" is equal to + ; pwm_min / pwm_period + + + ;******************* + ;* Sample rate for throttle/ backemf/ pulses, etc + ;******************* +.SET pwm_settle_count= 16 ; settling time for analog measurements + ; (x 40uS) +.SET pwm_full_count= 250 ; time (x 40uS) between recalculations + ; (255 max) + +;********************************************************* +;* Variables associated with backemf speed control +;********************************************************* +.ifdef BACKEMF_ENABLED + + ;******************* + ;* General settings + ;******************* + + .SET error_mult= 2 ; Error Multiplier. The error between + ; the throttle_set and back_emf is + ; multiplied by 2^error_mult + ; limit -8 < n < 7 + ; 1/256 to 128 + + .ifdef BACKEMF_SCALE_ENABLED + .SET err_scale= 5 ; Maximum error gain is as set by error_mult. + ; Error gain decreases exponentially toward + ; zero. When the throttle is set at 2^err_scale + ; the error be reduced by 2 + ; Err scale must not be less than 0. + ; The sum of err_scale and err_mult MUST NOT + ; exceed 7. + .endif ;BACKEMF_SCALE_ENABLED + + .ifdef LOWPASS_ENABLED + + .SET emf_lowpass_gain= 2 ; tau is about 2^emf_lowpass_gain / 100 + ; emf_lowpass_gain 0 to 8 (7?) + .endif ;LOWPASS_ENABLED + +.endif ;BACKEMF_ENABLED + +;********************************************************* +;* Variables associated with lowspeed pulses +;********************************************************* +.ifdef PULSE_ENABLED + .SET pwm_min= 0x00 ; override previous setting + .SET pulse_slope_up= 0x0C + .SET pulse_slope_down= 0x08 + .SET pulse_width_min= 0x08 ; minimum 0x01 +.endif ; PULSE_ENABLED + +;********************************************************* +;* Variables associated with momentum +;********************************************************* +.ifdef MOMENTUM_ENABLED + ; MAY NOT BE MORE THAN 7 + + .SET accel_offset=1 ; divide tau_base by 2^accel_offset to give + ; acceleration time constant + .SET brake_offset=2 ; divide tau_base by 2^brake_offset to give + ; brake time constant + + +.endif MOMENTUM_ENABLED + + +;********************************************************* +;* Variables associated with direction +;********************************************************* +.ifdef DIRECTION_ENABLED + + .SET direction_threshold= 16 ; direction relay will switch as long as + ; the throttle (handle and momentum) are + ; less than this value +.endif ;DIRECTION_ENABLED + +;********************************************************* +;* Variables associated with traditional throttle +;********************************************************* +.ifdef TRADITIONAL_ENABLED + + +.ifdef SWITCH_LOWPASS_ENABLED + .SET stop_count_max= 10 ; number of identical samples to indicate + .SET brake_count_max= 10 ; number of identical samples to indicate + .SET reverse_count_max= 10 ; number of identical samples to indicate + .SET foreward_count_max= 10 ; number of identical samples to indicate +.endif ;SWITCH_LOWPASS_ENABLED + +.ifdef THROTTLE_LOWPASS_ENABLED + .SET throttle_lowpass_gain= 5 ; tau is about 2^throttle_lowpass_gain / 100 + ; throttle_lowpass_gain range 0 to 8 (7?) +.endif ;THROTTLE_LOWPASS_ENABLED + +.ifdef MOMENTUM_LOWPASS_ENABLED + .SET momentum_lowpass_gain= 7 ; tau is about 2^momentum_lowpass_gain / 100 + ; momentum_lowpass_gain range 0 to 8 (7?) +.endif ;MOMENTUM_LOWPASS_ENABLED + +.ifdef LEDS_ENABLED + + .SET accel_led_threshold=2 ; dont light led when acceleration/deceleration + ; is closer than this to the actual speed + .SET decel_led_threshold=2 ; dont light led when acceleration/deceleration + ; is closer than this to the actual speed +.endif;LEDS_ENABLED + +.ifdef LOCO_LIGHT_ENABLED + .SET light_pwm= 6 ; run this pwm "duty cycle when throttle is off +.endif ;LOCO_LIGHT_ENABLED ; to keep loco light on +.endif ;TRADITIONAL_ENABLED + +.LIST diff --git a/contrib/toolchain/avra/examples/throttle_pulse.asm b/contrib/toolchain/avra/examples/throttle_pulse.asm new file mode 100644 index 000000000..b6b91851b --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_pulse.asm @@ -0,0 +1,140 @@ +;throttle_pulse.asm + +.NOLIST +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** +.LIST + +.ifdef PULSE_ENABLED +;******************************************************************************** +;* PULSE_GENERATE * +;* Top level routine * +;* * +;* Inputs: throttle_set * +;* Returns: none * +;* Changed: B_Temp,ramp_target,ramp_target1 * +;* Calls: SET_PWM_DUTY * +;* COUNT_PWM_CYCLES * +;* Goto: none * +;******************************************************************************** + +HILOCAL1 ramp_target +HILOCAL2 ramp_target1 + + ;***************************************************************** + ;* If throttle_set is less than 128 (0x80) + ;* Ramp up from wherever the pwm is up to (255 - throttle) + ;* If throttle_set is greater than 127 0x7F) + ;* Ramp up to throttle_set + ;***************************************************************** + + mov ramp_target1,throttle_set + sbrs ramp_target1,7 + +.ifdef PULSE_AMPLITUDE_SCALE + com ramp_target1 ; Ramp up to this value +.else + ldi ramp_target1,0x80 +.endif + + mov ramp_target,ramp_target1 + + subi ramp_target,pulse_slope_up ; Ramp up value - pulse_slope + +WAIT_FOR_PWM_1: ; Wait for PWM to reset to 0 + in B_Temp,TIFR + sbrs B_Temp,OCF1A + rjmp WAIT_FOR_PWM_1 + + ldi B_Temp,0b01000000 + out TIFR,B_Temp + + inc Cycle_count + + in B_Temp,OCR1A ; Find PWM value + cp B_Temp,ramp_target ; Make sure won't go past max. + brsh DONE_SLOPING_UP + + subi B_Temp, 0x100-pulse_slope_up ; OCR1A + pulse_slope_up + + rcall SET_PWM_DUTY + rjmp WAIT_FOR_PWM_1 + +DONE_SLOPING_UP: + mov B_Temp,ramp_target1 + rcall SET_PWM_DUTY + + ;***************************************************************** + ;* See if we need to slope down to the throttle setting + ;***************************************************************** + in B_Temp,OCR1A ; Find PWM value + cp B_Temp,throttle_set + breq PULSE_GENERATE_RETURN ; Do nothing if already at final voltage + + ;***************************************************************** + ;* Hang about at the top of the pulse for a while... + ;***************************************************************** + +.ifdef PULSE_WIDTH_SCALE + mov ramp_target1,throttle_set +.else + clr ramp_target1 +.endif + + add ramp_target1,Cycle_count + + subi ramp_target1,0x100-pulse_width_min ; ramp_target1 + pulse_width_min + + mov B_Temp1,ramp_target1 + + rcall COUNT_PWM_CYCLES + + ;***************************************************************** + ;* Slope down + ;***************************************************************** + + mov ramp_target,throttle_set ; Ramp DOWN to this value + + subi ramp_target,0x100-pulse_slope_down ;ramp_target + pulse_slope_down + +WAIT_FOR_PWM_2: ; Wait for PWM to reset to 0 + in B_Temp,TIFR + sbrs B_Temp,OCF1A + rjmp WAIT_FOR_PWM_2 + + ldi B_Temp,0b01000000 + out TIFR,B_Temp + + inc Cycle_count + + in B_Temp,OCR1A ; Find PWM value + cp ramp_target,B_Temp ; Make sure won't go past min + brsh PULSE_GENERATE_RETURN + + subi B_Temp,pulse_slope_down + + rcall SET_PWM_DUTY + rjmp WAIT_FOR_PWM_2 + +PULSE_GENERATE_RETURN: +.endif ;PULSE_ENABLED diff --git a/contrib/toolchain/avra/examples/throttle_set_lowpass.asm b/contrib/toolchain/avra/examples/throttle_set_lowpass.asm new file mode 100644 index 000000000..e188152bc --- /dev/null +++ b/contrib/toolchain/avra/examples/throttle_set_lowpass.asm @@ -0,0 +1,69 @@ +;throttle_set_lowpass.asm + +.NOLIST + +; *************************************************************************************** +; * PWM MODEL RAILROAD THROTTLE * +; * * +; * WRITTEN BY: PHILIP DEVRIES * +; * * +; * Copyright (C) 2003 Philip DeVries * +; * * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License as published by * +; * the Free Software Foundation; either version 2 of the License, or * +; * (at your option) any later version. * +; * * +; * This program is distributed in the hope that it will be useful, * +; * but WITHOUT ANY WARRANTY; without even the implied warranty of * +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +; * GNU General Public License for more details. * +; * * +; * You should have received a copy of the GNU General Public License * +; * along with this program; if not, write to the Free Software * +; * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +; * * +; *************************************************************************************** +.LIST + +.ifdef THROTTLE_LOWPASS_ENABLED + ;***************************************************************** + ;* A transversal low pass filter * + ;* * + ;* This is copied from throttle_backemf.asm. * + ;* See the documentation there. * + ;***************************************************************** + HILOCAL1 throttle_lo ; assign local variables + HILOCAL2 throttle_hi + + mov throttle_lo,throttle_set + clr throttle_hi + + ;**** + ;* 1. Add in cumulative previous throttle + ;**** + add throttle_lo,throttle_lo_prev ; Add in scaled previous samples + adc throttle_hi,throttle_hi_prev ; + + ;**** + ;* 2. + ;**** + mov throttle_lo_prev,throttle_lo ; Store new value + mov throttle_hi_prev,throttle_hi ; Store new value + + ;**** + ;* 3. + ;**** + + B_TEMPLOCAL _lowpass_lo_byte + ldi _lowpass_lo_byte, throttle_lowpass_gain + rcall DIVIDE_16_SIMPLE + + ;**** + ;* 4. + ;**** + sub throttle_lo_prev,throttle_lo + sbc throttle_hi_prev,throttle_hi + + mov throttle_set,throttle_lo +.endif ;THROTTLE_LOWPASS_FILTER diff --git a/contrib/toolchain/avra/examples/tn15def.inc b/contrib/toolchain/avra/examples/tn15def.inc new file mode 100644 index 000000000..84b634a75 --- /dev/null +++ b/contrib/toolchain/avra/examples/tn15def.inc @@ -0,0 +1,195 @@ +.NOLIST + +;*************************************************************************** +;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y +;* +;* Number :AVR000 +;* File Name :"tn15def.inc" +;* Title :Register/Bit Definitions for the ATtiny15 +;* Date :99.07.05 +;* Version :1.00 +;* Support telephone :+47 72 88 87 20 (ATMEL Norway) +;* Support fax :+47 72 88 87 18 (ATMEL Norway) +;* Support E-mail :avr@atmel.com +;* Target MCU :ATtiny15 +;* +;* DESCRIPTION +;* When including this file in the assembly program file, all I/O register +;* names and I/O register bit names appearing in the data book can be used. +;* In addition, the six registers forming the three data pointers X, Y and +;* Z have been assigned names XL - ZH. Highest RAM address for Internal +;* SRAM is also defined +;* +;* The Register names are represented by their hexadecimal address. +;* +;* The Register Bit names are represented by their bit number (0-7). +;* +;* Please observe the difference in using the bit names with instructions +;* such as "sbr"/"cbr" (set/clear bit in register) and "sbrs"/"sbrc" +;* (skip if bit in register set/cleared). The following example illustrates +;* this: +;* +;* in r16,PORTB ;read PORTB latch +;* sbr r16,(1< +#include +#include + +#include "misc.h" +#include "args.h" + + +struct args *alloc_args(int arg_count) +{ + struct args *args; + + args = malloc(sizeof(struct args)); + if(args) { + args->arg = malloc(sizeof(struct arg) * arg_count); + if(args->arg) { + args->count = arg_count; + args->first_data = NULL; + return(args); + } + free(args); + } + printf("Error: Unable to allocate memory\n"); + return(NULL); +} + + +int read_args(struct args *args, int argc, char *argv[]) +{ + int i, j, k, ok, i_old; + struct data_list **last_data; + /*** init ***/ + ok = True; + args->first_data = NULL; + /*** end of init ***/ + + last_data = &args->first_data; + + for(i = 1; (i < argc) && ok; i++) { + if(argv[i][0] == '-') { + last_data = &args->first_data; + if(argv[i][1] == 0) { + printf("Error: Unknown option: -\n"); + ok = False; + } else + if(argv[i][1] == '-') { + j = 0; + while((j != args->count) && strcmp(&argv[i][2], args->arg[j].longarg)) { + j++; + } + if(j == args->count) { + printf("Error: Unknown option: %s\n", argv[i]); + ok = False; + } else { + switch(args->arg[j].type) { + case ARGTYPE_STRING: + case ARGTYPE_STRING_MULTISINGLE: + /* if argument is a string parameter we will do this: */ + if((i + 1) == argc) { + printf("Error: No argument supplied with option: %s\n", argv[i]); + ok = False; + } else + if(args->arg[j].type != ARGTYPE_STRING_MULTISINGLE) + args->arg[j].data = argv[++i]; + else + ok = add_arg((struct data_list **)&args->arg[j].data, argv[++i]); + break; + case ARGTYPE_BOOLEAN: + args->arg[j].data = (char *)True; + break; + case ARGTYPE_STRING_MULTI: + last_data = (struct data_list **)&args->arg[j].data; + break; + } + } + } else { + for(k = 1, i_old = i; (argv[i][k] != '\0') && ok && (i == i_old); k++) { + j = 0; + while((j != args->count) && (argv[i][k] != args->arg[j].letter)) + j++; + if(j == args->count) { + printf("Error: Unknown option: -%c\n", argv[i][k]); + ok = False; + } else { + switch(args->arg[j].type) { + case ARGTYPE_STRING: + case ARGTYPE_STRING_MULTISINGLE: + if(argv[i][k + 1] != '\0') { + printf("Error: Option -%c must be followed by it's argument\n", argv[i][k]); + ok = False; + } else { + if((i + 1) == argc) { + printf("Error: No argument supplied with option: -%c\n", argv[i][k]); + ok = False; + } else + if(args->arg[j].type != ARGTYPE_STRING_MULTISINGLE) + args->arg[j].data = argv[++i]; + else + ok = add_arg((struct data_list **)&args->arg[j].data, argv[++i]); + } + break; + case ARGTYPE_BOOLEAN: + args->arg[j].data = (char *)True; + break; + case ARGTYPE_STRING_MULTI: + last_data = (struct data_list **)&args->arg[j].data; + break; + /* Parameters that have only one char attached */ + case ARGTYPE_CHAR_ATTACHED: + if((i + 1) == argc) { + printf("Error: missing arguments: asm file"); + ok = False; + } else { + switch(argv[i][++k]) { + case 'O': + args->arg[j].data = (char *)AVRSTUDIO; + break; + case 'G': + args->arg[j].data = (char *)GENERIC; + break; + case 'I': + args->arg[j].data = (char *)INTEL; + break; + case 'M': + args->arg[j].data = (char *)MOTOROLA; + break; + default: + printf("Error: wrong file type '%c'",argv[i][2]); + ok = False; + } + } + } + } + } + } + } else + ok = add_arg(last_data, argv[i]); + } + return(ok); +} + + +int add_arg(struct data_list **last_data, char *argv) +{ + struct data_list *data; + + while(*last_data) + last_data = &((*last_data)->next); + + data = malloc(sizeof(struct data_list)); + if(data) { + data->next = NULL; + data->data = argv; + *last_data = data; + last_data = &data->next; + } else { + printf("Error: Unable to allocate memory\n"); + return(False); + } + return(True); +} + + +void free_args(struct args *args) +{ + int i; + struct data_list *data, *temp; + + for(data = args->first_data; data;) { + temp = data; + data = data->next; + free(temp); + } + for(i = 0; i != args->count; i++) + if((args->arg[i].type == ARGTYPE_STRING_MULTI) + || (args->arg[i].type == ARGTYPE_STRING_MULTISINGLE)) + for(data = args->arg[i].data; data;) { + temp = data; + data = data->next; + free(temp); + } + free(args); +} + + +void define_arg(struct args *args, int index, int type, char letter, char *longarg, void *def_value) +{ + args->arg[index].type = type; + args->arg[index].letter = letter; + args->arg[index].longarg = longarg; + args->arg[index].data = def_value; +} + +/* end of args.c */ + diff --git a/contrib/toolchain/avra/src/args.h b/contrib/toolchain/avra/src/args.h new file mode 100644 index 000000000..e7db9ac34 --- /dev/null +++ b/contrib/toolchain/avra/src/args.h @@ -0,0 +1,67 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2006 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#ifndef _args_h_ +#define _args_h_ + +enum { + ARGTYPE_BOOLEAN = 0, /* boolean Value (0 = False) */ + ARGTYPE_STRING, /* Stringpointer in Data */ + ARGTYPE_STRING_MULTI, /* List of strings in Data */ + ARGTYPE_STRING_MULTISINGLE, /* List of strings in Data. requires an option for each element */ + ARGTYPE_CHAR_ATTACHED +}; + +#define GET_ARG(args, argnum) (args->arg[argnum].data) +#define SET_ARG(args, argnum, value) (args->arg[argnum].data = (void *)value) + +struct args { + struct arg *arg; + int count; + struct data_list *first_data; +}; + +struct arg { + int type; + char letter; + char *longarg; + void *data; +}; + +struct data_list { + struct data_list *next; + void *data; +}; + +struct args *alloc_args(int arg_count); +int read_args(struct args *args, int argc, char *argv[]); +int add_arg(struct data_list **last_data, char *argv); +void free_args(struct args *args); +void define_arg(struct args *args, int index, int type, char letter, char *longarg, void *def_value); + +#endif /* end of args.h */ + diff --git a/contrib/toolchain/avra/src/avra.c b/contrib/toolchain/avra/src/avra.c new file mode 100644 index 000000000..81a79b664 --- /dev/null +++ b/contrib/toolchain/avra/src/avra.c @@ -0,0 +1,800 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2006 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include +#include + +#include "misc.h" +#include "args.h" +#include "avra.h" +#include "device.h" + +#define debug 0 + +const char *title = + "AVRA: advanced AVR macro assembler Version %i.%i.%i Build %i (%s)\n" + "Copyright (C) 1998-2010. Check out README file for more info\n" + "\n" + " AVRA is an open source assembler for Atmel AVR microcontroller family\n" + " It can be used as a replacement of 'AVRASM32.EXE' the original assembler\n" + " shipped with AVR Studio. We do not guarantee full compatibility for avra.\n" + "\n" + " AVRA comes with NO WARRANTY, to the extent permitted by law.\n" + " You may redistribute copies of avra under the terms\n" + " of the GNU General Public License.\n" + " For more information about these matters, see the files named COPYING.\n" + "\n"; + +const char *usage = + "usage: avra [-f][O|M|I|G] output file type\n" + " [-o ] output file name\n" + " [-l ] generate list file\n" + " [-m ] generate map file\n" + "[--define [=]] [--includedir ] [--listmac]\n" + " [--max_errors ] [--devices] [--version]\n" + " [-h] [--help] general help\n" + " " + " \n" + "\n" + " --listfile -l : Create list file\n" + " --mapfile -m : Create map file\n" + " --define -D : Define symbol.\n" + " --includepath -I : Additional include paths.\n" + " --listmac : List macro expansion in listfile.\n" + " --max_errors : Maximum number of errors before exit\n" + " (default: 10)\n" + " --devices : List out supported devices.\n" + " --version : Version information.\n" + " --help, -h : This help text.\n" + "\n" + "Just replace the AVRASM32.EXE with AVRA.EXE in your\n" + "AVRStudio directories to avra's binary.\n"; + +int main(int argc, char *argv[]) +{ + int show_usage = False; + struct prog_info *pi=NULL; + struct args *args; + unsigned char c; + +#if debug == 1 + int i; + for(i = 0; i < argc; i++) { + printf(argv[i]); + printf("\n"); + } +#endif + + printf(title, VER_MAJOR, VER_MINOR, VER_RELEASE, VER_BUILD, VER_DATE); + + args = alloc_args(ARG_COUNT); + if(args) { + define_arg(args, ARG_DEFINE, ARGTYPE_STRING_MULTISINGLE, 'D', "define", NULL); + define_arg(args, ARG_INCLUDEPATH, ARGTYPE_STRING_MULTISINGLE, 'I', "includepath", NULL); + define_arg(args, ARG_LISTMAC, ARGTYPE_BOOLEAN, 0, "listmac", "1"); + define_arg(args, ARG_MAX_ERRORS, ARGTYPE_STRING, 0, "max_errors", "10"); + define_arg(args, ARG_COFF, ARGTYPE_BOOLEAN, 0, "coff", NULL); + define_arg(args, ARG_DEVICES, ARGTYPE_BOOLEAN, 0, "devices", NULL); + define_arg(args, ARG_VER, ARGTYPE_BOOLEAN, 0, "version", NULL); + define_arg(args, ARG_HELP, ARGTYPE_BOOLEAN, 'h', "help", NULL); + define_arg(args, ARG_WRAP, ARGTYPE_BOOLEAN, 'w', "wrap", NULL); // Not implemented ? B.A. + define_arg(args, ARG_WARNINGS, ARGTYPE_STRING_MULTISINGLE, 'W', "warn", NULL); + define_arg(args, ARG_FILEFORMAT, ARGTYPE_CHAR_ATTACHED, 'f', "filetype", "0"); // Not implemented ? B.A. + define_arg(args, ARG_LISTFILE, ARGTYPE_STRING, 'l', "listfile", NULL); + define_arg(args, ARG_OUTFILE, ARGTYPE_STRING, 'o', "outfile", NULL); // Not implemented ? B.A. + define_arg(args, ARG_MAPFILE, ARGTYPE_STRING, 'm', "mapfile", NULL); + define_arg(args, ARG_DEBUGFILE, ARGTYPE_STRING, 'd', "debugfile", NULL); // Not implemented ? B.A. + define_arg(args, ARG_EEPFILE, ARGTYPE_STRING, 'e', "eepfile", NULL); // Not implemented ? B.A. + + + c = read_args(args, argc, argv); + + if(c != 0) { + if(!GET_ARG(args, ARG_HELP) && (argc != 1)) { + if(!GET_ARG(args, ARG_VER)) { + if(!GET_ARG(args, ARG_DEVICES)) { + pi = get_pi(args); + if(pi) { + get_rootpath(pi, args); /* get assembly root path */ + if (assemble(pi) != 0) { /* the main assembly call */ + exit(EXIT_FAILURE); + } + free_pi(pi); /* free all allocated memory */ + } + } + else { + list_devices(); /* list all supported devices */ + } + } + } + else + show_usage = True; + } + free_args(args); + } + else { + show_usage = True; + printf("\n"); + } + if(show_usage) { + printf("%s", usage); + } + exit(EXIT_SUCCESS); + return (0); /* compiler warning, JEG 4-23-03 */ +} + +void get_rootpath(struct prog_info *pi, struct args *args) +{ + int i; + int j; + char c; + struct data_list *data; + + data = args->first_data; + if(!data) + return; + while(data->next) data = ((data)->next); + + if (data != NULL) { + i = strlen((char *)data->data); + if (i > 0) { + pi->root_path = malloc(i + 1); + strcpy(pi->root_path,(char *)data->data); + j = 0; + do { + c = pi->root_path[i]; + if(c == '\\' || c == '/') { + j = i + 1; + break; + } + } while(i-- > 0); + pi->root_path[j] = '\0'; + return; + } + } + pi->root_path = ""; +} + + +int assemble(struct prog_info *pi) { + unsigned char c; + + if(pi->args->first_data) { + printf("Pass 1...\n"); + if(load_arg_defines(pi)==False) + return -1; + if(predef_dev(pi)==False) /* B.A.: Now with error check */ + return -1; + /*** FIRST PASS ***/ + def_orglist(pi); /* B.A. : Store first active segment and seg_addr (Default : Code, Adr=0) */ + c = parse_file(pi, (char *)pi->args->first_data->data); + fix_orglist(pi); /* B.A. : Update last active segment */ + test_orglist(pi); /* B.A.: Test for overlapping memory segments and out of chip space */ + if(c != False) { +#if debug == 1 + printf("error_count = %i\n", pi->error_count); +#endif + /* B.A.: This part is obsolete. Now check is done in test_orglist() */ + /* before we go to the 2nd pass, make sure used space is ok */ + /* if(pi->eseg_count > pi->device->eeprom_size) { + print_msg(pi, MSGTYPE_ERROR, + "EEPROM space exceeded by %i bytes!", pi->eseg_count-pi->device->eeprom_size); + return -1; + } + if(pi->cseg_count > pi->device->flash_size) { + print_msg(pi, MSGTYPE_ERROR, + "FLASH space exceeded by %i bytes!", pi->cseg_count-pi->device->flash_size); + return -1; + } */ + + /* if there are no furter errors, we can continue with 2nd pass */ + if(pi->error_count == 0) { + prepare_second_pass(pi); + if(load_arg_defines(pi)==False) + return -1; + if(predef_dev(pi)==False) /* B.A.: Now with error check */ + return -1; + c = open_out_files(pi, pi->args->first_data->data); + if(c != 0) { + printf("Pass 2...\n"); + parse_file(pi, (char *)pi->args->first_data->data); + printf("done\n\n"); + print_orglist(pi); /* B.A.: List used memory segments */ + if(GET_ARG(pi->args, ARG_COFF) && (pi->error_count == 0)) { + write_coff_file(pi); + } + write_map_file(pi); + if(pi->error_count) { /* if there were errors */ + printf("\nAssembly aborted with %d errors and %d warnings.\n", pi->error_count, pi->warning_count); + unlink_out_files(pi, pi->args->first_data->data); + } else { /* assembly was succesfull */ + if(pi->warning_count) + printf("\nAssembly complete with no errors (%d warnings).\n", pi->warning_count); + else + printf("\nAssembly complete with no errors.\n"); + close_out_files(pi); + } + } + } else { + unlink_out_files(pi, pi->args->first_data->data); + } + } + } else { + printf("Error: You need to specify a file to assemble\n"); + } + return pi->error_count; +} + + +int load_arg_defines(struct prog_info *pi) +{ + int i; + char *expr; + char buff[256]; + struct data_list *define; + + for(define = GET_ARG(pi->args, ARG_DEFINE); define; define = define->next) { + strcpy(buff, define->data); + expr = get_next_token( buff, TERM_EQUAL); + if(expr) { + // we reach this, when there is actually a value passed.. + if(!get_expr(pi, expr, &i)) { + return(False); + } + } else { + // if user didnt specify a value, we default to 1 + i = 1; + } + /* B.A. : New. Forward references allowed. But check, if everything is ok ... */ + if(pi->pass==PASS_1) { /* Pass 1 */ + if(test_constant(pi,buff,NULL)!=NULL) { + fprintf(stderr,"Error: Can't define symbol %s twice\n", buff); + return(False); + } + if(def_const(pi, buff, i)==False) + return(False); + } else { /* Pass 2 */ + int j; + if(get_constant(pi, buff, &j)==False) { /* Defined in Pass 1 and now missing ? */ + fprintf(stderr,"Constant %s is missing in pass 2\n",buff); + return(False); + } + if(i != j) { + fprintf(stderr,"Constant %s changed value from %d in pass1 to %d in pass 2\n",buff,j,i); + return(False); + } + /* OK. Definition is unchanged */ + } + } + return(True); +} + +/****************************************** + * prog_info + ******************************************/ +struct prog_info *get_pi(struct args *args) { + struct prog_info *pi; + struct data_list *warnings; + + pi = (struct prog_info *)calloc(1, sizeof(struct prog_info)); + if(!pi) + return(NULL); + memset(pi, 0, sizeof(struct prog_info)); + pi->args = args; + pi->device = get_device(pi,NULL); + if(GET_ARG(args, ARG_LISTFILE) == NULL) { + pi->list_on = False; + } else { + pi->list_on = True; + } + if(GET_ARG(args, ARG_MAPFILE) == NULL) { + pi->map_on = False; + } else { + pi->map_on = True; + } + for(warnings = GET_ARG(args, ARG_WARNINGS); warnings; warnings = warnings->next) { + if(!nocase_strcmp(warnings->data, "NoRegDef")) + pi->NoRegDef = 1; + } + pi->segment = SEGMENT_CODE; + pi->dseg_addr = pi->device->ram_start; + pi->max_errors = atoi(GET_ARG(args, ARG_MAX_ERRORS)); + pi->pass=PASS_1; /* B.A. : The pass variable is now stored in the pi struct */ + pi->time=time(NULL); /* B.A. : Now use a global timestamp */ + return(pi); +} + +void free_pi(struct prog_info *pi) { + free_defs(pi); /* B.A. : Now free in pi included structures first */ + free_labels(pi); + free_constants(pi); + free_variables(pi); + free_blacklist(pi); + free_orglist(pi); + free(pi); +} + +void prepare_second_pass(struct prog_info *pi) { + + pi->segment = SEGMENT_CODE; + pi->cseg_addr = 0; + pi->dseg_addr = pi->device->ram_start; + pi->eseg_addr = 0; + //pi->macro_nstlblnr = 0; + pi->pass=PASS_2; /* B.A. : Change to pass 2. Now stored in pi struct. */ + free_defs(pi); + // free_constants(pi); /* B.A. : Now don't kill stored constants. We need them in the second pass now */ + free_variables(pi); +} + + +void print_msg(struct prog_info *pi, int type, char *fmt, ... ) +{ + char *pc; + if(type == MSGTYPE_OUT_OF_MEM) { + fprintf(stderr, "Error: Unable to allocate memory!\n"); + } else { + if(type != MSGTYPE_APPEND) { /* B.A. Added for .message directive */ + if((pi->fi != NULL) && (pi->fi->include_file->name != NULL)) { /* B.A.: Skip, if filename or fi is NULL (Bug 1462900) */ + /* check if adding path name is needed*/ + pc = strstr(pi->fi->include_file->name, pi->root_path); + if(pc == NULL) { + fprintf(stderr, "%s%s(%d) : ", pi->root_path ,pi->fi->include_file->name, pi->fi->line_number); + } else { + fprintf(stderr, "%s(%d) : ", pi->fi->include_file->name, pi->fi->line_number); + } + } + } + switch(type) { + case MSGTYPE_ERROR: + pi->error_count++; + fprintf(stderr, "Error : "); + break; + case MSGTYPE_WARNING: + pi->warning_count++; + fprintf(stderr, "Warning : "); + break; + case MSGTYPE_MESSAGE: +/* case MSGTYPE_MESSAGE_NO_LF: + case MSGTYPE_APPEND: */ + break; + } + if(type != MSGTYPE_APPEND) { /* B.A. Added for .message directive */ + if(pi->macro_call) { + fprintf(stderr, "[Macro: %s: %d:] ", pi->macro_call->macro->include_file->name, + pi->macro_call->line_index + pi->macro_call->macro->first_line_number); + } + } + if(fmt != NULL) { + va_list args; + va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); + } + + if( (type != MSGTYPE_APPEND) && (type != MSGTYPE_MESSAGE_NO_LF) ) /* B.A. Added for .message directive */ + fprintf(stderr, "\n"); + } +} + + +/* B.A. : New functions to create / search / remove constant, variables, labels */ +/* def_const, def_var moved from device.c to this place */ +int def_const(struct prog_info *pi, const char *name, int value) +{ + struct label *label; + label = malloc(sizeof(struct label)); + if(!label) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + label->next = NULL; + if(pi->last_constant) + pi->last_constant->next = label; + else + pi->first_constant = label; + pi->last_constant = label; + label->name = malloc(strlen(name) + 1); + if(!label->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(label->name, name); + label->value = value; + return(True); +} + +int def_var(struct prog_info *pi, char *name, int value) +{ + struct label *label; + + for(label = pi->first_variable; label; label = label->next) + if(!nocase_strcmp(label->name, name)) { + label->value = value; + return(True); + } + label = malloc(sizeof(struct label)); + if(!label) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + label->next = NULL; + if(pi->last_variable) + pi->last_variable->next = label; + else + pi->first_variable = label; + pi->last_variable = label; + label->name = malloc(strlen(name) + 1); + if(!label->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(label->name, name); + label->value = value; + return(True); +} + + +int def_blacklist(struct prog_info *pi, const char *name) +{ + struct label *label; + label = malloc(sizeof(struct label)); + if(!label) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + label->next = NULL; + if(pi->last_blacklist) + pi->last_blacklist->next = label; + else + pi->first_blacklist = label; + pi->last_blacklist = label; + label->name = malloc(strlen(name) + 1); + if(!label->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(label->name, name); + label->value = 0; + return(True); +} + +/* B.A.: Store programmed areas for later check */ +int def_orglist(struct prog_info *pi) +{ + struct orglist *orglist; + if(pi->pass != PASS_1) + return(True); + orglist = malloc(sizeof(struct orglist)); + if(!orglist) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + orglist->next = NULL; + if(pi->last_orglist) + pi->last_orglist->next = orglist; + else + pi->first_orglist = orglist; + pi->last_orglist = orglist; + orglist->segment=pi->segment; + switch(pi->segment) { + case SEGMENT_CODE: + orglist->start = pi->cseg_addr; + break; + case SEGMENT_DATA: + orglist->start = pi->dseg_addr; + break; + case SEGMENT_EEPROM: + orglist->start = pi->eseg_addr; + } + orglist->length=0; + return(True); +} + +/* B.A.: Fill length entry of last orglist */ +int fix_orglist(struct prog_info *pi) +{ + if(pi->pass != PASS_1) + return(True); + if((pi->last_orglist == NULL) || (pi->last_orglist->length!=0)) { + fprintf(stderr,"Internal Error: fix_orglist\n"); + return(False); + } + pi->last_orglist->segment=pi->segment; + switch(pi->segment) { + case SEGMENT_CODE: + pi->last_orglist->length = pi->cseg_addr - pi->last_orglist->start; + break; + case SEGMENT_DATA: + pi->last_orglist->length = pi->dseg_addr - pi->last_orglist->start; + break; + case SEGMENT_EEPROM: + pi->last_orglist->length = pi->eseg_addr - pi->last_orglist->start; + } + return(True); +} + +/* B.A.: Debug output of orglist */ +void print_orglist(struct prog_info *pi) +{ + struct orglist *orglist=pi->first_orglist; + printf("Used memory blocks:\n"); + while(orglist!=NULL) { + if(orglist->length) { /* Skip blocks with size == 0 */ + switch(orglist->segment) { + case SEGMENT_CODE: + printf(" Code "); break; + case SEGMENT_DATA: + printf(" Data "); break; + case SEGMENT_EEPROM: + printf(" EEPROM"); break; + printf("INVALID SEGMENT DATA !\n"); + } + printf(" : Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist->start,orglist->start+orglist->length-1,orglist->length); + } + orglist=orglist->next; + } +} + +/* B.A.: Test for overlapping segments and device space */ +int test_orglist(struct prog_info *pi) +{ + struct orglist *orglist2,*orglist=pi->first_orglist; + int error_count=0; + if(pi->device->name==NULL) { + fprintf(stderr,"Warning : No .DEVICE definition found. Cannot make useful address range check !\n"); + pi->warning_count++; + } + while(orglist!=NULL) { + if(orglist->length) { /* Skip blocks with size == 0 */ + // printf("Segment %d, Start = %5d, Length = %5d\n",orglist->segment,orglist->start,orglist->length); + /* Make sure address area is valid */ + switch(orglist->segment) { + case SEGMENT_CODE: + if((orglist->start + orglist->length) > pi->device->flash_size) { + fprintf(stderr,"Code segment exceeds valid address range [0..0x%04X] :", + pi->device->flash_size-1); + fprintf(stderr," Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist->start,orglist->start+orglist->length-1,orglist->length); + error_count++; + } + break; + case SEGMENT_DATA: + if(pi->device->ram_size == 0) { + // Error message is generated in .DSEG directive. Skip ... + // fprintf(stderr,"This device has no RAM. Don't use .DSEG \n"); + // error_count++; + break; + } // Fix bug 1742436. Added missing pi->device->ram_start + if(((orglist->start + orglist->length) > (pi->device->ram_size + pi->device->ram_start)) || + (orglist->start < pi->device->ram_start)) { + fprintf(stderr,"Data segment exceeds valid address range [0x%04X..0x%04X] :", + pi->device->ram_start,pi->device->ram_start+pi->device->ram_size-1); + fprintf(stderr," Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist->start,orglist->start+orglist->length-1,orglist->length); + error_count++; + } + break; + case SEGMENT_EEPROM: // Fix bug 1742437 : replace ram_size by eeprom_size + if(pi->device->eeprom_size == 0) { + // Error message is generated in .ESEG directive. Skip ... + // fprintf(stderr,"This device has no EEPROM. Don't use .ESEG !\n"); + // error_count++; + break; + } + if((orglist->start + orglist->length) > pi->device->eeprom_size) { + fprintf(stderr,"EEPROM segment exceeds valid address range [0..0x%04X] :", + pi->device->eeprom_size-1); + fprintf(stderr," Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist->start,orglist->start+orglist->length-1,orglist->length); + error_count++; + } + break; + } + /* Overlap-test */ + orglist2=orglist->next; + while(orglist2!=NULL) { + if((orglist != orglist2) && (orglist2->length) && (orglist->segment == orglist2->segment)) { + // printf("<> Segment %d, Start = %5d, Length = %5d\n",orglist2->segment,orglist2->start,orglist2->length); + if((orglist->start < (orglist2->start + orglist2->length)) && + (orglist2->start < ( orglist->start + orglist->length))) { + fprintf(stderr,"Error: Overlapping "); + switch(orglist->segment) { + case SEGMENT_CODE: + fprintf(stderr,"Code"); break; + case SEGMENT_DATA: + fprintf(stderr,"Data"); break; + case SEGMENT_EEPROM: + fprintf(stderr,"EEPROM"); break; + } + fprintf(stderr,"-segments :\n"); + fprintf(stderr," Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist->start,orglist->start+orglist->length-1,orglist->length); + fprintf(stderr," Start = 0x%04X, End = 0x%04X, Length = 0x%04X\n", + orglist2->start,orglist2->start+orglist2->length-1,orglist2->length); + fprintf(stderr,"Please check your .ORG directives !\n"); + error_count++; + } + } + orglist2=orglist2->next; + } + } + orglist=orglist->next; + } + if(!error_count) + return(True); + pi->error_count+=error_count; + return(False); +} + + + +/* Get the value of a label. Return FALSE if label was not found */ +int get_label(struct prog_info *pi,char *name,int *value) +{ + struct label *label=search_symbol(pi,pi->first_label,name,NULL); + if(label==NULL) return False; + if(value!=NULL) *value=label->value; + return True; +} + +int get_constant(struct prog_info *pi,char *name,int *value) +{ + struct label *label=search_symbol(pi,pi->first_constant,name,NULL); + if(label==NULL) return False; + if(value!=NULL) *value=label->value; + return True; +} + +int get_variable(struct prog_info *pi,char *name,int *value) +{ + struct label *label=search_symbol(pi,pi->first_variable,name,NULL); + if(label==NULL) return False; + if(value!=NULL) *value=label->value; + return True; +} + +/* Test, if label exists. Return NULL -> not defined, else return the pointer to label struct */ +/* If message != NULL print error message if symbol is defined */ +struct label *test_label(struct prog_info *pi,char *name,char *message) +{ + return search_symbol(pi,pi->first_label,name,message); +} + +struct label *test_constant(struct prog_info *pi,char *name,char *message) +{ + return search_symbol(pi,pi->first_constant,name,message); +} + +struct label *test_variable(struct prog_info *pi,char *name,char *message) +{ + return search_symbol(pi,pi->first_variable,name,message); +} + +struct label *test_blacklist(struct prog_info *pi,char *name,char *message) +{ + return search_symbol(pi,pi->first_blacklist,name,message); +} + +/* Search in label,constant,variable,blacklist - list for a matching entry */ +/* Use first = pi->first_label,first_constant,first_variable,first_blacklist to select list */ +/* If message != NULL Print error message if symbol is defined */ +struct label *search_symbol(struct prog_info *pi,struct label *first,char *name,char *message) +{ + struct label *label; + for(label = first; label; label = label->next) + if(!nocase_strcmp(label->name, name)) { + if(message) { + print_msg(pi, MSGTYPE_ERROR, message, name); + } + return(label); + } + return(NULL); +} + + +void free_defs(struct prog_info *pi) +{ + struct def *def, *temp_def; + for(def = pi->first_def; def;) { + temp_def = def; + def = def->next; + free(temp_def->name); + free(temp_def); + } + pi->first_def = NULL; + pi->last_def = NULL; +} + +void free_labels(struct prog_info *pi) +{ + struct label *label, *temp_label; + for(label = pi->first_label; label;) { + temp_label = label; + label = label->next; + free(temp_label->name); + free(temp_label); + } + pi->first_label = NULL; + pi->last_label = NULL; +} + +void free_constants(struct prog_info *pi) +{ + struct label *label, *temp_label; + for(label = pi->first_constant; label;) { + temp_label = label; + label = label->next; + free(temp_label->name); + free(temp_label); + } + pi->first_constant = NULL; + pi->last_constant = NULL; +} + +void free_blacklist(struct prog_info *pi) +{ + struct label *label, *temp_label; + for(label = pi->first_blacklist; label;) { + temp_label = label; + label = label->next; + free(temp_label->name); + free(temp_label); + } + pi->first_blacklist = NULL; + pi->last_blacklist = NULL; +} + +void free_variables(struct prog_info *pi) +{ + struct label *label, *temp_label; + for(label = pi->first_variable; label;) { + temp_label = label; + label = label->next; + free(temp_label->name); + free(temp_label); + } + pi->first_variable = NULL; + pi->last_variable = NULL; +} + +void free_orglist(struct prog_info *pi) +{ + struct orglist *orglist, *temp_orglist; + for(orglist = pi->first_orglist; orglist;) { + temp_orglist = orglist; + orglist = orglist->next; + free(temp_orglist); + } + pi->first_orglist = NULL; + pi->last_orglist = NULL; +} + + +/* avra.c */ + diff --git a/contrib/toolchain/avra/src/avra.h b/contrib/toolchain/avra/src/avra.h new file mode 100644 index 000000000..257f745b7 --- /dev/null +++ b/contrib/toolchain/avra/src/avra.h @@ -0,0 +1,370 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2006 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#ifndef _AVRA_H_ /* avoid multiple inclusion */ +#define _AVRA_H_ + +#include +#include + +#ifndef VER_MAJOR +# define VER_MAJOR 1 +#endif +#ifndef VER_MINOR +# define VER_MINOR 3 +#endif +#ifndef VER_RELEASE +# define VER_RELEASE 0 +#endif +#ifndef VER_BUILD +# define VER_BUILD 1 +#endif +#ifndef VER_DATE +# define VER_DATE "8 May 2010" +#endif + +#define IS_HOR_SPACE(x) ((x == ' ') || (x == 9)) +#define IS_LABEL(x) (isalnum(x) || (x == '%') || (x == '_')) +#define IS_END_OR_COMMENT(x) ((x == ';') || (x == 10) || (x == 13) || (x == '\0') || (x == 12)) +#define IS_ENDLINE(x) ((x == 10) || (x == 13) || (x == '\0') || (x == 12)) +#define IS_SEPARATOR(x) ((x == ' ') || (x == ',') || (x == '[') || (x == ']')) + +#define LINEBUFFER_LENGTH 256 +#define MAX_NESTED_MACROLOOPS 256 + +#define MAX_MACRO_ARGS 10 + +/* warning switches */ + +/* Option enumeration */ +enum { + ARG_DEFINE = 0, /* --define, -D */ + ARG_INCLUDEPATH, /* --includedir, -I */ + ARG_LISTMAC, /* --listmac */ + ARG_MAX_ERRORS, /* --max_errors */ + ARG_COFF, /* --coff */ + ARG_DEVICES, /* --devices */ + ARG_VER, /* --version */ + ARG_HELP, /* --help, -h */ + ARG_WRAP, /* --wrap */ + ARG_WARNINGS, /* --warn, -W */ + ARG_FILEFORMAT, /* --filetype */ + ARG_LISTFILE, /* --listfile */ + ARG_OUTFILE, /* --outfile */ + ARG_MAPFILE, /* --mapfile */ + ARG_DEBUGFILE, /* --debugfile */ + ARG_EEPFILE, /* --eepfile */ + ARG_COUNT +}; + +enum { + MSGTYPE_ERROR = 0, + MSGTYPE_WARNING, + MSGTYPE_MESSAGE, + MSGTYPE_OUT_OF_MEM, + MSGTYPE_MESSAGE_NO_LF, /* B.A. : Like MSGTYPE_MESSAGE, but without /n */ + MSGTYPE_APPEND /* B.A. : Print Message without any header and without /n. To append messages */ + /* MSGTYPE_INCLUDE B.A. Removed. Was not in used */ +}; + +enum { + PASS_1 = 0, + PASS_2 +}; + +enum { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_EEPROM +}; + +enum { + TERM_END = 0, + TERM_SPACE, + TERM_COMMA, + TERM_EQUAL, + TERM_DASH, + TERM_DOUBLEQUOTE, + TERM_COLON +}; + +/* Structures */ + +struct prog_info +{ + struct args *args; + struct device *device; + struct file_info *fi; + struct macro_call *macro_call; + struct macro_line *macro_line; + FILE *list_file; + int list_on; + int map_on; + char *list_line; + char *root_path; + FILE *obj_file; + struct hex_file_info *hfi; + struct hex_file_info *eep_hfi; + int segment; + int cseg_addr; + int dseg_addr; + int eseg_addr; + int cseg_count; + int dseg_count; + int eseg_count; + int error_count; + int max_errors; + int warning_count; + struct include_file *last_include_file; + struct include_file *first_include_file; + struct def *first_def; + struct def *last_def; + struct label *first_label; + struct label *last_label; + struct label *first_constant; + struct label *last_constant; + struct label *first_variable; + struct label *last_variable; + struct label *first_blacklist; /* B.A. : List for undefined symbols. Needed to make forward references safe */ + struct label *last_blacklist; + struct macro *first_macro; + struct macro *last_macro; + struct macro_call *first_macro_call; + struct macro_call *last_macro_call; + struct orglist *first_orglist; /* B.A. : List of used memory segments. Needed for overlap-check */ + struct orglist *last_orglist; + int conditional_depth; + time_t time; /* B.A. : Use a global timestamp for listing header and %hour% ... tags */ + /* coff additions */ + FILE *coff_file; + /* Warning additions */ + int NoRegDef; + int pass; + +}; + +struct file_info +{ + FILE *fp; + struct include_file *include_file; + char buff[LINEBUFFER_LENGTH]; + char scratch[LINEBUFFER_LENGTH]; + int line_number; + int exit_file; + struct label *label; +}; + +struct hex_file_info +{ + FILE *fp; + int count; + int linestart_addr; + int segment; + unsigned char hex_line[16]; +}; + +struct include_file +{ + struct include_file *next; + char *name; + int num; +}; + +struct def +{ + struct def *next; + char *name; + int reg; +}; + +struct label +{ + struct label *next; + char *name; + int value; +}; + +struct macro +{ + struct macro *next; + char *name; + struct include_file *include_file; + int first_line_number; + struct macro_line *first_macro_line; + struct macro_label *first_label; +}; + +struct macro_label +{ + char *label; + struct macro_label *next; + int running_number; +}; + +struct macro_line +{ + struct macro_line *next; + char *line; +}; + +struct macro_call +{ + struct macro_call *next; + int line_number; + struct include_file *include_file; + struct macro_call *prev_on_stack; + struct macro *macro; + int line_index; + int prev_line_index; + int nest_level; + struct label *first_label; + struct label *last_label; +}; + +struct orglist +{ + struct orglist *next; + int segment; + int start; + int length; +}; + +/* Prototypes */ +/* avra.c */ +int assemble(struct prog_info *pi); +int load_arg_defines(struct prog_info *pi); +struct prog_info *get_pi(struct args *args); +void free_pi(struct prog_info *pi); +void prepare_second_pass(struct prog_info *pi); +void print_msg(struct prog_info *pi, int type, char *fmt, ... ); +void get_rootpath(struct prog_info *pi, struct args *args); + +int def_const(struct prog_info *pi, const char *name, int value); +int def_var(struct prog_info *pi, char *name, int value); +int def_blacklist(struct prog_info *pi, const char *name); +int def_orglist(struct prog_info *pi); /* B.A. : Test for overlapping segments */ +int fix_orglist(struct prog_info *pi); +void print_orglist(struct prog_info *pi); +int test_orglist(struct prog_info *pi); +int get_label(struct prog_info *pi,char *name,int *value); +int get_constant(struct prog_info *pi,char *name,int *value); +int get_variable(struct prog_info *pi,char *name,int *value); +struct label *test_label(struct prog_info *pi,char *name,char *message); +struct label *test_constant(struct prog_info *pi,char *name,char *message); +struct label *test_variable(struct prog_info *pi,char *name,char *message); +struct label *test_blacklist(struct prog_info *pi,char *name,char *message); +struct label *search_symbol(struct prog_info *pi,struct label *first,char *name,char *message); +void free_defs(struct prog_info *pi); +void free_labels(struct prog_info *pi); +void free_constants(struct prog_info *pi); +void free_blacklist(struct prog_info *pi); +void free_variables(struct prog_info *pi); +void free_orglist(struct prog_info *pi); + + +/* parser.c */ +int parse_file(struct prog_info *pi, char *filename); +int parse_line(struct prog_info *pi, char *line); +char *get_next_token(char *scratch, int term); +char *fgets_new(struct prog_info *pi, char *s, int size, FILE *stream); + +/* expr.c */ +int get_expr(struct prog_info *pi, char *data, int *value); +//int get_operator(char *op); +//int test_operator_at_precedence(int operator, int precedence); +//int calc(struct prog_info *pi, int left, int operator, int right); +//int get_function(char *function); +//int do_function(int function, int value); +//int log2(int value); +int get_symbol(struct prog_info *pi, char *label_name, int *data); +int par_length(char *data); + +/* mnemonic.c */ +int parse_mnemonic(struct prog_info *pi); +int get_mnemonic_type(char *mnemonic); +int get_register(struct prog_info *pi, char *data); +int get_bitnum(struct prog_info *pi, char *data, int *ret); +int get_indirect(struct prog_info *pi, char *operand); +int is_supported(struct prog_info *pi, char *name); +int count_supported_instructions(int flags); + +/* directiv.c */ +int parse_directive(struct prog_info *pi); +int get_directive_type(char *directive); +char *term_string(struct prog_info *pi, char *string); +int parse_db(struct prog_info *pi, char *next); +void write_db(struct prog_info *pi, char byte, char *prev, int count); +int spool_conditional(struct prog_info *pi, int only_endif); +int check_conditional(struct prog_info *pi, char *buff, int *current_depth, int *do_next, int only_endif); +int test_include(const char *filename); + +/* macro.c */ +int read_macro(struct prog_info *pi, char *name); +struct macro *get_macro(struct prog_info *pi, char *name); +struct macro_label *get_macro_label(char *line, struct macro *macro); +int expand_macro(struct prog_info *pi, struct macro *macro, char *rest_line); + + +/* file.c */ +int open_out_files(struct prog_info *pi, char *filename); +void close_out_files(struct prog_info *pi); +struct hex_file_info *open_hex_file(char *filename); +void close_hex_file(struct hex_file_info *hfi); +void write_ee_byte(struct prog_info *pi, int address, unsigned char data); +void write_prog_word(struct prog_info *pi, int address, int data); +void do_hex_line(struct hex_file_info *hfi); +FILE *open_obj_file(struct prog_info *pi, char *filename); +void close_obj_file(struct prog_info *pi, FILE *fp); +void write_obj_record(struct prog_info *pi, int address, int data); +void unlink_out_files(struct prog_info *pi, char *filename); + +/* map.c */ +void write_map_file(struct prog_info *pi); +char *Space(char *n); + +/* stdextra.c */ +char *nocase_strcmp(char *s, char *t); +char *nocase_strncmp(char *s, char *t, int n); +char *nocase_strstr(char *s, char *t); +int atox(char *s); +int atoi_n(char *s, int n); +int atox_n(char *s, int n); +char *my_strlwr(char *in); +char *my_strupr(char *in); + +/* coff.c */ +FILE *open_coff_file(struct prog_info *pi, char *filename); +void write_coff_file(struct prog_info *pi); +void write_coff_eeprom( struct prog_info *pi, int address, unsigned char data); +void write_coff_program( struct prog_info *pi, int address, unsigned int data); +void close_coff_file(struct prog_info *pi, FILE *fp); +int parse_stabs( struct prog_info *pi, char *p ); +int parse_stabn( struct prog_info *pi, char *p ); + +#endif /* end of avra.h */ + + diff --git a/contrib/toolchain/avra/src/coff.c b/contrib/toolchain/avra/src/coff.c new file mode 100644 index 000000000..f131d1205 --- /dev/null +++ b/contrib/toolchain/avra/src/coff.c @@ -0,0 +1,2089 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * coff.c - Common Object File Format (COFF) support + * + * This file was developed for the avra assembler in order to produce COFF output files + * for use with the Atmel AVR Studio. The Lean C Compiler (LCC) debugging stabs + * output was used as input to the assembler. The information used to develop this file + * was obtained from various sources on the Internet, most notably, the Free Software Foundation, + * The "stabs" debug format, ??? Chapter 7: Common Object File Format (COFF), + * + * This software has absolutely no warrantee! The money you paid for this will be + * promptly refunded if not fully satisfied. + * + * Beta release 1/20/2000 by Bob Harris + * + * This software has not been fully tested and probably has a few software deficiencies. + * Some software support may be possible by sending a problem description report to + * rth@mclean.sparta.com + * + * Made the recommended change in write_coff_program(). + * Fixed an obvious typo in SkipPastDigits(). The if() statement was terminated + * with a semicolon, which terminated the if(); early. JEG 4-01-03 + */ + +#include +#include +#include +#include +#include + +#include "misc.h" +#include "avra.h" +#include "args.h" + +#include "coff.h" +#include "device.h" /* device flash and eeprom size */ + + +struct FundamentalType { + + char const *pString; + int Type; + int Size; +}; + +struct FundamentalType FundamentalTypes[] = { + {"null", T_NULL, 0}, + {"void", T_VOID, 0}, + {"char", T_CHAR, 1}, + {"short", T_SHORT, 1}, + {"int", T_INT, 1}, + {"long", T_LONG, 2}, + {"float", T_FLOAT, 4}, + {"double", T_DOUBLE, 4}, + {"struct", T_STRUCT, 0}, + {"union", T_UNION, 0}, + {"enum", T_ENUM, 0}, + {"moe", T_MOE, 0}, + {"unsigned char", T_UCHAR, 1}, + {"unsigned short", T_USHORT, 1}, + {"unsigned int", T_UINT, 1}, + {"unsigned long", T_ULONG, 2}, + {"long double", T_LNGDBL, 2}, + {"long long int", T_LONG, 2}, + {"long int", T_LONG, 2}, + {"unsigned long long", T_ULONG, 2}, + {"signed char", T_CHAR, 1}, + {0, 0} +}; + + +struct coff_info *ci; + +/****************************************************************************************/ + +FILE *open_coff_file(struct prog_info *pi, char *filename){ + + int ok /*, i*/; + FILE *fp; + //unsigned long *pu4; + char*p; + + + ci = calloc( 1, sizeof(struct coff_info) ); + if ( !ci ) + return( 0 ); + + ok = True; + /* default values */ + ci->CurrentFileNumber = 0; + ci->pRomMemory = 0; + ci->pEEPRomMemory = 0; + ci->MaxRomAddress = 0; + ci->MaxEepromAddress = 0; + ci->NeedLineNumberFixup = 0; + ci->GlobalStartAddress = -1; + ci->GlobalEndAddress = 0; + + /* Linked lists start out at zero */ + InitializeList( &ci->ListOfSectionHeaders ); + InitializeList( &ci->ListOfRawData ); + InitializeList( &ci->ListOfRelocations ); + InitializeList( &ci->ListOfLineNumbers ); + InitializeList( &ci->ListOfSymbols ); + InitializeList( &ci->ListOfGlobals ); + InitializeList( &ci->ListOfSpecials ); + InitializeList( &ci->ListOfUndefined ); + InitializeList( &ci->ListOfStrings ); + InitializeList( &ci->ListOfTypes ); + InitializeList( &ci->ListOfSplitLines ); + + /* add two default sections to SectionHeaders */ + if ( !AllocateListObject( &ci->ListOfSectionHeaders, sizeof(struct external_scnhdr) ) || + !AllocateListObject( &ci->ListOfSectionHeaders, sizeof(struct external_scnhdr) ) ) { + + fprintf(stderr, "\nOut of memory allocating section headers!"); + return( 0 ); + } + + /* add to string table */ + p = (char *)AllocateListObject( &ci->ListOfStrings, 4 ); + if ( !p ) { + fprintf(stderr, "\nOut of memory allocating string table space!"); + return( 0 ); + } + + /* Allocate space for binary output into ROM, and EEPROM memory buffers for COFF output */ + /* ASSUMES ci->device is accurate */ + if ( (ci->pRomMemory = AllocateListObject( &ci->ListOfRawData, pi->device->flash_size * 2 ) ) != 0) { + if ( (ci->pEEPRomMemory = AllocateListObject( &ci->ListOfRawData, pi->device->eeprom_size )) != 0) { + ok = True; /* only true if both buffers are properly allocated */ + /* now fill them with 0xff's to simulate flash erasure */ + memset( (void *)ci->pRomMemory, 0xff, pi->device->flash_size * 2 ); + memset( ( void *)ci->pEEPRomMemory, 0xff, pi->device->eeprom_size ); + } + } + if ( ok != True ) + return( 0 ); + + fp = fopen(filename,"wb"); + if ( fp == NULL ) { + fprintf(stderr,"Error: cannot write coff file\n"); + return( fp ); + } + /* simulate void type .stabs void:t15=r1;*/ + stab_add_local_type( "void", "15=r1;0;0;" ); + + return( fp ); +} + +/****************************************************************************************/ +void write_coff_file(struct prog_info *pi){ + + //FILE *fp; + //struct label *label; + char /* File[256],*/*p; + struct external_scnhdr *pSectionHdr; + struct syment *pEntry; + union auxent *pAux; + unsigned long *plong; + int NumberOfSymbols, SymbolIndex, LastFileIndex, LastFunctionIndex, LastFunctionAddress; + LISTNODE *pNode; + int LinesOffset, SymbolsOffset, StringsOffset, RawOffset; + struct lineno *pLine; + + /* add two special sections */ + /* one for .text */ + if ( ( pEntry = (struct syment*)AllocateTwoListObjects( &ci->ListOfSpecials, sizeof(struct syment) * 2 ) ) == 0 ) { + fprintf(stderr, "\nOut of memory allocating special headers for .text!"); + return; + } + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".text" ); + pEntry->n_value = 0; + pEntry->n_scnum = 1; + pEntry->n_type = 0; + pEntry->n_sclass = C_STAT; + pEntry->n_numaux = 1; + pEntry++; + pAux = (union auxent *)pEntry; + pAux->x_scn.x_scnlen = ci->MaxRomAddress + 2; + pAux->x_scn.x_nreloc = 0; + pAux->x_scn.x_nlinno = ci->ListOfLineNumbers.TotalItems; + /* one for .bss */ + if ( ( pEntry = (struct syment*)AllocateTwoListObjects( &ci->ListOfSpecials, sizeof(struct syment) * 2 ) ) == 0 ) { + fprintf(stderr, "\nOut of memory allocating special header for .bss!"); + return; + } + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".bss" ); + if ( ci->GlobalStartAddress == -1 ) { + ci->GlobalEndAddress = ci->GlobalStartAddress = 0x60; + } + pEntry->n_value = ci->GlobalStartAddress; + pEntry->n_scnum = 2; + pEntry->n_type = 0; + pEntry->n_sclass = C_STAT; + pEntry->n_numaux = 1; + pEntry++; + pAux = (union auxent *)pEntry; + pAux->x_scn.x_scnlen = 0; /* we don't store any data here */ + pAux->x_scn.x_nreloc = 0; + pAux->x_scn.x_nlinno = 0; + + /* one more for .data - eeprom ??? */ + + /* Calculate common offsets into the file */ + RawOffset = sizeof(struct external_filehdr) + ci->ListOfSectionHeaders.TotalBytes; + LinesOffset = RawOffset + ci->MaxRomAddress + 2; /* ignore eeprom for now */ + SymbolsOffset = LinesOffset + ci->ListOfLineNumbers.TotalBytes; + StringsOffset = SymbolsOffset + ci->ListOfSymbols.TotalBytes + ci->ListOfSpecials.TotalBytes + ci->ListOfGlobals.TotalBytes; + + /* Clean up loose ends in string table */ + if ( !(plong = (unsigned long *)FindFirstListObject(&ci->ListOfStrings)) ) { + fprintf(stderr,"\nInternal error in string table!"); + return; + } + *plong = ci->ListOfStrings.TotalBytes; /* Size of string table */ + + /* Clean up loose ends in symbol table */ + + /* symbol table - Filename value - index to next .file or global symbol */ + /* The value of that symbol equals the symbol table entry index of the next .file symbol or .global */ + LastFunctionAddress = ci->MaxRomAddress; + NumberOfSymbols = ci->ListOfSymbols.TotalItems + ci->ListOfSpecials.TotalItems + ci->ListOfGlobals.TotalItems; + SymbolIndex = LastFileIndex = NumberOfSymbols; + LastFunctionIndex = 0; /* set to zero on last function */ + for ( pEntry = (struct syment *)FindLastListObject(&ci->ListOfSymbols); + pEntry != 0; + pEntry = (struct syment *)FindNextLastListObject(&ci->ListOfSymbols) ) { + + /* Search for .file entries designated by C_FILE */ + if ( pEntry->n_sclass == C_FILE ) { + pEntry->n_value = LastFileIndex; + LastFileIndex = SymbolIndex; /* save current index */ + } + /* Search for Function entries C_EXT */ + else if ( pEntry->n_sclass == C_EXT ) { + pEntry++; + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_fsize = LastFunctionAddress - pEntry->n_value; /* function updated size */ + pAux->x_sym.x_fcnary.x_fcn.x_lnnoptr += LinesOffset; + LastFunctionAddress = pEntry->n_value; + pAux->x_sym.x_fcnary.x_fcn.x_endndx = LastFunctionIndex; /* point to next function index */ + pAux->x_sym.x_tvndx = 0; /* ??? */ + LastFunctionIndex = SymbolIndex; + } else if ( (pEntry->n_sclass == C_FCN ) || ( pEntry->n_sclass == C_BLOCK) ) { + if ( pEntry->n_name[1] == 'b' ) { + /* .bf and .bb */ + pEntry++; + pAux = (union auxent *)pEntry; + pAux->x_sym.x_fcnary.x_fcn.x_endndx = LastFunctionIndex; + } + } + /* else do nothing */ + + /* update current symbol index */ + pNode = GetCurrentNode( &ci->ListOfSymbols ); + SymbolIndex -= ( pNode->Size / sizeof(struct syment) ); + } + + // File Header + ci->FileHeader.f_magic = MAGIC_NUMBER_AVR; + ci->FileHeader.f_nscns = 2; +// ci->FileHeader.f_timdat = time( (time_t *)&ci->FileHeader.f_timdat); + ci->FileHeader.f_timdat = pi->time; + ci->FileHeader.f_symptr = SymbolsOffset; + ci->FileHeader.f_nsyms = NumberOfSymbols; + ci->FileHeader.f_opthdr = 0; + ci->FileHeader.f_flags = 0xff; /*F_RELFLG;*/ /* No relocation information available */ + + /* write it out */ + if ( fwrite(&ci->FileHeader, 1, sizeof(struct external_filehdr), pi->coff_file ) != sizeof(struct external_filehdr) ) { + fprintf(stderr,"\nFile error writing header ...(disk full?)"); + return; + } + + // Optional Information + + // Section 1 Header + pSectionHdr = (struct external_scnhdr *)FindFirstListObject(&ci->ListOfSectionHeaders); + if ( !pSectionHdr ) { + fprintf(stderr, "\nInternal Coff error - cannot find section header .text!"); + return; + } + memset( &pSectionHdr->s_name[0], 0, sizeof(struct external_scnhdr) ); + strcpy( &pSectionHdr->s_name[0], ".text"); + pSectionHdr->s_paddr = 0; + pSectionHdr->s_vaddr = 0; + pSectionHdr->s_size = ci->MaxRomAddress + 2; /* remember the last instruction */ + pSectionHdr->s_scnptr = RawOffset; + pSectionHdr->s_relptr = 0; + pSectionHdr->s_lnnoptr = LinesOffset; + pSectionHdr->s_nreloc = 0; + pSectionHdr->s_nlnno = ci->ListOfLineNumbers.TotalBytes/sizeof(struct lineno); + pSectionHdr->s_flags = STYP_TEXT; + + /* write it out */ + if ( fwrite(&pSectionHdr->s_name[0], 1, sizeof(struct external_scnhdr), pi->coff_file ) != sizeof(struct external_scnhdr) ) { + fprintf(stderr,"\nFile error writing section header ...(disk full?)"); + return; + } + + // Section 2 Header + pSectionHdr = (struct external_scnhdr *)FindNextListObject(&ci->ListOfSectionHeaders); + if ( !pSectionHdr ) { + fprintf(stderr, "\nInternal Coff error - cannot find section header .bss!"); + return; + } + memset( &pSectionHdr->s_name[0], 0, sizeof(struct external_scnhdr) ); + strcpy( &pSectionHdr->s_name[0], ".bss"); + /* later expansion */ + pSectionHdr->s_paddr = ci->GlobalStartAddress; + pSectionHdr->s_vaddr = ci->GlobalStartAddress; + pSectionHdr->s_flags = STYP_DATA; /* seems it should be STYP_BSS */ + + /* write it out */ + if ( fwrite(&pSectionHdr->s_name[0], 1, sizeof(struct external_scnhdr), pi->coff_file ) != sizeof(struct external_scnhdr) ) { + fprintf(stderr,"\nFile error writing section header ...(disk full?)"); + return; + } + + /* Section N Header - .data or eeprom */ + + // Raw Data for Section 1 + if ( (p = FindFirstListObject(&ci->ListOfRawData) ) == 0 ) { + fprintf(stderr,"\nInternal error - unable to find binary data!"); + return; + } + + /* write it out */ + if ( fwrite( p, 1, ci->MaxRomAddress + 2, pi->coff_file ) != (size_t)(ci->MaxRomAddress + 2) ) { + fprintf(stderr,"\nFile error writing raw .text data ...(disk full?)"); + return; + } + // Raw data for section n + + // Relocation Info for section 1 + + // Relocation info for section n + + // Line numbers for section 1 + for ( pLine = (struct lineno *)FindFirstListObject( &ci->ListOfLineNumbers ); + pLine != 0; + pLine = (struct lineno *)FindNextListObject( &ci->ListOfLineNumbers ) ) { + + pNode = GetCurrentNode( &ci->ListOfLineNumbers ); + + /* write it out */ + if ( fwrite( pLine, 1, pNode->Size, pi->coff_file ) != pNode->Size ) { + fprintf(stderr,"\nFile error writing line numbers ...(disk full?)"); + return; + } + } + + + // Line numbers for section n + + // Symbol table + for ( pEntry = (struct syment *)FindFirstListObject( &ci->ListOfSymbols ); + pEntry != 0; + pEntry = (struct syment *)FindNextListObject( &ci->ListOfSymbols ) ) { + + pNode = GetCurrentNode( &ci->ListOfSymbols ); + + /* write it out */ + if ( fwrite( pEntry, 1, pNode->Size, pi->coff_file ) != pNode->Size ) { + fprintf(stderr,"\nFile error writing symbol table ...(disk full?)"); + return; + } + } + + // Symbol table of Globals + for ( pEntry = (struct syment *)FindFirstListObject( &ci->ListOfGlobals ); + pEntry != 0; + pEntry = (struct syment *)FindNextListObject( &ci->ListOfGlobals ) ) { + + pNode = GetCurrentNode( &ci->ListOfGlobals ); + + /* write it out */ + if ( fwrite( pEntry, 1, pNode->Size, pi->coff_file ) != pNode->Size ) { + fprintf(stderr,"\nFile error writing global symbols ...(disk full?)"); + return; + } + } + + /* Specials .text, .bss, .data */ + + for ( pEntry = (struct syment *)FindFirstListObject( &ci->ListOfSpecials ); + pEntry != 0; + pEntry = (struct syment *)FindNextListObject( &ci->ListOfSpecials ) ) { + + pNode = GetCurrentNode( &ci->ListOfSpecials ); + + /* write it out */ + if ( fwrite( pEntry, 1, pNode->Size, pi->coff_file ) != pNode->Size ) { + fprintf(stderr,"\nFile error writing special symbols ...(disk full?)"); + return; + } + } + + // String Table + for ( p = (char *)FindFirstListObject( &ci->ListOfStrings ); + p != 0; + p = (char *)FindNextListObject( &ci->ListOfStrings ) ) { + + pNode = GetCurrentNode( &ci->ListOfStrings ); + + /* write it out */ + if ( fwrite( p, 1, pNode->Size, pi->coff_file ) != pNode->Size ) { + fprintf(stderr,"\nFile error writing strings data ...(disk full?)"); + return; + } + } + + return; +} + +/****************************************************************************************/ + +void write_coff_eeprom( struct prog_info *pi, int address, unsigned char data){ + + if ( !GET_ARG(pi->args, ARG_COFF) ) + return; + + /* Coff output keeps track of binary data in memory buffers */ + if ( ci->pEEPRomMemory ) { + if ( address <= pi->device->eeprom_size ) { + *(ci->pEEPRomMemory + address) = data; + if ( address >= ci->MaxEepromAddress ) + ci->MaxEepromAddress = address; /* keep high water mark */ + } else { + pi->error_count++; + fprintf(stderr, "Error: EEPROM address %d exceeds max range %d", address, pi->device->eeprom_size ); + } + } +} +/****************************************************************************************/ + +void write_coff_program( struct prog_info *pi, int address, unsigned int data){ + + unsigned char *pByte; + + if ( !GET_ARG(pi->args, ARG_COFF) ) + return; + + /* Coff output keeps track of binary data in memory buffers, address is in bytes not words */ + if ( ci->pRomMemory ) { +/* JEG if ( address <= pi->device->flash_size ) { */ /* JEG 4-23-03 */ + if ( address <= pi->device->flash_size*2 ) { + pByte = (unsigned char *)(ci->pRomMemory + address); /* point to low byte in memory */ + *pByte++ = (data & 0xff); /* low byte */ + *pByte = ((data >> 8) & 0xff); /* high byte */ + + if ( address >= ci->MaxRomAddress ) + ci->MaxRomAddress = address; /* keep high water mark */ + } else { + pi->error_count++; +/* JEG fprintf(stderr, "Error: FLASH address %d exceeds max range %d", address, pi->device->flash_size ); */ + fprintf(stderr, "Error: FLASH address %d exceeds max range %d", address, pi->device->flash_size*2 ); + } + } +} + +/****************************************************************************************/ + +void close_coff_file(struct prog_info *pi, FILE *fp){ + + /* close the output file */ + fclose( fp ); + pi->coff_file = 0; + + /* free all the internal memory buffers used by ci */ + + FreeList( &ci->ListOfSectionHeaders ); + FreeList( &ci->ListOfRawData ); + FreeList( &ci->ListOfRelocations ); + FreeList( &ci->ListOfLineNumbers ); + FreeList( &ci->ListOfSymbols ); + FreeList( &ci->ListOfGlobals ); + FreeList( &ci->ListOfUndefined ); + FreeList( &ci->ListOfStrings ); + FreeList( &ci->ListOfTypes ); + FreeList( &ci->ListOfSplitLines ); + + /* now free ci */ + free( ci ); + ci = 0; +} + +/****************************************************************************************/ + +int parse_stabs( struct prog_info *pi, char *p ){ + + int ok = True; + int TypeCode, n; + char *pString, *p2, *p3, *p4, *p5, *pType, *pEnd, *pp, *pJoined; + + + if ( !GET_ARG(pi->args, ARG_COFF) || ( pi->pass == PASS_1 ) ) + return(True); + + /* stabs debugging information is in the form: + .stabs "symbolic info string", HexorDecimalTypecode, parm3, parm4, parm5 + parm1, parm2, parm3 depend on typecode + + N_LSYM 0x80 local sym: name,,0,type,offset + N_OPT 0x3c compiler options + N_SO 0x64 source file name: name,,0,0,address + N_SOL 0x84 #included file name: name,,0,0,address + N_FUN 0x24 procedure: name,,0,linenumber,address + N_GSYM 0x20 global symbol: name,,0,type,0 + N_LCSYM 0x28 .lcomm symbol: name,,0,type,address + N_STSYM 0x26 static symbol: name,,0,type,address + N_RSYM 0x40 register sym: name,,0,type,register + N_PSYM 0xa0 parameter: name,,0,type,offset + + */ + + /* Look for multiple commands per line */ + + /* .stabs "linktag:T19=s46next:20=*19,0,16;last:20,16,16;a:21=ar1;0;2;22=ar1;0;3;1,32,96;\\",128,0,0,0 */ + /* .stabs "b:23=ar1;0;4;24=ar1;0;5;2,128,240;;",128,0,0,0 */ + + + /* Look for continuation lines per line */ + + /* Get String information as a token */ + /* Parse the tokens in the stabn line buffer */ + pString = get_next_token(p, TERM_DOUBLEQUOTE ); /* zap first doublequote */ + p2 = get_next_token(pString, TERM_DOUBLEQUOTE ); /* zap last doublequote */ + p2 = get_next_token(p2, TERM_COMMA ); /* zap comma */ + p3 = get_next_token(p2, TERM_COMMA ); + p4 = get_next_token(p3, TERM_COMMA ); + p5 = get_next_token(p4, TERM_COMMA ); + pEnd = get_next_token(p5, TERM_END ); /* zap CR LF, make ASCIIZ */ + + if ( !pString || !p2 || !p3 || !p4 || !p5 ) + return( False ); + + /* Check for split lines */ + n = strlen( pString ); + if ( ( pString[n - 1] == '\\' ) && (pString[n - 2] == '\\') ) { + /* We have a continuation string here */ + pString[n - 2] = 0; + n -= 2; + if ( !(pp = (char *)AllocateListObject( &ci->ListOfSplitLines, n + 1 )) ) { + fprintf(stderr, "\nOut of memory allocating continuation line!"); + return( False ); + } + strcpy( pp, pString ); /* loose the continuation characters */ + return(True); + } + if ( ci->ListOfSplitLines.TotalItems > 0 ) { + /* Join lines together and process */ + if ( !(pJoined = calloc( 1, n + ci->ListOfSplitLines.TotalBytes ) ) ) { + fprintf(stderr, "\nOut of memory joining continuation lines!"); + return( False ); + } + for ( pp = (char *)FindFirstListObject( &ci->ListOfSplitLines ); + pp != 0; + pp = (char *)FindNextListObject( &ci->ListOfSplitLines ) ) { + + strcat( pJoined, pp ); /* connect the lines */ + } + strcat( pJoined, pString ); + FreeList( &ci->ListOfSplitLines ); + if ( !AddListObject( &ci->ListOfSplitLines, pJoined, n + ci->ListOfSplitLines.TotalBytes ) ) { + fprintf(stderr, "\nUnable to add joined continuation line"); + return( False ); + } + pString = pJoined; + } + + + if ( *p2 == '0' ) + TypeCode = atox(p2); /* presume to be hex 0x */ + else + TypeCode = atoi(p2); + + switch ( TypeCode ) { + + case N_OPT: /* compiler options */ + break; /* nothing used here */ + + case N_SO: /* source file name: name,,0,0,address */ + ok = stab_add_filename( pString, p5 ); + break; + + case N_GSYM: /* global symbol: name,,0,type,0 */ + pType = get_next_token(pString, TERM_COLON ); /* separate at colon */ + ok = stab_add_global( pi, pString, pType ); + break; + + case N_FUN: /* procedure: name,,0,linenumber,address */ + ok = stab_add_function( pi, pString, p5 ); + break; + + case N_LSYM: /* local sym: name,,0,type,offset */ + /* pString, p2 = TypeCode, p3 = 0, p4 = 0, p5 = offset */ + pType = get_next_token(pString, TERM_COLON ); /* pType = symbol descriptor (character after the colon) */ + if ( *pType == 't') + ok = stab_add_local_type( pString, ++pType ); + else if (*pType == 'T') + ok = stab_add_tag_type( pString, ++pType ); + else + ok = stab_add_local( pi, pString, pType, p5 ); + break; + + case N_RSYM: /* Symbol:[P|r]type,0,size,register */ + pType = get_next_token(pString, TERM_COLON ); /* separate at colon */ + ok = stab_add_local_register( pi, pString, pType, p5 ); + break; + + case N_LCSYM: /* .lcomm symbol: name,,0,type,address */ + ok = True; + break; /* ignore constants */ + + case N_STSYM: /* static symbol: name,,0,type,address */ + pType = get_next_token(pString, TERM_COLON ); /* separate at colon */ + ok = stab_add_static_symbol( pi, pString, pType, p5 ); + break; + + case N_PSYM: /* parameter: name,,0,type,offset */ + pType = get_next_token(pString, TERM_COLON ); /* separate at colon */ + ok = stab_add_parameter_symbol( pi, pString, pType, p5 ); + break; + + case N_SOL: /* #included file name: name,,0,0,address */ + ok = True; + break; /* ignore include files */ + + default: + ok = False; + } + + if ( ci->ListOfSplitLines.TotalItems > 0 ) + FreeList( &ci->ListOfSplitLines ); + + return( ok ); +} +/****************************************************************************************/ + +int parse_stabn( struct prog_info *pi, char *p ){ + + int ok = True; + int TypeCode /* , LineNumber */, Level; + char *p1, *p2, *p3, *p4, *pLabel, *pFunction, *pEnd; + + /* stabn debugging information is in the form: + .stabn TypeCode, 0, parm1, parm2 + parm1 is level + parm2 is Label-Function + + compiler currently produces the following TypeCodes: + N_LBRAC 0xc0 left bracket: 0,,0,nesting level,address + N_RBRAC 0xe0 right bracket: 0,,0,nesting level,address + N_SLINE 0x44 src line: 0,,0,linenumber,address + */ + + if ( !GET_ARG(pi->args, ARG_COFF) || ( pi->pass == PASS_1 ) ) + return(True); + + /* Parse the tokens in the stabn line buffer */ + p1 = get_next_token(p, TERM_SPACE ); + p2 = get_next_token(p1, TERM_COMMA ); + p3 = get_next_token(p2, TERM_COMMA ); + p4 = get_next_token(p3, TERM_COMMA ); + pEnd = get_next_token(p4, TERM_END ); /* zap CR LF, make ASCIIZ */ + + if ( !p1 || !p2 || !p3 || !p4 ) + return( False ); + + /* first convert TypeCode to binary */ + if ( *p1 == '0' ) + TypeCode = atox(p1); /* presume to be hex 0x */ + else + TypeCode = atoi(p1); + + Level = atoi(p3); /* line number or level */ + pLabel = p4; /* Assembly label */ + pFunction = get_next_token( pLabel, TERM_DASH ); /* Function */ + + switch ( TypeCode ) { + case N_SLINE: /* src line: 0,,0,linenumber,address */ + ok = stab_add_lineno( pi, Level, pLabel, pFunction ); + break; + + case N_LBRAC: /* left bracket: 0,,0,nesting level,address */ + ok = stab_add_lbracket( pi, Level, pLabel, pFunction ); + break; + + case N_RBRAC: /* right bracket: 0,,0,nesting level,address */ + ok = stab_add_rbracket( pi, Level, pLabel, pFunction ); + break; + + default: + fprintf(stderr, "\nUnknown .stabn TypeCode = 0x%x", TypeCode ); + ok = False; + } + return( ok ); +} + +/****************************************************************************************/ +int stab_add_lineno( struct prog_info *pi, int LineNumber, char *pLabel, char *pFunction ){ + + int Address; + struct lineno *pln; + struct syment *pEntry; + union auxent *pAux; + + /* Allocate LineNumber Table entry and fill it in */ + pln = (struct lineno *)AllocateListObject(&ci->ListOfLineNumbers, sizeof(struct lineno) ); + if ( !pln ) { + fprintf(stderr, "\nOut of memory allocating lineno table for function %s", pFunction ); + return( False ); + } + /* set value field to be address of label in bytes */ + if ( !get_symbol(pi, pLabel, &Address) ) { + fprintf(stderr, "\nUnable to locate label %s", pLabel ); + return( False ); + } + pln->l_addr.l_paddr = Address * 2; /* need byte quanities */ + + /* Line number is relative to beginning of function, starts at 1 */ + if ( ci->FunctionStartLine == 0 ) { + /* This line number is that same as the function start */ + ci->FunctionStartLine = LineNumber; + } + pln->l_lnno = LineNumber - ci->FunctionStartLine + 1; + ci->CurrentSourceLine = LineNumber; /* keep track of source line for .eb .ef arrays */ + if ( ci->NeedLineNumberFixup ) { + /* need to go into symbol table and fix last NeedLineNumberFixup entries */ + for ( pEntry = (struct syment *)FindLastListObject(&ci->ListOfSymbols); + (pEntry != 0) && ( ci->NeedLineNumberFixup != 0); + pEntry = (struct syment *)FindNextLastListObject(&ci->ListOfSymbols) ) { + + /* Fix up line number entries */ + if ( (pEntry->n_sclass == C_FCN ) || ( pEntry->n_sclass == C_BLOCK ) || ( pEntry->n_sclass == C_EXT) ) { + pEntry++; + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_lnsz.x_lnno = LineNumber; + ci->NeedLineNumberFixup--; + } + } + } + + return(True); +} +/****************************************************************************************/ + +int stab_add_lbracket( struct prog_info *pi, int Level, char *pLabel, char *pFunction ){ + + int Address; + struct syment *pEntry; + union auxent *pAux; + //char *p; + //struct lineno *pln; + + if ( !get_symbol(pi, pLabel, &Address) ) { + fprintf(stderr, "\nUnable to locate label %s", pLabel ); + return( False ); + } + + /* Now create a .bb symbol table entry and aux entry too */ + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfSymbols, sizeof(struct syment) * 2 ); + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry for .bb %s", pLabel ); + return( False ); + } + /* n_name */ + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".bb" ); + + pEntry->n_value = Address * 2; /* bytes not words */ + pEntry->n_scnum = 1; /* .text */ + pEntry->n_type = 0; + pEntry->n_sclass = C_BLOCK; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_lnsz.x_lnno = 0; /* UNKNOWN - post process */ + pAux->x_sym.x_misc.x_lnsz.x_size = 0; /* UNKNOWN - post process */ + ci->NeedLineNumberFixup++; /* once for .bb block */ + return(True); +} + +/****************************************************************************************/ +int stab_add_rbracket( struct prog_info *pi, int Level, char *pLabel, char *pFunction ){ + + int Address; + struct syment *pEntry; + union auxent *pAux; + //char *p; + //struct lineno *pln; + + if ( !get_symbol(pi, pLabel, &Address) ) { + fprintf(stderr, "\nUnable to locate label %s", pLabel ); + return( False ); + } + + /* Now create a .eb symbol table entry */ + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfSymbols, sizeof(struct syment) * 2 ); + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry for .eb %s", pLabel ); + return( False ); + } + /* n_name */ + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".eb" ); + pEntry->n_sclass = C_BLOCK; + pEntry->n_value = Address * 2; /* bytes not words */ + pEntry->n_scnum = 1; /* .text */ + pEntry->n_type = 0; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_lnsz.x_lnno = ci->CurrentSourceLine; + + /* create an .ef if at level 0 */ + if ( Level == 0 ) { + + /* Now create a .ef symbol table entry */ + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfSymbols, sizeof(struct syment) * 2 ); + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry for .ef %s", pLabel ); + return( False ); + } + /* n_name */ + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".ef" ); + pEntry->n_sclass = C_FCN; + pEntry->n_value = Address * 2; /* bytes not words */ + pEntry->n_scnum = 1; /* .text */ + pEntry->n_type = 0; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_lnsz.x_lnno = ci->CurrentSourceLine; + } + return(True); +} + +/****************************************************************************************/ +int stab_add_filename( char *pName, char *pLabel ){ + + int ok, n; + struct syment *pEntry; + union auxent *pAux; + char *p; + + /* if( pLabel == "Ltext0" ) then beginning of .text, pName = cwd, next pName = file */ + + /* if( pLabel == "Letext" ) then end of .text , pName == NULL */ + + /* we only need the one not ending in Slash */ + ok = True; + n = strlen(pName); + if ( n > 0 ) { + if ( ( pName[ n - 1] == '\\') || (pName[ n - 1] == '/') ) + return(True); /* ignore */ + } else + return(True); + + + /* allocate entry in symbol table list */ + pEntry = (struct syment *)AllocateTwoListObjects( + &ci->ListOfSymbols, sizeof(struct syment) * 2 ); /* aux entry too */ + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry for global %s", pName ); + return( False ); + } + /* n_name */ + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".file" ); + /* n_value is determined after processing done UNKNOWN - post process */ + /* The value of that symbol equals the symbol table entry index of the next .file symbol or .global */ + /* post process */ + pEntry->n_scnum = N_DEBUG; + pEntry->n_sclass = C_FILE; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + + /* Add Label name to symbol table */ + if ( n <= FILNMLEN ) { + /* inline filename */ + memset( pAux->x_file.x_fname, 0, FILNMLEN ); + strncpy( pAux->x_file.x_fname, pName, n ); /* might not be zero terminated */ + } else { + pAux->x_file.x_n.x_zeroes = 0; /* symbol name is in string table */ + pAux->x_file.x_n.x_offset = ci->ListOfStrings.TotalBytes; + + /* add to string table */ + p = (char *)AllocateListObject( &ci->ListOfStrings, n + 1 ); + if ( !p ) { + fprintf(stderr, "\nOut of memory allocating string table space!"); + return( False ); + } + strcpy( p, pName ); + } + return( ok ); +} + +/****************************************************************************************/ +int stab_add_function( struct prog_info *pi, char *pName, char *pLabel ){ + + int n, Address; + unsigned short CoffType, Type; + struct syment *pEntry; + char *pType; + struct lineno *pln; + union auxent *pAux; + int SymbolIndex; + + pType = get_next_token(pName, TERM_COLON ); /* pType = symbol descriptor (character after the colon) */ + Type = atoi(pType + 1); /* skip past F, predefined variable type */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized return type found for function %s = %d", pName, Type ); + return(False); + } + /* Get Current Symbol Index, Allocate Symbol Table entry and fill it in */ + SymbolIndex = ci->ListOfSymbols.TotalItems; + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfSymbols, sizeof(struct syment) * 2 ); + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry for function %s", pName ); + return( False ); + } + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + } + if ( !get_symbol(pi, pLabel, &Address) ) { + fprintf(stderr, "\nUnable to locate function %s", pName ); + return( False ); + } + pEntry->n_value = Address * 2; /* convert words to bytes */ + pEntry->n_scnum = 2; /* .bss */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for function %s = %d", pName, Type ); + return(False); + } + pEntry->n_type = (unsigned short)(CoffType | (DT_FCN << 4)); + pEntry->n_sclass = C_EXT; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_tagndx = SymbolIndex + 1; /* point to the .bf entry index */ + // wrong! + // pAux->x_sym.x_misc.x_lnsz.x_lnno = ci->ListOfLineNumbers.TotalBytes; /* Relative Fixup point to where line numbers start */ + // pAux->x_sym.x_misc.x_lnsz.x_size = 0; /* UNKNOWN till next function called */ + pAux->x_sym.x_misc.x_fsize = 0; /* unknown till end */ + pAux->x_sym.x_fcnary.x_fcn.x_lnnoptr = ci->ListOfLineNumbers.TotalBytes; /* relative offset to line number entry */ + pAux->x_sym.x_fcnary.x_fcn.x_endndx = 0; /* index to next entry */ + + /* Now add function entry into the line number table */ + /* Allocate Symbol Table entry and fill it in */ + pln = (struct lineno *)AllocateListObject(&ci->ListOfLineNumbers, sizeof(struct lineno) ); + if ( !pln ) { + fprintf(stderr, "\nOut of memory allocating lineno table for function %s", pName ); + return( False ); + } + pln->l_lnno = 0; + pln->l_addr.l_symndx = SymbolIndex; + + /* Initialize the FunctionStartLine from the beginning of the function */ + ci->FunctionStartLine = 0; + + /* Allocate Symbol Table entry and fill it in */ + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfSymbols, sizeof(struct syment) * 2 ); + if ( !pEntry ) { + fprintf(stderr, "\nOut of memory allocating symbol table entry .bf for function %s", pName ); + return( False ); + } + memset( pEntry->n_name, 0, 8 ); + strcpy( pEntry->n_name, ".bf" ); + pEntry->n_value = Address * 2; /* bytes not words */ + pEntry->n_scnum = 1; /* .text */ + pEntry->n_type = 0; + pEntry->n_sclass = C_FCN; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_misc.x_lnsz.x_lnno = 0; /* UNKNOWN - post process */ + pAux->x_sym.x_misc.x_lnsz.x_size = 0; /* UNKNOWN - post process */ + + ci->NeedLineNumberFixup++; /* once for function C_EXT symbol */ + ci->NeedLineNumberFixup++; /* once for .bf block */ + return( True ); +} +/****************************************************************************************/ + +int stab_add_global( struct prog_info *pi, char *pName, char *pType ){ + + int n, Address, IsArray, SymbolIndex; + unsigned short CoffType, Type; + struct syment *pEntry; + char *p; + STABCOFFMAP *pMap; + + + n = strlen( pName ); /* see if it's 8 bytes or less */ + Type = atoi(pType + 1); /* skip past G, predefined variable type */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for global %s = %d", pName, Type ); + return(False); + } + pMap = (STABCOFFMAP *)GetCurrentListObject( &ci->ListOfTypes ); + + SymbolIndex = ci->ListOfSymbols.TotalItems; + /* Allocate Symbol Table entry and fill it in, Auxiliary table if its an array */ + if ( IsTypeArray( CoffType ) == True ) { + IsArray = True; + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfGlobals, sizeof(struct syment) * 2 ); + } else { + IsArray = False; + pEntry = (struct syment *)AllocateListObject( &ci->ListOfGlobals, sizeof(struct syment) ); + } + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + } + /* set value field to be address of label in bytes */ + /* add underscore to lookup label */ + if ( (p = calloc( 1, n + 2)) == 0 ) { + fprintf(stderr,"\nOut of memory adding global %s", pName ); + return(False); + } + *p = '_'; + strcpy( p + 1, pName ); + if ( !get_symbol(pi, p, &Address) ) { + fprintf(stderr, "\nUnable to locate global %s", p ); + free( p ); + return( False ); + } + free( p ); + pEntry->n_value = Address; /* already in bytes */ + if ( ci->GlobalStartAddress == -1 ) { + ci->GlobalStartAddress = Address; + } + if ( Address < ci->GlobalStartAddress ) + ci->GlobalStartAddress = Address; + if ( Address > ci->GlobalEndAddress ) + ci->GlobalEndAddress = Address; + + pEntry->n_scnum = 2; /* .bss */ + pEntry->n_type = CoffType; + pEntry->n_sclass = C_STAT; + if ( IsArray == False ) + pEntry->n_numaux = 0; + else { + pEntry->n_numaux = 1; + pEntry++; + AddArrayAuxInfo( (union auxent *)pEntry, (unsigned short)SymbolIndex, pMap ); + } + return( True ); +} + +/****************************************************************************************/ +int stab_add_local( struct prog_info *pi, char *pName, char *pType, char *pOffset ){ + + int n, Offset, IsArray; + unsigned short CoffType, Type, SymbolIndex; + struct syment *pEntry; + STABCOFFMAP *pMap; + + n = strlen( pName ); /* see if it's 8 bytes or less */ + Type = atoi(pType); /* predefined variable type */ + Offset = atoi(pOffset); /* offset in stack frame */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for local %s = %d", pName, Type ); + return(False); + } + pMap = (STABCOFFMAP *)GetCurrentListObject( &ci->ListOfTypes ); + SymbolIndex = ci->ListOfSymbols.TotalItems; + /* Allocate Symbol Table entry and fill it in, Auxiliary table if its an array */ + if ( IsTypeArray( CoffType ) == True ) { + IsArray = True; + pEntry = (struct syment *)AllocateTwoListObjects( &ci->ListOfGlobals, sizeof(struct syment) * 2 ); + } else { + IsArray = False; + pEntry = (struct syment *)AllocateListObject( &ci->ListOfSymbols, sizeof(struct syment) ); + } + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + } + pEntry->n_type = CoffType; + pEntry->n_sclass = C_AUTO; + pEntry->n_scnum = N_ABS; + pEntry->n_value = Offset + 1; /* Silly avr studio is set in its ways */ + if ( IsArray == False ) + pEntry->n_numaux = 0; + else { + pEntry->n_numaux = 1; + pEntry++; + AddArrayAuxInfo( (union auxent *)pEntry, SymbolIndex, pMap ); + } + return( True ); +} + +/****************************************************************************************/ +int stab_add_parameter_symbol( struct prog_info *pi, char *pName, char *pType, char *pOffset ){ + + int n, Offset; + unsigned short CoffType, Type; + struct syment *pEntry; + + n = strlen( pName ); /* see if it's 8 bytes or less */ + Type = atoi(pType); /* predefined variable type */ + Offset = atoi(pOffset); /* offset in stack frame */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for %s = %d", pName, Type ); + return(False); + } + /* Allocate Symbol Table entry and fill it in */ + pEntry = (struct syment *)AllocateListObject( &ci->ListOfSymbols, sizeof(struct syment) ); + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + } + pEntry->n_type = CoffType; + pEntry->n_sclass = C_ARG; + pEntry->n_scnum = N_ABS; + pEntry->n_value = Offset; + pEntry->n_numaux = 0; + return( True ); +} +/****************************************************************************************/ +int stab_add_static_symbol( struct prog_info *pi, char *pName, char *pType, char *pLabel ){ + + int n, Address; + unsigned short CoffType, Type; + struct syment *pEntry; + + n = strlen( pName ); /* see if it's 8 bytes or less */ + Type = atoi(pType + 1); /* skip past S, predefined variable type */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for %s = %d", pName, Type ); + return(False); + } + /* Allocate Symbol Table entry and fill it in */ + pEntry = (struct syment *)AllocateListObject( &ci->ListOfSymbols, sizeof(struct syment) ); + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + } + pEntry->n_type = CoffType; + pEntry->n_sclass = C_STAT; + pEntry->n_scnum = N_ABS; + if ( !get_symbol(pi, pLabel, &Address) ) { + fprintf(stderr, "\nUnable to locate label %s", pLabel ); + return( False ); + } + pEntry->n_value = Address * 2; /* find address of variable in bytes */ + pEntry->n_numaux = 0; + return( True ); +} +/****************************************************************************************/ + +int stab_add_local_register( struct prog_info *pi, char *pName, char *pType, char *pRegister ){ + + int n, Register, Size; + unsigned short CoffType, Type; + struct syment *pEntry; + + n = strlen( pName ); /* see if it's 8 bytes or less */ + Type = (unsigned short)atoi(pType + 1); /* skip past P, predefined variable type */ + Register = atoi(pRegister); /* offset in stack frame */ + if ( (CoffType = GetCoffType( Type )) == 0 ) { + fprintf(stderr, "\nUnrecognized type found for %s = %d", pName, Type ); + return(False); + } + Size = GetCoffTypeSize( Type ); /* Silly requirement for avr studio */ + /* Allocate Symbol Table entry and fill it in */ + pEntry = (struct syment *)AllocateListObject( &ci->ListOfSymbols, sizeof(struct syment) ); + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pName ); + return(False); + } + pEntry->n_type = CoffType; + // if( (*pType == 'r') || (*pType == 'R') ) + // pEntry->n_sclass = C_REG; + // else if( (*pType == 'p') || (*pType == 'P') ) + pEntry->n_sclass = C_REGPARM; /* Silly avr studio only accepts this for registers */ + // else{ + // fprintf(stderr,"\nUnknown register type -> %s", pType ); + // return(False); + // } + pEntry->n_scnum = N_ABS; + pEntry->n_numaux = 0; + if ( Size == 1 ) + pEntry->n_value = 0xffffff00 | Register; /* Silly requirement for avr studio */ + else if ( Size == 2 ) + pEntry->n_value = 0xffff0000 | ((Register + 1) << 8) | Register; /* Silly requirement for avr studio */ + else if ( Size == 4 ) + pEntry->n_value = ((Register + 3) << 24) | ((Register + 3) << 16) | ((Register + 1) << 8) | Register; /* Silly requirement for avr studio */ + else { + fprintf(stderr,"\nUnknown register size (%d) and coff type (%d)", Size, CoffType ); + return(False); + } + return( True ); +} + +/****************************************************************************************/ + +int stab_add_local_type( char *pName, char *pType ){ + + char *p; + unsigned short StabType; + + /* .stabs "int:t1=r1;-128;127;",128,0,0,0 */ + /* .stabs ":t20=ar1;0;1;21=ar1;0;1;2",128,0,0,0 */ + /* pType-----^ */ + /* Stab Type - convert to Coff type at end (after inline assignments */ + if ( GetStabType( pType, &StabType, &p ) != True ) { + fprintf(stderr,"\nInvalid tag type found in structure item -> %s", p); + return(False); + } + + return(True); +} + +/****************************************************************************************/ + +int GetStructUnionTagItem( char *p, char **pEnd, char **pName, unsigned short *pType, unsigned short *pBitOffset, unsigned short *pBitSize) { + + unsigned short StabType; + /* Structure or Union Tag Item consists of -> name:type,bitoffset,bitsize; */ + + /* name */ + *pName = p; + while ( *p && (*p != ':') ) p++; // locate colon + if ( *p != ':' ) { + fprintf(stderr,"\nNo colon found in structure item -> %s", *pName); + return(False); + } + *p++ = 0; // Asciiz + + /* Stab Type - convert to Coff type at end (after inline assignments */ + if ( GetStabType( p, &StabType, &p ) != True ) { + fprintf(stderr,"\nInvalid tag type found in structure item -> %s", p); + return(False); + } + + /* BitSize */ + if ( *p != ',' ) { + fprintf(stderr,"\nNo Bit size found in structure item -> %s", p ); + return(False); + } + *pBitOffset = (unsigned short)atoi( ++p ); + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + + /* BitOffset */ + if ( *p != ',' ) { + fprintf(stderr,"\nNo Bit offset found in structure item -> %s", p ); + return(False); + } + *pBitSize = (unsigned short)atoi( ++p ); + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + + /* Now convert stab type to COFF */ + if ( (*pType = GetCoffType( (unsigned short)StabType)) == 0 ) { + fprintf(stderr,"\nNo COFF type found for stab type %d", StabType ); + return( False); + } + if ( *++p == ';' ) /* Now eat last semicolon(s) */ + p++; + *pEnd = p; + + return( True ); +} +/****************************************************************************************/ + +int GetEnumTagItem( char *p, char **pEnd, char **pEnumName, int *pEnumValue ) { + + /* Enum Tag Item consists of -> member1:value,member2:value2,; */ + *pEnumName = p; + while ( *p && (*p != ':') ) p++; // locate colon + if ( *p != ':' ) { + fprintf(stderr,"\nNo colon found in enum item -> %s", *pEnumName); + return(False); + } + *p++ = 0; // Asciiz + *pEnumValue = atoi(p); + + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + if ( *p != ',' ) { + fprintf(stderr,"\nNo comma found after enum value -> %s", p ); + return(False); + } + if ( *++p ==';' ) + p++; /* eat last semicolon */ + *pEnd = p; + return( True ); +} + +/****************************************************************************************/ +int GetArrayType( char *p, char **pEnd, STABCOFFMAP *pMap, unsigned short *DerivedBits, int ExtraLevels ){ + + int MinIndex, MaxIndex, Result, Size, i; + char *pMinIndex, *pMaxIndex, *pType; + unsigned short Type; + + Result = True; + + pMinIndex = pMaxIndex = pType = 0; + while ( *p && (*p != ';') ) p++; /* find min index */ + pMinIndex = ++p; + while ( *p && (*p != ';') ) p++; /* find max index */ + pMaxIndex = ++p; + while ( *p && (*p != ';') ) p++; /* find type index */ + pType = ++p; + + /* bump the pointers to the digits */ + if ( !isdigit(*pMinIndex) ) + Result = False; + if ( !isdigit(*pMaxIndex) ) + Result = False; + if ( !isdigit(*pType) ) + Result = False; + /* Is syntax ok ? */ + if ( Result != True ) { + fprintf(stderr,"\nSyntax error on array parameters %s%s%s", pMinIndex, pMaxIndex, pType ); + return(False); + } + MinIndex = atoi(pMinIndex); + MaxIndex = atoi(pMaxIndex); + + if ( GetStabType( p, &Type, &p ) != True ) + return(False); + + if ( !SetupDefinedType( Type, pMap, DerivedBits, ExtraLevels ) ) + return( False ); + + /* Now update the size based on the indicies */ + Size = (MaxIndex - MinIndex) + 1; + pMap->ByteSize *= Size; + pMap->Line = ci->CurrentSourceLine; + /* add the dimension information */ + for ( i = 5; i >= 0; i-- ) { + if ( pMap->Dimensions[i] != 0 ) { + i++; + pMap->Dimensions[i] = Size; + break; + } + } + + *pEnd = p; + return(True); +} + +/****************************************************************************************/ +int GetStabType( char *p, unsigned short *pType, char **pEnd ) { + + STABCOFFMAP *pMap; + int extra, ok; + unsigned short derivedbits[6]; + unsigned short LStabType, RStabType; + char *pHigh, *pLow; + + + LStabType = atoi( p ); + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + + *pType = LStabType; + + if ( GetCoffType( LStabType ) != 0 ) { + *pEnd = p; + return(True); + } + if ( *p != '=' ) { + fprintf(stderr, "\nSyntax error in type assignment -> %s", p ); + return(False); + } + p++; + + /* Allocate space for new internal type */ + if ( !(pMap = (STABCOFFMAP *)AllocateListObject(&ci->ListOfTypes, sizeof(STABCOFFMAP)) ) ) { + fprintf(stderr, "\nOut of memory allocating type info!"); + return(False); + } + pMap->StabType = LStabType; + + /* process items to right of equals */ + for ( extra = 0; extra < 6; extra++ ) { + + if ( isdigit( *p ) ) { + /* Finally found base type, try to terminate loop */ + GetStabType( p, &RStabType, &p ); + // RStabType = atoi( p ); + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + if ( SetupDefinedType( RStabType, pMap, &derivedbits[0], extra ) != True ) + return( False ); + break; + } else if ( *p == 'a' ) { + derivedbits[extra] = DT_ARY; + p++; + /* Calculate size */ + /* Since type assignment will be made we need to set extra bits here */ + extra++; + /* =ar1;MinIndex;MaxIndex;BaseType */ + if ( GetArrayType( p, &p, pMap, &derivedbits[0], extra ) != True ) + return(False); + break; + + } else if ( *p == 'f' ) { + derivedbits[extra] = DT_FCN; + p++; + } else if ( *p == '*' ) { + derivedbits[extra] = DT_PTR; + p++; + } else if ( *p == 'r' ) { + // if( LStabType < 15 ) + // ok = GetInternalType( pString, pMap ); /* internal types not yet installed */ + // else + while ( *p && (*p != ';' ) ) p++; + pLow = p++; + while ( *p && (*p != ';' ) ) p++; + pHigh = p++; + ok = GetSubRangeType( LStabType, pMap, pLow, pHigh ); + if ( ok != True ) + return(False); + while ( *p && (*p != ';' ) ) p++; /* find end of range */ + p++; + break; + } else { + fprintf(stderr, "\nUnrecognized Type modifier %c!", *p ); + return(False); + } + } + *pEnd = p; /* Update return pointer */ + + return(True); +} + + +/****************************************************************************************/ +int stab_add_tag_type( char *pName, char *pString ){ + + int SymbolIndex, StabType, TotalSize, n, EnumValue; + unsigned short TagType, ItemType, BitOffset, BitSize; + char *p; + struct syment* pEntry; + union auxent *pAux; + STABCOFFMAP *pMap; + + /* We arrived here due to :T defining either a structure, union or enumeration */ + /* store the basic type as for internals and emit coff structures for debugging */ + /* .stabs "stag:T17=s2i:1,0,8;c:2,8,8;;",128,0,0,0 */ + /* .stabs "2:T18=u2a:2,0,8;b:1,0,8;c:6,0,16;;",128,0,0,0 */ + /* .stabs "1:T19=eenum1:1,enum2:2,enum3:3,;",128,0,0,0 */ + /* we don't care about the name */ + + + /* check for bogus errors */ + if ( !pName || !pString ) { + fprintf(stderr,"\nInvalid .stabs type format - no information!"); + return(False); + } + + p = pString; + /* Stab Type - convert to Coff type at end (after inline assignments */ + if ( (StabType = (unsigned short)atoi(p)) == 0 ) { + fprintf(stderr,"\nInvalid .stabs type format - no information! - > %s", p ); + return(False); + } + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + if ( *p != '=' ) { + fprintf(stderr,"\nInvalid .stabs type format - no equals - > %s", p ); + return(False); + } + SymbolIndex = ci->ListOfSymbols.TotalItems; + if ( ( pEntry = (struct syment*)AllocateTwoListObjects( &ci->ListOfGlobals, sizeof(struct syment) * 2 ) ) == 0 ) { + fprintf(stderr, "\nOut of memory allocating symbol tag entries"); + return(False); + } + /* Prepare Tag Header */ + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pString ); + return(False); + } + if ( !(pMap = (STABCOFFMAP *)AllocateListObject(&ci->ListOfTypes, sizeof(STABCOFFMAP)) ) ) { + fprintf(stderr, "\nOut of memory allocating type info!"); + return(False); + } + pMap->StabType = StabType; + pEntry->n_value = 0; + pEntry->n_scnum = N_DEBUG; + pEntry->n_numaux = 1; + if ( *++p == 's' ) { + TagType = pEntry->n_type = pMap->CoffType = T_STRUCT; + pEntry->n_sclass = C_STRTAG; + TotalSize = (unsigned short)atoi(++p); + } else if ( *p == 'u' ) { + TagType = pEntry->n_type = pMap->CoffType = T_UNION; + pEntry->n_sclass = C_UNTAG; + TotalSize = (unsigned short)atoi(++p); + } else if ( *p == 'e' ) { + TagType = pEntry->n_type = pMap->CoffType = T_ENUM; + pEntry->n_sclass = C_ENTAG; + TotalSize = FundamentalTypes[T_INT].Size; /* use size of int for enums */ + } else { + fprintf(stderr,"\nUnknown tag type -> %s", p ); + return(False); + } + while ( *p && (*p >= '0') && (*p <= '9') ) p++; // locate end of digits + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_tagndx = SymbolIndex; + pAux->x_sym.x_misc.x_lnsz.x_size = TotalSize; + + /* update our local knowledge of tag type */ + pMap->CoffType = TagType; + pMap->ByteSize = TotalSize; + pMap->Line = ci->CurrentSourceLine; + + /* Process the items until the end of the line */ + while ( *pName ) { + + if ( ( pEntry = (struct syment*)AllocateTwoListObjects( &ci->ListOfGlobals, sizeof(struct syment) * 2 ) ) == 0 ) { + fprintf(stderr, "\nOut of memory allocating symbol tag member entries"); + return(False); + } + + if ( TagType == T_STRUCT ) { + if ( GetStructUnionTagItem( p, &p, &pName, &ItemType, &BitOffset, &BitSize) != True ) { + return(False); + } + pEntry->n_value = BitOffset/8; + pEntry->n_type = ItemType; + pEntry->n_sclass = C_MOS; + } else if ( TagType == T_UNION ) { + if ( GetStructUnionTagItem( p, &p, &pName, &ItemType, &BitOffset, &BitSize) != True ) { + return(False); + } + pEntry->n_value = BitOffset/8; + pEntry->n_type = ItemType; + pEntry->n_sclass = C_MOU; + } else { /* T_ENUM */ + if ( GetEnumTagItem( p, &p, &pName, &EnumValue ) != True ) { + return(False); + } + pEntry->n_value = EnumValue; + pEntry->n_type = TotalSize; + pEntry->n_sclass = C_MOE; + } + + /* Prepare Common Tag Header items */ + if ( (n = AddNameToEntry( pName, pEntry )) == 0 ) { + fprintf(stderr,"\nOut of memory adding local %s to string table", pString ); + return(False); + } + pEntry->n_scnum = N_ABS; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_tagndx = SymbolIndex; + pAux->x_sym.x_misc.x_lnsz.x_size = TotalSize; + pName = p; + } + + /* End of Structures/Unions/Enumberations */ + if ( ( pEntry = (struct syment*)AllocateTwoListObjects( &ci->ListOfGlobals, sizeof(struct syment) * 2 ) ) == 0 ) { + fprintf(stderr, "\nOut of memory allocating special headers for structure!"); + return(False); + } + strcpy( pEntry->n_name, ".eos" ); + pEntry->n_value = TotalSize; + pEntry->n_scnum = N_ABS; + pEntry->n_type = 0; + pEntry->n_sclass = C_EOS; + pEntry->n_numaux = 1; + pEntry++; /* point to aux entry */ + pAux = (union auxent *)pEntry; + pAux->x_sym.x_tagndx = SymbolIndex; /* point to the .bf entry index */ + pAux->x_sym.x_misc.x_lnsz.x_size = TotalSize; + + return(True); +} + +/****************************************************************************************/ +int SetupDefinedType( unsigned short Type, STABCOFFMAP *pMap, unsigned short *DerivedBits, int ExtraLevels ){ + + int i, Dlimit, Dstart; + unsigned short StabType; + + StabType = pMap->StabType; /* save the new type we found earlier */ + if ( CopyStabCoffMap( Type, pMap ) != True ) { + fprintf(stderr, "\nCould not find defined type %d", Type ); + return(False); + } + pMap->StabType = StabType; /* save the new type we found earlier */ + + /* Determine existing derived types for base class */ + for ( i = 0; i < 6; i++ ) { + if ( (pMap->CoffType & ( 3 << (4 + i + i))) == 0 ) + break; + } + Dstart = i; + Dlimit = i + ExtraLevels; + if ( (Dlimit) >= 6 ) { + fprintf(stderr, "\nStab Type %d has too many derived (%d) types!", pMap->StabType, Dlimit ); + return(False); + } + /* Add the new derived levels */ + for ( ; i < Dlimit; i++ ) { + pMap->CoffType |= ( ( DerivedBits[i - Dstart] & 3) << (4 + i + i) ); /* add in the derived bits */ + } + return(True); +} + +/****************************************************************************************/ +int GetArrayDefinitions( STABCOFFMAP *pMap , char *pMinIndex, char *pMaxIndex, char *pType, unsigned short *DerivedBits, int ExtraLevels ){ + + int MinIndex, MaxIndex, Result, Size, i; + unsigned short Type; + + Result = True; + if ( (*pMinIndex != ';') || (*pMaxIndex != ';') || (*pType != ';') ) + Result = False; + /* bump the pointers to the digits */ + pMinIndex++; + if ( !isdigit(*pMinIndex) ) + Result = False; + pMaxIndex++; + if ( !isdigit(*pMaxIndex) ) + Result = False; + pType++; + if ( !isdigit(*pType) ) + Result = False; + /* Is syntax ok ? */ + if ( Result != True ) { + fprintf(stderr,"\nSyntax error on array parameters %s%s%s", pMinIndex, pMaxIndex, pType ); + return(False); + } + MinIndex = atoi(pMinIndex); + MaxIndex = atoi(pMaxIndex); + Type = (unsigned short)atoi(pType); + if ( SetupDefinedType( Type, pMap, DerivedBits, ExtraLevels ) != True ) + return( False ); + /* Now update the size based on the indicies */ + Size = (MaxIndex - MinIndex) + 1; + pMap->ByteSize *= Size; + pMap->Line = ci->CurrentSourceLine; + /* add the dimension information */ + for ( i = 5; i >= 0; i-- ) { + if ( pMap->Dimensions[i] != 0 ) { + i++; + pMap->Dimensions[i] = Size; + break; + } + } + return(True); +} + +/****************************************************************************************/ + +int GetInternalType( char *pName, STABCOFFMAP *pMap ){ + + int n, found, i; + + if ( !pName ) { + return(False); + } + + found = False; + n = strlen(pName); + /* Find out if it is a local type */ + for (i = 0; FundamentalTypes[i].pString != 0; i++) { + if ( !strncmp(pName, FundamentalTypes[i].pString, n) ) { + /* found an internal type */ + pMap->CoffType = FundamentalTypes[i].Type; + pMap->ByteSize = FundamentalTypes[i].Size; + found = True; + } + } + return(found); +} + +/****************************************************************************************/ +int GetSubRangeType( unsigned short Type, STABCOFFMAP *pMap , char *pLow, char *pHigh ){ + + int Result, i; + long High, Low; + unsigned long Test; + + Result = True; + if ( (*pLow != ';') || (*pHigh != ';') || (Type <= 0) ) + Result = False; + + /* Is syntax ok ? */ + if ( Result != True ) { + fprintf(stderr,"\nSyntax error on sub range parameters!" ); + return(False); + } + Low = atol(++pLow); + High = atol(++pHigh); + + /* Special handling of type void */ + if ( (Low == 0) && (High == 0) ) { + /* Declare type void */ + pMap->ByteSize =0; + pMap->CoffType = T_VOID; + pMap->Line = ci->CurrentSourceLine; + return(True); + } + + if ( (pMap->CoffType = GetCoffType( Type )) != 0 ) { + pMap->ByteSize = GetCoffTypeSize( Type ); + } else { + /* Try to base everything off integer */ + pMap->ByteSize = FundamentalTypes[T_INT].Size; + } + + /* Now calculate the byte size */ + if ( High == 0 ) { + pMap->ByteSize = (unsigned short)Low; /* floating point */ + } else { + if ( Low == 0 ) { + /* Unsigned */ + Test = (unsigned long)High; + } else if ( Low < 0 ) { + /* signed */ + Test = (unsigned long)High << 1; + } else { + if ( Low <= High ) + Test = (unsigned long)High; + else + Test = (unsigned long)Low; + } + if ( pMap->ByteSize == 0 ) { + fprintf(stderr,"\nType Range Error 1, need previous type %d size!", pMap->CoffType ); + return(False); + } + for ( i = 0; i < sizeof(unsigned long); i++ ) { + if ( !(Test & (0xff << (i * 8))) ) + break; + } + pMap->ByteSize = i; + } + /* Now determine the best fit based on byte size, compare against IAR Compiler */ + if ( pMap->ByteSize == 1 ) { + if ( Low < 0 ) + pMap->CoffType = T_CHAR; + else + pMap->CoffType = T_UCHAR; + } else if ( pMap->ByteSize == 2 ) { + if ( Low < 0 ) + pMap->CoffType = T_INT; + else + pMap->CoffType = T_UINT; + } else if ( pMap->ByteSize == 4 ) { + if ( Low == 0 ) + pMap->CoffType = T_FLOAT; + if ( Low < 0 ) + pMap->CoffType = T_LONG; + else + pMap->CoffType = T_ULONG; + } else { + fprintf(stderr,"\nGetSubRangeType failure - byte size %d", pMap->ByteSize ); + return(False); + } + return(True); +} + +/****************************************************************************************/ +int CopyStabCoffMap( unsigned short StabType, STABCOFFMAP *pMap ){ + + STABCOFFMAP *p; + + for ( p = FindFirstListObject( &ci->ListOfTypes ); p != 0; p = FindNextListObject( &ci->ListOfTypes) ) { + if ( p->StabType == StabType ) { + memcpy( pMap, p, sizeof(STABCOFFMAP) ); + return(True); + } + } + return( False ); /* Nothing found */ +} + +/****************************************************************************************/ +unsigned short GetCoffType( unsigned short StabType ){ + + STABCOFFMAP *p; + + for ( p = FindFirstListObject( &ci->ListOfTypes ); p != 0; p = FindNextListObject( &ci->ListOfTypes) ) { + if ( p->StabType == StabType ) + return( p->CoffType ); + } + return( 0 ); /* Nothing found */ +} + +/****************************************************************************************/ +unsigned short GetCoffTypeSize( unsigned short StabType ){ + + STABCOFFMAP *p; + + for ( p = FindFirstListObject( &ci->ListOfTypes ); p != 0; p = FindNextListObject( &ci->ListOfTypes) ) { + if ( p->StabType == StabType ) + return( p->ByteSize ); + } + return( 0 ); /* Nothing found */ +} + + +/****************************************************************************************/ +int GetDigitLength( char *p ){ + + int i; + + if ( p == 0 ) + return(0); + + for ( i = 0; (*p != 0) && ( *p >= '0' ) && ( *p <= '9' ); i++ ); + + return( i ); + +} + +/****************************************************************************************/ +int GetStringDelimiters( char *pString, char **pTokens, int MaxTokens ){ + + int i; + char *p; + + p = pString; + + if ( !p ) + return( 0 ); + + for ( i = 0; i < MaxTokens; i++ ) { + while ( True ) { + if ( (*p == ':') || (*p == ';') || (*p == '=') || (*p == ',') || (*p == '"') || (*p == 0 ) ) { + *(pTokens + i) = p; /* Remember this location */ + p++; + if ( *p == 0 ) + return( i ); + break; + } + p++; + } + } + return( i ); +} + +/****************************************************************************************/ +int IsTypeArray( unsigned short CoffType ){ + + int Result; + + Result = False; + + if ( (CoffType & (DT_ARY << 4 )) == (DT_ARY << 4 ) ) + Result = True; + if ( (CoffType & (DT_ARY << 6 )) == (DT_ARY << 6 ) ) + Result = True; + if ( (CoffType & (DT_ARY << 8 )) == (DT_ARY << 8 ) ) + Result = True; + if ( (CoffType & (DT_ARY << 10 )) == (DT_ARY << 10 ) ) + Result = True; + if ( (CoffType & (DT_ARY << 12 )) == (DT_ARY << 12 ) ) + Result = True; + if ( (CoffType & (DT_ARY << 14 )) == (DT_ARY << 14 ) ) + Result = True; + + return(Result); +} + +/****************************************************************************************/ +void AddArrayAuxInfo( union auxent *pAux, unsigned short SymbolIndex, STABCOFFMAP *pMap ){ + + int i; + + pAux->x_sym.x_tagndx = SymbolIndex; /* point to the .bf entry index */ + pAux->x_sym.x_misc.x_lnsz.x_lnno = pMap->Line; + pAux->x_sym.x_misc.x_lnsz.x_size = pMap->ByteSize; + for ( i = 0; i < 4; i++ ) + pAux->x_sym.x_fcnary.x_ary.x_dimen[i] = pMap->Dimensions[i]; +} + +/****************************************************************************************/ +int AddNameToEntry( char *pName, struct syment *pEntry ) { + + int n; + char *p; + + n = strlen( pName ); /* see if it's 8 bytes or less */ + if ( n <= 8 ) { + strncpy( pEntry->n_name, pName, 8 ); + } else { + /* point to current offset in string table */ + pEntry->n_offset = ci->ListOfStrings.TotalBytes; + /* Allocate string table entry */ + if ( (p = (char *)AllocateListObject( &ci->ListOfStrings, n + 1 )) == 0 ) { + return(0); + } + strcpy( p, pName ); + } + return(n); /* return size of string */ +} + +/****************************************************************************************/ + +char *SkipPastDigits( char *p ){ + + if ( !p ) + return(p); +/* if ( *p == 0 ); */ /* JEG 5-01-03 */ + if ( *p == 0 ) + return(p); /* This line s/b indented JEG */ + for ( p--; (*p >= '0') && (*p <= '9') && (*p != 0); p-- ); + return(p); +} + +/****************************************************************************************/ + +/****************************************************************************************/ +/****************************************************************************************/ +/* List management routines */ +/****************************************************************************************/ +/****************************************************************************************/ + +/****************************************************************************************/ + +/****************************************************************************************/ +void InitializeList( LISTNODEHEAD *pHead ){ + + pHead->Node.Next = &pHead->Node; + pHead->Node.Last = &pHead->Node; + pHead->TotalBytes = 0; + pHead->TotalItems = 0; + pHead->current = &pHead->Node; + return; +} + +/****************************************************************************************/ + +void *AllocateTwoListObjects( LISTNODEHEAD *pHead, int size ){ + + void *p; + + if ( (p = AllocateListObject( pHead, size ) ) ) + pHead->TotalItems++; /* already incremented once in addtolist */ + return( p ); +} + +/****************************************************************************************/ +void *AllocateListObject( LISTNODEHEAD *pHead, int size ){ + + void *pObject; + + LISTNODE *pNode; + + if ( (pObject = calloc( 1, size )) != 0 ) { + if ( !(pNode = AddListObject( pHead, pObject, size )) ) { + free( pObject ); + pObject = 0; + } + } + return( pObject ); +} + +/****************************************************************************************/ +LISTNODE *AddListObject(LISTNODEHEAD *pHead, void *pObject, int size ){ + + LISTNODE *pNode; + + if ( (pNode = calloc( 1, sizeof(LISTNODE) )) != 0 ) { + pNode->pObject = pObject; + pNode->Size = size; + pNode->FileNumber = ci->CurrentFileNumber; + AddNodeToList( pHead, pNode ); + } + return( pNode ); +} + +/****************************************************************************************/ +LISTNODE *AllocateListNode( void *pObject, int size ){ + + LISTNODE *pNew; + + if ( (pNew = calloc( 1, sizeof( LISTNODE ) ) ) != 0 ) { + /* Then we initialize the node */ + pNew->pObject = pObject; + pNew->Size = size; + pNew->FileNumber = ci->CurrentFileNumber; + } + return(pNew); +} + +/****************************************************************************************/ +void AddNodeToList( LISTNODEHEAD *pHead, LISTNODE *pNode ){ + + LISTNODE *p; + + p = &pHead->Node; + + pNode->Next = p->Last->Next; + p->Last->Next = pNode; + pNode->Last = p->Last; + p->Last = pNode; + + /* and update current size of data contained in the list */ + pHead->TotalBytes += pNode->Size; + pHead->TotalItems++; +} + +/****************************************************************************************/ +void RemoveNodeFromList( LISTNODEHEAD *pHead, LISTNODE *pNode ){ + + pNode->Last->Next = pNode->Next; + pNode->Next->Last = pNode->Last; + + pHead->TotalBytes -= pNode->Size; + pHead->TotalItems--; +} + + +/****************************************************************************************/ +void *FindFirstListObject( LISTNODEHEAD *pHead ){ + + if ( pHead->Node.Next == &pHead->Node ) + return(0); /* Nothing in list */ + + pHead->current = pHead->Node.Next; + return( pHead->current->pObject ); +} +/****************************************************************************************/ +void *FindNextListObject( LISTNODEHEAD *pHead ){ + + if ( pHead->current->Next == &pHead->Node ) + return( 0 ); + + pHead->current = pHead->current->Next; + + return( pHead->current->pObject ); +} +/****************************************************************************************/ + +LISTNODE *GetCurrentNode( LISTNODEHEAD *pHead ){ + + return( pHead->current ); +} + +/****************************************************************************************/ +void *GetCurrentListObject( LISTNODEHEAD *pHead ){ + + return( pHead->current->pObject ); +} + + +/****************************************************************************************/ +void *FindLastListObject( LISTNODEHEAD *pHead ){ + + if ( pHead->Node.Last == &pHead->Node ) + return(0); /* Nothing in list */ + + pHead->current = pHead->Node.Last; + return( pHead->current->pObject ); +} +/****************************************************************************************/ +void *FindNextLastListObject( LISTNODEHEAD *pHead ){ + + if ( pHead->current->Last == &pHead->Node ) + return( 0 ); + + pHead->current = pHead->current->Last; + + return( pHead->current->pObject ); +} + +/****************************************************************************************/ + +void FreeList( LISTNODEHEAD *pHead ){ + + LISTNODE *pNode; + + for ( pNode = pHead->Node.Last; pNode->Next != &pHead->Node; pNode = pHead->Node.Last ) { + + RemoveNodeFromList( pHead, pNode ); + free( pNode->pObject ); + free( pNode ); + } + pHead->TotalBytes = 0; + pHead->TotalItems = 0; + pHead->current = &pHead->Node; +} +/****************************************************************************************/ + + diff --git a/contrib/toolchain/avra/src/coff.h b/contrib/toolchain/avra/src/coff.h new file mode 100644 index 000000000..e33e08469 --- /dev/null +++ b/contrib/toolchain/avra/src/coff.h @@ -0,0 +1,403 @@ +// +// coff.h - Common Object File Format (COFF) support +// +// This file was developed for the avra assembler in order to produce COFF output files +// for use with the Atmel AVR Studio. The Lean C Compiler (LCC) debugging stabs +// output was used as input to the assembler. +// +// This software has absolutely no warrantee! The money you paid for this will be +// promptly refunded if not fully satisfied. +// +// Beta release 1/20/2000 by Bob Harris +// +// This software has not been fully tested and probably has a few software deficiencies. +// Some software support may be possible by sending a problem description report to +// rth@mclean.sparta.com + +#define MAGIC_NUMBER_AVR 0xa12 + +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */ +#define N_ROSYM 0x2c /* ro_data objects */ +#define N_OBJ 0x38 /* object file path or name */ +#define N_OPT 0x3c /* compiler options */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_FLINE 0x4c /* function start.end */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_ENDM 0x62 /* last stab emitted for module */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_BINCL 0x82 /* header file: name,,0,0,0 */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_EINCL 0xa2 /* end of include file */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_EXCL 0xc2 /* excluded include file */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + + +/* + * Type of a symbol, in low N bits of the word + */ +#define T_NULL 0 +#define T_VOID 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration*/ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ +#define T_LNGDBL 16 /* long double */ + +/* + * derived types, in n_type +*/ +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +struct external_filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + unsigned long f_timdat; /* time & date stamp */ + unsigned long f_symptr; /* file pointer to symtab */ + unsigned long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + +/*********************************************************************/ +struct external_scnhdr { + char s_name[8]; /* section name */ + unsigned long s_paddr; /* physical address, aliased s_nlib */ + unsigned long s_vaddr; /* virtual address */ + unsigned long s_size; /* section size */ + unsigned long s_scnptr; /* file ptr to raw data for section */ + unsigned long s_relptr; /* file ptr to relocation */ + unsigned long s_lnnoptr; /* file ptr to line numbers */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of line number entries*/ + unsigned long s_flags; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/* + * s_flags "type" + */ +#define STYP_TEXT (0x0020) /* section contains text only */ +#define STYP_DATA (0x0040) /* section contains data only */ +#define STYP_BSS (0x0080) /* section contains bss only */ + + +/*********************************************************************/ + +struct lineno +{ + union + { + long l_symndx; /* symtbl index of func name */ + long l_paddr; /* paddr of line number */ + } l_addr; + unsigned short l_lnno; /* line number */ +}; + +#define LINENO struct lineno +#define LINESZ 6 + + + +#define N_UNDEF ((short)0) /* undefined symbol */ +#define N_ABS ((short)-1) /* value of symbol is absolute */ +#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */ + +/********************** STORAGE CLASSES **********************/ + +/* This used to be defined as -1, but now n_sclass is unsigned. */ +#define C_EFCN 0xff /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib */ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct syment +{ + union + { + char _n_name[E_SYMNMLEN]; /* symbol name*/ + struct + { + long _n_zeroes; /* symbol name */ + + long _n_offset; /* location in string table */ + } _n_n; + char *_n_nptr[2]; /* allows overlaying */ + } _n; + unsigned long n_value; /* value of symbol */ + + short n_scnum; /* section number */ + + unsigned short n_type; /* type and derived */ + + char n_sclass; /* storage class */ + + char n_numaux; /* number of aux entries */ +}; + +#define n_name _n._n_name +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset +#define n_nptr _n._n_nptr[1] + +#define SYMNMLEN 8 +#define SYMESZ 18 /* size of a symbol table entry */ + +union auxent +{ + struct + { + long x_tagndx; + union + { + struct + { + unsigned short x_lnno; + unsigned short x_size; + } x_lnsz; + long x_fsize; + } x_misc; + union + { + struct + { + long x_lnnoptr; + long x_endndx; + } x_fcn; + struct + { + unsigned short x_dimen[E_DIMNUM]; + } x_ary; + } x_fcnary; + unsigned short x_tvndx; + } x_sym; + union + { + char x_fname[E_FILNMLEN]; + struct { + unsigned long x_zeroes; + unsigned long x_offset; + } x_n; + } x_file; + struct + { + long x_scnlen; + unsigned short x_nreloc; + unsigned short x_nlinno; + } x_scn; + struct + { + long x_tvfill; + unsigned short x_tvlen; + unsigned short x_tvran[2]; + } x_tv; +}; + +#define FILNMLEN 14 +#define DIMNUM 4 +#define AUXENT union auxent +#define AUXESZ 18 + + +/* Coff additions */ +typedef struct ListNodeTag{ + struct ListNodeTag *Next; /* Double Linked List */ + struct ListNodeTag *Last; /* Double Linked List */ + void *pObject; /* points to list object */ + unsigned long Size; + int FileNumber; /* corresponds to individual file(s) */ +} LISTNODE; + +//#define LISTNODE struct ListNodeTag; + +typedef struct ListNodeHeadTag { + LISTNODE Node; +// struct ListNodeTag *Next; /* Double Linked List */ +// struct ListNodeTag *Last; /* Double Linked List */ + int TotalBytes; /* size of allocated object(s) */ + int TotalItems; /* number of allocated objects */ + LISTNODE *current; /* pointer for FindFirst/FindNext */ +} LISTNODEHEAD ; + + +typedef struct { + unsigned short StabType; + unsigned short CoffType; + unsigned short ByteSize; + unsigned short Line; /* used by arrays */ + unsigned short Dimensions[6]; /* used by arrays */ +} STABCOFFMAP; + +struct coff_info { + + int CurrentFileNumber; + int FunctionStartLine; /* used in Line number table */ + int CurrentSourceLine; + + /* Internal */ + unsigned char *pRomMemory; /* 16 bit wide words/addresses */ + unsigned char *pEEPRomMemory; /* 8 bit wide words/addresses */ + int MaxRomAddress; + int MaxEepromAddress; + int NeedLineNumberFixup; + int GlobalStartAddress; + int GlobalEndAddress; + LISTNODEHEAD ListOfSplitLines; + + /* External */ + struct external_filehdr FileHeader; /* Only one of these per output file */ + LISTNODEHEAD ListOfSectionHeaders; /* .text, .bss */ + LISTNODEHEAD ListOfRawData; /* Program, EEPROM */ + LISTNODEHEAD ListOfRelocations; /* Not used now */ + LISTNODEHEAD ListOfLineNumbers; + LISTNODEHEAD ListOfSymbols; + LISTNODEHEAD ListOfGlobals; + LISTNODEHEAD ListOfSpecials; + LISTNODEHEAD ListOfUndefined; + LISTNODEHEAD ListOfStrings; + LISTNODEHEAD ListOfTypes; +}; + +#if 0 /* defined in avra.h */ + +FILE *open_coff_file(struct prog_info *pi, char *filename); +void write_coff_file(struct prog_info *pi); +void write_coff_eeprom( struct prog_info *pi, int address, unsigned char data); +void write_coff_program( struct prog_info *pi, int address, unsigned char data); +void close_coff_file(struct prog_info *pi, FILE *fp); +int parse_stabs( struct prog_info *pi, char *p ); +int parse_stabn( struct prog_info *pi, char *p ); + +#endif + +/**************************************************************/ +/*********** Internal Routines ********************************/ +/**************************************************************/ +int stab_add_lineno( struct prog_info *pi, int LineNumber, char *pLabel, char *pFunction ); +int stab_add_lbracket( struct prog_info *pi, int Level, char *pLabel, char *pFunction ); +int stab_add_rbracket( struct prog_info *pi, int Level, char *pLabel, char *pFunction ); +int stab_add_filename( char *pName, char *pLabel ); +int stab_add_function( struct prog_info *pi, char *pName, char *pLabel ); +int stab_add_global( struct prog_info *pi, char *pName, char *pType ); +int stab_add_local( struct prog_info *pi, char *pName, char *pType, char *pOffset ); +int stab_add_parameter_symbol( struct prog_info *pi, char *pName, char *pType, char *pOffset ); +int stab_add_static_symbol( struct prog_info *pi, char *pName, char *pType, char *pLabel ); +int stab_add_local_register( struct prog_info *pi, char *pName, char *pType, char *pRegister ); +int stab_add_local_type( char *pString, char *pType ); +int stab_add_tag_type( char *pName, char *pDesciptor ); + +int GetStabType( char *p, unsigned short *pType, char **pEnd ); +int AddNameToEntry( char *pName, struct syment *pEntry ); +int GetArrayType( char *p, char **pEnd, STABCOFFMAP *pMap, unsigned short *DerivedBits, int ExtraLevels ); +int GetEnumTagItem( char *p, char **pEnd, char **pEnumName, int *pEnumValue ); +int GetStructUnionTagItem( char *p, char **pEnd, char **pName, unsigned short *pType, unsigned short *pBitOffset, unsigned short *pBitSize); +int GetStringDelimiters( char *pString, char **pTokens, int MaxTokens ); +int SetupDefinedType( unsigned short Type, STABCOFFMAP *pMap, unsigned short *DerivedBits, int ExtraLevels ); +int GetArrayDefinitions( STABCOFFMAP *pMap , char *pMinIndex, char *pMaxIndex, char *pType, unsigned short *DerivedBits, int ExtraLevels ); +int GetInternalType( char *pName, STABCOFFMAP *pMap ); +unsigned short GetCoffType( unsigned short StabType ); +unsigned short GetCoffTypeSize( unsigned short StabType ); +int CopyStabCoffMap( unsigned short StabType, STABCOFFMAP *pMap ); +int IsTypeArray( unsigned short CoffType ); +void AddArrayAuxInfo( union auxent *pAux, unsigned short SymbolIndex, STABCOFFMAP *pMap ); +int GetSubRangeType( unsigned short Type, STABCOFFMAP *pMap , char *pLow, char *pHigh ); +char *SkipPastDigits( char *p ); +int GetDigitLength( char *p ); + +/****************************************************************************************/ +/* List management routines */ +/****************************************************************************************/ + +void InitializeList( LISTNODEHEAD *pNode ); +void *AllocateTwoListObjects( LISTNODEHEAD *pHead, int size ); +void *AllocateListObject( LISTNODEHEAD *pHead, int size ); +LISTNODE *AllocateListNode( void *pObject, int size ); +void AddNodeToList( LISTNODEHEAD *pHead, LISTNODE *pNode ); +void *FindFirstListObject( LISTNODEHEAD *pHead ); +void *FindNextListObject( LISTNODEHEAD *pHead ); +LISTNODE *GetCurrentNode( LISTNODEHEAD *pHead ); +void *GetCurrentListObject( LISTNODEHEAD *pHead ); +void *FindLastListObject( LISTNODEHEAD *pHead ); +void *FindNextLastListObject( LISTNODEHEAD *pHead ); +void FreeList( LISTNODEHEAD *pHead ); +LISTNODE *AddListObject(LISTNODEHEAD *pHead, void *pObject, int size ); + diff --git a/contrib/toolchain/avra/src/device.c b/contrib/toolchain/avra/src/device.c new file mode 100644 index 000000000..d94e81f29 --- /dev/null +++ b/contrib/toolchain/avra/src/device.c @@ -0,0 +1,214 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2010 Jon Anders Haugum, Tobias Weber, Jerry Jacobs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + * + */ + + +#include +#include + +#include "misc.h" +#include "avra.h" +#include "device.h" + +#define DEV_VAR "__DEVICE__" // Device var name +#define FLASH_VAR "__FLASH_SIZE__" // Flash size var name +#define EEPROM_VAR "__EEPROM_SIZE__" // EEPROM size var name +#define RAM_VAR "__RAM_SIZE__" // RAM size var name +#define DEV_PREFIX "__" // Device name prefix +#define DEV_SUFFIX "__" // Device name suffix +#define DEF_DEV_NAME "DEFAULT" // Default device name (without prefix/suffix) +#define MAX_DEV_NAME 32 // Max device name length + + +struct device device_list[] = +{ + /* Name, Flash(words),RAM start, RAM size, EEPROM, flags */ + { NULL, 4194304, 0x60, 8388608, 65536, 0}, // Total instructions: 137 + /* ATtiny Series */ + // ATtiny4 + // ATtiny5 + // ATtiny9 + { "ATtiny10", 512, 0x00, 0, 0, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny11", 512, 0x00, 0, 0, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny12", 512, 0x00, 0, 64, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny13", 512, 0x60, 64, 64, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny13A", 512, 0x60, 64, 64, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny15", 512, 0x00, 0, 64, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + // ATtiny20 + { "ATtiny22", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny24", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny24A", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny25", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny26", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny28", 1024, 0x00, 0, 0, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + // ATtiny43U + { "ATtiny44", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny44A", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny45", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny84", 4096, 0x60, 512, 512, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny85", 4096, 0x60, 512, 512, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + // ATtiny87 + // ATtiny167 + // ATtiny261A + // ATtiny461A + // ATtiny861A + { "ATtiny2313", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny2313A", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + { "ATtiny4313", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_ELPM|DF_NO_ESPM|DF_NO_EICALL|DF_NO_EIJMP}, + /* AT90 series */ + { "AT90S1200", 512, 0x00, 0, 64, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, // 137 - MUL(6) - JMP(2) - TINY(10) + { "AT90S2313", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S2323", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S2333", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S2343", 1024, 0x60, 128, 128, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S4414", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S4433", 2048, 0x60, 128, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S4434", 2048, 0x60, 256, 256, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S8515", 4096, 0x60, 512, 512, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, // 137 - MUL(6) - JMP(2) - LPM_X(2) - ELPM(3) - SPM - ESPM - MOVW - BREAK - EICALL - EIJMP = 118 + { "AT90C8534", 4096, 0x60, 256, 512, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + { "AT90S8535", 4096, 0x60, 512, 512, DF_NO_MUL|DF_NO_JMP|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP}, + /* AT90USB series*/ + // AT90USB168 + // AT90USB1287 + /* ATmega series */ + { "ATmega8", 4096, 0x60, 1024, 512, DF_NO_JMP|DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega161", 8192, 0x60, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega162", 8192, 0x100, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega163", 8192, 0x60, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega16", 8192, 0x60, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega323", 16384, 0x60, 2048, 1024, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, // 137 - EICALL - EIJMP - ELPM(3) - ESPM = 131 (Data sheet says 130 but it's wrong) + { "ATmega328P", 16384, 0x100, 2048, 1024, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega32", 16384, 0x60, 2048, 1024, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega603", 32768, 0x60, 4096, 2048, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_MUL|DF_NO_MOVW|DF_NO_LPM_X|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_BREAK}, + { "ATmega103", 65536, 0x60, 4096, 4096, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_MUL|DF_NO_MOVW|DF_NO_LPM_X|DF_NO_ELPM_X|DF_NO_SPM|DF_NO_ESPM|DF_NO_BREAK}, // 137 - EICALL - EIJMP - MUL(6) - MOVW - LPM_X(2) - ELPM_X(2) - SPM - ESPM - BREAK = 121 + { "ATmega104", 65536, 0x60, 4096, 4096, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ESPM}, // Old name for mega128 + { "ATmega128", 65536, 0x100, 4096, 4096, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ESPM}, // 137 - EICALL - EIJMP - ESPM = 134 (Data sheet says 133 but it's wrong) + { "ATmega48", 2048, 0x100, 512, 256, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega88", 4096, 0x100, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega168", 8192, 0x100, 1024, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + { "ATmega8515", 8192, 0x60, 512, 512, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_ESPM}, + /* Other */ + { "AT94K", 8192, 0x60, 16384, 0, DF_NO_EICALL|DF_NO_EIJMP|DF_NO_ELPM|DF_NO_SPM|DF_NO_ESPM|DF_NO_BREAK}, // 137 - EICALL - EIJMP - ELPM(3) - SPM - ESPM - BREAK = 129 + {NULL, 0, 0, 0, 0} +}; + +static int LastDevice=0; + +/*********************************************/ +/* Define vars for device in LastDevice */ +/*********************************************/ + +static void def_dev(struct prog_info *pi) +{ + def_var(pi,DEV_VAR,LastDevice); + def_var(pi,FLASH_VAR,device_list[LastDevice].flash_size); + def_var(pi,EEPROM_VAR,device_list[LastDevice].eeprom_size); + def_var(pi,RAM_VAR,device_list[LastDevice].ram_size); +} + +struct device *get_device(struct prog_info *pi, char *name) +{ + int i = 1; + + LastDevice = 0; + if(name == NULL) { + def_dev(pi); + return(&device_list[0]); + } + while(device_list[i].name) { + if(!nocase_strcmp(name, device_list[i].name)) { + LastDevice=i; + def_dev(pi); + return(&device_list[i]); + } + i++; + } + def_dev(pi); + return(NULL); +} + +// Pre-define devices. B.A. : Return value change from void to int +int predef_dev(struct prog_info *pi) +{ + int i; + char temp[MAX_DEV_NAME+1]; + def_dev(pi); + for (i=0;(!i)||(device_list[i].name);i++) { + strncpy(temp,DEV_PREFIX,MAX_DEV_NAME); + if (!i) strncat(temp,DEF_DEV_NAME,MAX_DEV_NAME); + else strncat(temp,device_list[i].name,MAX_DEV_NAME); + strncat(temp,DEV_SUFFIX,MAX_DEV_NAME); + /* B.A. : New. Forward references allowed. But check, if everything is ok ... */ + if(pi->pass==PASS_1) { /* Pass 1 */ + if(test_constant(pi,temp,NULL)!=NULL) { + fprintf(stderr,"Error: Can't define symbol %s twice. Please don't use predefined symbols !\n", temp); + return(False); + } + if(def_const(pi, temp, i)==False) + return(False); + } else { /* Pass 2 */ + int j; + if(get_constant(pi, temp, &j)==False) { /* Defined in Pass 1 and now missing ? */ + fprintf(stderr,"Constant %s is missing in pass 2\n",temp); + return(False); + } + if(i != j) { + fprintf(stderr,"Constant %s changed value from %d in pass1 to %d in pass 2\n",temp,j,i); + return(False); + } + /* OK. definition is unchanged */ + } + } + return(True); +} + +void list_devices() +{ + int i = 1; + printf("Device name | Flash size | RAM start | RAM size | EEPROM size | Supported\n" + " | (words) | (bytes) | (bytes) | (bytes) | instructions\n" + "------------+------------+-----------+----------+-------------+--------------\n" + " (default) | %7d | 0x%04x | %7d | %5d | %3d\n", + device_list[0].flash_size, + device_list[0].ram_start, + device_list[0].ram_size, + device_list[0].eeprom_size, + count_supported_instructions(device_list[0].flag)); + while(device_list[i].name) { + printf(" %-10s | %7d | 0x%04x | %7d | %5d | %3d\n", + device_list[i].name, + device_list[i].flash_size, + device_list[i].ram_start, + device_list[i].ram_size, + device_list[i].eeprom_size, + count_supported_instructions(device_list[i].flag)); + i++; + } +} + +/* end of device.c */ + diff --git a/contrib/toolchain/avra/src/device.h b/contrib/toolchain/avra/src/device.h new file mode 100644 index 000000000..8734444ac --- /dev/null +++ b/contrib/toolchain/avra/src/device.h @@ -0,0 +1,33 @@ + +/* Device flags */ +#define DF_NO_MUL 0x00000001 +#define DF_NO_JMP 0x00000002 // No JMP, CALL +#define DF_NO_XREG 0x00000004 // No X register +#define DF_NO_YREG 0x00000008 // No Y register +#define DF_TINY1X 0x00000010 /* AT90S1200, ATtiny10-12 set: No ADIW, SBIW, + IJMP, ICALL, LDD, STD, LDS, STS, PUSH, POP */ +#define DF_NO_LPM 0x00000020 // No LPM instruction +#define DF_NO_LPM_X 0x00000040 // No LPM Rd,Z or LPM Rd,Z+ instruction +#define DF_NO_ELPM 0x00000080 // No ELPM instruction +#define DF_NO_ELPM_X 0x00000100 // No ELPM Rd,Z or LPM Rd,Z+ instruction +#define DF_NO_SPM 0x00000200 // No SPM instruction +#define DF_NO_ESPM 0x00000400 // No ESPM instruction +#define DF_NO_MOVW 0x00000800 // No MOVW instruction +#define DF_NO_BREAK 0x00001000 // No BREAK instruction +#define DF_NO_EICALL 0x00002000 // No EICALL instruction +#define DF_NO_EIJMP 0x00004000 // No EIJMP instruction + +struct device + { + char *name; + int flash_size; + int ram_start; + int ram_size; + int eeprom_size; + int flag; + }; + +/* device.c */ +struct device *get_device(struct prog_info *pi,char *name); +int predef_dev(struct prog_info *pi); +void list_devices(); diff --git a/contrib/toolchain/avra/src/directiv.c b/contrib/toolchain/avra/src/directiv.c new file mode 100644 index 000000000..8f8f4afa9 --- /dev/null +++ b/contrib/toolchain/avra/src/directiv.c @@ -0,0 +1,934 @@ +/*********************************************************************** +// Modified at line 252 to print out DW value in list file by davidrjburke@hotmail.com 11 Nov 2005 + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include +#include + +#include "misc.h" +#include "args.h" +#include "avra.h" +#include "device.h" + +enum +{ + DIRECTIVE_BYTE = 0, + DIRECTIVE_CSEG, + DIRECTIVE_CSEGSIZE, + DIRECTIVE_DB, + DIRECTIVE_DEF, + DIRECTIVE_DEVICE, + DIRECTIVE_DSEG, + DIRECTIVE_DW, + DIRECTIVE_ENDM, + DIRECTIVE_ENDMACRO, + DIRECTIVE_EQU, + DIRECTIVE_ESEG, + DIRECTIVE_EXIT, + DIRECTIVE_INCLUDE, + DIRECTIVE_INCLUDEPATH, + DIRECTIVE_LIST, + DIRECTIVE_LISTMAC, + DIRECTIVE_MACRO, + DIRECTIVE_NOLIST, + DIRECTIVE_ORG, + DIRECTIVE_SET, + DIRECTIVE_DEFINE, + DIRECTIVE_UNDEF, + DIRECTIVE_IFDEF, + DIRECTIVE_IFNDEF, + DIRECTIVE_IF, + DIRECTIVE_ELSE, + DIRECTIVE_ELSEIF, /* B.A. : The Atmel AVR Assembler version 1.71 and later use ELSEIF and not ELIF */ + DIRECTIVE_ELIF, + DIRECTIVE_ENDIF, + DIRECTIVE_MESSAGE, + DIRECTIVE_WARNING, + DIRECTIVE_ERROR, + DIRECTIVE_PRAGMA, + DIRECTIVE_COUNT +}; + +char *directive_list[] = +{ + "BYTE", + "CSEG", + "CSEGSIZE", + "DB", + "DEF", + "DEVICE", + "DSEG", + "DW", + "ENDM", + "ENDMACRO", + "EQU", + "ESEG", + "EXIT", + "INCLUDE", + "INCLUDEPATH", + "LIST", + "LISTMAC", + "MACRO", + "NOLIST", + "ORG", + "SET", + "DEFINE", + "UNDEF", + "IFDEF", + "IFNDEF", + "IF", + "ELSE", + "ELSEIF", /* B.A. : The Atmel AVR Assembler version 1.71 and later use ELSEIF and not ELIF */ + "ELIF", + "ENDIF", + "MESSAGE", + "WARNING", + "ERROR", + "PRAGMA" +}; + + +int parse_directive(struct prog_info *pi) +{ + int directive; + int ok = True; + int i; + char *next, *data; + struct file_info *fi_bak; + + struct def *def; + struct data_list *incpath, *dl; + + next = get_next_token(pi->fi->scratch, TERM_SPACE); + + for(i = 0; pi->fi->scratch[i] != '\0'; i++) { + pi->fi->scratch[i] = toupper(pi->fi->scratch[i]); + } + directive = get_directive_type(pi->fi->scratch + 1); + if(directive == -1) { + print_msg(pi, MSGTYPE_ERROR, "Unknown directive: %s", pi->fi->scratch); + return(True); + } + switch(directive) { + case DIRECTIVE_BYTE: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".BYTE needs a size operand"); + return(True); + } + if(pi->segment != SEGMENT_DATA) + print_msg(pi, MSGTYPE_ERROR, ".BYTE directive can only be used in data segment (.DSEG)"); + get_next_token(next, TERM_END); + if(!get_expr(pi, next, &i)) + return(False); + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, "D:%06x %s\n", pi->dseg_addr, pi->list_line); + pi->list_line = NULL; + } + pi->dseg_addr += i; + if(pi->pass == PASS_1) + pi->dseg_count += i; + break; + case DIRECTIVE_CSEG: + fix_orglist(pi); + pi->segment = SEGMENT_CODE; + def_orglist(pi); + break; + case DIRECTIVE_CSEGSIZE: + break; + case DIRECTIVE_DB: + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + return(parse_db(pi, next)); +// break; + /* Directive .def */ + case DIRECTIVE_DEF: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".DEF needs an operand"); + return(True); + } + data = get_next_token(next, TERM_EQUAL); + if(!(data && (tolower(data[0]) == 'r') && isdigit(data[1]))) { + print_msg(pi, MSGTYPE_ERROR, "%s needs a register (e.g. .def BZZZT = r16)", next); + return(True); + } + i = atoi(&data[1]); + /* check range of given register */ + if(i > 31) + print_msg(pi, MSGTYPE_ERROR, "R%d is not a valid register", i); + /* check if this reg is already assigned */ + for(def = pi->first_def; def; def = def->next) { + if(def->reg == i && pi->pass == PASS_1 && !pi->NoRegDef) { + print_msg(pi, MSGTYPE_WARNING, "r%d is already assigned to '%s'!", i, def->name); + return(True); + } + } + /* check if this regname is already defined */ + for(def = pi->first_def; def; def = def->next) { + if(!nocase_strcmp(def->name, next)) { + if(pi->pass == PASS_1 && !pi->NoRegDef) { + print_msg(pi, MSGTYPE_WARNING, "'%s' is already assigned as r%d but will now be set to r%i!", next, def->reg, i); + } + def->reg = i; + return(True); + } + } + /* B.A.: Check, if symbol is already defined as a label or constant */ + if(pi->pass == PASS_2) { + if(get_label(pi,next,NULL)) + print_msg(pi, MSGTYPE_WARNING, "Name '%s' is used for a register and a label", next); + if(get_constant(pi,next,NULL)) + print_msg(pi, MSGTYPE_WARNING, "Name '%s' is used for a register and a constant", next); + } + + def = malloc(sizeof(struct def)); + if(!def) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + def->next = NULL; + if(pi->last_def) + pi->last_def->next = def; + else + pi->first_def = def; + pi->last_def = def; + def->name = malloc(strlen(next) + 1); + if(!def->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(def->name, next); + def->reg = i; + break; + case DIRECTIVE_DEVICE: + if(pi->pass == PASS_2) + return(True); + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".DEVICE needs an operand"); + return(True); + } + if(pi->device->name!=NULL) { /* B.A.: Check for multiple device definitions */ + print_msg(pi, MSGTYPE_ERROR, "More than one .DEVICE definition"); + } + if(pi->cseg_count || pi->dseg_count || pi->eseg_count) { /* B.A.: Check if something was already assembled */ + print_msg(pi, MSGTYPE_ERROR, ".DEVICE definition must be before any code lines"); + } else { + if(pi->cseg_addr || pi->eseg_addr || (pi->dseg_addr != pi->device->ram_start)) { /* B.A.: Check if something was already assembled */ + print_msg(pi, MSGTYPE_ERROR, ".DEVICE definition must be before any .ORG directive"); + } + } + + get_next_token(next, TERM_END); + pi->device = get_device(pi,next); + if(!pi->device) { + print_msg(pi, MSGTYPE_ERROR, "Unknown device: %s", next); + pi->device = get_device(pi,NULL); /* B.A.: Fix segmentation fault if device is unknown */ + } + + /* Now that we know the device type, we can + * start memory allocation from the correct offsets. + */ + fix_orglist(pi); + pi->cseg_addr = 0; + pi->dseg_addr = pi->device->ram_start; + pi->eseg_addr = 0; + def_orglist(pi); + break; + case DIRECTIVE_DSEG: + fix_orglist(pi); + pi->segment = SEGMENT_DATA; + def_orglist(pi); + if(pi->device->ram_size == 0) { + print_msg(pi, MSGTYPE_ERROR, "Can't use .DSEG directive because device has no RAM"); + } + break; + case DIRECTIVE_DW: + if(pi->segment == SEGMENT_DATA) { + print_msg(pi, MSGTYPE_ERROR, "Can't use .DW directive in data segment (.DSEG)"); + return(True); + } + while(next) { + data = get_next_token(next, TERM_COMMA); + if(pi->pass == PASS_2) { + if(!get_expr(pi, next, &i)) + return(False); + if((i < -32768) || (i > 65535)) + print_msg(pi, MSGTYPE_WARNING, "Value %d is out of range (-32768 <= k <= 65535). Will be masked", i); + } + if(pi->segment == SEGMENT_EEPROM) { + if(pi->pass == PASS_2) { + write_ee_byte(pi, pi->eseg_addr, (unsigned char)i); + write_ee_byte(pi, pi->eseg_addr + 1, (unsigned char)(i >> 8)); + } + pi->eseg_addr += 2; + if(pi->pass == PASS_1) + pi->eseg_count += 2; + } + // Modified by David Burke to print DW word in list file 4/Nov/2005 + else { + if((pi->pass == PASS_2) && pi->hfi) { + write_prog_word(pi, pi->cseg_addr, i); + // Actual fiddling + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + fprintf(pi->list_file, "C:%06x %04x\n", pi->cseg_addr,i); + } + } + pi->cseg_addr++; + if(pi->pass == PASS_1) pi->cseg_count++; + } + // End of Modification by David Burke + next = data; + } + break; + case DIRECTIVE_ENDM: + case DIRECTIVE_ENDMACRO: + print_msg(pi, MSGTYPE_ERROR, "No .MACRO found before .ENDMACRO"); + break; + case DIRECTIVE_EQU: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".EQU needs an operand"); + return(True); + } + data = get_next_token(next, TERM_EQUAL); + if(!data) { + print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .EQU BZZZT = 0x2a)", next); + return(True); + } + get_next_token(data, TERM_END); + if(!get_expr(pi, data, &i)) + return(False); + if(test_label(pi,next,"%s have already been defined as a label")!=NULL) + return(True); + if(test_variable(pi,next,"%s have already been defined as a .SET variable")!=NULL) + return(True); + /* B.A. : New. Forward references allowed. But check, if everything is ok ... */ + if(pi->pass==PASS_1) { /* Pass 1 */ + if(test_constant(pi,next,"Can't redefine constant %s, use .SET instead")!=NULL) + return(True); + if(def_const(pi, next, i)==False) + return(False); + } else { /* Pass 2 */ + int j; + if(get_constant(pi, next, &j)==False) { /* Defined in Pass 1 and now missing ? */ + print_msg(pi, MSGTYPE_ERROR, "Constant %s is missing in pass 2", next); + return(False); + } + if(i != j) { + print_msg(pi, MSGTYPE_ERROR, "Constant %s changed value from %d in pass1 to %d in pass 2", next,j,i); + return(False); + } + /* OK. Definition is unchanged */ + } + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + break; + case DIRECTIVE_ESEG: + fix_orglist(pi); + pi->segment = SEGMENT_EEPROM; + def_orglist(pi); + if(pi->device->eeprom_size == 0) { + print_msg(pi, MSGTYPE_ERROR, "Can't use .ESEG directive because device has no EEPROM"); + } + break; + case DIRECTIVE_EXIT: + pi->fi->exit_file = True; + break; + /*** .include ***/ + case DIRECTIVE_INCLUDE: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, "Nothing to include"); + return(True); + } + next = term_string(pi, next); + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + // Test if include is in local directory + ok = test_include(next); + data = NULL; + if(!ok) + for(incpath = GET_ARG(pi->args, ARG_INCLUDEPATH); incpath && !ok; incpath = incpath->next) { + i = strlen(incpath->data); + if(data) + free(data); + data = malloc(i + strlen(next) + 2); + if(!data) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(data, incpath->data); + if((data[i - 1] != '\\') && (data[i - 1] != '/')) + data[i++] = '/'; + strcpy(&data[i], next); + //printf("testing: %s\n", data); + ok = test_include(data); + } + if(ok) { + fi_bak = pi->fi; + ok = parse_file(pi, data ? data : next); + pi->fi = fi_bak; + } + else + print_msg(pi, MSGTYPE_ERROR, "Cannot find include file: %s", next); + if(data) + free(data); + break; + /*** .includepath ***/ + case DIRECTIVE_INCLUDEPATH: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".INCLUDEPATH needs an operand"); + return(True); + } + data = get_next_token(next, TERM_SPACE); + if(data) { + print_msg(pi, MSGTYPE_ERROR, ".INCLUDEPATH needs an operand!!!"); + get_next_token(data, TERM_END); + if(!get_expr(pi, data, &i)) + return(False); + } + next = term_string(pi, next); + /* get arg list start pointer */ + incpath = GET_ARG(pi->args, ARG_INCLUDEPATH); + /* search for last element */ + if(incpath == NULL) { + dl = malloc(sizeof(struct data_list)); + data = malloc(strlen(next)+1); + if(dl && data) { + dl->next = NULL; + strcpy(data, next); + dl->data = data; + SET_ARG(pi->args, ARG_INCLUDEPATH, dl); + } + else { + printf("Error: Unable to allocate memory\n"); + return(False); + } + } + else + add_arg(&incpath, next); + break; + case DIRECTIVE_LIST: + if(pi->pass == PASS_2) + if(pi->list_file) + pi->list_on = True; + break; + case DIRECTIVE_LISTMAC: + if(pi->pass == PASS_2) + SET_ARG(pi->args, ARG_LISTMAC, True); + break; + case DIRECTIVE_MACRO: + return(read_macro(pi, next)); +// break; + case DIRECTIVE_NOLIST: + if(pi->pass == PASS_2) + pi->list_on = False; + break; + case DIRECTIVE_ORG: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".ORG needs an operand"); + return(True); + } + get_next_token(next, TERM_END); + if(!get_expr(pi, next, &i)) + return(False); + fix_orglist(pi); /* Update last segment */ + switch(pi->segment) { + case SEGMENT_CODE: + pi->cseg_addr = i; + break; + case SEGMENT_DATA: + pi->dseg_addr = i; + break; + case SEGMENT_EEPROM: + pi->eseg_addr = i; + } + def_orglist(pi); /* Create new segment */ + if(pi->fi->label) + pi->fi->label->value = i; + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + break; + case DIRECTIVE_SET: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".SET needs an operand"); + return(True); + } + data = get_next_token(next, TERM_EQUAL); + if(!data) { + print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .SET BZZZT = 0x2a)", next); + return(True); + } + get_next_token(data, TERM_END); + if(!get_expr(pi, data, &i)) + return(False); + + if(test_label(pi,next,"%s have already been defined as a label")!=NULL) + return(True); + if(test_constant(pi,next,"%s have already been defined as a .EQU constant")!=NULL) + return(True); + return(def_var(pi, next, i)); +// break; + case DIRECTIVE_DEFINE: + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".DEFINE needs an operand"); + return(True); + } + data = get_next_token(next, TERM_SPACE); + if(data) { + get_next_token(data, TERM_END); + if(!get_expr(pi, data, &i)) + return(False); + } + else + i = 1; + if(test_label(pi,next,"%s have already been defined as a label")!=NULL) + return(True); + if(test_variable(pi,next,"%s have already been defined as a .SET variable")!=NULL) + return(True); + /* B.A. : New. Forward references allowed. But check, if everything is ok ... */ + if(pi->pass==PASS_1) { /* Pass 1 */ + if(test_constant(pi,next,"Can't redefine constant %s, use .SET instead")!=NULL) + return(True); + if(def_const(pi, next, i)==False) + return(False); + } else { /* Pass 2 */ + int j; + if(get_constant(pi, next, &j)==False) { /* Defined in Pass 1 and now missing ? */ + print_msg(pi, MSGTYPE_ERROR, "Constant %s is missing in pass 2", next); + return(False); + } + if(i != j) { + print_msg(pi, MSGTYPE_ERROR, "Constant %s changed value from %d in pass1 to %d in pass 2", next,j,i); + return(False); + } + /* OK. Definition is unchanged */ + } + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + break; + case DIRECTIVE_PRAGMA: +#if 0 + may_do_something_with_pragma_someday(); +#else + // if ( !flag_no_warnings ) + print_msg(pi, MSGTYPE_MESSAGE, "PRAGMA directives currently ignored"); +#endif + break; + case DIRECTIVE_UNDEF: // TODO + break; + case DIRECTIVE_IFDEF: + if(!next) + { + print_msg(pi, MSGTYPE_ERROR, ".IFDEF needs an operand"); + return(True); + } + get_next_token(next, TERM_END); + /* B.A. : Forward referenc is not allowed for ifdef and ifndef */ + /* Store undefined symbols in blacklist in pass1 and check, if they are still undefined in pass2 */ + if(get_symbol(pi, next, NULL)) { +#if 0 + // If it's not defined in the first pass, but was defined later + // then it should be considered OK with regards to ifdef..endif and + // ifndef..endif code sections. Removed this code. + if(pi->pass==PASS_2) { /* B.A. : 'Still undefined'-test in pass 2 */ + if(test_blacklist(pi,next,"Forward reference (%s) not allowed in .ifdef directive")!=NULL) + return(False); + } +#else + pi->conditional_depth++; +#endif + } else { + if(pi->pass==PASS_1) { /* B.A. : Store undefined symbols in pass 1 */ + if(def_blacklist(pi, next)==False) + return(False); + } + if(!spool_conditional(pi, False)) + return(False); + } + break; + case DIRECTIVE_IFNDEF: + if(!next) + { + print_msg(pi, MSGTYPE_ERROR, ".IFNDEF needs an operand"); + return(True); + } + get_next_token(next, TERM_END); + /* B.A. : Forward referenc is not allowed for ifdef and ifndef */ + /* Store undefined symbols in blacklist in pass1 and check, if they are still undefined in pass2 */ + if(get_symbol(pi, next, NULL)) + { +#if 0 + if(pi->pass==PASS_2) { /* B.A. : 'Still undefined'-test in pass 2 */ + // If it's not defined in the first pass, but was defined later + // then it should be considered OK with regards to ifdef..endif and + // ifndef..endif code sections. Removed this code. + if(test_blacklist(pi,next,"Forward reference (%s) not allowed in .ifndef directive")!=NULL) + return(False); + } + if(!spool_conditional(pi, False)) + return(False); +#else + pi->conditional_depth++; +#endif + } + else { + if(pi->pass==PASS_1) { /* B.A. : Store undefined symbols in pass 1 */ + if(def_blacklist(pi, next)==False) + return(False); + } + pi->conditional_depth++; + } + break; + case DIRECTIVE_IF: + if(!next) + { + print_msg(pi, MSGTYPE_ERROR, ".IF needs an expression"); + return(True); + } + get_next_token(next, TERM_END); + if(!get_expr(pi, next, &i)) + return(False); + if(i) + pi->conditional_depth++; + else + { + if(!spool_conditional(pi, False)) + return(False); + } + break; + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ELSEIF: + if(!spool_conditional(pi, True)) + return(False); + break; + case DIRECTIVE_ENDIF: + if(pi->conditional_depth == 0) + print_msg(pi, MSGTYPE_ERROR, "Too many .ENDIF"); + else + pi->conditional_depth--; + break; + case DIRECTIVE_MESSAGE: + if(pi->pass == PASS_1) + return(True); + if(!next) { + print_msg(pi, MSGTYPE_ERROR, "No message parameter supplied"); + return(True); + } + /* B.A : Extended .MESSAGE. Now a comma separated list like in .db is possible and not only a string */ + print_msg(pi, MSGTYPE_MESSAGE_NO_LF, NULL); /* Prints Line Header (filename, linenumber) without trailing /n */ + while(next) { /* Modified code from parse_db(). Thank you :-) */ + data = get_next_token(next, TERM_COMMA); + if(next[0] == '\"') { /* string parsing */ + next = term_string(pi, next); + print_msg(pi, MSGTYPE_APPEND,"%s",next); + while(*next != '\0') { + next++; + } + } else { + if(!get_expr(pi, next, &i)) { + print_msg(pi, MSGTYPE_APPEND,"\n"); /* Add newline */ + return(False); + } + print_msg(pi, MSGTYPE_APPEND,"0x%02X",i); + } + next = data; + } + print_msg(pi, MSGTYPE_APPEND,"\n"); /* Add newline */ + break; + case DIRECTIVE_WARNING: + if(pi->pass == PASS_1) + return(True); + if(!next) { + print_msg(pi, MSGTYPE_ERROR, "No warning string supplied"); + return(True); + } + next = term_string(pi, next); + print_msg(pi, MSGTYPE_WARNING, next); + break; + case DIRECTIVE_ERROR: + if(!next) { /* B.A : Fix segfault bug if .error without parameter was used */ + print_msg(pi, MSGTYPE_ERROR, "No error string supplied"); + return(True); + } + next = term_string(pi, next); + /* B.A. : Don't use this. It may cause segfaults if the 'next' contains printf control sequences %s,%d etc. + print_msg(pi, MSGTYPE_ERROR, next); + */ + print_msg(pi, MSGTYPE_ERROR,"%s",next); /* B.A. : This is '%s' save :-) */ + pi->error_count = pi->max_errors; + if(pi->pass == PASS_1) + return(True); + break; + } + return(ok); +} + + +int get_directive_type(char *directive) { + int i; + + for(i = 0; i < DIRECTIVE_COUNT; i++) { + if(!strcmp(directive, directive_list[i])) return(i); + } + return(-1); +} + + +char *term_string(struct prog_info *pi, char *string) { + int i; + + if(string[0] != '\"') { + print_msg(pi, MSGTYPE_ERROR, "String must be enclosed in \"-signs"); + } + else { + string++; + } + /* skip to the end of the string*/ + for(i = 0; (string[i] != '\"') && !((string[i] == 10) || (string[i] == 13) || (string[i] == '\0')); i++); + if((string[i] == 10) || (string[i] == 13) || (string[i] == '\0')) { + print_msg(pi, MSGTYPE_ERROR, "String is missing a closing \"-sign"); + } + string[i] = '\0'; /* and terminate it where the " was */ + return(string); +} + +/* Parse data byte directive */ +int parse_db(struct prog_info *pi, char *next) { + int i; + int count; + char *data; + char prev = 0; + + /* check if .db is allowed in this segment type */ + if(pi->segment == SEGMENT_DATA) { + print_msg(pi, MSGTYPE_ERROR, "Can't use .DB directive in data segment (.DSEG) !"); + return(True); + } + + count = 0; + if(pi->pass == PASS_2 && pi->list_on) { + if(pi->segment == SEGMENT_EEPROM) + fprintf(pi->list_file, "E:%06X ", pi->eseg_addr); + if(pi->segment == SEGMENT_CODE) + fprintf(pi->list_file, "C:%06X ", pi->cseg_addr); + } + /* get each db token */ + while(next) { + data = get_next_token(next, TERM_COMMA); + /* string parsing */ + if(next[0] == '\"') { + next = term_string(pi, next); + while(*next != '\0') { + count++; + write_db(pi, *next, &prev, count); + if(pi->pass == PASS_2 && pi->list_on) + fprintf(pi->list_file, "%02X", (unsigned char)*next); // B.A.: Patch for chars with bit 7 = 1 (Example: °) + if((unsigned char)*next > 127 && pi->pass == PASS_2) + print_msg(pi, MSGTYPE_WARNING, "Found .DB string with characters > code 127. Be careful !"); // B.A.: Print warning for codes > 127 + next++; + } + } + else { + if(pi->pass == PASS_2) { + if(!get_expr(pi, next, &i)) + return(False); + if((i < -128) || (i > 255)) + print_msg(pi, MSGTYPE_WARNING, "Value %d is out of range (-128 <= k <= 255). Will be masked", i); + if(pi->list_on) fprintf(pi->list_file, "%02X", i); + } + count++; + write_db(pi, (char)i, &prev, count); + } + next = data; + } + if(pi->segment == SEGMENT_CODE) { + if((count % 2) == 1) { + if(pi->pass == PASS_2) { + if(pi->list_on) fprintf(pi->list_file, "00 ; zero byte added"); + write_prog_word(pi, pi->cseg_addr, prev & 0xFF); + print_msg(pi, MSGTYPE_WARNING, "A .DB segment with an odd number of bytes is detected. A zero byte is added."); + } + pi->cseg_addr++; + if(pi->pass == PASS_1) { + pi->cseg_count++; + } + } + } + if(pi->pass == PASS_2 && pi->list_on) { + fprintf(pi->list_file, "\n"); + pi->list_line = NULL; + } + return(True); +} + + +void write_db(struct prog_info *pi, char byte, char *prev, int count) { + if(pi->segment == SEGMENT_EEPROM) { + if(pi->pass == PASS_2) { + write_ee_byte(pi, pi->eseg_addr, byte); + } + pi->eseg_addr++; + if(pi->pass == PASS_1) { + pi->eseg_count++; + } + } + else { /* pi->segment == SEGMENT_CODE */ + if((count % 2) == 0) { + if(pi->pass == PASS_2) { + write_prog_word(pi, pi->cseg_addr, (byte << 8) | (*prev & 0xff)); + } + pi->cseg_addr++; + if(pi->pass == PASS_1) { + pi->cseg_count++; + } + } + else { + *prev = byte; + } + } +} + + +int spool_conditional(struct prog_info *pi, int only_endif) { + int current_depth = 0, do_next; + + if(pi->macro_line) { + while((pi->macro_line = pi->macro_line->next)) { + pi->macro_call->line_index++; + if(check_conditional(pi, pi->macro_line->line, ¤t_depth, &do_next, only_endif)) { + if(!do_next) + return(True); + } + else + return(False); + } + print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF in macro"); + } + else { + while(fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) { + pi->fi->line_number++; + if(check_conditional(pi, pi->fi->buff, ¤t_depth, &do_next, only_endif)) { + if(!do_next) + return(True); + } + else + return(False); + } + if(feof(pi->fi->fp)) { + print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF"); + return(True); + } + else { + perror(pi->fi->include_file->name); + return(False); + } + } + return(True); +} + + +int check_conditional(struct prog_info *pi, char *pbuff, int *current_depth, int *do_next, int only_endif) +{ + int i = 0; + char *next; + char linebuff[LINEBUFFER_LENGTH]; + + strcpy(linebuff, pbuff); /* avoid cutting of the end of .elif line */ + + *do_next = False; + while(IS_HOR_SPACE(linebuff[i]) && !IS_END_OR_COMMENT(linebuff[i])) i++; +#if 0 + if(linebuff[i] == '.') { +#else + if((linebuff[i] == '.') || (linebuff[i] == '#')){ +#endif + i++; + if(!nocase_strncmp(&linebuff[i], "if", 2)) + (*current_depth)++; + else + if(!nocase_strncmp(&linebuff[i], "endif", 5)) { + if(*current_depth == 0) + return(True); + (*current_depth)--; + } else + if(!only_endif && (*current_depth == 0)) { + /* B.A. : Add ELSEIF = ELIF */ + if((!nocase_strncmp(&linebuff[i], "else", 4)) && (nocase_strncmp(&linebuff[i], "elseif", 6))) { + pi->conditional_depth++; + return(True); + } else + if((!nocase_strncmp(&linebuff[i], "elif", 4)) || (!nocase_strncmp(&linebuff[i], "elseif", 6))) { + next = get_next_token(&linebuff[i], TERM_SPACE); + if(!next) { + print_msg(pi, MSGTYPE_ERROR, ".ELSEIF / .ELIF needs an operand"); + return(True); + } + get_next_token(next, TERM_END); + if(!get_expr(pi, next, &i)) + return(False); + if(i) + pi->conditional_depth++; + else { + if(!spool_conditional(pi, False)) + return(False); + } + return(True); + } + } + } + *do_next = True; + return(True); +} + +int test_include(const char *filename) +{ + FILE *fp; + fp = fopen(filename, "r"); + if(fp) + { + fclose(fp); + return(True); + } + else + return(False); +} + +/* end of directiv.c */ + + diff --git a/contrib/toolchain/avra/src/expr.c b/contrib/toolchain/avra/src/expr.c new file mode 100644 index 000000000..3ef245976 --- /dev/null +++ b/contrib/toolchain/avra/src/expr.c @@ -0,0 +1,573 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include +#include + +#include "misc.h" +#include "avra.h" +#include "device.h" + +#define IS_UNARY(x) ((x == '!') || (x == '-') || (x == '~')) +#define IS_OPERATOR(x) ((x == '+') || (x == '-') || (x == '*') || (x == '/') || (x == '%') || (x == '<') || (x == '>') || (x == '=') || (x == '!') || (x == '&') || (x == '^') || (x == '|')) +#define IS_2ND_OPERATOR(x) ((x == '<') || (x == '>') || (x == '=') || (x == '&') || (x == '|')) + +enum { + OPERATOR_ERROR = 0, + OPERATOR_MUL, + OPERATOR_DIV, + OPERATOR_MOD, + OPERATOR_ADD, + OPERATOR_SUB, + OPERATOR_SHIFT_LEFT, + OPERATOR_SHIFT_RIGHT, + OPERATOR_LESS_THAN, + OPERATOR_LESS_OR_EQUAL, + OPERATOR_GREATER_THAN, + OPERATOR_GREATER_OR_EQUAL, + OPERATOR_EQUAL, + OPERATOR_NOT_EQUAL, + OPERATOR_BITWISE_AND, + OPERATOR_BITWISE_XOR, + OPERATOR_BITWISE_OR, + OPERATOR_LOGICAL_AND, + OPERATOR_LOGICAL_OR + }; + +enum { + FUNCTION_LOW = 0, + FUNCTION_BYTE1, + FUNCTION_HIGH, + FUNCTION_BYTE2, + FUNCTION_BYTE3, + FUNCTION_BYTE4, + FUNCTION_LWRD, + FUNCTION_HWRD, + FUNCTION_PAGE, + FUNCTION_EXP2, + FUNCTION_LOG2, + FUNCTION_COUNT +}; + +struct element + { + struct element *next; + int data; + }; + +char *function_list[] = { + /* + ** allow whitespace between function name + ** and opening brace... + */ + "low", + "byte1", + "high", + "byte2", + "byte3", + "byte4", + "lwrd", + "hwrd", + "page", + "exp2", + "log2" +}; + +int log_2(int value) +{ + int i = 0; + while(value >>= 1) + i++; + return(i); +} + +int get_operator(char *op) +{ + switch(op[0]) { + case '*': + return(OPERATOR_MUL); + case '/': + return(OPERATOR_DIV); + case '%': + return(OPERATOR_MOD); + case '+': + return(OPERATOR_ADD); + case '-': + return(OPERATOR_SUB); + case '<': + switch(op[1]) { + case '<': + return(OPERATOR_SHIFT_LEFT); + case '=': + return(OPERATOR_LESS_OR_EQUAL); + default: + return(OPERATOR_LESS_THAN); + } + case '>': + switch(op[1]) { + case '>': + return(OPERATOR_SHIFT_RIGHT); + case '=': + return(OPERATOR_GREATER_OR_EQUAL); + default: + return(OPERATOR_GREATER_THAN); + } + case '=': + if(op[1] == '=') + return(OPERATOR_EQUAL); + case '!': + if(op[1] == '=') + return(OPERATOR_NOT_EQUAL); + case '&': + if(op[1] == '&') + return(OPERATOR_LOGICAL_AND); + else + return(OPERATOR_BITWISE_AND); + case '^': + return(OPERATOR_BITWISE_XOR); + case '|': + if(op[1] == '|') + return(OPERATOR_LOGICAL_OR); + else + return(OPERATOR_BITWISE_OR); + } + return(OPERATOR_ERROR); +} + + + + +int test_operator_at_precedence(int operator, int precedence) +{ + switch(precedence) { + case 13: + return((operator == OPERATOR_MUL) || (operator == OPERATOR_DIV) + || (operator == OPERATOR_MOD)); + case 12: + return((operator == OPERATOR_ADD) || (operator == OPERATOR_SUB)); + case 11: + return((operator == OPERATOR_SHIFT_LEFT) || (operator == OPERATOR_SHIFT_RIGHT)); + case 10: + return((operator == OPERATOR_LESS_THAN) || (operator == OPERATOR_LESS_OR_EQUAL) + || (operator == OPERATOR_GREATER_THAN) || (operator == OPERATOR_GREATER_OR_EQUAL)); + case 9: + return((operator == OPERATOR_EQUAL) || (operator == OPERATOR_NOT_EQUAL)); + case 8: + return(operator == OPERATOR_BITWISE_AND); + case 7: + return(operator == OPERATOR_BITWISE_XOR); + case 6: + return(operator == OPERATOR_BITWISE_OR); + case 5: + return(operator == OPERATOR_LOGICAL_AND); + default: /* Makes the compiler shut up */ + case 4: + return(operator == OPERATOR_LOGICAL_OR); + } +} + + +int calc(struct prog_info *pi, int left, int operator, int right) // TODO: Sjekk litt resultater +{ + switch(operator) { + case OPERATOR_MUL: + return(left * right); + case OPERATOR_DIV: + if(right == 0) { + print_msg(pi, MSGTYPE_ERROR, "Division by zero"); + return(0); + } + return(left / right); + case OPERATOR_MOD: + if(right == 0) { + print_msg(pi, MSGTYPE_ERROR, "Division by zero (modulus operator)"); + return(0); + } + return(left % right); + case OPERATOR_ADD: + return(left + right); + case OPERATOR_SUB: + return(left - right); + case OPERATOR_SHIFT_LEFT: + return(left << right); + case OPERATOR_SHIFT_RIGHT: + return((unsigned)left >> right); + case OPERATOR_LESS_THAN: + return(left < right); + case OPERATOR_LESS_OR_EQUAL: + return(left <= right); + case OPERATOR_GREATER_THAN: + return(left > right); + case OPERATOR_GREATER_OR_EQUAL: + return(left >= right); + case OPERATOR_EQUAL: + return(left == right); + case OPERATOR_NOT_EQUAL: + return(left != right); + case OPERATOR_BITWISE_AND: + return(left & right); + case OPERATOR_BITWISE_XOR: + return(left ^ right); + case OPERATOR_BITWISE_OR: + return(left | right); + case OPERATOR_LOGICAL_AND: + return(left && right); + default: /* Make the compiler shut up */ + case OPERATOR_LOGICAL_OR: + return(left || right); + } +} + +/* If found, return the ID of the internal function */ +int get_function(char *function) +{ + int i; + + for(i = 0; i < FUNCTION_COUNT; i++) { + if(!nocase_strncmp(function, function_list[i], strlen(function_list[i]))) + { + /* + ** some more checks to allow whitespace between function name + ** and opening brace... + */ + char *tmp = function + strlen(function_list[i]); + while (*tmp <= ' ') + tmp++; + if (*tmp != '(') + continue; + + return(i); + } + } + return(-1); +} + +unsigned int do_function(int function, int value) +{ + switch(function) { + case FUNCTION_LOW: + case FUNCTION_BYTE1: + return(value & 0xFF); + case FUNCTION_HIGH: + case FUNCTION_BYTE2: + return((value >> 8) & 0xff); + case FUNCTION_BYTE3: + return((value >> 16) & 0xff); + case FUNCTION_BYTE4: + return((value >> 24) & 0xff); + case FUNCTION_LWRD: + return(value & 0xffff); + case FUNCTION_HWRD: + return((value >> 16) & 0xffff); + case FUNCTION_PAGE: + return((value >> 16) & 0xff); + case FUNCTION_EXP2: + return(1 << value); + case FUNCTION_LOG2: + return(log_2(value)); + default: + return(0); + } +} + + +int get_symbol(struct prog_info *pi, char *label_name, int *data) +{ + struct label *label; + struct macro_call *macro_call; + + if(get_constant(pi,label_name,data)) return(True); + if(get_variable(pi,label_name,data)) return(True); + + for(macro_call = pi->macro_call; macro_call; macro_call = macro_call->prev_on_stack) { + for(label = pi->macro_call->first_label; label; label = label->next) + if(!nocase_strcmp(label->name, label_name)) { + if(data) + *data = label->value; + return(True); + } + } + + if(get_label(pi,label_name,data)) return(True); + return(False); +} + + +int par_length(char *data) +{ + int i = 0, b_count = 1; + + for(;;) { + if(data[i] == ')') { + b_count--; + if(!b_count) + return(i); + } + else if(data[i] == '(') + b_count++; + else if(data[i] == '\0') + return(-1); + i++; + } +} + +int get_expr(struct prog_info *pi, char *data, int *value) { + /* Definition */ + int ok, end, i, count, first_flag, length, function; + char unary, *label; + struct element *element, *first_element = NULL, *temp_element; + struct element **last_element = &first_element; + + /* Initialisation */ + first_flag = True; + ok = True; + end = False; + count = 0; + unary = 0; + /* the expression parser loop */ + for(i = 0; ; i++) { + /* horizontal space is just skipped */ + if(IS_HOR_SPACE(data[i])); + /* test for clean or premature end */ + else if(IS_END_OR_COMMENT(data[i])) { + if((count % 2) != 1) + print_msg(pi, MSGTYPE_ERROR, "Missing value in expression"); + else + end = True; + break; + } + else if(first_flag && IS_UNARY(data[i])) { + unary = data[i]; + first_flag = False; + } + else if((count % 2) == 1) { + if(!IS_OPERATOR(data[i])) { + print_msg(pi, MSGTYPE_ERROR, "Illegal operator '%c'", data[i]); + break; + } + element = malloc(sizeof(struct element)); + if(!element) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + ok = False; + break; + } + element->next = NULL; + element->data = get_operator(&data[i]); + if(element->data == OPERATOR_ERROR) { + if(IS_2ND_OPERATOR(data[i + 1])) + print_msg(pi, MSGTYPE_ERROR, "Unknown operator %c%c", data[i], data[i + 1]); + else + print_msg(pi, MSGTYPE_ERROR, "Unknown operator %c", data[i]); + break; + } + *last_element = element; + last_element = &element->next; + if(IS_2ND_OPERATOR(data[i + 1])) + i++; + count++; + first_flag = True; + unary = 0; + } + else { + element = malloc(sizeof(struct element)); + if(!element) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + ok = False; + break; + } + element->next = NULL; + length = 0; + if(isdigit(data[i])) { + if(tolower(data[i + 1]) == 'x') { + i += 2; + while(isxdigit(data[i + length])) length++; // TODO: Sjekk overflow + element->data = atox_n(&data[i], length); + } + else if(tolower(data[i + 1]) == 'b') { + i += 2; + element->data = 0; + while((data[i + length] == '1') || (data[i + length] == '0')) { + element->data <<= 1; + element->data |= data[i + length++] - '0'; // TODO: Sjekk overflow + } + } + else { + while(isdigit(data[i + length])) length++; + element->data = atoi_n(&data[i], length); // TODO: Sjekk overflow + } + } + else if(data[i] == '$') { + i++; + while(isxdigit(data[i + length])) length++; + element->data = atox_n(&data[i], length); // TODO: Sjekk overflow + } + else if(data[i] == '\'') { + i++; + if(data[i+1] != '\'') { + print_msg(pi, MSGTYPE_ERROR, "Not a correct character ! Use 'A' !"); + break; + } + element->data = data[i]; + length = 2; + } + else if(data[i] == '(') { + i++; + length = par_length(&data[i]); + if(length == -1) { + print_msg(pi, MSGTYPE_ERROR, "Missing ')'"); + break; + } + data[i + length++] = '\0'; + ok = get_expr(pi, &data[i], &element->data); + if(!ok) + break; + } + /* test for internal function */ + else if((function = get_function(&data[i])) != -1) { + while(data[i] != '(') + i++; + i++; + length = par_length(&data[i]); + if(length == -1) { + print_msg(pi, MSGTYPE_ERROR, "Missing ')'"); + break; + } + data[i + length++] = '\0'; + ok = get_expr(pi, &data[i], &element->data); + if(!ok) + break; + element->data = do_function(function, element->data); + } + else if(!nocase_strncmp(&data[i], "defined(", 8)) { + i += 8; + length = par_length(&data[i]); + if(length == -1) { + print_msg(pi, MSGTYPE_ERROR, "Missing ')'"); + break; + } + data[i + length++] = '\0'; + if(get_symbol(pi, &data[i], NULL)) + element->data = 1; + else + element->data = 0; + } + else if(!nocase_strncmp(&data[i], "supported(", 10)) { + i += 10; + length = par_length(&data[i]); + if(length == -1) { + print_msg(pi, MSGTYPE_ERROR, "Missing ')'"); + break; + } + data[i + length++] = '\0'; + element->data=is_supported(pi, &data[i]); + if (element->data<0) { + if (toupper(data[i])=='X') { + if (pi->device->flag&DF_NO_XREG) element->data = 0; + else element->data = 1; + } + else if (toupper(data[i])=='Y') { + if (pi->device->flag&DF_NO_YREG) element->data = 0; + else element->data = 1; + } + else if (toupper(data[i])=='Z') + element->data = 1; + else { + print_msg(pi, MSGTYPE_ERROR, "Unknown mnemonic: %s",&data[i]); + element->data = 0; + } + } + } + else { + while(IS_LABEL(data[i + length])) length++; + if((length == 2) && !nocase_strncmp(&data[i], "PC", 2)) + element->data = pi->cseg_addr; + else { + label = malloc(length + 1); + if(!label) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + ok = False; + break; + } + strncpy(label, &data[i], length); + label[length] = '\0'; + if(get_symbol(pi, label, &element->data)) + free(label); + else { + print_msg(pi, MSGTYPE_ERROR, "Found no label/variable/constant named %s", label); + free(label); + break; + } + } + } + /* now the expression has been evaluated */ + i += length - 1; + switch(unary) { // TODO: Få den til å takle flere unary på rad. + case '-': + element->data = -element->data; + break; + case '!': + element->data = !element->data; + break; + case '~': + element->data = ~element->data; + } + *last_element = element; + last_element = &element->next; + count++; + first_flag = False; + } + } + if(end) { + for(i = 13; (i >= 4) && (count != 1); i--) { + for(element = first_element; element->next;) { + if(test_operator_at_precedence(element->next->data, i)) { // TODO: Vurder en hi_i for kjapphet + element->data = calc(pi, element->data, element->next->data, element->next->next->data); + temp_element = element->next->next->next; + free(element->next->next); + free(element->next); + count -= 2; + element->next = temp_element; + } + else + element = element->next->next; + } + } + *value = first_element->data; + } + for(element = first_element; element;) { + temp_element = element; + element = element->next; + free(temp_element); + } + return(ok); +} + + +/* end of expr.c */ + diff --git a/contrib/toolchain/avra/src/file.c b/contrib/toolchain/avra/src/file.c new file mode 100644 index 000000000..42d5db468 --- /dev/null +++ b/contrib/toolchain/avra/src/file.c @@ -0,0 +1,317 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include +#include +#include /* B.A. for unlink function */ + + +#include "misc.h" +#include "avra.h" +#include "args.h" + + +int open_out_files(struct prog_info *pi, char *filename) +{ + int length; + char *buff; + int ok = True; /* flag for coff results */ + + length = strlen(filename); + buff = malloc(length + 9); + if(buff == NULL) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(buff, filename); + if(length < 4) { + printf("Error: wrong input file name\n"); + } + if(!nocase_strcmp(&buff[length - 4], ".asm")) { + length -= 4; + buff[length] = '\0'; + } + //printf("pi->cseg_count = %i\n", pi->cseg_count); + //printf("pi->eseg_count = %i\n", pi->eseg_count); + + /* open files for code output */ + strcpy(&buff[length], ".hex"); + if(!(pi->hfi = open_hex_file(buff))) { /* check if open failed */ + print_msg(pi, MSGTYPE_ERROR, "Could not create output hex file!"); + ok = False; + } + strcpy(&buff[length], ".obj"); + if(!(pi->obj_file = open_obj_file(pi, buff))) { + print_msg(pi, MSGTYPE_ERROR, "Could not create object file!"); + ok = False; + } + + /* open files for eeprom output */ + strcpy(&buff[length], ".eep.hex"); + if(!(pi->eep_hfi = open_hex_file(buff))) { + print_msg(pi, MSGTYPE_ERROR, "Could not create eeprom hex file!"); + ok = False; + } + /* coff file is always generated */ + strcpy(&buff[length], ".cof"); + pi->coff_file = open_coff_file(pi, buff); + /* open list file */ + if (pi->list_on) { + strcpy(buff, GET_ARG(pi->args, ARG_LISTFILE)); + pi->list_file = fopen(buff, "w"); + if(pi->list_file == NULL) { + print_msg(pi, MSGTYPE_ERROR, "Could not create list file!"); + ok = False; + } + /* write list file header */ + fprintf(pi->list_file, "\nAVRA Ver. %i.%i.%i %s %s\n\n",VER_MAJOR, VER_MINOR, VER_RELEASE, filename, ctime(&pi->time)); + } + else { + pi->list_file = NULL; + } + free(buff); + + if(ok) + return(True); + else + close_out_files(pi); + return(False); +} + +/* delete all output files */ +void unlink_out_files(struct prog_info *pi, char *filename) +{ + char *buff; + int length; + + close_out_files(pi); + + length = strlen(filename); + buff = malloc(length + 9); + if(buff == NULL) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return; + } + strcpy(buff, filename); + if(!nocase_strcmp(&buff[length - 4], ".asm")) { + length -= 4; + buff[length] = '\0'; + } +#if debug == 1 + printf("unlinking files"); +#endif + strcpy(&buff[length], ".hex"); + unlink(buff); + strcpy(&buff[length], ".obj"); + unlink(buff); + strcpy(&buff[length], ".eep.hex"); + unlink(buff); + strcpy(&buff[length], ".cof"); + unlink(buff); + strcpy(&buff[length], ".lst"); + unlink(buff); + strcpy(&buff[length], ".map"); + unlink(buff); +} + +void close_out_files(struct prog_info *pi) +{ + char stmp[2048]; + + if(pi->error_count == 0) { + sprintf(stmp, + "Segment usage:\n" + " Code : %7d words (%d bytes)\n" + " Data : %7d bytes\n" + " EEPROM : %7d bytes\n", + pi->cseg_count, pi->cseg_count * 2, pi->dseg_count, pi->eseg_count); + printf("%s", stmp); + } + if(pi->hfi) + close_hex_file(pi->hfi); + if(pi->eep_hfi) + close_hex_file(pi->eep_hfi); + if(pi->list_file) { + fprintf(pi->list_file, "\n\n%s", stmp); + if(pi->error_count == 0) + fprintf(pi->list_file, "\nAssembly completed with no errors.\n"); + fclose(pi->list_file); + } + if(pi->obj_file) + close_obj_file(pi, pi->obj_file); + if(pi->coff_file) + close_coff_file(pi, pi->coff_file); +} + + +struct hex_file_info *open_hex_file(char *filename) +{ + struct hex_file_info *hfi; + + hfi = calloc(1, sizeof(struct hex_file_info)); + if(hfi) { + hfi->segment = -1; + hfi->fp = fopen(filename, "wb"); + if(!hfi->fp) { + close_hex_file(hfi); + hfi = NULL; + } + } + return(hfi); +} + + +void close_hex_file(struct hex_file_info *hfi) +{ + if(hfi->fp) { + if(hfi->count != 0) + do_hex_line(hfi); + fprintf(hfi->fp, ":00000001FF\x0d\x0a"); + fclose(hfi->fp); + } + free(hfi); +} + + +void write_ee_byte(struct prog_info *pi, int address, unsigned char data) +{ + if((pi->eep_hfi->count == 16) || ((address != (pi->eep_hfi->linestart_addr + pi->eep_hfi->count)) && (pi->eep_hfi->count != 0))) + do_hex_line(pi->eep_hfi); + if(pi->eep_hfi->count == 0) + pi->eep_hfi->linestart_addr = address; + pi->eep_hfi->hex_line[pi->eep_hfi->count++] = data; + + if(pi->coff_file) + write_coff_eeprom(pi, address, data); +} + +void write_prog_word(struct prog_info *pi, int address, int data) +{ + write_obj_record(pi, address, data); + address *= 2; + if(pi->hfi->segment != (address >> 16)) { + if(pi->hfi->count != 0) + do_hex_line(pi->hfi); + pi->hfi->segment = address >> 16; + if(pi->hfi->segment >= 16) // Use 04 record for addresses above 1 meg since 02 can support max 1 meg + fprintf(pi->hfi->fp, ":02000004%04X%02X\x0d\x0a", pi->hfi->segment & 0xffff, + (0 - 2 - 4 - ((pi->hfi->segment >> 8) & 0xff) - (pi->hfi->segment & 0xff)) & 0xff); + else // Use 02 record for addresses below 1 meg since more programmers know about the 02 instead of the 04 + fprintf(pi->hfi->fp, ":02000002%04X%02X\x0d\x0a", (pi->hfi->segment << 12) & 0xffff, + (0 - 2 - 2 - ((pi->hfi->segment << 4) & 0xf0)) & 0xff); + } + if((pi->hfi->count == 16) || ((address != (pi->hfi->linestart_addr + pi->hfi->count)) && (pi->hfi->count != 0))) + do_hex_line(pi->hfi); + if(pi->hfi->count == 0) + pi->hfi->linestart_addr = address; + pi->hfi->hex_line[pi->hfi->count++] = data & 0xff; + pi->hfi->hex_line[pi->hfi->count++] = (data >> 8) & 0xff; + + if(pi->coff_file != 0) + write_coff_program(pi, address, data); +} + + +void do_hex_line(struct hex_file_info *hfi) +{ + int i; + unsigned char checksum = 0; + + fprintf(hfi->fp, ":%02X%04X00", hfi->count, hfi->linestart_addr & 0xffff); + checksum -= hfi->count + ((hfi->linestart_addr >> 8) & 0xff) + (hfi->linestart_addr & 0xff); + for(i = 0; i < hfi->count; i++) { + fprintf(hfi->fp, "%02X", hfi->hex_line[i]); + checksum -= hfi->hex_line[i]; + } + fprintf(hfi->fp, "%02X\x0d\x0a", checksum); + hfi->count = 0; +} + + +FILE *open_obj_file(struct prog_info *pi, char *filename) +{ + int i; + FILE *fp; + struct include_file *include_file; + + fp = fopen(filename, "wb"); + if(fp) { + i = pi->cseg_count * 9 + 26; + fputc((i >> 24) & 0xff, fp); + fputc((i >> 16) & 0xff, fp); + fputc((i >> 8) & 0xff, fp); + fputc(i & 0xff, fp); + i = 26; + fputc((i >> 24) & 0xff, fp); + fputc((i >> 16) & 0xff, fp); + fputc((i >> 8) & 0xff, fp); + fputc(i & 0xff, fp); + fputc(9, fp); + i = 0; + for(include_file = pi->first_include_file; include_file; include_file = include_file->next) + i++; + fputc(i, fp); + fprintf(fp, "AVR Object File"); + fputc('\0', fp); + } + return(fp); +} + + +void close_obj_file(struct prog_info *pi, FILE *fp) +{ + struct include_file *include_file; + + for(include_file = pi->first_include_file; include_file; include_file = include_file->next) { + fprintf(fp, "%s", include_file->name); + fputc('\0', fp); + } + fputc('\0', fp); + fclose(fp); +} + + +void write_obj_record(struct prog_info *pi, int address, int data) +{ + fputc((address >> 16) & 0xff, pi->obj_file); + fputc((address >> 8) & 0xff, pi->obj_file); + fputc(address & 0xff, pi->obj_file); + fputc((data >> 8) & 0xff, pi->obj_file); + fputc(data & 0xff, pi->obj_file); + fputc(pi->fi->include_file->num & 0xff, pi->obj_file); + fputc((pi->fi->line_number >> 8) & 0xff, pi->obj_file); + fputc(pi->fi->line_number & 0xff, pi->obj_file); + if(pi->macro_call) + fputc(1, pi->obj_file); + else + fputc(0, pi->obj_file); +} + +/* end of file.c */ + diff --git a/contrib/toolchain/avra/src/macro.c b/contrib/toolchain/avra/src/macro.c new file mode 100644 index 000000000..e62c5a19d --- /dev/null +++ b/contrib/toolchain/avra/src/macro.c @@ -0,0 +1,560 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, TObias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +/* + * In append_type: added generic register names support + * Alexey Pavluchenko, 16.Nov.2005 + */ + +#include +#include +#include +#include + +#include "misc.h" +#include "args.h" +#include "avra.h" +#include "device.h" + +/* Only Windows LIBC does support itoa, so we add this + function for other systems here manually. Thank you + Peter Hettkamp for your work. */ + +#ifndef WIN32 +char * itoa(int num, char *str, const int number_format) +{ + int num1 = num; + int num_chars = 0; + int pos; + + while (num1>0) + { + num_chars++; + num1 /= number_format; + } + + if (num_chars == 0) num_chars = 1; + + str[num_chars] = 0; + + for (pos = num_chars-1; pos>=0; pos--) + { + int cur_char = num % number_format; + + if (cur_char < 10) /* Insert number */ + { + str[pos] = cur_char + '0'; + } + else + { + str[pos] = cur_char-10 + 'A'; + } + + num /= number_format; + } + return(str); +} +#endif + + +int read_macro(struct prog_info *pi, char *name) +{ + int loopok; + int i; + int start; + struct macro *macro; + struct macro_line *macro_line; + struct macro_line **last_macro_line = NULL; + struct macro_label *macro_label; + + if(pi->pass == PASS_1) { + if(!name) { + print_msg(pi, MSGTYPE_ERROR, "missing macro name"); + return(True); + } + get_next_token(name, TERM_END); + + for(i = 0; !IS_END_OR_COMMENT(name[i]); i++) { + if(!IS_LABEL(name[i])) { + print_msg(pi, MSGTYPE_ERROR, "illegal characters used in macro name '%s'",name); + return(False); + } + } + + macro = calloc(1, sizeof(struct macro)); + if(!macro) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + + if(pi->last_macro) + pi->last_macro->next = macro; + else + pi->first_macro = macro; + pi->last_macro = macro; + macro->name = malloc(strlen(name) + 1); + if(!macro->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(macro->name, name); + macro->include_file = pi->fi->include_file; + macro->first_line_number = pi->fi->line_number; + last_macro_line = ¯o->first_macro_line; + } + else { /* pi->pass == PASS_2 */ + if(pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + // reset macro label running numbers + get_next_token(name, TERM_END); + macro = get_macro(pi, name); + if (!macro) { + print_msg(pi, MSGTYPE_ERROR, "macro inconsistency in '%s'", name); + return(True); + } + for(macro_label = macro->first_label; macro_label; macro_label = macro_label->next) { + macro_label->running_number = 0; + } + } + + loopok = True; + while(loopok) { + if(fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) { + pi->fi->line_number++; + i = 0; + while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) i++; + if(pi->fi->buff[i] == '.') { + i++; + if(!nocase_strncmp(&pi->fi->buff[i], "endm", 4)) + loopok = False; + if(!nocase_strncmp(&pi->fi->buff[i], "endmacro", 8)) + loopok = False; + } + if(pi->pass == PASS_1) { + if(loopok) { + i = 0; /* find start of line */ + while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) { + i++; + } + start = i; + /* find end of line */ + while(!IS_END_OR_COMMENT(pi->fi->buff[i]) && (IS_LABEL(pi->fi->buff[i]) || pi->fi->buff[i] == ':')) { + i++; + } + if(pi->fi->buff[i-1] == ':' && (pi->fi->buff[i-2] == '%' + && (IS_HOR_SPACE(pi->fi->buff[i]) || IS_END_OR_COMMENT(pi->fi->buff[i])))) { + if(macro->first_label) { + for(macro_label = macro->first_label; macro_label->next; macro_label=macro_label->next){} + macro_label->next = calloc(1,sizeof(struct macro_label)); + macro_label = macro_label->next; + } + else { + macro_label = calloc(1,sizeof(struct macro_label)); + macro->first_label = macro_label; + } + macro_label->label = malloc(strlen(&pi->fi->buff[start])+1); + pi->fi->buff[i-1] = '\0'; + strcpy(macro_label->label, &pi->fi->buff[start]); + pi->fi->buff[i-1] = ':'; + macro_label->running_number = 0; + } + + macro_line = calloc(1, sizeof(struct macro_line)); + if(!macro_line) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + *last_macro_line = macro_line; + last_macro_line = ¯o_line->next; + macro_line->line = malloc(strlen(pi->fi->buff) + 1); + if(!macro_line->line) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(macro_line->line, &pi->fi->buff[start]); + } + } + else if(pi->fi->buff && pi->list_file && pi->list_on) { + if(pi->fi->buff[i] == ';') + fprintf(pi->list_file, " %s\n", pi->fi->buff); + else + fprintf(pi->list_file, " %s\n", pi->fi->buff); + } + } + else { + if(feof(pi->fi->fp)) { + print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDMACRO"); + return(True); + } + else { + perror(pi->fi->include_file->name); + return(False); + } + } + } + return(True); +} + + +struct macro *get_macro(struct prog_info *pi, char *name) +{ + struct macro *macro; + + for(macro = pi->first_macro; macro; macro = macro->next) + if(!nocase_strcmp(macro->name, name)) + return(macro); + return(NULL); +} + +void append_type(struct prog_info *pi, char *name, int c, char *value) +{ + int p, l; + struct def *def; + + p = strlen(name); + name[p++] = '_'; + + if(c == 0) + { + name[p++] = 'v'; + name[p] = '\0'; + return; + } + + l = strlen(value); + if ((l==2 || l==3) && (tolower(value[0])=='r') && isdigit(value[1]) && (l==3?isdigit(value[2]):1) && (atoi(&value[1])<32)) + { + itoa((c*8),&name[p],10); + return; + } + + + for(def = pi->first_def; def; def = def->next) + if(!nocase_strcmp(def->name, value)) + { + itoa((c*8),&name[p],10); + return; + } + + name[p++] = 'i'; + name[p] = '\0'; +} + + +/********************************************************* + * This routine replaces the macro call with mnemonics. * + *********************************************************/ + +int expand_macro(struct prog_info *pi, struct macro *macro, char *rest_line) +{ + int ok = True, macro_arg_count = 0, off, a, b = 0, c, i = 0, j = 0; + char *line = NULL; + char *temp; + char *macro_args[MAX_MACRO_ARGS]; + char tmp[7]; + char buff[LINEBUFFER_LENGTH]; + char arg = False; + char *nmn; //string buffer for 'n'ew 'm'acro 'n'ame + struct macro_line *old_macro_line; + struct macro_call *macro_call; + struct macro_label *macro_label; + + if(rest_line) { + //we reserve some extra space for extended macro parameters + line = malloc(strlen(rest_line) + 20); + if(!line) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + + /* exchange amca word 'src' with YH:YL and 'dst' with ZH:ZL */ + for(c = 0, a = strlen(rest_line); c < a; c++) { + switch (tolower(rest_line[c])) { + case 's': + if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 'r') && (rest_line[c+2] == 'c') && IS_SEPARATOR(rest_line[c+3])) { + strcpy(&line[b],"YH:YL"); + b += 5; + c += 2; + } + else { + line[b++] = rest_line[c]; + } + break; + case 'd': + if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 's') && (rest_line[c+2] == 't') && IS_SEPARATOR(rest_line[c+3])) { + strcpy(&line[b],"ZH:ZL"); + b += 5; + c += 2; + } + else { + line[b++] = rest_line[c]; + } + break; +// case ';': +// break; + default: + line[b++] = rest_line[c]; + } + } + strcpy(&line[b],"\n"); /* set CR/LF at the end of the line */ + + + /* here we split up the macro arguments into "macro_args" + * Extended macro code interpreter added by TW 2002 + */ + + temp = line; + /* test for advanced parameters */ + if( temp[0] == '[' ) { // there must be "[" " then "]", else it is garbage + if(!strchr(temp, ']')) { + print_msg(pi, MSGTYPE_ERROR, "found no closing ']'"); + return(False); + } + + // Okay now we are within the advanced code interpreter + + temp++; // = &temp[1]; // skip the first bracket + nmn = malloc(LINEBUFFER_LENGTH); + if(!nmn) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(nmn,macro->name); // create a new macro name buffer + c = 1; // byte counter + arg = True; // loop flag + + while(arg) { + while(IS_HOR_SPACE(temp[0])) { //skip leading spaces + temp++; // = &temp[1]; + } + off = 0; // pointer offset + do { + switch(temp[off]) { //test current character code + case ':': + temp[off] = '\0'; + if(off > 0) { + c++; + macro_args[macro_arg_count++] = temp; + } + else { + print_msg(pi, MSGTYPE_ERROR, "missing register before ':'",nmn); + return(False); + } + break; + case ']': + arg = False; + case ',': + a = off; + do temp[a--] = '\0'; while( IS_HOR_SPACE(temp[a]) ); + if(off > 0) { + macro_args[macro_arg_count++] = temp; + append_type(pi, nmn, c, temp); + c = 1; + } + else { + append_type(pi, nmn, 0, temp); + c = 1; + } + break; + + default: + off++; + } + } + while(temp[off] != '\0'); + + if(arg) temp = &temp[off+1]; + else break; + } + + macro = get_macro(pi,nmn); + if(macro == NULL) { + print_msg(pi, MSGTYPE_ERROR, "Macro %s is not defined !",nmn); + return(False); + } + free(nmn); + } + /* or else, we handle the macro as normal macro */ + else { + line = malloc(strlen(rest_line) + 1); + if(!line) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(line, rest_line); + temp = line; + while(temp) { + macro_args[macro_arg_count++] = temp; + temp = get_next_token(temp, TERM_COMMA); + } + } + } + + if(pi->pass == PASS_1) { + macro_call = calloc(1, sizeof(struct macro_call)); + if(!macro_call) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + if(pi->last_macro_call) + pi->last_macro_call->next = macro_call; + else + pi->first_macro_call = macro_call; + + pi->last_macro_call = macro_call; + macro_call->line_number = pi->fi->line_number; + macro_call->include_file = pi->fi->include_file; + macro_call->macro = macro; + macro_call->prev_on_stack = pi->macro_call; + + if(macro_call->prev_on_stack) { + macro_call->nest_level = macro_call->prev_on_stack->nest_level + 1; + macro_call->prev_line_index = macro_call->prev_on_stack->line_index; + } + } + else { + for(macro_call = pi->first_macro_call; macro_call; macro_call = macro_call->next) { + if((macro_call->include_file->num == pi->fi->include_file->num) && (macro_call->line_number == pi->fi->line_number)) { + if(pi->macro_call) { + /* Find correct macro_call when using recursion and nesting */ + if(macro_call->prev_on_stack == pi->macro_call) + if((macro_call->nest_level == (pi->macro_call->nest_level + 1)) && (macro_call->prev_line_index == pi->macro_call->line_index)) + break; + } + else break; + } + } + if(pi->list_line && pi->list_on) { + fprintf(pi->list_file, "C:%06x + %s\n", pi->cseg_addr, pi->list_line); + pi->list_line = NULL; + } + } + + macro_call->line_index = 0; + pi->macro_call = macro_call; + old_macro_line = pi->macro_line; + + //printf("\nconvert macro: '%s'\n",macro->name); + + for(pi->macro_line = macro->first_macro_line; pi->macro_line && ok; pi->macro_line = pi->macro_line->next) { + macro_call->line_index++; + if(GET_ARG(pi->args, ARG_LISTMAC)) + pi->list_line = buff; + else + pi->list_line = NULL; + + /* here we change jumps/calls within macro that corresponds to macro labels. + Only in case there is an entry in macro_label list */ + + strcpy(buff,"\0"); + macro_label = get_macro_label(pi->macro_line->line,macro); + if(macro_label) { + /* test if the right macro label has been found */ + temp = strstr(pi->macro_line->line,macro_label->label); + c = strlen(macro_label->label); + if(temp[c] == ':') { /* it is a label definition */ + macro_label->running_number++; + strncpy(buff, macro_label->label, c - 1); + buff[c - 1] = 0; + i = strlen(buff) + 2; /* we set the process indeafter label */ + /* add running number to it */ + strcpy(&buff[c-1],itoa(macro_label->running_number, tmp, 10)); + strcat(buff, ":\0"); + } + else if(IS_HOR_SPACE(temp[c]) || IS_END_OR_COMMENT(temp[c])) { /* it is a jump to a macro defined label */ + strcpy(buff,pi->macro_line->line); + temp = strstr(buff, macro_label->label); + i = temp - buff + strlen(macro_label->label); + strncpy(temp, macro_label->label, c - 1); + strcpy(&temp[c-1], itoa(macro_label->running_number, tmp, 10)); + } + } + else { + i = 0; + } + + /* here we check every character of current line */ + for(j = i; pi->macro_line->line[i] != '\0'; i++) { + /* check for register place holders */ + if(pi->macro_line->line[i] == '@') { + i++; + if(!isdigit(pi->macro_line->line[i])) + print_msg(pi, MSGTYPE_ERROR, "@ must be followed by a number"); + else if((pi->macro_line->line[i] - '0') >= macro_arg_count) + print_msg(pi, MSGTYPE_ERROR, "Missing macro argument (for @%c)", pi->macro_line->line[i]); + else { + /* and replace them with given registers */ + strcat(&buff[j], macro_args[pi->macro_line->line[i] - '0']); + j += strlen(macro_args[pi->macro_line->line[i] - '0']); + } + } + else if (pi->macro_line->line[i] == ';') { + strncat(buff, "\n", 1); + break; + } + else { + strncat(buff, &pi->macro_line->line[i], 1); + } + } + + ok = parse_line(pi, buff); + if(ok) { + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) + fprintf(pi->list_file, " %s\n", pi->list_line); + if(pi->error_count >= pi->max_errors) { + print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting..."); + ok = False; + break; + } + } + } + + pi->macro_line = old_macro_line; + pi->macro_call = macro_call->prev_on_stack; + if(rest_line) + free(line); + return(ok); +} + +struct macro_label *get_macro_label(char *line, struct macro *macro) +{ + char *temp ; + struct macro_label *macro_label; + + for(macro_label = macro->first_label; macro_label; macro_label = macro_label->next) { + temp = strstr(line,macro_label->label); + if(temp) { + return macro_label; + } + } + return NULL; +} + +/* end of macro.c */ + diff --git a/contrib/toolchain/avra/src/map.c b/contrib/toolchain/avra/src/map.c new file mode 100644 index 000000000..1f2d205e2 --- /dev/null +++ b/contrib/toolchain/avra/src/map.c @@ -0,0 +1,76 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include "avra.h" +#include "args.h" + +char *Space(char *n); + +void write_map_file(struct prog_info *pi) +{ + FILE *fp; + struct label *label; + char Filename[200]; + + if (!pi->map_on) { + return; + } + + strcpy(Filename, GET_ARG(pi->args, ARG_MAPFILE)); + fp = fopen(Filename,"w"); + if( fp == NULL ) { + fprintf(stderr,"Error: cannot create map file\n"); + return; + } + for(label = pi->first_constant; label; label = label->next) + fprintf(fp,"%s%sC\t%04x\t%d\n",label->name,Space(label->name),label->value,label->value); + + for(label = pi->first_variable; label; label = label->next) + fprintf(fp,"%s%sV\t%04x\t%d\n",label->name,Space(label->name),label->value,label->value); + + for(label = pi->first_label; label; label = label->next) + fprintf(fp,"%s%sL\t%04x\t%d\n",label->name,Space(label->name),label->value,label->value); + + fprintf(fp,"\n"); + fclose(fp); + return; +} + +char *Space(char *n) +{ + int i; + + i = strlen(n); + if( i < 1) return "\t\t\t"; + if( i < 8 ) return "\t\t"; + return "\t"; +} + +/* end of map.c */ + diff --git a/contrib/toolchain/avra/src/misc.h b/contrib/toolchain/avra/src/misc.h new file mode 100644 index 000000000..8b3513b00 --- /dev/null +++ b/contrib/toolchain/avra/src/misc.h @@ -0,0 +1,19 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2003 Jon Anders Haugum, Tobias Weber + * + * Misc stuff + */ + +enum boolean {False = 0, True}; + +enum filetype +{ + AVRSTUDIO = 0, + GENERIC, + INTEL, + MOTOROLA +}; + diff --git a/contrib/toolchain/avra/src/mnemonic.c b/contrib/toolchain/avra/src/mnemonic.c new file mode 100644 index 000000000..a6dcceb39 --- /dev/null +++ b/contrib/toolchain/avra/src/mnemonic.c @@ -0,0 +1,793 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +#include +#include +#include +#include + +#include "misc.h" +#include "avra.h" +#include "device.h" + +#define MAX_MNEMONIC_LEN 8 // Maximum mnemonic length + +enum { + MNEMONIC_NOP = 0, // 0000 0000 0000 0000 + MNEMONIC_SEC, // 1001 0100 0000 1000 + MNEMONIC_CLC, // 1001 0100 1000 1000 + MNEMONIC_SEN, // 1001 0100 0010 1000 + MNEMONIC_CLN, // 1001 0100 1010 1000 + MNEMONIC_SEZ, // 1001 0100 0001 1000 + MNEMONIC_CLZ, // 1001 0100 1001 1000 + MNEMONIC_SEI, // 1001 0100 0111 1000 + MNEMONIC_CLI, // 1001 0100 1111 1000 + MNEMONIC_SES, // 1001 0100 0100 1000 + MNEMONIC_CLS, // 1001 0100 1100 1000 + MNEMONIC_SEV, // 1001 0100 0011 1000 + MNEMONIC_CLV, // 1001 0100 1011 1000 + MNEMONIC_SET, // 1001 0100 0110 1000 + MNEMONIC_CLT, // 1001 0100 1110 1000 + MNEMONIC_SEH, // 1001 0100 0101 1000 + MNEMONIC_CLH, // 1001 0100 1101 1000 + MNEMONIC_SLEEP, // 1001 0101 1000 1000 + MNEMONIC_WDR, // 1001 0101 1010 1000 + MNEMONIC_IJMP, // 1001 0100 0000 1001 + MNEMONIC_EIJMP, // 1001 0100 0001 1001 + MNEMONIC_ICALL, // 1001 0101 0000 1001 + MNEMONIC_EICALL, // 1001 0101 0001 1001 + MNEMONIC_RET, // 1001 0101 0000 1000 + MNEMONIC_RETI, // 1001 0101 0001 1000 + MNEMONIC_SPM, // 1001 0101 1110 1000 + MNEMONIC_ESPM, // 1001 0101 1111 1000 + MNEMONIC_BREAK, // 1001 0101 1001 1000 + MNEMONIC_LPM, // 1001 0101 1100 1000 + MNEMONIC_ELPM, // 1001 0101 1101 1000 + MNEMONIC_BSET, // s 1001 0100 0sss 1000 + MNEMONIC_BCLR, // s 1001 0100 1sss 1000 + MNEMONIC_SER, // Rd 1110 1111 dddd 1111 + MNEMONIC_COM, // Rd 1001 010d dddd 0000 + MNEMONIC_NEG, // Rd 1001 010d dddd 0001 + MNEMONIC_INC, // Rd 1001 010d dddd 0011 + MNEMONIC_DEC, // Rd 1001 010d dddd 1010 + MNEMONIC_LSR, // Rd 1001 010d dddd 0110 + MNEMONIC_ROR, // Rd 1001 010d dddd 0111 + MNEMONIC_ASR, // Rd 1001 010d dddd 0101 + MNEMONIC_SWAP, // Rd 1001 010d dddd 0010 + MNEMONIC_PUSH, // Rr 1001 001r rrrr 1111 + MNEMONIC_POP, // Rd 1001 000d dddd 1111 + MNEMONIC_TST, // Rd 0010 00dd dddd dddd + MNEMONIC_CLR, // Rd 0010 01dd dddd dddd + MNEMONIC_LSL, // Rd 0000 11dd dddd dddd + MNEMONIC_ROL, // Rd 0001 11dd dddd dddd + MNEMONIC_BREQ, // k 1111 00kk kkkk k001 + MNEMONIC_BRNE, // k 1111 01kk kkkk k001 + MNEMONIC_BRCS, // k 1111 00kk kkkk k000 + MNEMONIC_BRCC, // k 1111 01kk kkkk k000 + MNEMONIC_BRSH, // k 1111 01kk kkkk k000 + MNEMONIC_BRLO, // k 1111 00kk kkkk k000 + MNEMONIC_BRMI, // k 1111 00kk kkkk k010 + MNEMONIC_BRPL, // k 1111 01kk kkkk k010 + MNEMONIC_BRGE, // k 1111 01kk kkkk k100 + MNEMONIC_BRLT, // k 1111 00kk kkkk k100 + MNEMONIC_BRHS, // k 1111 00kk kkkk k101 + MNEMONIC_BRHC, // k 1111 01kk kkkk k101 + MNEMONIC_BRTS, // k 1111 00kk kkkk k110 + MNEMONIC_BRTC, // k 1111 01kk kkkk k110 + MNEMONIC_BRVS, // k 1111 00kk kkkk k011 + MNEMONIC_BRVC, // k 1111 01kk kkkk k011 + MNEMONIC_BRIE, // k 1111 00kk kkkk k111 + MNEMONIC_BRID, // k 1111 01kk kkkk k111 + MNEMONIC_RJMP, // k 1100 kkkk kkkk kkkk + MNEMONIC_RCALL, // k 1101 kkkk kkkk kkkk + MNEMONIC_JMP, // k 1001 010k kkkk 110k + 16k + MNEMONIC_CALL, // k 1001 010k kkkk 111k + 16k + MNEMONIC_BRBS, // s, k 1111 00kk kkkk ksss + MNEMONIC_BRBC, // s, k 1111 01kk kkkk ksss + MNEMONIC_ADD, // Rd, Rr 0000 11rd dddd rrrr + MNEMONIC_ADC, // Rd, Rr 0001 11rd dddd rrrr + MNEMONIC_SUB, // Rd, Rr 0001 10rd dddd rrrr + MNEMONIC_SBC, // Rd, Rr 0000 10rd dddd rrrr + MNEMONIC_AND, // Rd, Rr 0010 00rd dddd rrrr + MNEMONIC_OR, // Rd, Rr 0010 10rd dddd rrrr + MNEMONIC_EOR, // Rd, Rr 0010 01rd dddd rrrr + MNEMONIC_CP, // Rd, Rr 0001 01rd dddd rrrr + MNEMONIC_CPC, // Rd, Rr 0000 01rd dddd rrrr + MNEMONIC_CPSE, // Rd, Rr 0001 00rd dddd rrrr + MNEMONIC_MOV, // Rd, Rr 0010 11rd dddd rrrr + MNEMONIC_MUL, // Rd, Rr 1001 11rd dddd rrrr + MNEMONIC_MOVW, // Rd, Rr 0000 0001 dddd rrrr + MNEMONIC_MULS, // Rd, Rr 0000 0010 dddd rrrr + MNEMONIC_MULSU, // Rd, Rr 0000 0011 0ddd 0rrr + MNEMONIC_FMUL, // Rd, Rr 0000 0011 0ddd 1rrr + MNEMONIC_FMULS, // Rd, Rr 0000 0011 1ddd 0rrr + MNEMONIC_FMULSU, // Rd, Rr 0000 0011 1ddd 1rrr + MNEMONIC_ADIW, // Rd, K 1001 0110 KKdd KKKK + MNEMONIC_SBIW, // Rd, K 1001 0111 KKdd KKKK + MNEMONIC_SUBI, // Rd, K 0101 KKKK dddd KKKK + MNEMONIC_SBCI, // Rd, K 0100 KKKK dddd KKKK + MNEMONIC_ANDI, // Rd, K 0111 KKKK dddd KKKK + MNEMONIC_ORI, // Rd, K 0110 KKKK dddd KKKK + MNEMONIC_SBR, // Rd, K 0110 KKKK dddd KKKK + MNEMONIC_CPI, // Rd, K 0011 KKKK dddd KKKK + MNEMONIC_LDI, // Rd, K 1110 KKKK dddd KKKK + MNEMONIC_CBR, // Rd, K 0111 KKKK dddd KKKK ~K + MNEMONIC_SBRC, // Rr, b 1111 110r rrrr 0bbb + MNEMONIC_SBRS, // Rr, b 1111 111r rrrr 0bbb + MNEMONIC_BST, // Rr, b 1111 101d dddd 0bbb + MNEMONIC_BLD, // Rd, b 1111 100d dddd 0bbb + MNEMONIC_IN, // Rd, P 1011 0PPd dddd PPPP + MNEMONIC_OUT, // P, Rr 1011 1PPr rrrr PPPP + MNEMONIC_SBIC, // P, b 1001 1001 PPPP Pbbb + MNEMONIC_SBIS, // P, b 1001 1011 PPPP Pbbb + MNEMONIC_SBI, // P, b 1001 1010 PPPP Pbbb + MNEMONIC_CBI, // P, b 1001 1000 PPPP Pbbb + MNEMONIC_LDS, // Rd, k 1001 000d dddd 0000 + 16k + MNEMONIC_STS, // k, Rr 1001 001d dddd 0000 + 16k + MNEMONIC_LD, // Rd, __ dummy + MNEMONIC_ST, // __, Rr dummy + MNEMONIC_LDD, // Rd, _+q dummy + MNEMONIC_STD, // _+q, Rr dummy + MNEMONIC_COUNT, + MNEMONIC_LPM_Z, // Rd, Z 1001 000d dddd 0100 + MNEMONIC_LPM_ZP, // Rd, Z+ 1001 000d dddd 0101 + MNEMONIC_ELPM_Z, // Rd, Z 1001 000d dddd 0110 + MNEMONIC_ELPM_ZP, // Rd, Z+ 1001 000d dddd 0111 + MNEMONIC_LD_X, // Rd, X 1001 000d dddd 1100 + MNEMONIC_LD_XP, // Rd, X+ 1001 000d dddd 1101 + MNEMONIC_LD_MX, // Rd, -X 1001 000d dddd 1110 + MNEMONIC_LD_Y, // Rd, Y 1000 000d dddd 1000 + MNEMONIC_LD_YP, // Rd, Y+ 1001 000d dddd 1001 + MNEMONIC_LD_MY, // Rd, -Y 1001 000d dddd 1010 + MNEMONIC_LD_Z, // Rd, Z 1000 000d dddd 0000 + MNEMONIC_LD_ZP, // Rd, Z+ 1001 000d dddd 0001 + MNEMONIC_LD_MZ, // Rd, -Z 1001 000d dddd 0010 + MNEMONIC_ST_X, // X, Rr 1001 001d dddd 1100 + MNEMONIC_ST_XP, // X+, Rr 1001 001d dddd 1101 + MNEMONIC_ST_MX, // -X, Rr 1001 001d dddd 1110 + MNEMONIC_ST_Y, // Y, Rr 1000 001d dddd 1000 + MNEMONIC_ST_YP, // Y+, Rr 1001 001d dddd 1001 + MNEMONIC_ST_MY, // -Y, Rr 1001 001d dddd 1010 + MNEMONIC_ST_Z, // Z, Rr 1000 001d dddd 0000 + MNEMONIC_ST_ZP, // Z+, Rr 1001 001d dddd 0001 + MNEMONIC_ST_MZ, // -Z, Rr 1001 001d dddd 0010 + MNEMONIC_LDD_Y, // Rd, Y+q 10q0 qq0d dddd 1qqq + MNEMONIC_LDD_Z, // Rd, Z+q 10q0 qq0d dddd 0qqq + MNEMONIC_STD_Y, // Y+q, Rr 10q0 qq1r rrrr 1qqq + MNEMONIC_STD_Z, // Z+q, Rr 10q0 qq1r rrrr 0qqq + MNEMONIC_END +}; + +struct instruction { + char *mnemonic; + int opcode; + int flag; /* Device flags meaning the instruction is not + supported */ +}; + +struct instruction instruction_list[] = { + {"nop", 0x0000, 0}, + {"sec", 0x9408, 0}, + {"clc", 0x9488, 0}, + {"sen", 0x9428, 0}, + {"cln", 0x94a8, 0}, + {"sez", 0x9418, 0}, + {"clz", 0x9498, 0}, + {"sei", 0x9478, 0}, + {"cli", 0x94f8, 0}, + {"ses", 0x9448, 0}, + {"cls", 0x94c8, 0}, + {"sev", 0x9438, 0}, + {"clv", 0x94b8, 0}, + {"set", 0x9468, 0}, + {"clt", 0x94e8, 0}, + {"seh", 0x9458, 0}, + {"clh", 0x94d8, 0}, + {"sleep", 0x9588, 0}, + {"wdr", 0x95a8, 0}, + {"ijmp", 0x9409, DF_TINY1X}, + {"eijmp", 0x9419, DF_NO_EIJMP}, + {"icall", 0x9509, DF_TINY1X}, + {"eicall",0x9519, DF_NO_EICALL}, + {"ret", 0x9508, 0}, + {"reti", 0x9518, 0}, + {"spm", 0x95e8, DF_NO_SPM}, + {"espm", 0x95f8, DF_NO_ESPM}, + {"break", 0x9598, DF_NO_BREAK}, + {"lpm", 0x95c8, DF_NO_LPM}, + {"elpm", 0x95d8, DF_NO_ELPM}, + {"bset", 0x9408, 0}, + {"bclr", 0x9488, 0}, + {"ser", 0xef0f, 0}, + {"com", 0x9400, 0}, + {"neg", 0x9401, 0}, + {"inc", 0x9403, 0}, + {"dec", 0x940a, 0}, + {"lsr", 0x9406, 0}, + {"ror", 0x9407, 0}, + {"asr", 0x9405, 0}, + {"swap", 0x9402, 0}, + {"push", 0x920f, DF_TINY1X}, + {"pop", 0x900f, DF_TINY1X}, + {"tst", 0x2000, 0}, + {"clr", 0x2400, 0}, + {"lsl", 0x0c00, 0}, + {"rol", 0x1c00, 0}, + {"breq", 0xf001, 0}, + {"brne", 0xf401, 0}, + {"brcs", 0xf000, 0}, + {"brcc", 0xf400, 0}, + {"brsh", 0xf400, 0}, + {"brlo", 0xf000, 0}, + {"brmi", 0xf002, 0}, + {"brpl", 0xf402, 0}, + {"brge", 0xf404, 0}, + {"brlt", 0xf004, 0}, + {"brhs", 0xf005, 0}, + {"brhc", 0xf405, 0}, + {"brts", 0xf006, 0}, + {"brtc", 0xf406, 0}, + {"brvs", 0xf003, 0}, + {"brvc", 0xf403, 0}, + {"brie", 0xf007, 0}, + {"brid", 0xf407, 0}, + {"rjmp", 0xc000, 0}, + {"rcall", 0xd000, 0}, + {"jmp", 0x940c, DF_NO_JMP}, + {"call", 0x940e, DF_NO_JMP}, + {"brbs", 0xf000, 0}, + {"brbc", 0xf400, 0}, + {"add", 0x0c00, 0}, + {"adc", 0x1c00, 0}, + {"sub", 0x1800, 0}, + {"sbc", 0x0800, 0}, + {"and", 0x2000, 0}, + {"or", 0x2800, 0}, + {"eor", 0x2400, 0}, + {"cp", 0x1400, 0}, + {"cpc", 0x0400, 0}, + {"cpse", 0x1000, 0}, + {"mov", 0x2c00, 0}, + {"mul", 0x9c00, DF_NO_MUL}, + {"movw", 0x0100, DF_NO_MOVW}, + {"muls", 0x0200, DF_NO_MUL}, + {"mulsu", 0x0300, DF_NO_MUL}, + {"fmul", 0x0308, DF_NO_MUL}, + {"fmuls", 0x0380, DF_NO_MUL}, + {"fmulsu",0x0388, DF_NO_MUL}, + {"adiw", 0x9600, DF_TINY1X}, + {"sbiw", 0x9700, DF_TINY1X}, + {"subi", 0x5000, 0}, + {"sbci", 0x4000, 0}, + {"andi", 0x7000, 0}, + {"ori", 0x6000, 0}, + {"sbr", 0x6000, 0}, + {"cpi", 0x3000, 0}, + {"ldi", 0xe000, 0}, + {"cbr", 0x7000, 0}, + {"sbrc", 0xfc00, 0}, + {"sbrs", 0xfe00, 0}, + {"bst", 0xfa00, 0}, + {"bld", 0xf800, 0}, + {"in", 0xb000, 0}, + {"out", 0xb800, 0}, + {"sbic", 0x9900, 0}, + {"sbis", 0x9b00, 0}, + {"sbi", 0x9a00, 0}, + {"cbi", 0x9800, 0}, + {"lds", 0x9000, DF_TINY1X}, + {"sts", 0x9200, DF_TINY1X}, + {"ld", 0, 0}, + {"st", 0, 0}, + {"ldd", 0, DF_TINY1X}, + {"std", 0, DF_TINY1X}, + {"count", 0, 0}, + {"lpm", 0x9004, DF_NO_LPM|DF_NO_LPM_X}, + {"lpm", 0x9005, DF_NO_LPM|DF_NO_LPM_X}, + {"elpm", 0x9006, DF_NO_ELPM|DF_NO_ELPM_X}, + {"elpm", 0x9007, DF_NO_ELPM|DF_NO_ELPM_X}, + {"ld", 0x900c, DF_NO_XREG}, + {"ld", 0x900d, DF_NO_XREG}, + {"ld", 0x900e, DF_NO_XREG}, + {"ld", 0x8008, DF_NO_YREG}, + {"ld", 0x9009, DF_NO_YREG}, + {"ld", 0x900a, DF_NO_YREG}, + {"ld", 0x8000, 0}, + {"ld", 0x9001, DF_TINY1X}, + {"ld", 0x9002, DF_TINY1X}, + {"st", 0x920c, DF_NO_XREG}, + {"st", 0x920d, DF_NO_XREG}, + {"st", 0x920e, DF_NO_XREG}, + {"st", 0x8208, DF_NO_YREG}, + {"st", 0x9209, DF_NO_YREG}, + {"st", 0x920a, DF_NO_YREG}, + {"st", 0x8200, 0}, + {"st", 0x9201, DF_TINY1X}, + {"st", 0x9202, DF_TINY1X}, + {"ldd", 0x8008, DF_TINY1X}, + {"ldd", 0x8000, DF_TINY1X}, + {"std", 0x8208, DF_TINY1X}, + {"std", 0x8200, DF_TINY1X}, + {"end", 0, 0} + }; + + +/* We try to parse the command name. Is it a assembler mnemonic or anything else ? + * If so, it may be a macro. +*/ + +int parse_mnemonic(struct prog_info *pi) +{ + int mnemonic; + int i; + int opcode = 0; + int opcode2 = 0; + int instruction_long = False; + char *operand1; + char *operand2; + struct macro *macro; + char temp[MAX_MNEMONIC_LEN + 1]; + + operand1 = get_next_token(pi->fi->scratch, TERM_SPACE); // we get the first word on line + mnemonic = get_mnemonic_type(my_strlwr(pi->fi->scratch)); + if(mnemonic == -1) { // if -1 this must be a macro name + macro = get_macro(pi, pi->fi->scratch); // and so, we try to get the corresponding macro struct. + if(macro) { + return(expand_macro(pi, macro, operand1)); // we expand the macro + } else { // if we cant find a name, this is a unknown word. + print_msg(pi, MSGTYPE_ERROR, "Unknown mnemonic/macro: %s", pi->fi->scratch); + return(True); + } + } + if(pi->pass == PASS_2) { + if(mnemonic <= MNEMONIC_BREAK) { + if(operand1) { + print_msg(pi, MSGTYPE_WARNING, "Garbage after instruction %s: %s", instruction_list[mnemonic].mnemonic, operand1); } + opcode = 0; // No operand + } else if(mnemonic <= MNEMONIC_ELPM) { + if(operand1) { + operand2 = get_next_token(operand1, TERM_COMMA); + if(!operand2) { + print_msg(pi, MSGTYPE_ERROR, "%s needs a second operand", instruction_list[mnemonic].mnemonic); + return(True); } + get_next_token(operand2, TERM_END); + i = get_register(pi, operand1); + opcode = i << 4; + i = get_indirect(pi, operand2); + if(i == 6) { // Means Z + if(mnemonic == MNEMONIC_LPM) + mnemonic = MNEMONIC_LPM_Z; + else if(mnemonic == MNEMONIC_ELPM) + mnemonic = MNEMONIC_ELPM_Z; + } else if(i == 7) { // Means Z+ + if(mnemonic == MNEMONIC_LPM) + mnemonic = MNEMONIC_LPM_ZP; + else if(mnemonic == MNEMONIC_ELPM) + mnemonic = MNEMONIC_ELPM_ZP; + } else { + print_msg(pi, MSGTYPE_ERROR, "Unsupported operand: %s", operand2); + return(True); + } + } else + opcode = 0; + } else { + if(!operand1) { + print_msg(pi, MSGTYPE_ERROR, "%s needs an operand", instruction_list[mnemonic].mnemonic); + return(True); + } + operand2 = get_next_token(operand1, TERM_COMMA); + if(mnemonic >= MNEMONIC_BRBS) { + if(!operand2) { + print_msg(pi, MSGTYPE_ERROR, "%s needs a second operand", instruction_list[mnemonic].mnemonic); + return(True); + } + get_next_token(operand2, TERM_END); + } + if(mnemonic <= MNEMONIC_BCLR) { + if(!get_bitnum(pi, operand1, &i)) + return(False); + opcode = i << 4; + } else if(mnemonic <= MNEMONIC_ROL) { + i = get_register(pi, operand1); + if((mnemonic == MNEMONIC_SER) && (i < 16)) { + print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic); + i &= 0x0f; + } + opcode = i << 4; + if(mnemonic >= MNEMONIC_TST) + opcode |= ((i & 0x10) << 5) | (i & 0x0f); + } else if(mnemonic <= MNEMONIC_RCALL) { + if(!get_expr(pi, operand1, &i)) + return(False); + i -= pi->cseg_addr + 1; + if(mnemonic <= MNEMONIC_BRID) { + if((i < -64) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "Branch out of range (-64 <= k <= 63)"); + opcode = (i & 0x7f) << 3; + } else { + if(((i < -2048) || (i > 2047)) && (pi->device->flash_size != 4096)) + print_msg(pi, MSGTYPE_ERROR, "Relative address out of range (-2048 <= k <= 2047)"); + opcode = i & 0x0fff; + } + } else if(mnemonic <= MNEMONIC_CALL) { + if(!get_expr(pi, operand1, &i)) + return(False); + if((i < 0) || (i > 4194303)) + print_msg(pi, MSGTYPE_ERROR, "Address out of range (0 <= k <= 4194303)"); + opcode = ((i & 0x3e0000) >> 13) | ((i & 0x010000) >> 16); + opcode2 = i & 0xffff; + instruction_long = True; + } else if(mnemonic <= MNEMONIC_BRBC) { + if(!get_bitnum(pi, operand1, &i)) + return(False); + opcode = i; + if(!get_expr(pi, operand2, &i)) + return(False); + i -= pi->cseg_addr + 1; + if((i < -64) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "Branch out of range (-64 <= k <= 63)"); + opcode |= (i & 0x7f) << 3; + } else if(mnemonic <= MNEMONIC_MUL) { + i = get_register(pi, operand1); + opcode = i << 4; + i = get_register(pi, operand2); + opcode |= ((i & 0x10) << 5) | (i & 0x0f); + } else if(mnemonic <= MNEMONIC_MOVW) { + i = get_register(pi, operand1); + if((i % 2) == 1) + print_msg(pi, MSGTYPE_ERROR, "%s must use a even numbered register for Rd", instruction_list[mnemonic].mnemonic); + opcode = (i / 2) << 4; + i = get_register(pi, operand2); + if((i % 2) == 1) + print_msg(pi, MSGTYPE_ERROR, "%s must use a even numbered register for Rr", instruction_list[mnemonic].mnemonic); + opcode |= i / 2; + } else if(mnemonic <= MNEMONIC_MULS) { + i = get_register(pi, operand1); + if(i < 16) + print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic); + opcode = (i & 0x0f) << 4; + i = get_register(pi, operand2); + if(i < 16) + print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic); + opcode |= (i & 0x0f); + } else if(mnemonic <= MNEMONIC_FMULSU) { + i = get_register(pi, operand1); + if((i < 16) || (i >= 24)) + print_msg(pi, MSGTYPE_ERROR, "%s can only use registers (r16 - r23)", instruction_list[mnemonic].mnemonic); + opcode = (i & 0x07) << 4; + i = get_register(pi, operand2); + if((i < 16) || (i >= 24)) + print_msg(pi, MSGTYPE_ERROR, "%s can only use registers (r16 - r23)", instruction_list[mnemonic].mnemonic); + opcode |= (i & 0x07); + } else if(mnemonic <= MNEMONIC_SBIW) { + i = get_register(pi, operand1); + if(!((i == 24) || (i == 26) || (i == 28) || (i == 30))) + print_msg(pi, MSGTYPE_ERROR, "%s can only use registers R24, R26, R28 or R30", instruction_list[mnemonic].mnemonic); + opcode = ((i - 24) / 2) << 4; + if(!get_expr(pi, operand2, &i)) + return(False); + if((i < 0) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "Constant out of range (0 <= k <= 63)"); + opcode |= ((i & 0x30) << 2) | (i & 0x0f); + } else if(mnemonic <= MNEMONIC_CBR) { + i = get_register(pi, operand1); + if(i < 16) + print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic); + opcode = (i & 0x0f) << 4; + if(!get_expr(pi, operand2, &i)) + return(False); + if((i < -128) || (i > 255)) + print_msg(pi, MSGTYPE_WARNING, "Constant out of range (-128 <= k <= 255). Will be masked"); + if(mnemonic == MNEMONIC_CBR) + i = ~i; + opcode |= ((i & 0xf0) << 4) | (i & 0x0f); + } else if(mnemonic <= MNEMONIC_BLD) { + i = get_register(pi, operand1); + opcode = i << 4; + if(!get_bitnum(pi, operand2, &i)) + return(False); + opcode |= i; + } else if(mnemonic == MNEMONIC_IN) { + i = get_register(pi, operand1); + opcode = i << 4; + if(!get_expr(pi, operand2, &i)) + return(False); + if((i < 0) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 63)"); + opcode |= ((i & 0x30) << 5) | (i & 0x0f); + } else if(mnemonic == MNEMONIC_OUT) { + if(!get_expr(pi, operand1, &i)) + return(False); + if((i < 0) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 63)"); + opcode = ((i & 0x30) << 5) | (i & 0x0f); + i = get_register(pi, operand2); + opcode |= i << 4; + } else if(mnemonic <= MNEMONIC_CBI) { + if(!get_expr(pi, operand1, &i)) + return(False); + if((i < 0) || (i > 31)) + print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 31)"); + opcode = i << 3; + if(!get_bitnum(pi, operand2, &i)) + return(False); + opcode |= i; + } else if(mnemonic == MNEMONIC_LDS) { + i = get_register(pi, operand1); + opcode = i << 4; + if(!get_expr(pi, operand2, &i)) + return(False); + if((i < 0) || (i > 65535)) + print_msg(pi, MSGTYPE_ERROR, "SRAM out of range (0 <= k <= 65535)"); + opcode2 = i; + instruction_long = True; + } else if(mnemonic == MNEMONIC_STS) { + if(!get_expr(pi, operand1, &i)) + return(False); + if((i < 0) || (i > 65535)) + print_msg(pi, MSGTYPE_ERROR, "SRAM out of range (0 <= k <= 65535)"); + opcode2 = i; + i = get_register(pi, operand2); + opcode = i << 4; + instruction_long = True; + } else if(mnemonic == MNEMONIC_LD) { + i = get_register(pi, operand1); + opcode = i << 4; + mnemonic = MNEMONIC_LD_X + get_indirect(pi, operand2); + } else if(mnemonic == MNEMONIC_ST) { + mnemonic = MNEMONIC_ST_X + get_indirect(pi, operand1); + i = get_register(pi, operand2); + opcode = i << 4; + } else if(mnemonic == MNEMONIC_LDD) { + i = get_register(pi, operand1); + opcode = i << 4; + if(tolower(operand2[0]) == 'z') + mnemonic = MNEMONIC_LDD_Z; + else if(tolower(operand2[0]) == 'y') + mnemonic = MNEMONIC_LDD_Y; + else + print_msg(pi, MSGTYPE_ERROR, "Garbage in second operand (%s)", operand2); + i = 1; + while((operand2[i] != '\0') && (operand2[i] != '+')) i++; + if(operand2[i] == '\0') { + print_msg(pi, MSGTYPE_ERROR, "Garbage in second operand (%s)", operand2); + return(False); + } + if(!get_expr(pi, &operand2[i + 1], &i)) + return(False); + if((i < 0) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "Displacement out of range (0 <= q <= 63)"); + opcode |= ((i & 0x20) << 8) | ((i & 0x18) << 7) | (i & 0x07); + } else if(mnemonic == MNEMONIC_STD) { + if(tolower(operand1[0]) == 'z') + mnemonic = MNEMONIC_STD_Z; + else if(tolower(operand1[0]) == 'y') + mnemonic = MNEMONIC_STD_Y; + else + print_msg(pi, MSGTYPE_ERROR, "Garbage in first operand (%s)", operand1); + i = 1; + while((operand1[i] != '\0') && (operand1[i] != '+')) i++; + if(operand1[i] == '\0') { + print_msg(pi, MSGTYPE_ERROR, "Garbage in first operand (%s)", operand1); + return(False); + } + if(!get_expr(pi, &operand1[i + 1], &i)) + return(False); + if((i < 0) || (i > 63)) + print_msg(pi, MSGTYPE_ERROR, "Displacement out of range (0 <= q <= 63)"); + opcode = ((i & 0x20) << 8) | ((i & 0x18) << 7) | (i & 0x07); + i = get_register(pi, operand2); + opcode |= i << 4; + } else + print_msg(pi, MSGTYPE_ERROR, "Shit! Missing opcode check [%d]...", mnemonic); + } + if (pi->device->flag & instruction_list[mnemonic].flag) { + strncpy(temp, instruction_list[mnemonic].mnemonic, MAX_MNEMONIC_LEN); + print_msg(pi, MSGTYPE_ERROR, "%s instruction is not supported on %s", + my_strupr(temp), pi->device->name); + } + opcode |= instruction_list[mnemonic].opcode; + if(pi->list_on && pi->list_line) { + if(instruction_long) + fprintf(pi->list_file, "C:%06x %04x %04x %s\n", pi->cseg_addr, opcode, opcode2, pi->list_line); + else + fprintf(pi->list_file, "C:%06x %04x %s\n", pi->cseg_addr, opcode, pi->list_line); + pi->list_line = NULL; + } + if(pi->hfi) { + write_prog_word(pi, pi->cseg_addr, opcode); + if(instruction_long) + write_prog_word(pi, pi->cseg_addr + 1, opcode2); + } + if(instruction_long) + pi->cseg_addr += 2; + else + pi->cseg_addr++; + } else { // Pass 1 + if((mnemonic == MNEMONIC_JMP) || (mnemonic == MNEMONIC_CALL) + || (mnemonic == MNEMONIC_LDS) || (mnemonic == MNEMONIC_STS)) { + pi->cseg_addr += 2; + pi->cseg_count += 2; + } else { + pi->cseg_addr++; + pi->cseg_count++; + } + } + return(True); +} + + +int get_mnemonic_type(char *mnemonic) +{ + int i; + + for(i = 0; i < MNEMONIC_COUNT; i++) { + if(!strcmp(mnemonic, instruction_list[i].mnemonic)) { + return(i); + } + } + return(-1); +} + + +int get_register(struct prog_info *pi, char *data) +{ + char *second_reg; + int reg = 0; + struct def *def; + + // Check for any occurence of r1:r0 pairs, and if so skip to second register + second_reg = strchr(data, ':'); + if(second_reg != NULL) + data = second_reg + 1; + + for(def = pi->first_def; def; def = def->next) + if(!nocase_strcmp(def->name, data)) + { + reg = def->reg; + return(reg); + } + if((tolower(data[0]) == 'r') && isdigit(data[1])) { + reg = atoi(&data[1]); + if(reg > 31) + print_msg(pi, MSGTYPE_ERROR, "R%d is not a valid register", reg); + } + else + print_msg(pi, MSGTYPE_ERROR, "No register associated with %s", data); + return(reg); +} + + +int get_bitnum(struct prog_info *pi, char *data, int *ret) +{ + if(!get_expr(pi, data, ret)) + return(False); + if((*ret < 0) || (*ret > 7)) { + print_msg(pi, MSGTYPE_ERROR, "Operand out of range (0 <= s <= 7)"); + return(False); + } + return(True); +} + + +int get_indirect(struct prog_info *pi, char *operand) +{ + int i = 1; + + switch(tolower(operand[0])) { + case '-': + while(IS_HOR_SPACE(operand[i])) i++; + if(operand[i + 1] != '\0') + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + switch(tolower(operand[i])) { + case 'x': + if (pi->device->flag & DF_NO_XREG) + print_msg(pi, MSGTYPE_ERROR, "X register is not supported on %s", pi->device->name); + return(2); + case 'y': + if (pi->device->flag & DF_NO_YREG) + print_msg(pi, MSGTYPE_ERROR, "Y register is not supported on %s", pi->device->name); + return(5); + case 'z': + return(8); + default: + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + return(0); + } + case 'x': + if (pi->device->flag & DF_NO_XREG) + print_msg(pi, MSGTYPE_ERROR, "X register is not supported on %s", pi->device->name); + while(IS_HOR_SPACE(operand[i])) i++; + if(operand[i] == '+') { + if(operand[i + 1] != '\0') + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + return(1); + } + else if(operand[i] == '\0') + return(0); + else + print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand); + return(0); + case 'y': + if (pi->device->flag & DF_NO_YREG) + print_msg(pi, MSGTYPE_ERROR, "Y register is not supported on %s", pi->device->name); + while(IS_HOR_SPACE(operand[i])) i++; + if(operand[i] == '+') { + if(operand[i + 1] != '\0') + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + return(4); + } + else if(operand[i] == '\0') + return(3); + else + print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand); + return(0); + case 'z': + while(IS_HOR_SPACE(operand[i])) i++; + if(operand[i] == '+') { + if(operand[i + 1] != '\0') + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + return(7); + } + else if(operand[i] == '\0') + return(6); + else + print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand); + return(0); + default: + print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand); + } + return(0); +} + +/* Return 1 if instruction name is supported by the current device, + 0 if unsupported, -1 if it is invalid */ +int is_supported(struct prog_info *pi, char *name) { + char temp[MAX_MNEMONIC_LEN+1]; + int mnemonic; + + strncpy(temp,name,MAX_MNEMONIC_LEN); + mnemonic = get_mnemonic_type(my_strlwr(temp)); + if (mnemonic == -1) return -1; + if (pi->device->flag & instruction_list[mnemonic].flag) return 0; + return 1; +} + +int count_supported_instructions(int flags) +{ + int i = 0, count = 0; + while(i < MNEMONIC_END) { + if((i < MNEMONIC_LD) || (i > MNEMONIC_COUNT)) + if(!(flags & instruction_list[i].flag)) + count++; + i++; + } + return(count); +} + +/* end of mnemonic.c */ + diff --git a/contrib/toolchain/avra/src/parser.c b/contrib/toolchain/avra/src/parser.c new file mode 100644 index 000000000..afbfed5f4 --- /dev/null +++ b/contrib/toolchain/avra/src/parser.c @@ -0,0 +1,412 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + * + * + * SourceForge.net: Detail:713798 Strings are not always correctly handled + * Change made by JEG 5-01-03 + * + * global keyword is now .global to match common sytnax. TW 10-11-05 + */ + +#include +#include +#include +#include +#include + +#include "misc.h" +#include "avra.h" +#include "args.h" + + +/* Special fgets. Like fgets, but with better check for CR, LF and FF and without the ending \n char */ +/* size must be >=2. No checks for s=NULL, size<2 or stream=NULL. B.A. */ +char *fgets_new(struct prog_info *pi, char *s, int size, FILE *stream) +{ + int c; + char *ptr=s; + do { + if((c=fgetc(stream))==EOF || IS_ENDLINE(c)) // Terminate at chr$ 10,12,13,0 and EOF + break; + /* + ** concatenate lines terminated with \ only... + */ + if (c == '\\') + { + /* only newline and cr may follow... */ + if((c=fgetc(stream))==EOF) + break; + + if(!IS_ENDLINE(c)) // Terminate at chr$ 10,12,13,0 and EOF + { + *ptr++ = '\\'; // no concatenation, insert it + } + else + { + // mit be additional LF (DOS) + c=fgetc(stream); + if (IS_ENDLINE(c)) + c=fgetc(stream); + + if (c == EOF) + break; + } + } + + *ptr++=c; + } while(--size); + if((c==EOF) && (ptr==s)) // EOF and no chars read -> that's all folks + return NULL; + if(!size) { + print_msg(pi, MSGTYPE_ERROR, "Line to long"); + return NULL; + } + *ptr=0; + if(c==12) // Check for Formfeed (Bug [1462886]) + print_msg(pi, MSGTYPE_WARNING, "Found Formfeed char. Please remove it."); + if(c==13) { // Check for CR LF sequence (DOS/ Windows line termination) + if((c=fgetc(stream)) != 10) { + ungetc(c,stream); + print_msg(pi, MSGTYPE_WARNING, "Found CR (0x0d) without LF (0x0a). Please add a LF."); + } + } + return s; +} + + +/* + * Parses given assembler file + */ + +int parse_file(struct prog_info *pi, char *filename) +{ +#if debug == 1 + printf("parse_file\n"); +#endif + int ok; + int loopok; + struct file_info *fi; + struct include_file *include_file; + ok = True; + if((fi=malloc(sizeof(struct file_info)))==NULL) { + print_msg(pi, MSGTYPE_OUT_OF_MEM,NULL); + return(False); + } + pi->fi = fi; + if(pi->pass == PASS_1) { + if((include_file = malloc(sizeof(struct include_file)))==NULL) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + free(fi); + return(False); + } + include_file->next = NULL; + if(pi->last_include_file) { + pi->last_include_file->next = include_file; + include_file->num = pi->last_include_file->num + 1; + } else { + pi->first_include_file = include_file; + include_file->num = 0; + } + pi->last_include_file = include_file; + if((include_file->name = malloc(strlen(filename) + 1))==NULL) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + free(fi); + return(False); + } + strcpy(include_file->name, filename); + } else { // PASS 2 + for(include_file = pi->first_include_file; include_file; include_file = include_file->next) { + if(!strcmp(include_file->name, filename)) + break; + } + } + if(!include_file) { + print_msg(pi, MSGTYPE_ERROR, "Internal assembler error"); + free(fi); + return(False); + } + fi->include_file = include_file; + fi->line_number = 0; + fi->exit_file = False; +#if debug == 1 + printf("Opening %s\n",filename); +#endif + if((fi->fp = fopen(filename, "r"))==NULL) { + perror(filename); + free(fi); + return(False); + } + loopok = True; + while(loopok && !fi->exit_file) { + if(fgets_new(pi,fi->buff, LINEBUFFER_LENGTH, fi->fp)) { + fi->line_number++; + pi->list_line = fi->buff; + ok = parse_line(pi, fi->buff); +#if debug == 1 + printf("parse_line was %i\n", ok); +#endif + if(ok) { + if((pi->pass == PASS_2) && pi->list_line && pi->list_on) + fprintf(pi->list_file, " %s\n", pi->list_line); + if(pi->error_count >= pi->max_errors) { + print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting..."); + loopok = False; + } + } else { + loopok = False; + } + } else { + loopok = False; + if(!feof(fi->fp)) { + ok = False; + perror(filename); + } + } + } + fclose(fi->fp); + free(fi); + return(ok); +} + + +/**************************************************************************** + * + * function parse_line + * + * Parses one line + * + ****************************************************************************/ + + +int parse_line(struct prog_info *pi, char *line) +{ + char *ptr=NULL; + int k; + int flag=0, i; + int global_label = False; + char temp[LINEBUFFER_LENGTH]; + struct label *label = NULL; + struct macro_call *macro_call; + + while(IS_HOR_SPACE(*line)) line++; /* At first remove leading spaces / tabs */ + if(IS_END_OR_COMMENT(*line)) /* Skip comment line or empty line */ + return(True); + /* Filter out .stab debugging information */ + /* .stabs sometimes contains colon : symbol - might be interpreted as label */ + if(*line == '.') { /* minimal slowdown of existing code */ + if(strncmp(temp,".stabs ",7) == 0 ) { /* compiler output is always lower case */ + strcpy(temp,line); /* TODO : Do we need this temp variable ? Please check */ + return parse_stabs( pi, temp ); + } + if(strncmp(temp,".stabn ",7) == 0 ) { + strcpy(temp,line); + return parse_stabn( pi, temp ); + } + } + /* Meta information translation */ + ptr=line; + k=0; + while((ptr=strchr(ptr, '%')) != NULL) { + if(!strncmp(ptr, "%MINUTE%", 8) ) { /* Replacement always shorter than tag -> no length check */ + k=strftime(ptr,3,"%M", localtime(&pi->time)); + strcpy(ptr+k,ptr+8); + ptr+=k; + continue; + } + if(!strncmp(ptr, "%HOUR%", 6) ) { + k=strftime(ptr,3,"%H", localtime(&pi->time)); + strcpy(ptr+k,ptr+6); + ptr+=k; + continue; + } + if(!strncmp(ptr, "%DAY%", 5) ) { + k=strftime(ptr,3,"%d", localtime(&pi->time)); + strcpy(ptr+k,ptr+5); + ptr+=k; + continue; + } + if(!strncmp(ptr, "%MONTH%", 7) ) { + k=strftime(ptr,3,"%m", localtime(&pi->time)); + strcpy(ptr+k,ptr+7); + ptr+=k; + continue; + } + if(!strncmp(ptr, "%YEAR%", 6) ) { + k=strftime(ptr,5,"%Y", localtime(&pi->time)); + strcpy(ptr+k,ptr+6); + ptr+=k; + continue; + } + ptr++; + } + +// if(pi->pass == PASS_2) // TODO : Test +// strcpy(pi->list_line, line); + + strcpy(pi->fi->scratch,line); + + for(i = 0; IS_LABEL(pi->fi->scratch[i]) || (pi->fi->scratch[i] == ':'); i++) + if(pi->fi->scratch[i] == ':') { /* it is a label */ + pi->fi->scratch[i] = '\0'; + if(pi->pass == PASS_1) { + for(macro_call = pi->macro_call; macro_call; macro_call = macro_call->prev_on_stack) { + for(label = pi->macro_call->first_label; label; label = label->next) { + if(!nocase_strcmp(label->name, &pi->fi->scratch[0])) { + print_msg(pi, MSGTYPE_ERROR, "Can't redefine local label %s", &pi->fi->scratch[0]); + break; + } + } + } + if(test_label(pi,&pi->fi->scratch[0],"Can't redefine label %s")!=NULL) + break; + if(test_variable(pi,&pi->fi->scratch[0],"%s have already been defined as a .SET variable")!=NULL) + break; + if(test_constant(pi,&pi->fi->scratch[0],"%s has already been defined as a .EQU constant")!=NULL) + break; + label = malloc(sizeof(struct label)); + if(!label) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + label->next = NULL; + label->name = malloc(strlen(&pi->fi->scratch[0]) + 1); + if(!label->name) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return(False); + } + strcpy(label->name, &pi->fi->scratch[0]); + switch(pi->segment) { + case SEGMENT_CODE: + label->value = pi->cseg_addr; + break; + case SEGMENT_DATA: + label->value = pi->dseg_addr; + break; + case SEGMENT_EEPROM: + label->value = pi->eseg_addr; + break; + } + if(pi->macro_call && !global_label) { + if(pi->macro_call->last_label) + pi->macro_call->last_label->next = label; + else + pi->macro_call->first_label = label; + pi->macro_call->last_label = label; + } else { + if(pi->last_label) + pi->last_label->next = label; + else + pi->first_label = label; + pi->last_label = label; + } + } + i++; + while(IS_HOR_SPACE(pi->fi->scratch[i]) && !IS_END_OR_COMMENT(pi->fi->scratch[i])) i++; + if(IS_END_OR_COMMENT(pi->fi->scratch[i])) { + if((pi->pass == PASS_2) && pi->list_on) { // Diff tilpassing + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + return(True); + } + strcpy(pi->fi->scratch, &pi->fi->scratch[i]); + break; + } + +#if 0 + if(pi->fi->scratch[0] == '.') { +#else + if((pi->fi->scratch[0] == '.') || (pi->fi->scratch[0] == '#')) { +#endif + pi->fi->label = label; + flag = parse_directive(pi); + if((pi->pass == PASS_2) && pi->list_on && pi->list_line) { // Diff tilpassing + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + return(flag); + } else { + return parse_mnemonic(pi); + } +} + + +/* + * Get the next token, and terminate the last one. + * Termination identifier is specified. + */ + +char *get_next_token(char *data, int term) +{ + int i = 0, j, anti_comma = False; + switch(term) { + case TERM_END: +// while(!IS_END_OR_COMMENT(data[i])) i++; Problems with 2. operand == ';' + while( ((data[i] != ',') || anti_comma) && !(((data[i] == ';') && !anti_comma) || IS_ENDLINE(data[i])) ) { + if((data[i] == '\'') || (data[i] == '"')) + anti_comma = anti_comma ? False : True; + i++; + } + break; + case TERM_SPACE: + while(!IS_HOR_SPACE(data[i]) && !IS_END_OR_COMMENT(data[i])) i++; + break; + case TERM_DASH: + while((data[i] != '-') && !IS_END_OR_COMMENT(data[i])) i++; + break; + case TERM_COLON: + while((data[i] != ':') && !IS_ENDLINE(data[i])) i++; + break; + case TERM_DOUBLEQUOTE: + while((data[i] != '"') && !IS_ENDLINE(data[i])) i++; + break; + case TERM_COMMA: + while(((data[i] != ',') || anti_comma) && !(((data[i] == ';') && !anti_comma) || IS_ENDLINE(data[i])) ) { + if((data[i] == '\'') || (data[i] == '"')) + anti_comma = anti_comma ? False : True; + i++; + } + break; + case TERM_EQUAL: + while((data[i] != '=') && !IS_END_OR_COMMENT(data[i])) i++; + break; + } + if(IS_END_OR_COMMENT(data[i])) { + data[i--] = '\0'; + while(IS_HOR_SPACE(data[i])) data[i--] = '\0'; + return(0); + } + j = i - 1; + while(IS_HOR_SPACE(data[j])) data[j--] = '\0'; + data[i++] = '\0'; + while(IS_HOR_SPACE(data[i]) && !IS_END_OR_COMMENT(data[i])) i++; + if(IS_END_OR_COMMENT(data[i])) + return(0); + return(&data[i]); +} + +/* end of parser.c */ + diff --git a/contrib/toolchain/avra/src/stab.h b/contrib/toolchain/avra/src/stab.h new file mode 100644 index 000000000..86c443e73 --- /dev/null +++ b/contrib/toolchain/avra/src/stab.h @@ -0,0 +1,114 @@ +/* @(#)stab.h 1.11 92/05/11 SMI */ +/* $Id: stab.h,v 1.2 2005/10/11 08:44:56 tobias-weber Exp $ */ +/* + * Copyright (c) 1990 by Sun Microsystems, Inc. + */ + +/* + * This file gives definitions supplementing + * for permanent symbol table entries. + * These must have one of the N_STAB bits on, + * and are subject to relocation according to the masks in . + */ + +#ifndef _STAB_H +#define _STAB_H + + +#if !defined(_a_out_h) && !defined(_A_OUT_H) +/* this file contains fragments of a.out.h and stab.h relevant to + * support of stabX processing within ELF files - see the + * Format of a symbol table entry + */ +struct nlist { + union { + char *n_name; /* for use when in-core */ + long n_strx; /* index into file string table */ + } n_un; + unsigned char n_type; /* type flag (N_TEXT,..) */ + char n_other; /* unused */ + short n_desc; /* see */ + unsigned long n_value; /* value of symbol (or sdb offset) */ +}; + +/* + * Simple values for n_type. + */ +#define N_UNDF 0x0 /* undefined */ +#define N_ABS 0x2 /* absolute */ +#define N_TEXT 0x4 /* text */ +#define N_DATA 0x6 /* data */ +#define N_BSS 0x8 /* bss */ +#define N_COMM 0x12 /* common (internal to ld) */ +#define N_FN 0x1f /* file name symbol */ + +#define N_EXT 01 /* external bit, or'ed in */ +#define N_TYPE 0x1e /* mask for all the type bits */ + +#endif + +/* + * for symbolic debugger, sdb(1): + */ +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */ +#define N_ROSYM 0x2c /* ro_data objects */ +#define N_OBJ 0x38 /* object file path or name */ +#define N_OPT 0x3c /* compiler options */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_FLINE 0x4c /* function start.end */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_ENDM 0x62 /* last stab emitted for module */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_BINCL 0x82 /* header file: name,,0,0,0 */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_EINCL 0xa2 /* end of include file */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_EXCL 0xc2 /* excluded include file */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + +/* + * for the berkeley pascal compiler, pc(1): + */ +#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */ +#define N_WITH 0xea /* pascal with statement: type,,0,0,offset */ + +/* + * for code browser only + */ +#define N_BROWS 0x48 /* path to associated .cb file */ + +/* + * Optional langauge designations for N_SO + */ +#define N_SO_AS 1 /* Assembler */ +#define N_SO_C 2 /* C */ +#define N_SO_ANSI_C 3 /* ANSI C */ +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 /* Fortran 77 */ +#define N_SO_PASCAL 6 /* Pascal */ + +/* + * Floating point type values + */ +#define NF_NONE 0 /* Undefined type */ +#define NF_SINGLE 1 /* IEEE 32 bit float */ +#define NF_DOUBLE 2 /* IEEE 64 bit float */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double */ + +#endif diff --git a/contrib/toolchain/avra/src/stdextra.c b/contrib/toolchain/avra/src/stdextra.c new file mode 100644 index 000000000..c3fdc2908 --- /dev/null +++ b/contrib/toolchain/avra/src/stdextra.c @@ -0,0 +1,191 @@ +/*********************************************************************** + * + * avra - Assembler for the Atmel AVR microcontroller series + * + * Copyright (C) 1998-2003 Jon Anders Haugum, Tobias Weber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + * Authors of avra can be reached at: + * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com + * www: http://sourceforge.net/projects/avra + */ + +/******************************************************************** + * Extra standard functions + */ + +#include +#include + +#include "misc.h" + + +/******************************************************************** + * Case insensetive strcmp() + */ + +int nocase_strcmp(char *s, char *t) +{ + int i; + + for(i = 0; tolower(s[i]) == tolower(t[i]); i++) + if(s[i] == '\0') + return(0); + return(tolower(s[i]) - tolower(t[i])); +} + + +/******************************************************************** + * Case insensetive strncmp() + */ + +int nocase_strncmp(char *s, char *t, int n) +{ + int i; + + for(i = 0; (tolower(s[i]) == tolower(t[i])); i++, n--) + if((s[i] == '\0') || (n == 1)) + return(0); + return(tolower(s[i]) - tolower(t[i])); +} + + +/******************************************************************** + * Case insensetive strstr() + */ + +char *nocase_strstr(char *s, char *t) +{ + int i = 0, j, found = False; + + while((s[i] != '\0') && !found) { + j = 0; + while(tolower(t[j]) == tolower(s[i + j])) { + j++; + if(t[j] == '\0') { + found = True; + break; + } + else if(s[i + j] == '\0') + break; + } + i++; + } + i--; + if(found) + return(&s[i]); + return(NULL); +} + + +/******************************************************************** + * ascii to hex + * ignores "0x" + */ + +int atox(char *s) +{ + int i = 0, ret = 0; + + while(s[i] != '\0') { + ret <<= 4; + if((s[i] <= 'F') && (s[i] >= 'A')) + ret |= s[i] - 'A' + 10; + else if((s[i] <= 'f') && (s[i] >= 'a')) + ret |= s[i] - 'a' + 10; + else if((s[i] <= '9') && (s[i] >= '0')) + ret |= s[i] - '0'; + i++; + } + return(ret); +} + + +/******************************************************************** + * n ascii chars to int + */ + +int atoi_n(char *s, int n) +{ + int i = 0, ret = 0; + + while((s[i] != '\0') && n) { + ret = 10 * ret + (s[i] - '0'); + i++; + n--; + } + return(ret); +} + + +/******************************************************************** + * n ascii chars to hex + * 0 < n <= 8 + * ignores "0x" + */ + +int atox_n(char *s, int n) +{ + int i = 0, ret = 0; + + while((s[i] != '\0') && n) { + ret <<= 4; + if((s[i] <= 'F') && (s[i] >= 'A')) + ret |= s[i] - 'A' + 10; + else if((s[i] <= 'f') && (s[i] >= 'a')) + ret |= s[i] - 'a' + 10; + else if((s[i] <= '9') && (s[i] >= '0')) + ret |= s[i] - '0'; + i++; + n--; + } + return(ret); +} + + +/* + * My own strlwr function since this one only exists in win + */ + +char *my_strlwr(char *in) +{ + int i; + + for(i = 0; in[i] != '\0'; i++) + in[i] = tolower(in[i]); + + return(in); +} + + +/* + * My own strupr function since this one only exists in win + */ + +char *my_strupr(char *in) +{ + int i; + + for(i = 0; in[i] != '\0'; i++) + in[i] = toupper(in[i]); + + return(in); +} + +/* stdextra.c */ +